788 lines
27 KiB
C++
788 lines
27 KiB
C++
#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;
|
|
}
|
|
}
|