claude-code-arcane 2.3.0 → 2.5.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 +23 -0
- package/README.md +131 -41
- 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 +642 -478
- package/docs/SKILLS-CATALOG.md +42 -3
- package/docs/USER-GUIDE.md +28 -54
- package/hooks/detect-unreal.sh +90 -0
- package/package.json +2 -1
- package/profiles/agile.yaml +1 -1
- package/profiles/ai.yaml +1 -1
- package/profiles/android-native.yaml +1 -1
- package/profiles/audio.yaml +1 -1
- package/profiles/backend-dotnet.yaml +1 -1
- package/profiles/backend-go.yaml +1 -1
- package/profiles/backend-nestjs.yaml +1 -1
- package/profiles/backend-nextjs.yaml +1 -1
- package/profiles/backend-ts.yaml +1 -1
- package/profiles/business.yaml +1 -1
- package/profiles/clevel.yaml +1 -1
- package/profiles/clickup.yaml +1 -1
- package/profiles/core.yaml +1 -1
- package/profiles/database.yaml +1 -1
- package/profiles/design.yaml +1 -1
- package/profiles/docs.yaml +1 -1
- package/profiles/ecommerce.yaml +1 -1
- package/profiles/finance.yaml +1 -1
- package/profiles/flutter.yaml +1 -1
- package/profiles/freelance.yaml +1 -1
- package/profiles/frontend.yaml +1 -1
- package/profiles/infra.yaml +1 -1
- package/profiles/integrations.yaml +1 -1
- package/profiles/ios-native.yaml +1 -1
- package/profiles/jira.yaml +1 -1
- package/profiles/job-hunt.yaml +1 -1
- package/profiles/marketing.yaml +1 -1
- package/profiles/mobile.yaml +1 -1
- package/profiles/regulatory.yaml +1 -1
- package/profiles/second-brain.yaml +1 -1
- package/profiles/security.yaml +1 -1
- package/profiles/self-improving.yaml +1 -1
- package/profiles/statusline.yaml +1 -1
- package/profiles/testing.yaml +1 -1
- package/profiles/unity-design.yaml +1 -1
- package/profiles/unity-dev.yaml +1 -1
- package/profiles/unreal-dev.yaml +97 -0
- package/profiles/visual-novel.yaml +1 -1
- package/rules/gamedev/unreal-code.md +125 -0
- package/skills/arcane-list/SKILL.md +12 -7
- package/skills/install-mcp/SKILL.md +135 -46
- package/skills/install-mcp/references/unreal-operations.md +55 -0
- 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,345 @@
|
|
|
1
|
+
# Threading Patterns Reference
|
|
2
|
+
|
|
3
|
+
Complete code templates for UE async and threading patterns. Each template is production-ready with proper lifecycle management and error handling.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## FRunnable Subclass Template
|
|
8
|
+
|
|
9
|
+
Full dedicated-thread pattern with cooperative shutdown via `std::atomic<bool>`.
|
|
10
|
+
|
|
11
|
+
```cpp
|
|
12
|
+
#include "HAL/Runnable.h"
|
|
13
|
+
#include "HAL/RunnableThread.h"
|
|
14
|
+
#include "HAL/PlatformProcess.h"
|
|
15
|
+
#include <atomic>
|
|
16
|
+
|
|
17
|
+
class FMyBackgroundWorker : public FRunnable
|
|
18
|
+
{
|
|
19
|
+
public:
|
|
20
|
+
FMyBackgroundWorker() = default;
|
|
21
|
+
|
|
22
|
+
// Start the thread — call from game thread
|
|
23
|
+
void StartThread()
|
|
24
|
+
{
|
|
25
|
+
Thread = FRunnableThread::Create(
|
|
26
|
+
this,
|
|
27
|
+
TEXT("MyBackgroundWorker"),
|
|
28
|
+
0, // StackSize (0 = platform default)
|
|
29
|
+
TPri_BelowNormal, // lower than game thread
|
|
30
|
+
FPlatformAffinity::GetPoolThreadMask()
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Request shutdown and wait — call from game thread
|
|
35
|
+
~FMyBackgroundWorker()
|
|
36
|
+
{
|
|
37
|
+
if (Thread)
|
|
38
|
+
{
|
|
39
|
+
Thread->Kill(true); // calls Stop(), then blocks until Run() exits
|
|
40
|
+
delete Thread;
|
|
41
|
+
Thread = nullptr;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// --- FRunnable interface ---
|
|
46
|
+
|
|
47
|
+
bool Init() override
|
|
48
|
+
{
|
|
49
|
+
// Runs on NEW thread before Run() starts
|
|
50
|
+
// Return false to abort thread creation
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
uint32 Run() override
|
|
55
|
+
{
|
|
56
|
+
// Runs on the NEW thread
|
|
57
|
+
while (!bShouldStop.load(std::memory_order_relaxed))
|
|
58
|
+
{
|
|
59
|
+
// --- Do your work here ---
|
|
60
|
+
ProcessNextWorkItem();
|
|
61
|
+
|
|
62
|
+
// Yield to prevent CPU spin when no work available
|
|
63
|
+
FPlatformProcess::Sleep(0.001f);
|
|
64
|
+
}
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void Stop() override
|
|
69
|
+
{
|
|
70
|
+
// Called from OUTSIDE the thread (by Kill or directly)
|
|
71
|
+
// Must be thread-safe — only set the atomic flag
|
|
72
|
+
bShouldStop.store(true, std::memory_order_relaxed);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
void Exit() override
|
|
76
|
+
{
|
|
77
|
+
// Runs on the worker thread AFTER Run() returns
|
|
78
|
+
// Clean up thread-local resources here
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private:
|
|
82
|
+
std::atomic<bool> bShouldStop{false};
|
|
83
|
+
FRunnableThread* Thread = nullptr;
|
|
84
|
+
|
|
85
|
+
void ProcessNextWorkItem()
|
|
86
|
+
{
|
|
87
|
+
// Your actual work implementation
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## FNonAbandonableTask + FAsyncTask Template
|
|
95
|
+
|
|
96
|
+
Thread pool work unit pattern. The `friend` declaration lets `FAsyncTask` construct the inner task.
|
|
97
|
+
|
|
98
|
+
```cpp
|
|
99
|
+
#include "Async/AsyncWork.h"
|
|
100
|
+
|
|
101
|
+
class FChunkProcessTask : public FNonAbandonableTask
|
|
102
|
+
{
|
|
103
|
+
friend class FAsyncTask<FChunkProcessTask>;
|
|
104
|
+
|
|
105
|
+
public:
|
|
106
|
+
// Results accessible after completion
|
|
107
|
+
TArray<FVector> ProcessedVertices;
|
|
108
|
+
|
|
109
|
+
private:
|
|
110
|
+
// Constructor — args forwarded from FAsyncTask constructor
|
|
111
|
+
FChunkProcessTask(TArray<FVector> InRawVertices, float InScale)
|
|
112
|
+
: RawVertices(MoveTemp(InRawVertices))
|
|
113
|
+
, Scale(InScale)
|
|
114
|
+
{}
|
|
115
|
+
|
|
116
|
+
void DoWork()
|
|
117
|
+
{
|
|
118
|
+
ProcessedVertices.Reserve(RawVertices.Num());
|
|
119
|
+
for (const FVector& V : RawVertices)
|
|
120
|
+
{
|
|
121
|
+
ProcessedVertices.Add(V * Scale);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
FORCEINLINE TStatId GetStatId() const
|
|
126
|
+
{
|
|
127
|
+
RETURN_QUICK_DECLARE_CYCLE_STAT(FChunkProcessTask, STATGROUP_ThreadPoolAsyncTasks);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
TArray<FVector> RawVertices;
|
|
131
|
+
float Scale;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// --- Usage: reusable task ---
|
|
135
|
+
auto* Task = new FAsyncTask<FChunkProcessTask>(MoveTemp(Vertices), 2.0f);
|
|
136
|
+
Task->StartBackgroundTask(); // dispatch to GThreadPool
|
|
137
|
+
// ... do other game thread work ...
|
|
138
|
+
Task->EnsureCompletion(); // block until done
|
|
139
|
+
TArray<FVector> Result = MoveTemp(Task->GetTask().ProcessedVertices);
|
|
140
|
+
delete Task;
|
|
141
|
+
|
|
142
|
+
// --- Usage: fire-and-forget ---
|
|
143
|
+
(new FAutoDeleteAsyncTask<FChunkProcessTask>(MoveTemp(Vertices), 2.0f))
|
|
144
|
+
->StartBackgroundTask();
|
|
145
|
+
// Task auto-deletes when DoWork completes — no result retrieval possible
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## TGraphTask Template with Prerequisites
|
|
151
|
+
|
|
152
|
+
Custom TaskGraph task with dependency chaining.
|
|
153
|
+
|
|
154
|
+
```cpp
|
|
155
|
+
#include "Async/TaskGraphInterfaces.h"
|
|
156
|
+
|
|
157
|
+
class FComputeNavTask
|
|
158
|
+
{
|
|
159
|
+
public:
|
|
160
|
+
FComputeNavTask(TArray<FVector>& InOutPath) : Path(InOutPath) {}
|
|
161
|
+
|
|
162
|
+
static ESubsequentsMode::Type GetSubsequentsMode()
|
|
163
|
+
{
|
|
164
|
+
return ESubsequentsMode::TrackSubsequents;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
ENamedThreads::Type GetDesiredThread()
|
|
168
|
+
{
|
|
169
|
+
return ENamedThreads::AnyThread;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
TStatId GetStatId() const
|
|
173
|
+
{
|
|
174
|
+
RETURN_QUICK_DECLARE_CYCLE_STAT(FComputeNavTask, STATGROUP_TaskGraphTasks);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
|
|
178
|
+
{
|
|
179
|
+
// Compute path — runs on worker thread
|
|
180
|
+
for (FVector& Point : Path)
|
|
181
|
+
{
|
|
182
|
+
Point = SmoothPoint(Point);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private:
|
|
187
|
+
TArray<FVector>& Path;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// --- Dispatch with prerequisites ---
|
|
191
|
+
FGraphEventArray NoPrereqs;
|
|
192
|
+
FGraphEventRef StepA = TGraphTask<FComputeNavTask>::CreateTask(&NoPrereqs)
|
|
193
|
+
.ConstructAndDispatchWhenReady(PathData);
|
|
194
|
+
|
|
195
|
+
FGraphEventArray StepAPrereq;
|
|
196
|
+
StepAPrereq.Add(StepA);
|
|
197
|
+
FGraphEventRef StepB = TGraphTask<FApplyNavTask>::CreateTask(&StepAPrereq)
|
|
198
|
+
.ConstructAndDispatchWhenReady(PathData);
|
|
199
|
+
|
|
200
|
+
// Wait for final step on game thread
|
|
201
|
+
FTaskGraphInterface::Get().WaitUntilTaskCompletes(StepB, ENamedThreads::GameThread);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## UE::Tasks::Launch with Prerequisites
|
|
207
|
+
|
|
208
|
+
Modern preferred API (UE 5.0+).
|
|
209
|
+
|
|
210
|
+
```cpp
|
|
211
|
+
#include "Tasks/Task.h"
|
|
212
|
+
|
|
213
|
+
// Step 1: compute positions
|
|
214
|
+
UE::Tasks::TTask<TArray<FVector>> PosTask = UE::Tasks::Launch(
|
|
215
|
+
UE_SOURCE_LOCATION,
|
|
216
|
+
[]() -> TArray<FVector>
|
|
217
|
+
{
|
|
218
|
+
TArray<FVector> Positions;
|
|
219
|
+
// ... expensive computation ...
|
|
220
|
+
return Positions;
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
// Step 2: depends on step 1
|
|
225
|
+
UE::Tasks::TTask<TArray<FVector>> SmoothTask = UE::Tasks::Launch(
|
|
226
|
+
UE_SOURCE_LOCATION,
|
|
227
|
+
[&PosTask]() -> TArray<FVector>
|
|
228
|
+
{
|
|
229
|
+
TArray<FVector> Raw = PosTask.GetResult();
|
|
230
|
+
// ... smooth positions ...
|
|
231
|
+
return Raw;
|
|
232
|
+
},
|
|
233
|
+
UE::Tasks::Prerequisites(PosTask)
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
// Retrieve on game thread (blocks until chain completes)
|
|
237
|
+
TArray<FVector> Final = SmoothTask.GetResult();
|
|
238
|
+
|
|
239
|
+
// Non-blocking check
|
|
240
|
+
if (SmoothTask.IsCompleted()) { /* safe to GetResult without blocking */ }
|
|
241
|
+
|
|
242
|
+
// Timed wait
|
|
243
|
+
if (SmoothTask.Wait(FTimespan::FromMilliseconds(5.0)))
|
|
244
|
+
{
|
|
245
|
+
// completed within timeout
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## ParallelFor Variants
|
|
252
|
+
|
|
253
|
+
```cpp
|
|
254
|
+
#include "Async/ParallelFor.h"
|
|
255
|
+
|
|
256
|
+
// Basic — all iterations equal cost
|
|
257
|
+
ParallelFor(Meshes.Num(), [&Meshes](int32 Index)
|
|
258
|
+
{
|
|
259
|
+
ProcessMesh(Meshes[Index]);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// With MinBatchSize — avoids thread overhead for small counts
|
|
263
|
+
ParallelFor(TEXT("MeshProcess"), Meshes.Num(), 128,
|
|
264
|
+
[&Meshes](int32 Index) { ProcessMesh(Meshes[Index]); }
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
// With flags — variable-cost iterations at background priority
|
|
268
|
+
ParallelFor(Meshes.Num(), [&Meshes](int32 Index)
|
|
269
|
+
{
|
|
270
|
+
ProcessMesh(Meshes[Index]);
|
|
271
|
+
}, EParallelForFlags::Unbalanced | EParallelForFlags::BackgroundPriority);
|
|
272
|
+
|
|
273
|
+
// With per-thread context — avoids per-iteration allocation
|
|
274
|
+
TArray<FMyThreadContext> OutContexts;
|
|
275
|
+
ParallelForWithTaskContext(TEXT("GenNormals"), OutContexts, Meshes.Num(), 64,
|
|
276
|
+
[&Meshes](FMyThreadContext& Ctx, int32 Index)
|
|
277
|
+
{
|
|
278
|
+
// Ctx is unique per worker thread — use as scratch buffer
|
|
279
|
+
Ctx.TempBuffer.Reset();
|
|
280
|
+
ComputeNormals(Meshes[Index], Ctx.TempBuffer);
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Async() with EAsyncExecution Modes
|
|
288
|
+
|
|
289
|
+
```cpp
|
|
290
|
+
#include "Async/Async.h"
|
|
291
|
+
|
|
292
|
+
// ThreadPool — most common for CPU work
|
|
293
|
+
TFuture<int32> F1 = Async(EAsyncExecution::ThreadPool,
|
|
294
|
+
[]() { return HeavyCompute(); });
|
|
295
|
+
|
|
296
|
+
// TaskGraphMainThread — runs on game thread next tick
|
|
297
|
+
TFuture<void> F2 = Async(EAsyncExecution::TaskGraphMainThread,
|
|
298
|
+
[]() { /* safe for UObject access */ });
|
|
299
|
+
|
|
300
|
+
// Thread — dedicated thread for blocking I/O
|
|
301
|
+
TFuture<TArray<uint8>> F3 = Async(EAsyncExecution::Thread,
|
|
302
|
+
[]() { return FFileHelper::LoadFileToArray(...); });
|
|
303
|
+
|
|
304
|
+
// Convenience wrappers
|
|
305
|
+
TFuture<int32> F4 = AsyncPool(GThreadPool,
|
|
306
|
+
[]() { return Compute(); });
|
|
307
|
+
TFuture<void> F5 = AsyncThread(
|
|
308
|
+
[]() { BlockingIOWork(); },
|
|
309
|
+
0, // StackSize (0 = default)
|
|
310
|
+
TPri_Normal);
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## TPromise/TFuture Producer-Consumer
|
|
316
|
+
|
|
317
|
+
Decouples the code that produces a value from the code that consumes it.
|
|
318
|
+
|
|
319
|
+
```cpp
|
|
320
|
+
#include "Async/Future.h"
|
|
321
|
+
#include "Async/Async.h"
|
|
322
|
+
|
|
323
|
+
// Create promise/future pair
|
|
324
|
+
TPromise<FAnalyticsResult> Promise;
|
|
325
|
+
TFuture<FAnalyticsResult> Future = Promise.GetFuture(); // call exactly once
|
|
326
|
+
|
|
327
|
+
// Producer — moves promise into background work
|
|
328
|
+
Async(EAsyncExecution::ThreadPool, [P = MoveTemp(Promise)]() mutable
|
|
329
|
+
{
|
|
330
|
+
FAnalyticsResult Result;
|
|
331
|
+
Result.PlayerCount = GatherPlayerMetrics();
|
|
332
|
+
Result.FrameStats = GatherFrameMetrics();
|
|
333
|
+
P.SetValue(MoveTemp(Result)); // or P.EmplaceValue(args...)
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// Consumer — chain continuation or block
|
|
337
|
+
Future.Then([](TFuture<FAnalyticsResult> F)
|
|
338
|
+
{
|
|
339
|
+
FAnalyticsResult R = F.Get(); // Get() does NOT invalidate
|
|
340
|
+
UE_LOG(LogGame, Log, TEXT("Players: %d"), R.PlayerCount);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// Or block directly on game thread (use sparingly)
|
|
344
|
+
FAnalyticsResult R = Future.Get();
|
|
345
|
+
```
|