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
- Open
BladeSmith.uprojectin UE5.6 editor - Use hot reload for C++ changes (Ctrl+F11 in editor)
- Test via "Play In Editor" (Alt+P)
- 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:
- Epic copyright header (required)
#pragma onceguard- Core UE5 headers (
CoreMinimal.hfirst) - Engine framework headers
- Project headers
- 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::vectorTMap<TKey, TValue>instead of std::mapTSet<T>instead of std::unordered_setFVector,FVector2D,FRotator,FQuatfor mathFStringfor strings (TEXT() macro for string literals)FNamefor names,FTextfor localized textfloatnot double (unless precision critical)int32not int,uint8for bytesboolfor booleans
Smart Pointers:
- Use UE5's garbage collection for UObject-derived classes
TSharedPtr<T>for non-UObject smart pointersTWeakObjectPtr<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
.hand.cppin 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