Update
This commit is contained in:
@@ -0,0 +1,787 @@
|
||||
#include "DismembermentGraph/DismembermentPreviewManager.h"
|
||||
#include "DismembermentGraph/DismembermentGraphNode.h"
|
||||
#include "DismembermentGraph/DismembermentGraphNodeCut.h"
|
||||
#include "DismembermentGraph/DismembermentGraphNodeBoneSelect.h"
|
||||
#include "DismembermentGraph/DismembermentGraphNodeBloodEffect.h"
|
||||
#include "DismembermentGraph/DismembermentGraphNodePhysics.h"
|
||||
#include "DismembermentGraph/DismembermentGraphNodeOrgan.h"
|
||||
#include "DismembermentGraph/DismembermentGraphNodeWound.h"
|
||||
#include "Components/SkeletalMeshComponent.h"
|
||||
#include "Components/StaticMeshComponent.h"
|
||||
#include "Components/DecalComponent.h"
|
||||
#include "NiagaraComponent.h"
|
||||
#include "NiagaraSystem.h"
|
||||
#include "Engine/StaticMesh.h"
|
||||
#include "Materials/MaterialInterface.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "Engine/World.h"
|
||||
|
||||
// Define log category
|
||||
DEFINE_LOG_CATEGORY(LogFLESHPreview);
|
||||
|
||||
UDismembermentPreviewManager::UDismembermentPreviewManager()
|
||||
: World(nullptr)
|
||||
, TargetActor(nullptr)
|
||||
, TargetSkeletalMesh(nullptr)
|
||||
, PreviewedNode(nullptr)
|
||||
, PreviewCutPlaneMesh(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void UDismembermentPreviewManager::Initialize(TObjectPtr<UWorld> InWorld)
|
||||
{
|
||||
World = InWorld;
|
||||
UE_LOG(LogFLESHPreview, Log, TEXT("Preview manager initialized"));
|
||||
}
|
||||
|
||||
void UDismembermentPreviewManager::Cleanup()
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Log, TEXT("Cleaning up preview manager"));
|
||||
ClearPreview();
|
||||
World = nullptr;
|
||||
TargetActor = nullptr;
|
||||
TargetSkeletalMesh = nullptr;
|
||||
}
|
||||
|
||||
void UDismembermentPreviewManager::SetTargetActor(TObjectPtr<AActor> InActor)
|
||||
{
|
||||
// Clear any existing preview
|
||||
ClearPreview();
|
||||
|
||||
// Set the new target actor
|
||||
TargetActor = InActor;
|
||||
|
||||
if (TargetActor)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Log, TEXT("Set target actor: %s"), *TargetActor->GetName());
|
||||
// Find the skeletal mesh component
|
||||
FindTargetSkeletalMesh();
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Set empty target actor"));
|
||||
}
|
||||
}
|
||||
|
||||
bool UDismembermentPreviewManager::PreviewNode(TObjectPtr<UDismembermentGraphNode> Node)
|
||||
{
|
||||
// Clear any existing preview
|
||||
ClearPreview();
|
||||
|
||||
// Set the new previewed node
|
||||
PreviewedNode = Node;
|
||||
|
||||
// Check if we have a valid target
|
||||
if (!TargetActor || !TargetSkeletalMesh)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot preview node: Invalid target actor or skeletal mesh"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Node)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot preview node: Node is null"));
|
||||
return false;
|
||||
}
|
||||
|
||||
UE_LOG(LogFLESHPreview, Log, TEXT("Previewing node: %s"), *Node->GetNodeTitle(ENodeTitleType::FullTitle).ToString());
|
||||
|
||||
// Preview based on node type
|
||||
if (TObjectPtr<UDismembermentGraphNodeCut> CutNode = Cast<UDismembermentGraphNodeCut>(Node))
|
||||
{
|
||||
return PreviewCutNode(CutNode);
|
||||
}
|
||||
else if (TObjectPtr<UDismembermentGraphNodeBoneSelect> BoneSelectNode = Cast<UDismembermentGraphNodeBoneSelect>(Node))
|
||||
{
|
||||
return PreviewBoneSelectNode(BoneSelectNode);
|
||||
}
|
||||
else if (TObjectPtr<UDismembermentGraphNodeBloodEffect> BloodEffectNode = Cast<UDismembermentGraphNodeBloodEffect>(Node))
|
||||
{
|
||||
return PreviewBloodEffectNode(BloodEffectNode);
|
||||
}
|
||||
else if (TObjectPtr<UDismembermentGraphNodePhysics> PhysicsNode = Cast<UDismembermentGraphNodePhysics>(Node))
|
||||
{
|
||||
return PreviewPhysicsNode(PhysicsNode);
|
||||
}
|
||||
else if (TObjectPtr<UDismembermentGraphNodeOrgan> OrganNode = Cast<UDismembermentGraphNodeOrgan>(Node))
|
||||
{
|
||||
return PreviewOrganNode(OrganNode);
|
||||
}
|
||||
else if (TObjectPtr<UDismembermentGraphNodeWound> WoundNode = Cast<UDismembermentGraphNodeWound>(Node))
|
||||
{
|
||||
return PreviewWoundNode(WoundNode);
|
||||
}
|
||||
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Unknown node type"));
|
||||
return false;
|
||||
}
|
||||
|
||||
void UDismembermentPreviewManager::ClearPreview()
|
||||
{
|
||||
// Clear the previewed node
|
||||
PreviewedNode = nullptr;
|
||||
|
||||
// Clear all preview components
|
||||
ClearPreviewComponents();
|
||||
|
||||
// Clear preview data
|
||||
PreviewBoneSelections.Empty();
|
||||
PreviewCutTransforms.Empty();
|
||||
PreviewBloodEffectTransforms.Empty();
|
||||
PreviewOrganTransforms.Empty();
|
||||
PreviewWoundTransforms.Empty();
|
||||
|
||||
UE_LOG(LogFLESHPreview, Verbose, TEXT("Preview cleared"));
|
||||
}
|
||||
|
||||
void UDismembermentPreviewManager::Tick(float DeltaTime)
|
||||
{
|
||||
// Update preview effects
|
||||
if (PreviewedNode && TargetActor && TargetSkeletalMesh)
|
||||
{
|
||||
// Update based on node type
|
||||
if (UDismembermentGraphNodeCut* CutNode = Cast<UDismembermentGraphNodeCut>(PreviewedNode))
|
||||
{
|
||||
// Update cut preview
|
||||
}
|
||||
else if (UDismembermentGraphNodeBloodEffect* BloodEffectNode = Cast<UDismembermentGraphNodeBloodEffect>(PreviewedNode))
|
||||
{
|
||||
// Update blood effect preview
|
||||
}
|
||||
else if (UDismembermentGraphNodePhysics* PhysicsNode = Cast<UDismembermentGraphNodePhysics>(PreviewedNode))
|
||||
{
|
||||
// Update physics preview
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool UDismembermentPreviewManager::FindTargetSkeletalMesh()
|
||||
{
|
||||
TargetSkeletalMesh = nullptr;
|
||||
|
||||
if (TargetActor)
|
||||
{
|
||||
// Find the first skeletal mesh component
|
||||
TargetSkeletalMesh = TargetActor->FindComponentByClass<USkeletalMeshComponent>();
|
||||
|
||||
if (TargetSkeletalMesh)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Log, TEXT("Found target skeletal mesh: %s"), *TargetSkeletalMesh->GetName());
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("No skeletal mesh component found on actor %s"), *TargetActor->GetName());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot find skeletal mesh: Target actor is null"));
|
||||
}
|
||||
|
||||
return TargetSkeletalMesh != nullptr;
|
||||
}
|
||||
|
||||
bool UDismembermentPreviewManager::PreviewCutNode(TObjectPtr<UDismembermentGraphNodeCut> CutNode)
|
||||
{
|
||||
if (!CutNode || !TargetActor || !TargetSkeletalMesh)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot preview cut node: Invalid parameters"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the cut parameters
|
||||
float CutWidth = CutNode->CutWidth;
|
||||
float CutDepth = CutNode->CutDepth;
|
||||
UMaterialInterface* CutMaterial = CutNode->bUseCustomMaterial ? CutNode->CustomCutMaterial : nullptr;
|
||||
|
||||
// Get the actor's transform
|
||||
FTransform ActorTransform = TargetActor->GetActorTransform();
|
||||
|
||||
// Create a default cut direction if not connected to an input
|
||||
FVector CutLocation = ActorTransform.GetLocation() + FVector(0.0f, 0.0f, 100.0f);
|
||||
FVector CutDirection = FVector(1.0f, 0.0f, 0.0f);
|
||||
|
||||
// Create the preview cut plane mesh
|
||||
PreviewCutPlaneMesh = CreatePreviewCutPlaneMesh(CutLocation, CutDirection, CutWidth, CutDepth, CutMaterial);
|
||||
|
||||
if (!PreviewCutPlaneMesh)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Error, TEXT("Failed to create cut plane mesh"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the cut transform for later use
|
||||
FTransform CutTransform;
|
||||
CutTransform.SetLocation(CutLocation);
|
||||
CutTransform.SetRotation(FQuat::MakeFromX(CutDirection));
|
||||
CutTransform.SetScale3D(FVector(CutWidth, CutDepth, 1.0f));
|
||||
PreviewCutTransforms.Add(CutTransform);
|
||||
|
||||
UE_LOG(LogFLESHPreview, Log, TEXT("Cut node preview created successfully"));
|
||||
|
||||
return PreviewCutPlaneMesh != nullptr;
|
||||
}
|
||||
|
||||
bool UDismembermentPreviewManager::PreviewBoneSelectNode(TObjectPtr<UDismembermentGraphNodeBoneSelect> BoneSelectNode)
|
||||
{
|
||||
if (!BoneSelectNode || !TargetActor || !TargetSkeletalMesh)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot preview bone select node: Invalid parameters"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the bone selection parameters
|
||||
TArray<FName> BoneNames = BoneSelectNode->BoneNames;
|
||||
bool bUseRegex = BoneSelectNode->bUseRegex;
|
||||
FString BoneNamePattern = BoneSelectNode->BoneNamePattern;
|
||||
bool bIncludeChildren = BoneSelectNode->bIncludeChildren;
|
||||
|
||||
// Store the bone selections for later use
|
||||
PreviewBoneSelections.Append(BoneNames);
|
||||
|
||||
UE_LOG(LogFLESHPreview, Log, TEXT("Bone select node preview created successfully, selected %d bones"), BoneNames.Num());
|
||||
|
||||
// TODO: Handle regex and child bones
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UDismembermentPreviewManager::PreviewBloodEffectNode(TObjectPtr<UDismembermentGraphNodeBloodEffect> BloodEffectNode)
|
||||
{
|
||||
if (!BloodEffectNode || !TargetActor || !TargetSkeletalMesh)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot preview blood effect node: Invalid parameters"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the blood effect parameters
|
||||
UNiagaraSystem* BloodEffect = BloodEffectNode->BloodEffect;
|
||||
float BloodAmount = BloodEffectNode->BloodAmount;
|
||||
float BloodPressure = BloodEffectNode->BloodPressure;
|
||||
bool bCreateBloodPool = BloodEffectNode->bCreateBloodPool;
|
||||
float BloodPoolSize = BloodEffectNode->BloodPoolSize;
|
||||
UMaterialInterface* BloodPoolMaterial = BloodEffectNode->BloodPoolMaterial;
|
||||
|
||||
if (!BloodEffect)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot preview blood effect: No blood effect system specified"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the actor's transform
|
||||
FTransform ActorTransform = TargetActor->GetActorTransform();
|
||||
|
||||
// Create a default blood effect location if not connected to an input
|
||||
FVector BloodLocation = ActorTransform.GetLocation() + FVector(0.0f, 0.0f, 100.0f);
|
||||
|
||||
// Create the preview blood effect
|
||||
TObjectPtr<UNiagaraComponent> BloodEffectComponent = CreatePreviewBloodEffect(BloodLocation, BloodEffect, BloodAmount, BloodPressure);
|
||||
|
||||
if (!BloodEffectComponent)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Error, TEXT("Failed to create blood effect component"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the preview blood pool if needed
|
||||
TObjectPtr<UDecalComponent> BloodPoolComponent = nullptr;
|
||||
if (bCreateBloodPool)
|
||||
{
|
||||
BloodPoolComponent = CreatePreviewBloodPool(BloodLocation, BloodPoolSize, BloodPoolMaterial);
|
||||
|
||||
if (!BloodPoolComponent)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Failed to create blood pool component"));
|
||||
}
|
||||
}
|
||||
|
||||
// Store the blood effect transform for later use
|
||||
FTransform BloodEffectTransform;
|
||||
BloodEffectTransform.SetLocation(BloodLocation);
|
||||
PreviewBloodEffectTransforms.Add(BloodEffectTransform);
|
||||
|
||||
UE_LOG(LogFLESHPreview, Log, TEXT("Blood effect node preview created successfully"));
|
||||
|
||||
return BloodEffectComponent != nullptr;
|
||||
}
|
||||
|
||||
bool UDismembermentPreviewManager::PreviewPhysicsNode(TObjectPtr<UDismembermentGraphNodePhysics> PhysicsNode)
|
||||
{
|
||||
if (!PhysicsNode || !TargetActor || !TargetSkeletalMesh)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot preview physics node: Invalid parameters"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the physics parameters
|
||||
float Mass = PhysicsNode->Mass;
|
||||
float LinearDamping = PhysicsNode->LinearDamping;
|
||||
float AngularDamping = PhysicsNode->AngularDamping;
|
||||
bool bEnableGravity = PhysicsNode->bEnableGravity;
|
||||
bool bSimulatePhysics = PhysicsNode->bSimulatePhysics;
|
||||
bool bGenerateOverlapEvents = PhysicsNode->bGenerateOverlapEvents;
|
||||
UPhysicalMaterial* PhysicalMaterial = PhysicsNode->PhysicalMaterial;
|
||||
float ImpulseForce = PhysicsNode->ImpulseForce;
|
||||
float ImpulseRadius = PhysicsNode->ImpulseRadius;
|
||||
|
||||
// Apply physics settings to the target skeletal mesh
|
||||
if (TargetSkeletalMesh)
|
||||
{
|
||||
// Store original values to restore later
|
||||
TargetSkeletalMesh->SetMassOverrideInKg(NAME_None, Mass, true);
|
||||
TargetSkeletalMesh->SetLinearDamping(LinearDamping);
|
||||
TargetSkeletalMesh->SetAngularDamping(AngularDamping);
|
||||
TargetSkeletalMesh->SetEnableGravity(bEnableGravity);
|
||||
TargetSkeletalMesh->SetSimulatePhysics(bSimulatePhysics);
|
||||
TargetSkeletalMesh->SetGenerateOverlapEvents(bGenerateOverlapEvents);
|
||||
|
||||
if (PhysicalMaterial)
|
||||
{
|
||||
TargetSkeletalMesh->SetPhysMaterialOverride(PhysicalMaterial);
|
||||
}
|
||||
|
||||
UE_LOG(LogFLESHPreview, Log, TEXT("Physics node preview applied successfully, mass: %.2f, linear damping: %.2f, angular damping: %.2f"),
|
||||
Mass, LinearDamping, AngularDamping);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UDismembermentPreviewManager::PreviewOrganNode(TObjectPtr<UDismembermentGraphNodeOrgan> OrganNode)
|
||||
{
|
||||
if (!OrganNode || !TargetActor || !TargetSkeletalMesh)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot preview organ node: Invalid parameters"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the organ parameters
|
||||
UStaticMesh* OrganMesh = OrganNode->OrganMesh;
|
||||
UMaterialInterface* OrganMaterial = OrganNode->OrganMaterial;
|
||||
FName AttachBoneName = OrganNode->AttachBoneName;
|
||||
FVector RelativeLocation = OrganNode->RelativeLocation;
|
||||
FRotator RelativeRotation = OrganNode->RelativeRotation;
|
||||
FVector RelativeScale = OrganNode->RelativeScale;
|
||||
bool bSimulatePhysics = OrganNode->bSimulatePhysics;
|
||||
float DamageMultiplier = OrganNode->DamageMultiplier;
|
||||
bool bIsCriticalOrgan = OrganNode->bIsCriticalOrgan;
|
||||
float BloodAmount = OrganNode->BloodAmount;
|
||||
|
||||
if (!OrganMesh)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot preview organ: No organ mesh specified"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the preview organ
|
||||
TObjectPtr<UStaticMeshComponent> OrganComponent = CreatePreviewOrgan(OrganMesh, OrganMaterial, AttachBoneName, RelativeLocation, RelativeRotation, RelativeScale);
|
||||
|
||||
if (!OrganComponent)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Error, TEXT("Failed to create organ component"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the organ transform for later use
|
||||
FTransform OrganTransform;
|
||||
if (TargetSkeletalMesh && !AttachBoneName.IsNone())
|
||||
{
|
||||
FTransform BoneTransform = TargetSkeletalMesh->GetBoneTransform(TargetSkeletalMesh->GetBoneIndex(AttachBoneName));
|
||||
OrganTransform = FTransform(RelativeRotation, RelativeLocation, RelativeScale) * BoneTransform;
|
||||
}
|
||||
else
|
||||
{
|
||||
OrganTransform = FTransform(RelativeRotation, RelativeLocation, RelativeScale) * TargetActor->GetActorTransform();
|
||||
}
|
||||
PreviewOrganTransforms.Add(OrganTransform);
|
||||
|
||||
UE_LOG(LogFLESHPreview, Log, TEXT("Organ node preview created successfully, attached to bone: %s"),
|
||||
AttachBoneName.IsNone() ? TEXT("None") : *AttachBoneName.ToString());
|
||||
|
||||
return OrganComponent != nullptr;
|
||||
}
|
||||
|
||||
bool UDismembermentPreviewManager::PreviewWoundNode(TObjectPtr<UDismembermentGraphNodeWound> WoundNode)
|
||||
{
|
||||
if (!WoundNode || !TargetActor || !TargetSkeletalMesh)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot preview wound node: Invalid parameters"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the wound parameters
|
||||
float WoundSize = WoundNode->WoundSize;
|
||||
float WoundDepth = WoundNode->WoundDepth;
|
||||
UMaterialInterface* WoundMaterial = WoundNode->WoundMaterial;
|
||||
UNiagaraSystem* WoundEffect = WoundNode->WoundEffect;
|
||||
bool bCreateDecal = WoundNode->bCreateDecal;
|
||||
UMaterialInterface* DecalMaterial = WoundNode->DecalMaterial;
|
||||
float DecalSize = WoundNode->DecalSize;
|
||||
float DecalLifetime = WoundNode->DecalLifetime;
|
||||
bool bAffectBoneHealth = WoundNode->bAffectBoneHealth;
|
||||
float BoneDamage = WoundNode->BoneDamage;
|
||||
|
||||
// Get the actor's transform
|
||||
FTransform ActorTransform = TargetActor->GetActorTransform();
|
||||
|
||||
// Create a default wound location if not connected to an input
|
||||
FVector WoundLocation = ActorTransform.GetLocation() + FVector(0.0f, 0.0f, 100.0f);
|
||||
|
||||
// Create the preview wound effect
|
||||
TObjectPtr<UNiagaraComponent> WoundEffectComponent = nullptr;
|
||||
if (WoundEffect)
|
||||
{
|
||||
WoundEffectComponent = UNiagaraComponent::SpawnSystemAttached(
|
||||
WoundEffect,
|
||||
TargetSkeletalMesh,
|
||||
NAME_None,
|
||||
WoundLocation,
|
||||
FRotator::ZeroRotator,
|
||||
EAttachLocation::KeepWorldPosition,
|
||||
false);
|
||||
|
||||
if (WoundEffectComponent)
|
||||
{
|
||||
PreviewNiagaraComponents.Add(WoundEffectComponent);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Failed to create wound effect component"));
|
||||
}
|
||||
}
|
||||
|
||||
// Create the preview wound decal if needed
|
||||
TObjectPtr<UDecalComponent> WoundDecalComponent = nullptr;
|
||||
if (bCreateDecal && DecalMaterial)
|
||||
{
|
||||
WoundDecalComponent = CreatePreviewWound(WoundLocation, DecalSize, DecalMaterial);
|
||||
|
||||
if (!WoundDecalComponent)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Failed to create wound decal component"));
|
||||
}
|
||||
}
|
||||
|
||||
// Store the wound transform for later use
|
||||
FTransform WoundTransform;
|
||||
WoundTransform.SetLocation(WoundLocation);
|
||||
PreviewWoundTransforms.Add(WoundTransform);
|
||||
|
||||
UE_LOG(LogFLESHPreview, Log, TEXT("Wound node preview created successfully, size: %.2f, depth: %.2f"), WoundSize, WoundDepth);
|
||||
|
||||
return WoundEffectComponent != nullptr || WoundDecalComponent != nullptr;
|
||||
}
|
||||
|
||||
TObjectPtr<UStaticMeshComponent> UDismembermentPreviewManager::CreatePreviewCutPlaneMesh(const FVector& Location, const FVector& Direction, float Width, float Depth, UMaterialInterface* Material)
|
||||
{
|
||||
if (!World || !TargetActor)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot create cut plane: Invalid world or target actor"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create a static mesh component for the cut plane
|
||||
TObjectPtr<UStaticMeshComponent> CutPlaneMeshComponent = NewObject<UStaticMeshComponent>(TargetActor);
|
||||
if (!CutPlaneMeshComponent)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Error, TEXT("Failed to create cut plane component"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Register the component
|
||||
CutPlaneMeshComponent->RegisterComponent();
|
||||
|
||||
// Set the mesh to a plane
|
||||
UStaticMesh* PlaneMesh = LoadObject<UStaticMesh>(nullptr, TEXT("/Engine/BasicShapes/Plane.Plane"));
|
||||
if (PlaneMesh)
|
||||
{
|
||||
CutPlaneMeshComponent->SetStaticMesh(PlaneMesh);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Failed to load plane mesh"));
|
||||
}
|
||||
|
||||
// Set the material
|
||||
if (Material)
|
||||
{
|
||||
CutPlaneMeshComponent->SetMaterial(0, Material);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use a default material
|
||||
UMaterialInterface* DefaultMaterial = LoadObject<UMaterialInterface>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial"));
|
||||
if (DefaultMaterial)
|
||||
{
|
||||
CutPlaneMeshComponent->SetMaterial(0, DefaultMaterial);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Failed to load default material"));
|
||||
}
|
||||
}
|
||||
|
||||
// Set the transform
|
||||
FRotator Rotation = FRotationMatrix::MakeFromX(Direction).Rotator();
|
||||
CutPlaneMeshComponent->SetWorldLocationAndRotation(Location, Rotation);
|
||||
CutPlaneMeshComponent->SetWorldScale3D(FVector(Width, Depth, 1.0f));
|
||||
|
||||
// Add to the preview components
|
||||
PreviewStaticMeshComponents.Add(CutPlaneMeshComponent);
|
||||
|
||||
UE_LOG(LogFLESHPreview, Verbose, TEXT("Created cut plane mesh, location: %s, direction: %s"),
|
||||
*Location.ToString(), *Direction.ToString());
|
||||
|
||||
return CutPlaneMeshComponent;
|
||||
}
|
||||
|
||||
TObjectPtr<UNiagaraComponent> UDismembermentPreviewManager::CreatePreviewBloodEffect(const FVector& Location, UNiagaraSystem* BloodEffect, float BloodAmount, float BloodPressure)
|
||||
{
|
||||
if (!World || !TargetActor || !BloodEffect)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot create blood effect: Invalid parameters"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create a Niagara component for the blood effect
|
||||
TObjectPtr<UNiagaraComponent> BloodEffectComponent = UNiagaraComponent::SpawnSystemAttached(
|
||||
BloodEffect,
|
||||
TargetSkeletalMesh,
|
||||
NAME_None,
|
||||
Location,
|
||||
FRotator::ZeroRotator,
|
||||
EAttachLocation::KeepWorldPosition,
|
||||
false);
|
||||
|
||||
if (!BloodEffectComponent)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Error, TEXT("Failed to create blood effect component"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Set parameters
|
||||
BloodEffectComponent->SetFloatParameter(TEXT("BloodAmount"), BloodAmount);
|
||||
BloodEffectComponent->SetFloatParameter(TEXT("BloodPressure"), BloodPressure);
|
||||
|
||||
// Add to the preview components
|
||||
PreviewNiagaraComponents.Add(BloodEffectComponent);
|
||||
|
||||
UE_LOG(LogFLESHPreview, Verbose, TEXT("Created blood effect, location: %s, blood amount: %.2f, blood pressure: %.2f"),
|
||||
*Location.ToString(), BloodAmount, BloodPressure);
|
||||
|
||||
return BloodEffectComponent;
|
||||
}
|
||||
|
||||
TObjectPtr<UDecalComponent> UDismembermentPreviewManager::CreatePreviewBloodPool(const FVector& Location, float Size, UMaterialInterface* Material)
|
||||
{
|
||||
if (!World || !TargetActor)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot create blood pool: Invalid world or target actor"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create a decal component for the blood pool
|
||||
TObjectPtr<UDecalComponent> BloodPoolComponent = NewObject<UDecalComponent>(TargetActor);
|
||||
if (!BloodPoolComponent)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Error, TEXT("Failed to create blood pool component"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Register the component
|
||||
BloodPoolComponent->RegisterComponent();
|
||||
|
||||
// Set the material
|
||||
if (Material)
|
||||
{
|
||||
BloodPoolComponent->SetMaterial(0, Material);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use a default material
|
||||
UMaterialInterface* DefaultMaterial = LoadObject<UMaterialInterface>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial"));
|
||||
if (DefaultMaterial)
|
||||
{
|
||||
BloodPoolComponent->SetMaterial(0, DefaultMaterial);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Failed to load default material"));
|
||||
}
|
||||
}
|
||||
|
||||
// Set the transform
|
||||
BloodPoolComponent->SetWorldLocation(Location);
|
||||
BloodPoolComponent->SetWorldRotation(FRotator(-90.0f, 0.0f, 0.0f));
|
||||
BloodPoolComponent->DecalSize = FVector(Size, Size, 10.0f);
|
||||
|
||||
// Add to the preview components
|
||||
PreviewDecalComponents.Add(BloodPoolComponent);
|
||||
|
||||
UE_LOG(LogFLESHPreview, Verbose, TEXT("Created blood pool decal, location: %s, size: %.2f"),
|
||||
*Location.ToString(), Size);
|
||||
|
||||
return BloodPoolComponent;
|
||||
}
|
||||
|
||||
TObjectPtr<UStaticMeshComponent> UDismembermentPreviewManager::CreatePreviewOrgan(UStaticMesh* OrganMesh, UMaterialInterface* OrganMaterial, const FName& AttachBoneName, const FVector& RelativeLocation, const FRotator& RelativeRotation, const FVector& RelativeScale)
|
||||
{
|
||||
if (!World || !TargetActor || !OrganMesh)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot create organ: Invalid parameters"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create a static mesh component for the organ
|
||||
TObjectPtr<UStaticMeshComponent> OrganComponent = NewObject<UStaticMeshComponent>(TargetActor);
|
||||
if (!OrganComponent)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Error, TEXT("Failed to create organ component"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Register the component
|
||||
OrganComponent->RegisterComponent();
|
||||
|
||||
// Set the mesh
|
||||
OrganComponent->SetStaticMesh(OrganMesh);
|
||||
|
||||
// Set the material
|
||||
if (OrganMaterial)
|
||||
{
|
||||
OrganComponent->SetMaterial(0, OrganMaterial);
|
||||
}
|
||||
|
||||
// Attach to bone if specified
|
||||
if (TargetSkeletalMesh && !AttachBoneName.IsNone())
|
||||
{
|
||||
if (TargetSkeletalMesh->GetBoneIndex(AttachBoneName) != INDEX_NONE)
|
||||
{
|
||||
OrganComponent->AttachToComponent(TargetSkeletalMesh, FAttachmentTransformRules::KeepRelativeTransform, AttachBoneName);
|
||||
OrganComponent->SetRelativeLocationAndRotation(RelativeLocation, RelativeRotation);
|
||||
OrganComponent->SetRelativeScale3D(RelativeScale);
|
||||
|
||||
UE_LOG(LogFLESHPreview, Verbose, TEXT("Organ attached to bone: %s"), *AttachBoneName.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Bone not found: %s, attaching to actor root component"), *AttachBoneName.ToString());
|
||||
// Set the transform
|
||||
OrganComponent->SetWorldLocationAndRotation(
|
||||
TargetActor->GetActorLocation() + RelativeLocation,
|
||||
TargetActor->GetActorRotation() + RelativeRotation);
|
||||
OrganComponent->SetWorldScale3D(RelativeScale);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the transform
|
||||
OrganComponent->SetWorldLocationAndRotation(
|
||||
TargetActor->GetActorLocation() + RelativeLocation,
|
||||
TargetActor->GetActorRotation() + RelativeRotation);
|
||||
OrganComponent->SetWorldScale3D(RelativeScale);
|
||||
}
|
||||
|
||||
// Add to the preview components
|
||||
PreviewStaticMeshComponents.Add(OrganComponent);
|
||||
|
||||
UE_LOG(LogFLESHPreview, Verbose, TEXT("Created organ component, relative location: %s"), *RelativeLocation.ToString());
|
||||
|
||||
return OrganComponent;
|
||||
}
|
||||
|
||||
TObjectPtr<UDecalComponent> UDismembermentPreviewManager::CreatePreviewWound(const FVector& Location, float Size, UMaterialInterface* Material)
|
||||
{
|
||||
if (!World || !TargetActor)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Cannot create wound: Invalid world or target actor"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create a decal component for the wound
|
||||
TObjectPtr<UDecalComponent> WoundComponent = NewObject<UDecalComponent>(TargetActor);
|
||||
if (!WoundComponent)
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Error, TEXT("Failed to create wound component"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Register the component
|
||||
WoundComponent->RegisterComponent();
|
||||
|
||||
// Set the material
|
||||
if (Material)
|
||||
{
|
||||
WoundComponent->SetMaterial(0, Material);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use a default material
|
||||
UMaterialInterface* DefaultMaterial = LoadObject<UMaterialInterface>(nullptr, TEXT("/Engine/BasicShapes/BasicShapeMaterial.BasicShapeMaterial"));
|
||||
if (DefaultMaterial)
|
||||
{
|
||||
WoundComponent->SetMaterial(0, DefaultMaterial);
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogFLESHPreview, Warning, TEXT("Failed to load default material"));
|
||||
}
|
||||
}
|
||||
|
||||
// Set the transform
|
||||
WoundComponent->SetWorldLocation(Location);
|
||||
WoundComponent->SetWorldRotation(FRotator(-90.0f, 0.0f, 0.0f));
|
||||
WoundComponent->DecalSize = FVector(Size, Size, 10.0f);
|
||||
|
||||
// Add to the preview components
|
||||
PreviewDecalComponents.Add(WoundComponent);
|
||||
|
||||
UE_LOG(LogFLESHPreview, Verbose, TEXT("Created wound decal, location: %s, size: %.2f"),
|
||||
*Location.ToString(), Size);
|
||||
|
||||
return WoundComponent;
|
||||
}
|
||||
|
||||
void UDismembermentPreviewManager::ClearPreviewComponents()
|
||||
{
|
||||
// Destroy all preview components
|
||||
for (TObjectPtr<UNiagaraComponent> Component : PreviewNiagaraComponents)
|
||||
{
|
||||
if (Component)
|
||||
{
|
||||
Component->DestroyComponent();
|
||||
}
|
||||
}
|
||||
PreviewNiagaraComponents.Empty();
|
||||
|
||||
UE_LOG(LogFLESHPreview, Verbose, TEXT("Cleared %d Niagara components"), PreviewNiagaraComponents.Num());
|
||||
|
||||
for (TObjectPtr<UDecalComponent> Component : PreviewDecalComponents)
|
||||
{
|
||||
if (Component)
|
||||
{
|
||||
Component->DestroyComponent();
|
||||
}
|
||||
}
|
||||
PreviewDecalComponents.Empty();
|
||||
|
||||
UE_LOG(LogFLESHPreview, Verbose, TEXT("Cleared %d decal components"), PreviewDecalComponents.Num());
|
||||
|
||||
for (TObjectPtr<UStaticMeshComponent> Component : PreviewStaticMeshComponents)
|
||||
{
|
||||
if (Component)
|
||||
{
|
||||
Component->DestroyComponent();
|
||||
}
|
||||
}
|
||||
PreviewStaticMeshComponents.Empty();
|
||||
|
||||
UE_LOG(LogFLESHPreview, Verbose, TEXT("Cleared %d static mesh components"), PreviewStaticMeshComponents.Num());
|
||||
|
||||
// Clear the cut plane mesh
|
||||
if (PreviewCutPlaneMesh)
|
||||
{
|
||||
PreviewCutPlaneMesh->DestroyComponent();
|
||||
PreviewCutPlaneMesh = nullptr;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user