|
10 | 10 | #include "NiagaraComponent.h"
|
11 | 11 | #include "SharedGameplayTags.h"
|
12 | 12 | #include "SignificanceManager.h"
|
| 13 | +#include "SkeletalMeshComponentBudgeted.h" |
13 | 14 | #include "UI/RogueWorldUserWidget.h"
|
14 | 15 | #include "Components/CapsuleComponent.h"
|
15 | 16 | #include "GameFramework/CharacterMovementComponent.h"
|
|
18 | 19 | #include "Components/AudioComponent.h"
|
19 | 20 | #include "Components/CanvasPanel.h"
|
20 | 21 | #include "Perception/AISense_Damage.h"
|
| 22 | +#include "IAnimationBudgetAllocator.h" |
| 23 | +#include "AnimationBudgetAllocator/Private/AnimationBudgetAllocatorModule.h" |
21 | 24 |
|
22 | 25 | #include UE_INLINE_GENERATED_CPP_BY_NAME(RogueAICharacter)
|
23 | 26 |
|
24 | 27 |
|
25 |
| -ARogueAICharacter::ARogueAICharacter() |
| 28 | +ARogueAICharacter::ARogueAICharacter(const FObjectInitializer& ObjectInitializer) |
| 29 | + // Override the SkelMesh with the Anim Budget variant for balancing anim cost across all AI bots |
| 30 | + :Super(ObjectInitializer.SetDefaultSubobjectClass<USkeletalMeshComponentBudgeted>(ACharacter::MeshComponentName)) |
26 | 31 | {
|
27 | 32 | ActionComp = CreateDefaultSubobject<URogueActionComponent>(TEXT("ActionComp"));
|
28 | 33 | // Set some defaults, ideally we handle this through some data asset instead
|
@@ -63,6 +68,14 @@ void ARogueAICharacter::BeginPlay()
|
63 | 68 | {
|
64 | 69 | Super::BeginPlay();
|
65 | 70 |
|
| 71 | + // Only needs to enable the module once, placing in beginplay for convenience |
| 72 | + // They didn't expose the blueprint library, so we instead call directly into the module |
| 73 | + FAnimationBudgetAllocatorModule& AnimationBudgetAllocatorModule = FModuleManager::LoadModuleChecked<FAnimationBudgetAllocatorModule>("AnimationBudgetAllocator"); |
| 74 | + if(IAnimationBudgetAllocator* AnimationBudgetAllocator = AnimationBudgetAllocatorModule.GetBudgetAllocatorForWorld(GetWorld())) |
| 75 | + { |
| 76 | + AnimationBudgetAllocator->SetEnabled(true); |
| 77 | + } |
| 78 | + |
66 | 79 | // Significance Manager
|
67 | 80 | {
|
68 | 81 | USignificanceManager* SigMan = USignificanceManager::Get(GetWorld());
|
@@ -96,19 +109,33 @@ void ARogueAICharacter::BeginPlay()
|
96 | 109 | DistanceSqrt *= 0.5f;
|
97 | 110 | }
|
98 | 111 |
|
99 |
| - // Note: AI can further define significance, for example, |
100 |
| - // while in combat or having the player as a known target we could increase its significance |
| 112 | + // Note: AI could further define significance, for example, while in combat or having the player as a known target we could increase its significance |
101 | 113 |
|
102 | 114 | // Negative distance to easily have larger distance mean lower significance
|
103 | 115 | return -DistanceSqrt;
|
104 | 116 | };
|
105 | 117 |
|
| 118 | + // Register with post significance function to easily tie-in with the animation budgeter |
| 119 | + // We could also choose to let the budgeter calculate the significance itself instead |
| 120 | + auto PostSignificanceFunc = [&](USignificanceManager::FManagedObjectInfo* ObjectInfo, float OldSignificance, float Significance, bool bFinal) |
| 121 | + { |
| 122 | + USkeletalMeshComponentBudgeted* BudgetMesh = Cast<USkeletalMeshComponentBudgeted>(GetMesh()); |
| 123 | + BudgetMesh->SetComponentSignificance(Significance); |
| 124 | + }; |
| 125 | + |
| 126 | + |
| 127 | + // Additional flag in the budgetter to allow us to 'toggle' and turn off certain animation features custom to the game, this could mean detaching components on our skeletal mesh |
| 128 | + // it's entirely game dependent on what we could throttle here |
| 129 | + USkeletalMeshComponentBudgeted* BudgetMesh = Cast<USkeletalMeshComponentBudgeted>(GetMesh()); |
| 130 | + BudgetMesh->OnReduceWork().BindUObject(this, &ARogueAICharacter::OnReduceAnimationWork); |
| 131 | + |
106 | 132 | // Instead of passing the entire Actor, we can pass the minimal data, such as the RootComponent, or SkeletalMeshComponent
|
107 | 133 | // This should allow us to be more cache efficient (from simple testing this does run slightly faster than using the Actor)
|
108 |
| - SigMan->RegisterObject(GetMesh(), SignificanceTag, SignificanceFunc); |
| 134 | + SigMan->RegisterObject(GetMesh(), SignificanceTag, SignificanceFunc, USignificanceManager::EPostSignificanceType::Concurrent, PostSignificanceFunc); |
109 | 135 | }
|
110 | 136 | }
|
111 | 137 |
|
| 138 | + |
112 | 139 | void ARogueAICharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
113 | 140 | {
|
114 | 141 | // Remove from SigMan
|
@@ -241,6 +268,14 @@ void ARogueAICharacter::SignificanceLODChanged(int32 NewLOD)
|
241 | 268 | }
|
242 | 269 |
|
243 | 270 |
|
| 271 | +void ARogueAICharacter::OnReduceAnimationWork(class USkeletalMeshComponentBudgeted* InComponent, bool bReduce) |
| 272 | +{ |
| 273 | + UE_LOG(LogGame, Warning, TEXT("OnReduceAnimWork for bot %s, reducing = %s"), *GetName(), (bReduce ? TEXT("true") : TEXT("false"))); |
| 274 | + |
| 275 | + // @todo: Actually throttle some work, for example, detach certain components on the skeletal mesh IF we had any in the first place |
| 276 | +} |
| 277 | + |
| 278 | + |
244 | 279 | FGenericTeamId ARogueAICharacter::GetGenericTeamId() const
|
245 | 280 | {
|
246 | 281 | // Fetch from the AI Controller who has built-in TeamId
|
|
0 commit comments