Files
BallisticsDocs/docs/docs/advanced/editor-tools.md
T
2025-07-03 00:11:01 -07:00

22 KiB

Editor Tools Guide

This guide covers the specialized editor tools and workflows provided by EasyBallistics for creating and managing ballistic assets.

Asset Creation System

Ballistics Category

EasyBallistics adds a dedicated "Ballistics" category to the Content Browser asset creation menu:

  1. Right-click in Content Browser
  2. Navigate to Ballistics category
  3. Choose from available asset types:
    • Bullet Properties - Define projectile characteristics
    • Material Response Map - Configure surface interactions
    • Mathematical Material Properties - Advanced material definitions

Asset Factories

The plugin includes specialized asset factories for streamlined creation:

// Bullet Properties Factory
class FEBBulletPropertiesFactory : public UFactory
{
public:
    FEBBulletPropertiesFactory()
    {
        SupportedClass = UEBBulletPropertiesAsset::StaticClass();
        bCreateNew = true;
        bEditAfterNew = true;
    }
    
    virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, 
                                    FName Name, EObjectFlags Flags,
                                    UObject* Context, 
                                    FFeedbackContext* Warn) override
    {
        return NewObject<UEBBulletPropertiesAsset>(InParent, Class, Name, Flags);
    }
};

Physical Material Integration

Enhanced Material Editor

EasyBallistics extends the Physical Material editor with ballistic properties:

Auto-Configuration

  • Smart Detection: Automatically configures properties based on material names
  • Common Presets: Steel, wood, concrete, fabric presets
  • One-Click Setup: Generate appropriate ballistic properties instantly

Custom Properties Panel

// Custom details panel for Physical Materials
class FEBPhysicalMaterialCustomization : public IDetailCustomization
{
public:
    virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override
    {
        // Add ballistic properties section
        IDetailCategoryBuilder& BallisticsCategory = 
            DetailBuilder.EditCategory("Ballistics");
            
        // Add custom property widgets
        BallisticsCategory.AddCustomRow(LOCTEXT("CreateBallistics", "Create Ballistics"))
        .WholeRowContent()
        [
            SNew(SButton)
            .Text(LOCTEXT("CreateNew", "Create New Ballistic Properties"))
            .OnClicked(this, &FEBPhysicalMaterialCustomization::OnCreateNewClicked)
        ];
    }
};

Material Property Creation

Automatic Property Generation

// Auto-generate properties based on material name
UEBMaterialPropertiesAsset* AutoGenerateProperties(UPhysicalMaterial* PhysMat)
{
    FString MaterialName = PhysMat->GetName().ToLower();
    
    if (MaterialName.Contains("steel") || MaterialName.Contains("metal"))
    {
        return CreateSteelProperties();
    }
    else if (MaterialName.Contains("wood"))
    {
        return CreateWoodProperties();
    }
    else if (MaterialName.Contains("concrete"))
    {
        return CreateConcreteProperties();
    }
    
    return CreateDefaultProperties();
}

Property Templates

// Steel template
FMathematicalMaterialProperties CreateSteelProperties()
{
    FMathematicalMaterialProperties Props;
    Props.DensityGPerCm3 = 7.85f;
    Props.MaterialHardness = 200.0f;
    Props.TensileStrengthMPa = 400.0f;
    Props.BallisticLimitVelocity = 800.0f;
    return Props;
}

// Wood template
FMathematicalMaterialProperties CreateWoodProperties()
{
    FMathematicalMaterialProperties Props;
    Props.DensityGPerCm3 = 0.6f;
    Props.MaterialHardness = 20.0f;
    Props.TensileStrengthMPa = 50.0f;
    Props.BallisticLimitVelocity = 300.0f;
    return Props;
}

Asset Type Actions

Bullet Properties Actions

class FEBBulletPropertiesActions : public FAssetTypeActions_Base
{
public:
    virtual FText GetName() const override 
    { 
        return NSLOCTEXT("AssetTypeActions", "EBBulletProperties", "Bullet Properties"); 
    }
    
    virtual FColor GetTypeColor() const override 
    { 
        return FColor(255, 196, 128); // Orange theme
    }
    
    virtual UClass* GetSupportedClass() const override 
    { 
        return UEBBulletPropertiesAsset::StaticClass(); 
    }
    
