claude-code-arcane 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +104 -55
- package/agents/career/career-strategist.md +88 -0
- package/agents/career/cv-reviewer.md +81 -0
- package/agents/career/hiring-manager.md +68 -0
- package/agents/career/mock-interviewer.md +76 -0
- package/agents/freelance/client-screener.md +84 -0
- package/agents/freelance/discovery-call.md +65 -0
- package/agents/freelance/pipeline-strategist.md +99 -0
- package/agents/freelance/proposal-reviewer.md +82 -0
- package/agents/game/ue-blueprint-specialist.md +125 -0
- package/agents/game/ue-gas-specialist.md +133 -0
- package/agents/game/ue-umg-specialist.md +131 -0
- package/dist/cli.js +57 -13
- package/docs/RELEASE-SETUP.md +1 -1
- package/docs/SKILLS-CATALOG.md +67 -4
- package/docs/USER-GUIDE.md +77 -72
- package/docs/agent-hierarchy.md +21 -1
- package/docs/presentations/build_arcane_deck.py +2 -2
- package/docs/presentations/build_arcane_deck_12.py +2 -2
- package/hooks/detect-unreal.sh +90 -0
- package/package.json +2 -2
- package/profiles/freelance.yaml +43 -0
- package/profiles/job-hunt.yaml +5 -2
- package/profiles/unreal-dev.yaml +97 -0
- package/rules/drafter-reviewer.md +16 -3
- package/rules/freelance-guardrails.md +53 -0
- package/rules/gamedev/unreal-code.md +125 -0
- package/skills/career-registry/SKILL.md +95 -0
- package/skills/career-registry/scripts/career_registry.py +488 -0
- package/skills/client-screen/SKILL.md +83 -0
- package/skills/client-screen/references/red-flags.md +95 -0
- package/skills/cover-letter/SKILL.md +4 -3
- package/skills/cv-tailor/SKILL.md +11 -2
- package/skills/freelance-deliver/SKILL.md +90 -0
- package/skills/freelance-hunt/SKILL.md +126 -0
- package/skills/freelance-hunt/references/templates/Connects.md +39 -0
- package/skills/freelance-hunt/references/templates/Contrato.md +60 -0
- package/skills/freelance-hunt/references/templates/Propuesta.md +66 -0
- package/skills/freelance-kickoff/SKILL.md +94 -0
- package/skills/freelance-pipeline/SKILL.md +109 -0
- package/skills/freelance-pipeline/scripts/import_history.py +425 -0
- package/skills/freelance-profile/SKILL.md +93 -0
- package/skills/freelance-proposal/SKILL.md +112 -0
- package/skills/freelance-scan/SKILL.md +196 -0
- package/skills/freelance-scan/references/dedup.md +35 -0
- package/skills/freelance-scan/references/platforms.md +167 -0
- package/skills/freelance-scan/scripts/freelance_search.py +1077 -0
- package/skills/install-mcp/SKILL.md +135 -46
- package/skills/install-mcp/references/unreal-operations.md +55 -0
- package/skills/interview-prep/SKILL.md +11 -3
- package/skills/job-aplicar/SKILL.md +5 -1
- package/skills/job-hunt/SKILL.md +17 -0
- package/skills/job-outcome/SKILL.md +15 -1
- package/skills/job-upskill/SKILL.md +10 -2
- package/skills/ue-actor-component-architecture/SKILL.md +509 -0
- package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
- package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
- package/skills/ue-ai-navigation/SKILL.md +526 -0
- package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
- package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
- package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
- package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
- package/skills/ue-animation-system/SKILL.md +521 -0
- package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
- package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
- package/skills/ue-async-threading/SKILL.md +433 -0
- package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
- package/skills/ue-async-threading/references/threading-patterns.md +345 -0
- package/skills/ue-audio-system/SKILL.md +527 -0
- package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
- package/skills/ue-blueprints/SKILL.md +134 -0
- package/skills/ue-blueprints/references/communication.md +82 -0
- package/skills/ue-character-movement/SKILL.md +475 -0
- package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
- package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
- package/skills/ue-cpp-foundations/SKILL.md +533 -0
- package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
- package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
- package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
- package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
- package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
- package/skills/ue-data-assets-tables/SKILL.md +527 -0
- package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
- package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
- package/skills/ue-editor-tools/SKILL.md +523 -0
- package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
- package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
- package/skills/ue-game-features/SKILL.md +477 -0
- package/skills/ue-game-features/references/experience-system.md +222 -0
- package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
- package/skills/ue-gameplay-abilities/SKILL.md +518 -0
- package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
- package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
- package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
- package/skills/ue-gameplay-framework/SKILL.md +466 -0
- package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
- package/skills/ue-input-system/SKILL.md +394 -0
- package/skills/ue-input-system/references/cpp-setup.md +131 -0
- package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
- package/skills/ue-input-system/references/input-action-reference.md +731 -0
- package/skills/ue-mass-entity/SKILL.md +476 -0
- package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
- package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
- package/skills/ue-materials-rendering/SKILL.md +526 -0
- package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
- package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
- package/skills/ue-module-build-system/SKILL.md +487 -0
- package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
- package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
- package/skills/ue-naming-conventions/SKILL.md +142 -0
- package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
- package/skills/ue-naming-conventions/references/content-structure.md +83 -0
- package/skills/ue-networking-replication/SKILL.md +452 -0
- package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
- package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
- package/skills/ue-niagara-effects/SKILL.md +531 -0
- package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
- package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
- package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
- package/skills/ue-packaging/SKILL.md +116 -0
- package/skills/ue-physics-collision/SKILL.md +423 -0
- package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
- package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
- package/skills/ue-procedural-generation/SKILL.md +505 -0
- package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
- package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
- package/skills/ue-project-context/SKILL.md +305 -0
- package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
- package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
- package/skills/ue-serialization-savegames/SKILL.md +524 -0
- package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
- package/skills/ue-state-trees/SKILL.md +489 -0
- package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
- package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
- package/skills/ue-testing-debugging/SKILL.md +520 -0
- package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
- package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
- package/skills/ue-ui-umg-slate/SKILL.md +431 -0
- package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
- package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
- package/skills/ue-world-level-streaming/SKILL.md +518 -0
- package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
- package/templates/gamedev/unreal-project-context.md +107 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# Ability Task Reference
|
|
2
|
+
|
|
3
|
+
Common built-in `UAbilityTask` subclasses and how to create custom tasks.
|
|
4
|
+
Ability tasks extend ability execution across multiple frames using internal latent logic.
|
|
5
|
+
|
|
6
|
+
All tasks must be called from within `ActivateAbility` (or from within other tasks).
|
|
7
|
+
Tasks broadcast results via dynamic delegates. When the task completes, call `EndAbility`
|
|
8
|
+
if the ability is meant to end at that point.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## How Ability Tasks Work
|
|
13
|
+
|
|
14
|
+
1. Create the task via a static factory function (never call `new` directly).
|
|
15
|
+
2. Bind delegates for each outcome (OnCompleted, OnInterrupted, etc.).
|
|
16
|
+
3. Call `ReadyForActivation()` to start the task.
|
|
17
|
+
4. The task runs asynchronously; the ability remains active but yields.
|
|
18
|
+
5. In delegate callbacks, perform follow-up logic and call `EndAbility` when done.
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
// Typical task usage in ActivateAbility:
|
|
22
|
+
void UMyAbility::ActivateAbility(...)
|
|
23
|
+
{
|
|
24
|
+
if (!CommitAbility(Handle, ActorInfo, ActivationInfo))
|
|
25
|
+
{
|
|
26
|
+
EndAbility(Handle, ActorInfo, ActivationInfo, true, true);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
UAbilityTask_PlayMontageAndWait* Task =
|
|
31
|
+
UAbilityTask_PlayMontageAndWait::CreatePlayMontageAndWaitProxy(
|
|
32
|
+
this, NAME_None, AttackMontage, 1.f);
|
|
33
|
+
|
|
34
|
+
Task->OnCompleted.AddDynamic(this, &UMyAbility::OnMontageCompleted);
|
|
35
|
+
Task->OnInterrupted.AddDynamic(this, &UMyAbility::OnMontageInterrupted);
|
|
36
|
+
Task->OnCancelled.AddDynamic(this, &UMyAbility::OnMontageCancelled);
|
|
37
|
+
Task->ReadyForActivation();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
void UMyAbility::OnMontageCompleted()
|
|
41
|
+
{
|
|
42
|
+
EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, true, false);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void UMyAbility::OnMontageInterrupted()
|
|
46
|
+
{
|
|
47
|
+
EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, true, true);
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## UAbilityTask_PlayMontageAndWait
|
|
54
|
+
|
|
55
|
+
Plays an `AnimMontage` on the avatar actor's skeletal mesh and waits for it to finish.
|
|
56
|
+
|
|
57
|
+
```cpp
|
|
58
|
+
#include "Abilities/Tasks/AbilityTask_PlayMontageAndWait.h"
|
|
59
|
+
|
|
60
|
+
UAbilityTask_PlayMontageAndWait* Task =
|
|
61
|
+
UAbilityTask_PlayMontageAndWait::CreatePlayMontageAndWaitProxy(
|
|
62
|
+
this, // OwningAbility
|
|
63
|
+
NAME_None, // Task instance name (NAME_None = auto)
|
|
64
|
+
AttackMontage, // UAnimMontage* to play
|
|
65
|
+
1.f, // Rate
|
|
66
|
+
NAME_None, // StartSection (NAME_None = start from beginning)
|
|
67
|
+
false, // bStopWhenAbilityEnds
|
|
68
|
+
1.f); // AnimRootMotionTranslationScale
|
|
69
|
+
|
|
70
|
+
Task->OnCompleted.AddDynamic(this, &UMyAbility::OnMontageCompleted);
|
|
71
|
+
Task->OnBlendOut.AddDynamic(this, &UMyAbility::OnMontageBlendOut);
|
|
72
|
+
Task->OnInterrupted.AddDynamic(this, &UMyAbility::OnMontageInterrupted);
|
|
73
|
+
Task->OnCancelled.AddDynamic(this, &UMyAbility::OnMontageCancelled);
|
|
74
|
+
Task->ReadyForActivation();
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Delegates:
|
|
78
|
+
- `OnCompleted`: Montage finished playing
|
|
79
|
+
- `OnBlendOut`: Montage started blending out
|
|
80
|
+
- `OnInterrupted`: Montage was interrupted by another montage
|
|
81
|
+
- `OnCancelled`: Task was cancelled (EndAbility called while running)
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## UAbilityTask_WaitGameplayEvent
|
|
86
|
+
|
|
87
|
+
Waits for a `FGameplayEventData` to be sent via `HandleGameplayEvent` on the ASC.
|
|
88
|
+
Common use: waiting for an animation notify to trigger (e.g., `Event.Montage.Attack.Hit`).
|
|
89
|
+
|
|
90
|
+
```cpp
|
|
91
|
+
#include "Abilities/Tasks/AbilityTask_WaitGameplayEvent.h"
|
|
92
|
+
|
|
93
|
+
FGameplayTag EventTag = FGameplayTag::RequestGameplayTag("Event.Montage.Attack.Hit");
|
|
94
|
+
|
|
95
|
+
UAbilityTask_WaitGameplayEvent* Task =
|
|
96
|
+
UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(
|
|
97
|
+
this,
|
|
98
|
+
EventTag,
|
|
99
|
+
nullptr, // OptionalExternalTarget (null = use self ASC)
|
|
100
|
+
true, // TriggerOnce (false = keep listening)
|
|
101
|
+
true); // OnlyMatchExact
|
|
102
|
+
|
|
103
|
+
Task->EventReceived.AddDynamic(this, &UMyAbility::OnAttackHitEvent);
|
|
104
|
+
Task->ReadyForActivation();
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Sending the event (e.g., from an `AnimNotify`):
|
|
108
|
+
```cpp
|
|
109
|
+
// In AnimNotify or character code:
|
|
110
|
+
FGameplayEventData EventData;
|
|
111
|
+
EventData.Instigator = GetOwner();
|
|
112
|
+
UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(
|
|
113
|
+
GetOwner(),
|
|
114
|
+
FGameplayTag::RequestGameplayTag("Event.Montage.Attack.Hit"),
|
|
115
|
+
EventData);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Delegate: `EventReceived(FGameplayEventData Payload)`
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## UAbilityTask_WaitDelay
|
|
123
|
+
|
|
124
|
+
Waits for a fixed duration and then fires a callback. Equivalent to a GAS-aware timer.
|
|
125
|
+
|
|
126
|
+
```cpp
|
|
127
|
+
#include "Abilities/Tasks/AbilityTask_WaitDelay.h"
|
|
128
|
+
|
|
129
|
+
UAbilityTask_WaitDelay* Task =
|
|
130
|
+
UAbilityTask_WaitDelay::WaitDelay(this, 2.f); // 2 second delay
|
|
131
|
+
|
|
132
|
+
Task->OnFinish.AddDynamic(this, &UMyAbility::OnDelayFinished);
|
|
133
|
+
Task->ReadyForActivation();
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Delegate: `OnFinish()`
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## UAbilityTask_WaitTargetData
|
|
141
|
+
|
|
142
|
+
Spawns a `AGameplayAbilityTargetActor` to gather targeting information (line trace,
|
|
143
|
+
sphere trace, actor selection, etc.) and returns `FGameplayAbilityTargetDataHandle`.
|
|
144
|
+
|
|
145
|
+
```cpp
|
|
146
|
+
#include "Abilities/Tasks/AbilityTask_WaitTargetData.h"
|
|
147
|
+
#include "Abilities/GameplayAbilityTargetActor_SingleLineTrace.h"
|
|
148
|
+
|
|
149
|
+
UAbilityTask_WaitTargetData* Task =
|
|
150
|
+
UAbilityTask_WaitTargetData::WaitTargetData(
|
|
151
|
+
this,
|
|
152
|
+
NAME_None,
|
|
153
|
+
EGameplayTargetingConfirmation::Instant, // Instant, UserConfirmed, Custom, etc.
|
|
154
|
+
AGameplayAbilityTargetActor_SingleLineTrace::StaticClass());
|
|
155
|
+
|
|
156
|
+
Task->ValidData.AddDynamic(this, &UMyAbility::OnValidTargetData);
|
|
157
|
+
Task->Cancelled.AddDynamic(this, &UMyAbility::OnTargetCancelled);
|
|
158
|
+
Task->ReadyForActivation();
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Targeting confirmation modes:
|
|
162
|
+
| Mode | Behavior |
|
|
163
|
+
|------|----------|
|
|
164
|
+
| `Instant` | Confirms immediately upon spawn |
|
|
165
|
+
| `UserConfirmed` | Waits for `SendGameplayEvent` with confirm tag |
|
|
166
|
+
| `Custom` | Custom confirmation logic in the TargetActor |
|
|
167
|
+
| `CustomMulti` | Confirms multiple targets over time |
|
|
168
|
+
|
|
169
|
+
Delegate `ValidData(FGameplayAbilityTargetDataHandle Data)`:
|
|
170
|
+
```cpp
|
|
171
|
+
void UMyAbility::OnValidTargetData(const FGameplayAbilityTargetDataHandle& Data)
|
|
172
|
+
{
|
|
173
|
+
// Apply effect to targets
|
|
174
|
+
FGameplayEffectSpecHandle SpecHandle = MakeOutgoingGameplayEffectSpec(DamageEffect, Level);
|
|
175
|
+
ApplyGameplayEffectSpecToTarget(CurrentSpecHandle, CurrentActorInfo,
|
|
176
|
+
CurrentActivationInfo, SpecHandle, Data);
|
|
177
|
+
EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, true, false);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## UAbilityTask_WaitAttributeChange
|
|
184
|
+
|
|
185
|
+
Waits for an attribute to cross a threshold or change at all.
|
|
186
|
+
|
|
187
|
+
```cpp
|
|
188
|
+
#include "Abilities/Tasks/AbilityTask_WaitAttributeChange.h"
|
|
189
|
+
|
|
190
|
+
UAbilityTask_WaitAttributeChange* Task =
|
|
191
|
+
UAbilityTask_WaitAttributeChange::WaitForAttributeChange(
|
|
192
|
+
this,
|
|
193
|
+
UMyHealthSet::GetHealthAttribute(),
|
|
194
|
+
FGameplayTag(), // WithTag: optional, only trigger if ASC has this tag
|
|
195
|
+
FGameplayTag(), // WithoutTag: only trigger if ASC lacks this tag
|
|
196
|
+
true); // TriggerOnce
|
|
197
|
+
|
|
198
|
+
Task->OnChange.AddDynamic(this, &UMyAbility::OnHealthChanged);
|
|
199
|
+
Task->ReadyForActivation();
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Delegate: `OnChange()`
|
|
203
|
+
|
|
204
|
+
For threshold-based (separate class — `UAbilityTask_WaitAttributeChangeThreshold`):
|
|
205
|
+
```cpp
|
|
206
|
+
#include "Abilities/Tasks/AbilityTask_WaitAttributeChangeThreshold.h"
|
|
207
|
+
|
|
208
|
+
UAbilityTask_WaitAttributeChangeThreshold* Task =
|
|
209
|
+
UAbilityTask_WaitAttributeChangeThreshold::WaitForAttributeChangeThreshold(
|
|
210
|
+
this,
|
|
211
|
+
UMyHealthSet::GetHealthAttribute(),
|
|
212
|
+
EWaitAttributeChangeComparison::LessThan,
|
|
213
|
+
0.3f, // Compare against: below 30%
|
|
214
|
+
false, // bTriggerOnce
|
|
215
|
+
nullptr);
|
|
216
|
+
|
|
217
|
+
Task->OnChange.AddDynamic(this, &UMyAbility::OnHealthBelowThreshold);
|
|
218
|
+
Task->ReadyForActivation();
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Delegate: `OnChange(bool bMatchesComparison, float CurrentValue)`
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## UAbilityTask_WaitGameplayEffectApplied
|
|
226
|
+
|
|
227
|
+
Fires when a GameplayEffect matching specified tag requirements is applied to a target.
|
|
228
|
+
|
|
229
|
+
```cpp
|
|
230
|
+
#include "Abilities/Tasks/AbilityTask_WaitGameplayEffectApplied.h"
|
|
231
|
+
|
|
232
|
+
FGameplayTargetDataFilterHandle FilterHandle;
|
|
233
|
+
FGameplayTagRequirements SourceTagReqs;
|
|
234
|
+
FGameplayTagRequirements TargetTagReqs;
|
|
235
|
+
FGameplayTagRequirements AssetTagReqs; // Tags the GE asset itself must have
|
|
236
|
+
FGameplayTagRequirements GrantedTagReqs; // Tags the GE grants to the target
|
|
237
|
+
|
|
238
|
+
UAbilityTask_WaitGameplayEffectApplied_Self* Task =
|
|
239
|
+
UAbilityTask_WaitGameplayEffectApplied_Self::WaitGameplayEffectAppliedToSelf(
|
|
240
|
+
this,
|
|
241
|
+
FilterHandle,
|
|
242
|
+
SourceTagReqs,
|
|
243
|
+
TargetTagReqs,
|
|
244
|
+
AssetTagReqs,
|
|
245
|
+
GrantedTagReqs,
|
|
246
|
+
false /*TriggerOnce*/,
|
|
247
|
+
nullptr /*OptionalExternalOwner*/,
|
|
248
|
+
false /*ListenForPeriodicEffect*/);
|
|
249
|
+
|
|
250
|
+
Task->OnApplied.AddDynamic(this, &UMyAbility::OnEffectApplied);
|
|
251
|
+
Task->ReadyForActivation();
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Creating a Custom Ability Task
|
|
257
|
+
|
|
258
|
+
```cpp
|
|
259
|
+
// MyAbilityTask_WaitInputRelease.h
|
|
260
|
+
#pragma once
|
|
261
|
+
#include "Abilities/Tasks/AbilityTask.h"
|
|
262
|
+
#include "MyAbilityTask_WaitInputRelease.generated.h"
|
|
263
|
+
|
|
264
|
+
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInputReleased);
|
|
265
|
+
|
|
266
|
+
UCLASS()
|
|
267
|
+
class UMyAbilityTask_WaitInputRelease : public UAbilityTask
|
|
268
|
+
{
|
|
269
|
+
GENERATED_BODY()
|
|
270
|
+
public:
|
|
271
|
+
// Factory function: always use a static factory, never construct directly
|
|
272
|
+
UFUNCTION(BlueprintCallable, Category = "Ability|Tasks",
|
|
273
|
+
meta = (HidePin = "OwningAbility", DefaultToSelf = "OwningAbility",
|
|
274
|
+
BlueprintInternalUseOnly = "true"))
|
|
275
|
+
static UMyAbilityTask_WaitInputRelease* WaitInputRelease(
|
|
276
|
+
UGameplayAbility* OwningAbility,
|
|
277
|
+
bool bTestAlreadyReleased = false);
|
|
278
|
+
|
|
279
|
+
UPROPERTY(BlueprintAssignable)
|
|
280
|
+
FOnInputReleased OnReleased;
|
|
281
|
+
|
|
282
|
+
virtual void Activate() override;
|
|
283
|
+
virtual void TickTask(float DeltaTime) override;
|
|
284
|
+
virtual void OnDestroy(bool bInOwnerFinished) override;
|
|
285
|
+
|
|
286
|
+
private:
|
|
287
|
+
bool bStartedAlreadyReleased = false;
|
|
288
|
+
};
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
```cpp
|
|
292
|
+
// MyAbilityTask_WaitInputRelease.cpp
|
|
293
|
+
#include "MyAbilityTask_WaitInputRelease.h"
|
|
294
|
+
#include "AbilitySystemComponent.h"
|
|
295
|
+
|
|
296
|
+
UMyAbilityTask_WaitInputRelease* UMyAbilityTask_WaitInputRelease::WaitInputRelease(
|
|
297
|
+
UGameplayAbility* OwningAbility,
|
|
298
|
+
bool bTestAlreadyReleased)
|
|
299
|
+
{
|
|
300
|
+
UMyAbilityTask_WaitInputRelease* Task =
|
|
301
|
+
NewAbilityTask<UMyAbilityTask_WaitInputRelease>(OwningAbility);
|
|
302
|
+
Task->bStartedAlreadyReleased = bTestAlreadyReleased;
|
|
303
|
+
return Task;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
void UMyAbilityTask_WaitInputRelease::Activate()
|
|
307
|
+
{
|
|
308
|
+
// Enable ticking so we can poll input state
|
|
309
|
+
bTickingTask = true;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
void UMyAbilityTask_WaitInputRelease::TickTask(float DeltaTime)
|
|
313
|
+
{
|
|
314
|
+
// GetAbilitySpecHandle and AbilitySystemComponent come from UAbilityTask base
|
|
315
|
+
if (AbilitySystemComponent.IsValid())
|
|
316
|
+
{
|
|
317
|
+
const FGameplayAbilitySpec* Spec =
|
|
318
|
+
AbilitySystemComponent->FindAbilitySpecFromHandle(GetAbilitySpecHandle());
|
|
319
|
+
if (Spec && !Spec->InputPressed)
|
|
320
|
+
{
|
|
321
|
+
if (ShouldBroadcastAbilityTaskDelegates())
|
|
322
|
+
{
|
|
323
|
+
OnReleased.Broadcast();
|
|
324
|
+
}
|
|
325
|
+
EndTask();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
void UMyAbilityTask_WaitInputRelease::OnDestroy(bool bInOwnerFinished)
|
|
331
|
+
{
|
|
332
|
+
Super::OnDestroy(bInOwnerFinished);
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Usage in an ability:
|
|
337
|
+
```cpp
|
|
338
|
+
UMyAbilityTask_WaitInputRelease* Task =
|
|
339
|
+
UMyAbilityTask_WaitInputRelease::WaitInputRelease(this);
|
|
340
|
+
Task->OnReleased.AddDynamic(this, &UMyChargeAbility::OnInputReleased);
|
|
341
|
+
Task->ReadyForActivation();
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## Task Lifecycle Notes
|
|
347
|
+
|
|
348
|
+
- Tasks are automatically cleaned up when `EndAbility` or `CancelAbility` is called.
|
|
349
|
+
- Call `EndTask()` inside the task when done; do not call `delete`.
|
|
350
|
+
- `ShouldBroadcastAbilityTaskDelegates()` guards against broadcasting after the ability ends.
|
|
351
|
+
- `bTickingTask = true` must be set in `Activate()` to enable `TickTask`. Default is false.
|
|
352
|
+
- `NewAbilityTask<T>()` is the correct factory; never use `NewObject<T>()` for tasks.
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Task Execution Flow
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
ActivateAbility()
|
|
360
|
+
└── Task::WaitXxx() (static factory)
|
|
361
|
+
└── Bind delegates
|
|
362
|
+
└── Task::ReadyForActivation()
|
|
363
|
+
└── Task::Activate() [task starts its internal logic]
|
|
364
|
+
└── (async frames pass)
|
|
365
|
+
└── Event fires → delegate broadcast
|
|
366
|
+
└── Ability callback runs gameplay logic
|
|
367
|
+
└── EndAbility() called
|
|
368
|
+
└── Task::OnDestroy() cleanup
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Common Task Mistakes
|
|
374
|
+
|
|
375
|
+
**Not calling ReadyForActivation:** The task is created but never starts. Always call this after
|
|
376
|
+
binding delegates.
|
|
377
|
+
|
|
378
|
+
**Binding delegates after ReadyForActivation:** Some tasks fire synchronously in `Activate()`
|
|
379
|
+
(e.g., `WaitDelay` with 0 duration). Bind delegates before calling `ReadyForActivation`.
|
|
380
|
+
|
|
381
|
+
**Calling EndAbility inside a task without ending the task first:** The task will linger.
|
|
382
|
+
Let `EndAbility` clean it up, or call `EndTask()` explicitly if the task should stop without
|
|
383
|
+
ending the ability.
|
|
384
|
+
|
|
385
|
+
**Broadcasting delegates after ability ends:** Always check `ShouldBroadcastAbilityTaskDelegates()`
|
|
386
|
+
before broadcasting inside `TickTask` or callback functions to avoid operating on a cleaned-up
|
|
387
|
+
ability.
|
|
388
|
+
|
|
389
|
+
**Tick-heavy tasks in non-instanced abilities:** If `InstancingPolicy` is `NonInstanced`, the
|
|
390
|
+
CDO runs the ability. Ticking tasks on a CDO can produce shared state issues. Use
|
|
391
|
+
`InstancedPerActor` or `InstancedPerExecution` when using ticking tasks.
|