Files
2025-05-18 13:04:45 +08:00

263 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "GeometryCollection/GeometryCollectionEngineRemoval.h"
#include "GeometryCollection/GeometryCollection.h"
#include "GeometryCollection/Facades/CollectionRemoveOnBreakFacade.h"
#include "GeometryCollectionProxyData.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace
{
const FName BreakTimerAttributeName = "BreakTimer";
const FName PostBreakDurationAttributeName = "PostBreakDuration";
const FName BreakRemovalDurationAttributeName = "BreakRemovalDuration";
const FName SleepTimerAttributeName = "SleepTimer";
const FName MaxSleepTimeAttributeName = "MaxSleepTime";
const FName SleepRemovalDurationAttributeName = "SleepRemovalDuration";
const FName LastPositionAttributeName = "LastPosition";
const FName DecayAttributeName = "Decay";
}
FGeometryCollectionRemoveOnBreakDynamicFacade::FGeometryCollectionRemoveOnBreakDynamicFacade(FGeometryDynamicCollection& InCollection)
: BreakTimerAttribute(InCollection, BreakTimerAttributeName, FGeometryCollection::TransformGroup)
, PostBreakDurationAttribute(InCollection, PostBreakDurationAttributeName, FGeometryCollection::TransformGroup)
, BreakRemovalDurationAttribute(InCollection, BreakRemovalDurationAttributeName, FGeometryCollection::TransformGroup)
, DynamicCollection(InCollection)
{
}
bool FGeometryCollectionRemoveOnBreakDynamicFacade::IsValid() const
{
return BreakTimerAttribute.IsValid()
&& PostBreakDurationAttribute.IsValid()
&& BreakRemovalDurationAttribute.IsValid();
}
bool FGeometryCollectionRemoveOnBreakDynamicFacade::IsConst() const
{
return BreakTimerAttribute.IsConst();
}
void FGeometryCollectionRemoveOnBreakDynamicFacade::DefineSchema()
{
check(!IsConst());
BreakTimerAttribute.AddAndFill(BreakTimerStartValue);
PostBreakDurationAttribute.Add();
BreakRemovalDurationAttribute.Add();
}
void FGeometryCollectionRemoveOnBreakDynamicFacade::SetAttributeValues(const GeometryCollection::Facades::FCollectionRemoveOnBreakFacade& RemoveOnBreakFacade)
{
check(!IsConst());
if (IsValid())
{
BreakTimerAttribute.Fill(BreakTimerStartValue);
// make sure we generate random value consistently between client and server
// we can use the length of the transform group for that
const int32 RandomSeed = DynamicCollection.GetNumTransforms();
FRandomStream Random(RandomSeed);
TManagedArray<float>& PostBreakDuration = PostBreakDurationAttribute.Modify();
for (int32 Idx = 0; Idx < PostBreakDuration.Num(); ++Idx)
{
const GeometryCollection::Facades::FRemoveOnBreakData RemoveOnBreakData{ RemoveOnBreakFacade.GetData(Idx) };
const FVector2f PostBreakTimer = RemoveOnBreakData.GetBreakTimer();
const float MinBreakTime = FMath::Max(0.0f, PostBreakTimer.X);
const float MaxBreakTime = FMath::Max(MinBreakTime, PostBreakTimer.Y);
PostBreakDuration[Idx] = RemoveOnBreakData.IsEnabled() ? Random.FRandRange(MinBreakTime, MaxBreakTime) : DisabledPostBreakDuration;
}
TManagedArray<float>& BreakRemovalDuration = BreakRemovalDurationAttribute.Modify();
for (int32 Idx = 0; Idx < PostBreakDuration.Num(); ++Idx)
{
const GeometryCollection::Facades::FRemoveOnBreakData RemoveOnBreakData{ RemoveOnBreakFacade.GetData(Idx) };
const FVector2f RemovalTimer = RemoveOnBreakData.GetRemovalTimer();
const float MinRemovalTime = FMath::Max(0.0f, RemovalTimer.X);
const float MaxRemovalTime = FMath::Max(MinRemovalTime, RemovalTimer.Y);
const bool bIsCluster = DynamicCollection.IsCluster(Idx);
const bool bUseClusterCrumbling = (bIsCluster && RemoveOnBreakData.GetClusterCrumbling());
BreakRemovalDuration[Idx] = bUseClusterCrumbling ? CrumblingRemovalTimer : Random.FRandRange(MinRemovalTime, MaxRemovalTime);
}
}
}
bool FGeometryCollectionRemoveOnBreakDynamicFacade::IsRemovalActive(int32 TransformIndex) const
{
return (PostBreakDurationAttribute.Get()[TransformIndex] > DisabledPostBreakDuration);
}
bool FGeometryCollectionRemoveOnBreakDynamicFacade::UseClusterCrumbling(int32 TransformIndex) const
{
return (BreakRemovalDurationAttribute.Get()[TransformIndex] <= CrumblingRemovalTimer);
}
float FGeometryCollectionRemoveOnBreakDynamicFacade::UpdateBreakTimerAndComputeDecay(int32 TransformIndex, float DeltaTime)
{
float& BreakTimerRef = BreakTimerAttribute.Modify()[TransformIndex];
const float PostBreakDuration = PostBreakDurationAttribute.Get()[TransformIndex];
const float BreakRemovalDuration = BreakRemovalDurationAttribute.Get()[TransformIndex];
float UpdatedBreakDecay = 0;
if (PostBreakDuration >= 0)
{
BreakTimerRef += DeltaTime;
const bool bPostBreakTimeExpired = (BreakTimerRef >= PostBreakDuration) && (PostBreakDuration >= 0);
const bool bZeroRemovalDuration = (BreakRemovalDuration < UE_SMALL_NUMBER);
if (bPostBreakTimeExpired)
{
UpdatedBreakDecay = bZeroRemovalDuration? 1.f: FMath::Clamp<float>((BreakTimerRef - PostBreakDuration) / BreakRemovalDuration, 0.f, 1.f);
}
}
return UpdatedBreakDecay;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FGeometryCollectionRemoveOnSleepDynamicFacade::FGeometryCollectionRemoveOnSleepDynamicFacade(FManagedArrayCollection& InCollection)
: SleepTimerAttribute(InCollection, SleepTimerAttributeName, FGeometryCollection::TransformGroup)
, MaxSleepTimeAttribute(InCollection, MaxSleepTimeAttributeName, FGeometryCollection::TransformGroup)
, SleepRemovalDurationAttribute(InCollection, SleepRemovalDurationAttributeName, FGeometryCollection::TransformGroup)
, LastPositionAttribute(InCollection, LastPositionAttributeName, FGeometryCollection::TransformGroup)
{
}
bool FGeometryCollectionRemoveOnSleepDynamicFacade::IsValid() const
{
return SleepTimerAttribute.IsValid()
&& MaxSleepTimeAttribute.IsValid()
&& SleepRemovalDurationAttribute.IsValid()
&& LastPositionAttribute.IsValid()
;
}
bool FGeometryCollectionRemoveOnSleepDynamicFacade::IsConst() const
{
return SleepTimerAttribute.IsConst();
}
void FGeometryCollectionRemoveOnSleepDynamicFacade::DefineSchema()
{
check(!IsConst());
SleepTimerAttribute.Add();
MaxSleepTimeAttribute.Add();
SleepRemovalDurationAttribute.Add();
LastPositionAttribute.AddAndFill(FVector::ZeroVector);
}
float FGeometryCollectionRemoveOnSleepDynamicFacade::GetSleepRemovalDuration(int32 TransformIndex) const
{
return SleepRemovalDurationAttribute[TransformIndex];
}
float FGeometryCollectionRemoveOnSleepDynamicFacade::GetMaxSleepTime(int32 TransformIndex) const
{
return MaxSleepTimeAttribute[TransformIndex];
}
void FGeometryCollectionRemoveOnSleepDynamicFacade::SetSleepRemovalDuration(int32 TransformIndex, float SleepRemovalDuration)
{
SleepRemovalDurationAttribute.ModifyAt(TransformIndex, SleepRemovalDuration);
}
void FGeometryCollectionRemoveOnSleepDynamicFacade::SetMaxSleepTime(int32 TransformIndex, float MaxSleepTime)
{
MaxSleepTimeAttribute.ModifyAt(TransformIndex, MaxSleepTime);
}
void FGeometryCollectionRemoveOnSleepDynamicFacade::SetAttributeValues(const FVector2D& MaximumSleepTime, const FVector2D& RemovalDuration)
{
check(!IsConst());
if (IsValid())
{
SleepTimerAttribute.Fill(0.0f);
LastPositionAttribute.Fill(FVector::ZeroVector);
TManagedArray<float>& MaxSleepTime = MaxSleepTimeAttribute.Modify();
const float MinTime = FMath::Max(0.0f, MaximumSleepTime.X);
const float MaxTime = FMath::Max(MinTime, MaximumSleepTime.Y);
for (int32 Idx = 0; Idx < MaxSleepTime.Num(); ++Idx)
{
MaxSleepTime[Idx] = FMath::RandRange(MinTime, MaxTime);
}
TManagedArray<float>& SleepRemovalDuration = SleepRemovalDurationAttribute.Modify();
float MinRemovalTime = FMath::Max(0.0f, RemovalDuration.X);
float MaxRemovalTime = FMath::Max(MinRemovalTime, RemovalDuration.Y);
for (int32 Idx = 0; Idx < SleepRemovalDuration.Num(); ++Idx)
{
SleepRemovalDuration[Idx] = FMath::RandRange(MinRemovalTime, MaxRemovalTime);
}
}
}
bool FGeometryCollectionRemoveOnSleepDynamicFacade::IsRemovalActive(int32 TransformIndex) const
{
return (MaxSleepTimeAttribute[TransformIndex] >= 0);
}
bool FGeometryCollectionRemoveOnSleepDynamicFacade::ComputeSlowMovingState(int32 TransformIndex, const FVector& Position, float DeltaTime, FVector::FReal VelocityThreshold)
{
bool IsSlowMoving = false;
FVector& LastPositionRef = LastPositionAttribute.Modify()[TransformIndex];
if (DeltaTime > 0)
{
const FVector::FReal InstantVelocity = (Position-LastPositionRef).Size() / (FVector::FReal)DeltaTime;
IsSlowMoving = (InstantVelocity < VelocityThreshold);
}
LastPositionRef = Position;
return IsSlowMoving;
}
void FGeometryCollectionRemoveOnSleepDynamicFacade::UpdateSleepTimer(int32 TransformIndex, float DeltaTime)
{
check(SleepTimerAttribute.IsValid());
SleepTimerAttribute.Modify()[TransformIndex] += DeltaTime;
}
float FGeometryCollectionRemoveOnSleepDynamicFacade::ComputeDecay(int32 TransformIndex) const
{
const float SleepRemovalDuration = SleepRemovalDurationAttribute.Get()[TransformIndex];
const float MaxSleepTime = MaxSleepTimeAttribute.Get()[TransformIndex];
const float SleepTimer = SleepTimerAttribute.Get()[TransformIndex];
const bool bZeroRemovalDuration = (SleepRemovalDuration < UE_SMALL_NUMBER);
return bZeroRemovalDuration? 1.f: FMath::Clamp<float>((SleepTimer -MaxSleepTime) / SleepRemovalDuration, 0.f, 1.f);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FGeometryCollectionDecayDynamicFacade::FGeometryCollectionDecayDynamicFacade(FManagedArrayCollection& InCollection)
: DecayAttribute(InCollection, DecayAttributeName, FGeometryCollection::TransformGroup)
{
}
bool FGeometryCollectionDecayDynamicFacade::IsValid() const
{
// on check the decay since the uniform attribute is optional ( see bScaleOnRemoval )
return DecayAttribute.IsValid();
}
void FGeometryCollectionDecayDynamicFacade::AddAttributes()
{
DecayAttribute.AddAndFill(0.0f);
}
float FGeometryCollectionDecayDynamicFacade::GetDecay(int32 TransformIndex) const
{
return DecayAttribute[TransformIndex];
}
void FGeometryCollectionDecayDynamicFacade::SetDecay(int32 TransformIndex, float DecayValue)
{
DecayAttribute.ModifyAt(TransformIndex, DecayValue);
}
int32 FGeometryCollectionDecayDynamicFacade::GetDecayAttributeSize() const
{
return DecayAttribute.Num();
}