    virtual uint32 GetCategories() override 
    { 
        return EAssetTypeCategories::Gameplay; 
    }
    
    virtual void GetActions(const TArray<UObject*>& InObjects, 
                           FMenuBuilder& MenuBuilder) override
    {
        MenuBuilder.AddMenuEntry(
            LOCTEXT("BulletProperties_CreateMaterial", "Create Material Response Map"),
            LOCTEXT("BulletProperties_CreateMaterialTooltip", "Creates a new Material Response Map for this bullet type"),
            FSlateIcon(),
            FUIAction(FExecuteAction::CreateSP(this, &FEBBulletPropertiesActions::ExecuteCreateMaterialMap, InObjects))
        );
    }
};

Material Response Map Actions

class FEBMaterialResponseMapActions : public FAssetTypeActions_Base
{
public:
    virtual FText GetName() const override 
    { 
        return NSLOCTEXT("AssetTypeActions", "EBMaterialResponseMap", "Material Response Map"); 
    }
    
    virtual void GetActions(const TArray<UObject*>& InObjects, 
                           FMenuBuilder& MenuBuilder) override
    {
        MenuBuilder.AddMenuEntry(
            LOCTEXT("MaterialMap_PopulateCommon", "Populate Common Materials"),
            LOCTEXT("MaterialMap_PopulateCommonTooltip", "Adds entries for common materials"),
            FSlateIcon(),
            FUIAction(FExecuteAction::CreateSP(this, &FEBMaterialResponseMapActions::ExecutePopulateCommon, InObjects))
        );
    }
};

Custom Property Editors

Bullet Properties Editor

// Custom property widget for ballistic coefficient
class SEBBallisticCoefficientWidget : public SCompoundWidget
{
public:
    SLATE_BEGIN_ARGS(SEBBallisticCoefficientWidget) {}
        SLATE_ATTRIBUTE(float, G1Value)
        SLATE_ATTRIBUTE(float, G7Value)
        SLATE_ATTRIBUTE(bool, UseG7)
    SLATE_END_ARGS()
    
    void Construct(const FArguments& InArgs)
    {
        ChildSlot
        [
            SNew(SVerticalBox)
            + SVerticalBox::Slot()
            .AutoHeight()
            [
                SNew(SHorizontalBox)
                + SHorizontalBox::Slot()
                [
                    SNew(STextBlock)
                    .Text(LOCTEXT("G1BC", "G1 BC:"))
                ]
                + SHorizontalBox::Slot()
                [
                    SNew(SSpinBox<float>)
                    .Value(InArgs._G1Value)
                    .MinValue(0.001f)
                    .MaxValue(2.0f)
                    .Delta(0.001f)
                ]
            ]
            // Add G7 section...
        ];
    }
};

Material Response Map Editor

// Custom editor for material response entries
class FEBMaterialResponseMapDetails : public IDetailCustomization
{
public:
    virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override
    {
        TSharedRef<IPropertyHandle> MapProperty = 
            DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UEBMaterialResponseMap, Map));
            
        IDetailCategoryBuilder& MapCategory = 
            DetailBuilder.EditCategory("Material Responses");
            
        // Custom array widget with material picker
        MapCategory.AddCustomRow(LOCTEXT("MaterialEntries", "Material Entries"))
        .WholeRowContent()
        [
            CreateMaterialMapWidget(MapProperty)
        ];
    }
    
private:
    TSharedRef<SWidget> CreateMaterialMapWidget(TSharedRef<IPropertyHandle> PropertyHandle)
    {
        return SNew(SVerticalBox)
            + SVerticalBox::Slot()
            [
                // Material picker + response settings
                CreateEntryWidget()
            ];
    }
};

Debug Visualization Tools

Editor Debug Panel

// Custom editor panel for ballistics debugging
class SEBDebugPanel : public SCompoundWidget
{
public:
    SLATE_BEGIN_ARGS(SEBDebugPanel) {}
    SLATE_END_ARGS()
    
