Files
BladeSmith/AGENTS.md
2026-01-21 23:21:13 +08:00

8.6 KiB

BladeSmith Agent Development Guide

Project Overview

BladeSmith is a UE5.6 C++ blacksmith simulation game featuring physics-based metal forging with GPU-accelerated compute shaders and dynamic mesh deformation.

Core Technologies:

  • Unreal Engine 5.6
  • Geometry Scripting API
  • Custom Compute Shaders (MiceShaders plugin)
  • Dynamic Mesh System
  • Enhanced Input
  • Voxel-based physics simulation

Build Commands

Building the Project

# Build game target (run from UE5 engine directory)
"C:\Program Files\Epic Games\UE_5.6\Engine\Build\BatchFiles\Build.bat" BladeSmith Win64 Development "E:\MiceCola\work\BladeSmith\BladeSmith.uproject"

# Build editor target
"C:\Program Files\Epic Games\UE_5.6\Engine\Build\BatchFiles\Build.bat" BladeSmithEditor Win64 Development "E:\MiceCola\work\BladeSmith\BladeSmith.uproject"

# Alternative: Open BladeSmith.sln in Visual Studio

Running Tests

UE5 uses the Automation System, not traditional test runners:

  • Editor: Window → Developer Tools → Automation Sessions
  • Command line: UE5Editor.exe BladeSmith.uproject -ExecCmds="Automation RunTests"
  • Single test: Run specific test class from Automation Sessions panel

Development Workflow

  1. Open BladeSmith.uproject in UE5.6 editor
  2. Use hot reload for C++ changes (Ctrl+F11 in editor)
  3. Test via "Play In Editor" (Alt+P)
  4. Use Visual Studio for compilation

Code Style Guidelines

File Structure

  • Header files (.h): Class declarations, forward declarations, USTRUCT/UCLASS definitions
  • Source files (.cpp): Implementations, includes in dependency order
  • Shader files (.usf): HLSL compute shaders in Plugins/MiceShaders/Shaders/Private/

Import Ordering

Header Files:

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ProjectModule.generated.h"

class UForwardDeclaredClass;  // Forward declarations

Source Files:

// Copyright Epic Games, Inc. All Rights Reserved.

#include "ClassName.h"
#include "SystemHeader1.h"
#include "SystemHeader2.h"

Pattern:

  1. Epic copyright header (required)
  2. #pragma once guard
  3. Core UE5 headers (CoreMinimal.h first)
  4. Engine framework headers
  5. Project headers
  6. Forward declarations (headers only)

Naming Conventions

Classes: PascalCase with UE5 prefixes

  • ABladeSmithCharacter - Actor classes (A prefix)
  • UBladeSmithWeaponComponent - Component classes (U prefix)
  • FDeformationVoxel - Structs (F prefix)
  • EGameStateEnum - Enums (E prefix)

Functions: PascalCase

public:
    void SwingHammer();
    FVector GetHammerHeadLocation() const;

private:
    void PerformHammerHit();  // Private helpers use PascalCase

Variables: camelCase

float HammerForce = 1000.0f;
FVector HammerHeadOffset;
UMaterialInstanceDynamic* DynamicMaterialInstance;
TArray<FTemperatureVoxel> TemperatureGrid;

Constants: PascalCase

const int32 MaxResolutionPerAxis = 200;
const float DefaultTemperature = 20.0f;

Formatting

Indentation: 4 spaces (no tabs) Braces: Allman style - opening brace on new line

void ABladeSmithCharacter::Move(const FInputActionValue& Value)
{
    FVector2D MovementVector = Value.Get<FVector2D>();
    // implementation
}

Line Length: Under 120 characters, wrap parameters as needed Spacing: Spaces around operators, after commas

UE5 Macros and Attributes

UPROPERTY Specifiers:

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Category")
UPropertyType* VariableName;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Category|Subcategory", meta = (ClampMin = "0.0", ClampMax = "1.0"))
float PropertyWithConstraints;

UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Category", meta = (AllowPrivateAccess = "true"))
UComponentType* PrivateComponent;

UFUNCTION Specifiers:

UFUNCTION(BlueprintCallable, Category = "Category Name")
ReturnType FunctionName(Parameters);

UFUNCTION(BlueprintImplementableEvent)
void BlueprintEventName();

USTRUCT:

USTRUCT(BlueprintType)
struct FStructName
{
    GENERATED_BODY()

    UPROPERTY()
    Type VariableName;
};

Type Annotations