    void Construct(const FArguments& InArgs)
    {
        ChildSlot
        [
            SNew(SVerticalBox)
            
            // Bullet visualization controls
            + SVerticalBox::Slot()
            .AutoHeight()
            [
                SNew(SCheckBox)
                .Content()
                [
                    SNew(STextBlock)
                    .Text(LOCTEXT("ShowTrajectories", "Show Bullet Trajectories"))
                ]
                .OnCheckStateChanged(this, &SEBDebugPanel::OnShowTrajectoriesChanged)
            ]
            
            // Performance metrics
            + SVerticalBox::Slot()
            .AutoHeight()
            [
                SNew(STextBlock)
                .Text(this, &SEBDebugPanel::GetPerformanceText)
            ]
        ];
    }
    
private:
    FText GetPerformanceText() const
    {
        int32 ActiveBullets = GetActiveBulletCount();
        float MemoryUsage = GetMemoryUsage();
        
        return FText::Format(
            LOCTEXT("PerformanceStats", "Active Bullets: {0}\nMemory: {1} MB"),
            ActiveBullets,
            MemoryUsage
        );
    }
};

Viewport Debug Rendering

// Custom viewport client for ballistics debugging
class FEBDebugViewportClient : public FEditorViewportClient
{
public:
    virtual void Draw(const FSceneView* View, FPrimitiveDrawInterface* PDI) override
    {
        FEditorViewportClient::Draw(View, PDI);
        
        if (bShowBulletTrajectories)
        {
            DrawBulletTrajectories(PDI);
        }
        
        if (bShowImpactAnalysis)
        {
            DrawImpactAnalysis(PDI);
        }
    }
    
private:
    void DrawBulletTrajectories(FPrimitiveDrawInterface* PDI)
    {
        for (const auto& Bullet : GetActiveBullets())
        {
            TArray<FVector> Trajectory = PredictTrajectory(Bullet);
            
            for (int32 i = 0; i < Trajectory.Num() - 1; i++)
            {
                PDI->DrawLine(Trajectory[i], Trajectory[i + 1], 
                             FColor::Green, SDPG_World, 2.0f);
            }
        }
    }
};

Asset Browser Integration

Thumbnail Renderer

// Custom thumbnail renderer for bullet properties
class UEBBulletPropertiesThumbnailRenderer : public UDefaultSizedThumbnailRenderer
{
public:
    virtual void Draw(UObject* Object, int32 X, int32 Y, uint32 Width, uint32 Height, 
                     FRenderTarget* RenderTarget, FCanvas* Canvas, bool bAdditionalViewFamily) override
    {
        UEBBulletPropertiesAsset* BulletProps = Cast<UEBBulletPropertiesAsset>(Object);
        if (!BulletProps)
            return;
            
        // Draw bullet icon/diagram
        DrawBulletThumbnail(Canvas, BulletProps, X, Y, Width, Height);
    }
    
private:
    void DrawBulletThumbnail(FCanvas* Canvas, UEBBulletPropertiesAsset* Props, 
                           int32 X, int32 Y, uint32 Width, uint32 Height)
    {
        // Draw bullet shape based on properties
        FCanvasBoxItem BulletBox(FVector2D(X + Width * 0.2f, Y + Height * 0.3f),
                                FVector2D(Width * 0.6f, Height * 0.4f));
        BulletBox.SetColor(FColor::Brass);
        Canvas->DrawItem(BulletBox);
        
        // Add caliber text
        FString CaliberText = FString::Printf(TEXT("%.3f\""), Props->DiameterInches);
        FCanvasTextItem TextItem(FVector2D(X + 5, Y + Height - 15), 
                               FText::FromString(CaliberText), 
                               GEngine->GetSmallFont(), FColor::White);
        Canvas->DrawItem(TextItem);
    }
};

Asset Details Customization

// Enhanced details panel for bullet properties
class FEBBulletPropertiesCustomization : public IDetailCustomization
{
public:
    virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override
    {
        // Add ballistic calculator section
        IDetailCategoryBuilder& CalculatorCategory = 
            DetailBuilder.EditCategory("Ballistic Calculator");
            
        CalculatorCategory.AddCustomRow(LOCTEXT("Calculator", "Calculator"))
        .WholeRowContent()
        [
            SNew(SVerticalBox)
            + SVerticalBox::Slot()
            [
                CreateBallisticCalculator()
            ]
        ];
    }
    
private:
    TSharedRef<SWidget> CreateBallisticCalculator()
    {
        return SNew(SExpandableArea)
            .AreaTitle(LOCTEXT("BallisticCalc", "Ballistic Calculator"))
            .InitiallyCollapsed(true)
            .BodyContent()
            [
                SNew(SVerticalBox)
                + SVerticalBox::Slot()
                [
                    SNew(SHorizontalBox)
                    + SHorizontalBox::Slot()
                    [
                        SNew(STextBlock)
                        .Text(LOCTEXT("SectionalDensity", "Sectional Density:"))
                    ]
                    + SHorizontalBox::Slot()
                    [
                        SNew(STextBlock)
                        .Text(this, &FEBBulletPropertiesCustomization::GetSectionalDensityText)
                    ]
                ]
                // Add more calculated values...
            ];
    }
};

Workflow Tools

Batch Asset Operations

// Batch operations for ballistic assets
class FEBAssetBatchOperations
{
public:
    // Update all bullet properties with new mathematical model
    static void UpdateAllBulletProperties()
    {
        TArray<UEBBulletPropertiesAsset*> AllBulletAssets;
        FindAllAssetsOfClass(AllBulletAssets);
        
        for (auto* Asset : AllBulletAssets)
        {
            UpdateBulletPropertiesFormulas(Asset);
            Asset->MarkPackageDirty();
        }
    }
    
    // Validate all material response maps
    static void ValidateAllMaterialMaps()
    {
        TArray<UEBMaterialResponseMap*> AllMaps;
        FindAllAssetsOfClass(AllMaps);
        
        for (auto* Map : AllMaps)
        {
            ValidateMaterialMap(Map);
        }
    }
    
private:
    template<typename T>
    static void FindAllAssetsOfClass(TArray<T*>& OutAssets)
    {
        FAssetRegistryModule& AssetRegistryModule = 
            FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
            
        TArray<FAssetData> AssetData;
        AssetRegistryModule.Get().GetAssetsByClass(T::StaticClass()->GetFName(), AssetData);
        
        for (const auto& Asset : AssetData)
        {
            if (T* LoadedAsset = Cast<T>(Asset.GetAsset()))
            {
                OutAssets.Add(LoadedAsset);
            }
        }
    }
};

Import/Export Tools

// CSV import/export for bullet properties
class FEBDataImportExport
{
public:
    // Export bullet properties to CSV
    static void ExportBulletPropertiesToCSV(const TArray<UEBBulletPropertiesAsset*>& Assets, 
                                           const FString& FilePath)
    {
        FString CSV = TEXT("Name,GrainWeight,DiameterInches,LengthInches,BCG1,BCG7\n");
        
        for (const auto* Asset : Assets)
        {
            CSV += FString::Printf(TEXT("%s,%.1f,%.3f,%.3f,%.3f,%.3f\n"),
                *Asset->GetName(),
                Asset->GrainWeight,
                Asset->DiameterInches,
                Asset->LengthInches,
                Asset->BallisticCoefficientG1,
                Asset->BallisticCoefficientG7
            );
        }
        
        FFileHelper::SaveStringToFile(CSV, *FilePath);
    }
    
    // Import bullet properties from CSV
    static TArray<UEBBulletPropertiesAsset*> ImportBulletPropertiesFromCSV(const FString& FilePath)
    {
        TArray<UEBBulletPropertiesAsset*> CreatedAssets;
        
        FString FileContent;
        if (!FFileHelper::LoadFileToString(FileContent, *FilePath))
        {
            return CreatedAssets;
        }
        
        TArray<FString> Lines;
        FileContent.ParseIntoArrayLines(Lines);
        
        // Skip header line
        for (int32 i = 1; i < Lines.Num(); i++)
        {
            UEBBulletPropertiesAsset* Asset = CreateAssetFromCSVLine(Lines[i]);
            if (Asset)
            {
                CreatedAssets.Add(Asset);
            }
        }
        
        return CreatedAssets;
    }
};

Content Browser Extensions

Custom Content Browser Columns

// Add custom columns for ballistic assets
class FEBContentBrowserExtensions
{
public:
    static void RegisterColumns()
    {
        FContentBrowserModule& ContentBrowserModule = 
            FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser");
            
        // Add caliber column for bullet properties
        ContentBrowserModule.GetAllAssetViewContextMenuExtenders().Add(
            FContentBrowserMenuExtender_SelectedAssets::CreateStatic(
                &FEBContentBrowserExtensions::OnExtendContentBrowserAssetSelectionMenu));
    }
    
private:
    static TSharedRef<FExtender> OnExtendContentBrowserAssetSelectionMenu(
        const TArray<FAssetData>& SelectedAssets)
    {
        TSharedRef<FExtender> Extender = MakeShared<FExtender>();
        
        if (SelectedAssets.Num() > 0 && 
            SelectedAssets[0].AssetClass == UEBBulletPropertiesAsset::StaticClass()->GetFName())
        {
            Extender->AddMenuExtension(
                "CommonAssetActions",
                EExtensionHook::After,
                nullptr,
                FMenuExtensionDelegate::CreateStatic(&FEBContentBrowserExtensions::CreateBulletPropertiesMenu)
            );
        }
        
        return Extender;
    }
    