UE5 Types (preferred):

  • TArray<T> instead of std::vector
  • TMap<TKey, TValue> instead of std::map
  • TSet<T> instead of std::unordered_set
  • FVector, FVector2D, FRotator, FQuat for math
  • FString for strings (TEXT() macro for string literals)
  • FName for names, FText for localized text
  • float not double (unless precision critical)
  • int32 not int, uint8 for bytes
  • bool for booleans

Smart Pointers:

  • Use UE5's garbage collection for UObject-derived classes
  • TSharedPtr<T> for non-UObject smart pointers
  • TWeakObjectPtr<T> for weak references to UObjects

Error Handling

Null Checks:

if (DynamicMeshComp == nullptr)
{
    UE_LOG(LogTemp, Error, TEXT("DynamicMeshComponent not found"));
    return;
}

Logging:

UE_LOG(LogTemp, Log, TEXT("Temperature: %.1f°C"), Temperature);        // Info
UE_LOG(LogTemp, Warning, TEXT("Temperature system disabled"));            // Warning
UE_LOG(LogTemp, Error, TEXT("Failed to initialize GPU buffers"));       // Error

Validation:

if (!IsValid(InputParam))
{
    return false;
}

// Early return pattern
if (Condition)
{
    return;
}

Documentation

Chinese Comments: Domain-specific logic uses Chinese comments

/** 锤子组件 */
/** 温度体素结构 - 存储单个体素的温度和塑性数据 */

Function Documentation:

/**
 * 函数简述
 * @param ParameterName 参数说明
 * @return 返回值说明
 */

Threading and GPU Operations

Atomic Flags:

std::atomic<bool> bGPUBuffersReady{false};

Render Thread Operations:

ENQUEUE_RENDER_COMMAND(CommandName)(
    [Params](FRHICommandListImmediate& RHICmdList)
    {
        // GPU operations here
    }
);

Component Structure Pattern

Actor Template:

UCLASS()
class BLADESMITH_API AClassName : public AParentClass
{
    GENERATED_BODY()

public:
    AClassName();

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Category")
    UComponentType* Component;

    UFUNCTION(BlueprintCallable, Category="Category")
    ReturnType PublicFunction();

protected:
    virtual void BeginPlay() override;
    virtual void Tick(float DeltaTime) override;

private:
    void PrivateHelper();
};

Module Dependencies

BladeSmith.Build.cs:

  • GeometryScriptingCore, GeometryFramework, DynamicMesh
  • GeometryCore, GeometryAlgorithms, ModelingComponents
  • RenderCore, RHI, Renderer, PhysicsCore
  • EnhancedInput, AudioExtensions, AudioMixer
  • Custom: MiceShaders (plugin)

Performance Guidelines

  • Deformation calculations: <7ms per frame target
  • 60 FPS: Maintain during hammer operations
  • High-poly meshes: ~100k vertices with GPU acceleration
  • Voxel resolution: 50x50x50 typical (balance performance/quality)
  • Use RDG (Render Dependency Graph) for GPU compute operations

Common Patterns

Material Parameters:

UMaterialInstanceDynamic* DynMaterial = UMaterialInstanceDynamic::Create(BaseMaterial, this);
DynMaterial->SetScalarParameterValue(TEXT("ParameterName"), Value);
DynMaterial->SetVectorParameterValue(TEXT("VectorParam"), FLinearColor(R,G,B,A));
DynMaterial->SetTextureParameterValue(TEXT("TextureParam"), Texture);

Dynamic Mesh Editing:

UDynamicMesh* DynMesh = DynMeshComp->GetDynamicMesh();
DynMesh->EditMesh([&](FDynamicMesh3& EditMesh)
{
    for (FVertexID VertexID : EditMesh.VertexIndicesItr())
    {
        EditMesh.SetVertex(VertexID, NewPosition);
    }
}, EDynamicMeshChangeType::GeneralEdit);

Input Binding (Enhanced Input):

if (UEnhancedInputComponent* EnhancedInput = Cast<UEnhancedInputComponent>(InputComponent))
{
    EnhancedInput->BindAction(Action, ETriggerEvent::Triggered, this, &ClassName::Handler);
}

Plugin System

MiceShaders Plugin:

  • Custom compute shaders for temperature simulation and deformation
  • Located in Plugins/MiceShaders/
  • Add new shaders: Create .h and .cpp in Source/MiceShaders, HLSL in Shaders/Private/
  • Use RDG for shader dispatch

Git Workflow

  • Ignore: Binaries/, Intermediate/, DerivedDataCache/, Saved/, .vs/, .idea/
  • Commit: Source/, Content/, Plugins/, Config/, docs/
  • No binary assets in Git (use version control for assets)

Documentation

Technical docs: Located in docs/plans/

  • Reference existing design docs before implementing new features
  • Update plans when architecture changes
  • Use markdown for design documents