    static void CreateBulletPropertiesMenu(FMenuBuilder& MenuBuilder)
    {
        MenuBuilder.AddMenuEntry(
            LOCTEXT("ExportToCSV", "Export to CSV"),
            LOCTEXT("ExportToCSVTooltip", "Export bullet properties to CSV file"),
            FSlateIcon(),
            FUIAction(FExecuteAction::CreateStatic(&FEBContentBrowserExtensions::ExportToCSV))
        );
    }
};

Editor Preferences

Plugin Settings

// Settings panel for EasyBallistics editor tools
UCLASS(config=EditorPerProjectUserSettings)
class EASYBALLISTICSEDITOR_API UEBEditorSettings : public UObject
{
    GENERATED_BODY()
    
public:
    UEBEditorSettings()
    {
        bShowDebugVisualization = true;
        bAutoGenerateMaterialProperties = true;
        DefaultBulletMaterial = EBulletMaterial::CopperJacket;
    }
    
    // Debug visualization options
    UPROPERTY(EditAnywhere, config, Category = "Debug", 
              meta = (ToolTip = "Show trajectory visualization in viewport"))
    bool bShowDebugVisualization;
    
    UPROPERTY(EditAnywhere, config, Category = "Debug")
    FColor TrajectoryColor = FColor::Green;
    
    UPROPERTY(EditAnywhere, config, Category = "Debug")
    float TrajectoryThickness = 2.0f;
    
    // Asset creation defaults
    UPROPERTY(EditAnywhere, config, Category = "Asset Creation")
    bool bAutoGenerateMaterialProperties;
    
    UPROPERTY(EditAnywhere, config, Category = "Asset Creation")
    EBulletMaterial DefaultBulletMaterial;
    
    UPROPERTY(EditAnywhere, config, Category = "Asset Creation")
    EBulletType DefaultBulletType;
};

Settings Registration

// Register settings with editor
void FEasyBallisticsEditorModule::RegisterSettings()
{
    if (ISettingsModule* SettingsModule = FModuleManager::GetModulePtr<ISettingsModule>("Settings"))
    {
        SettingsModule->RegisterSettings("Project", "Plugins", "EasyBallistics",
            LOCTEXT("RuntimeSettingsName", "EasyBallistics"),
            LOCTEXT("RuntimeSettingsDescription", "Configure EasyBallistics plugin"),
            GetMutableDefault<UEBEditorSettings>()
        );
    }
}

Best Practices

Asset Organization

  1. Consistent Naming: Use clear, descriptive names for ballistic assets
  2. Folder Structure: Organize by caliber, weapon type, or material category
  3. Version Control: Use proper check-in practices for shared assets
  4. Documentation: Add descriptions to asset properties

Performance in Editor

  1. Disable Debug Visualization: Turn off when not needed
  2. Limit Asset Count: Don't load too many ballistic assets simultaneously
  3. Use Asset References: Prefer soft references in editor tools
  4. Profile Editor Tools: Monitor performance of custom panels

Workflow Optimization

  1. Template Assets: Create template assets for common configurations
  2. Batch Operations: Use batch tools for large-scale updates
  3. Validation Tools: Implement asset validation for quality assurance
  4. Import/Export: Use CSV tools for external data integration

Troubleshooting Editor Issues

Common Problems

Issue Solution
Custom panels not appearing Check module dependencies and registration
Asset thumbnails not showing Verify thumbnail renderer registration
Properties not saving Ensure MarkPackageDirty() is called
Performance issues Disable debug features, optimize custom widgets

Debug Tools

  • Use Output Log to monitor editor messages
  • Enable Developer Tools for additional debugging
  • Check Asset Registry for asset loading issues
  • Profile with Unreal Insights for performance analysis

Next Steps


For more editor customization examples, see the UE5 Editor Extension Documentation.