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,480 @@
|
|
|
1
|
+
# Editor Module Setup
|
|
2
|
+
|
|
3
|
+
Complete boilerplate and registration patterns for Unreal Engine editor modules. All editor extension code must live in a module with `"Type": "Editor"` to ensure it is excluded from packaged builds.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Project Configuration
|
|
8
|
+
|
|
9
|
+
### .uproject Module Entries
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"Modules": [
|
|
14
|
+
{
|
|
15
|
+
"Name": "MyGame",
|
|
16
|
+
"Type": "Runtime",
|
|
17
|
+
"LoadingPhase": "Default"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"Name": "MyGameEditor",
|
|
21
|
+
"Type": "Editor",
|
|
22
|
+
"LoadingPhase": "PostEngineInit"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**LoadingPhase guidance**:
|
|
29
|
+
|
|
30
|
+
| Phase | Use When |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `Default` | Module has no editor-UI dependencies |
|
|
33
|
+
| `PostEngineInit` | Module registers detail customizations, menus, or editor modes — use this for all editor extension modules |
|
|
34
|
+
| `PreDefault` | Module provides services needed before other modules load |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Directory Layout
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
MyProject/
|
|
42
|
+
Source/
|
|
43
|
+
MyGame/ ← Runtime module
|
|
44
|
+
MyGame.Build.cs
|
|
45
|
+
MyGame.h
|
|
46
|
+
Public/
|
|
47
|
+
Private/
|
|
48
|
+
MyGameEditor/ ← Editor module
|
|
49
|
+
MyGameEditor.Build.cs
|
|
50
|
+
MyGameEditor.h
|
|
51
|
+
Public/
|
|
52
|
+
Customizations/
|
|
53
|
+
FMyDataAssetCustomization.h
|
|
54
|
+
Modes/
|
|
55
|
+
MyEditorMode.h
|
|
56
|
+
AssetTypes/
|
|
57
|
+
FMyAssetTypeActions.h
|
|
58
|
+
Private/
|
|
59
|
+
MyGameEditorModule.cpp
|
|
60
|
+
Customizations/
|
|
61
|
+
FMyDataAssetCustomization.cpp
|
|
62
|
+
Modes/
|
|
63
|
+
MyEditorMode.cpp
|
|
64
|
+
AssetTypes/
|
|
65
|
+
FMyAssetTypeActions.cpp
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Build.cs
|
|
71
|
+
|
|
72
|
+
```csharp
|
|
73
|
+
// MyGameEditor.Build.cs
|
|
74
|
+
using UnrealBuildTool;
|
|
75
|
+
|
|
76
|
+
public class MyGameEditor : ModuleRules
|
|
77
|
+
{
|
|
78
|
+
public MyGameEditor(ReadOnlyTargetRules Target) : base(Target)
|
|
79
|
+
{
|
|
80
|
+
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
|
81
|
+
|
|
82
|
+
PublicDependencyModuleNames.AddRange(new string[]
|
|
83
|
+
{
|
|
84
|
+
"Core",
|
|
85
|
+
"CoreUObject",
|
|
86
|
+
"Engine",
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
PrivateDependencyModuleNames.AddRange(new string[]
|
|
90
|
+
{
|
|
91
|
+
// Editor framework
|
|
92
|
+
"UnrealEd",
|
|
93
|
+
"EditorFramework",
|
|
94
|
+
|
|
95
|
+
// Slate for editor UI
|
|
96
|
+
"Slate",
|
|
97
|
+
"SlateCore",
|
|
98
|
+
"EditorStyle", // FEditorStyle / FAppStyle
|
|
99
|
+
|
|
100
|
+
// Detail panel customization
|
|
101
|
+
"PropertyEditor", // IDetailCustomization, FPropertyEditorModule
|
|
102
|
+
|
|
103
|
+
// Editor subsystems
|
|
104
|
+
"EditorSubsystem", // UEditorSubsystem base class
|
|
105
|
+
|
|
106
|
+
// Blutility (editor utility widgets & scripted actions)
|
|
107
|
+
"Blutility", // UEditorUtilityWidget, UAssetActionUtility, UActorActionUtility
|
|
108
|
+
|
|
109
|
+
// Menus and toolbars
|
|
110
|
+
"ToolMenus", // UToolMenus
|
|
111
|
+
|
|
112
|
+
// Asset type actions and content browser integration
|
|
113
|
+
"AssetTools", // FAssetTypeActions_Base, IAssetTools
|
|
114
|
+
"ContentBrowser", // Content browser integration (if needed)
|
|
115
|
+
|
|
116
|
+
// Editor mode framework
|
|
117
|
+
"EditorInteractiveToolsFramework", // for UInteractiveTool-based modes (UE5)
|
|
118
|
+
|
|
119
|
+
// Input
|
|
120
|
+
"InputCore", // FKey, EKeys
|
|
121
|
+
|
|
122
|
+
// Your runtime module
|
|
123
|
+
"MyGame",
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Only include these when building for editor targets
|
|
127
|
+
if (Target.bBuildEditor)
|
|
128
|
+
{
|
|
129
|
+
PrivateDependencyModuleNames.AddRange(new string[]
|
|
130
|
+
{
|
|
131
|
+
"EditorScriptingUtilities", // UEditorAssetLibrary, UEditorLevelLibrary
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Module Header
|
|
141
|
+
|
|
142
|
+
```cpp
|
|
143
|
+
// MyGameEditor.h
|
|
144
|
+
#pragma once
|
|
145
|
+
|
|
146
|
+
#include "Modules/ModuleManager.h"
|
|
147
|
+
|
|
148
|
+
class FMyGameEditorModule : public IModuleInterface
|
|
149
|
+
{
|
|
150
|
+
public:
|
|
151
|
+
// IModuleInterface
|
|
152
|
+
virtual void StartupModule() override;
|
|
153
|
+
virtual void ShutdownModule() override;
|
|
154
|
+
|
|
155
|
+
private:
|
|
156
|
+
void RegisterDetailCustomizations();
|
|
157
|
+
void UnregisterDetailCustomizations();
|
|
158
|
+
|
|
159
|
+
void RegisterAssetTypeActions();
|
|
160
|
+
void UnregisterAssetTypeActions();
|
|
161
|
+
|
|
162
|
+
void RegisterEditorModes();
|
|
163
|
+
void UnregisterEditorModes();
|
|
164
|
+
|
|
165
|
+
void RegisterMenuExtensions();
|
|
166
|
+
|
|
167
|
+
// Keep alive references for registered asset type actions
|
|
168
|
+
TArray<TSharedPtr<class IAssetTypeActions>> RegisteredAssetTypeActions;
|
|
169
|
+
};
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Module Implementation
|
|
175
|
+
|
|
176
|
+
```cpp
|
|
177
|
+
// MyGameEditorModule.cpp
|
|
178
|
+
#include "MyGameEditor.h"
|
|
179
|
+
|
|
180
|
+
// Detail customizations
|
|
181
|
+
#include "Customizations/FMyDataAssetCustomization.h"
|
|
182
|
+
#include "Customizations/FMyStructCustomization.h"
|
|
183
|
+
|
|
184
|
+
// Editor modes
|
|
185
|
+
#include "Modes/MyEditorMode.h"
|
|
186
|
+
|
|
187
|
+
// Asset type actions
|
|
188
|
+
#include "AssetTypes/FMyAssetTypeActions.h"
|
|
189
|
+
|
|
190
|
+
// Runtime types (from MyGame module)
|
|
191
|
+
#include "MyDataAsset.h"
|
|
192
|
+
#include "MyStruct.h"
|
|
193
|
+
|
|
194
|
+
// UE headers
|
|
195
|
+
#include "PropertyEditorModule.h"
|
|
196
|
+
#include "AssetToolsModule.h"
|
|
197
|
+
#include "EditorModeRegistry.h"
|
|
198
|
+
#include "ToolMenus.h"
|
|
199
|
+
#include "Framework/Application/SlateApplication.h"
|
|
200
|
+
#include "Styling/AppStyle.h"
|
|
201
|
+
|
|
202
|
+
IMPLEMENT_MODULE(FMyGameEditorModule, MyGameEditor)
|
|
203
|
+
|
|
204
|
+
// ---- StartupModule ----------------------------------------------------------
|
|
205
|
+
|
|
206
|
+
void FMyGameEditorModule::StartupModule()
|
|
207
|
+
{
|
|
208
|
+
RegisterDetailCustomizations();
|
|
209
|
+
RegisterAssetTypeActions();
|
|
210
|
+
RegisterEditorModes();
|
|
211
|
+
|
|
212
|
+
// Defer menu registration until Slate is ready
|
|
213
|
+
UToolMenus::RegisterStartupCallback(
|
|
214
|
+
FSimpleMulticastDelegate::FDelegate::CreateRaw(
|
|
215
|
+
this, &FMyGameEditorModule::RegisterMenuExtensions));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ---- ShutdownModule ---------------------------------------------------------
|
|
219
|
+
|
|
220
|
+
void FMyGameEditorModule::ShutdownModule()
|
|
221
|
+
{
|
|
222
|
+
// Menus must be unregistered before PropertyEditor / AssetTools modules unload
|
|
223
|
+
UToolMenus::UnRegisterStartupCallback(this);
|
|
224
|
+
if (UToolMenus* ToolMenus = UToolMenus::TryGet())
|
|
225
|
+
{
|
|
226
|
+
ToolMenus->UnregisterOwner(this);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
UnregisterEditorModes();
|
|
230
|
+
UnregisterAssetTypeActions();
|
|
231
|
+
UnregisterDetailCustomizations();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ---- Detail Customizations --------------------------------------------------
|
|
235
|
+
|
|
236
|
+
void FMyGameEditorModule::RegisterDetailCustomizations()
|
|
237
|
+
{
|
|
238
|
+
if (!FModuleManager::Get().IsModuleLoaded("PropertyEditor"))
|
|
239
|
+
{
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
FPropertyEditorModule& PropertyModule =
|
|
243
|
+
FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
|
|
244
|
+
|
|
245
|
+
PropertyModule.RegisterCustomClassLayout(
|
|
246
|
+
UMyDataAsset::StaticClass()->GetFName(),
|
|
247
|
+
FOnGetDetailCustomizationInstance::CreateStatic(
|
|
248
|
+
&FMyDataAssetCustomization::MakeInstance));
|
|
249
|
+
|
|
250
|
+
PropertyModule.RegisterCustomPropertyTypeLayout(
|
|
251
|
+
FMyStruct::StaticStruct()->GetFName(),
|
|
252
|
+
FOnGetPropertyTypeCustomizationInstance::CreateStatic(
|
|
253
|
+
&FMyStructCustomization::MakeInstance));
|
|
254
|
+
|
|
255
|
+
PropertyModule.NotifyCustomizationModuleChanged();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
void FMyGameEditorModule::UnregisterDetailCustomizations()
|
|
259
|
+
{
|
|
260
|
+
if (!FModuleManager::Get().IsModuleLoaded("PropertyEditor"))
|
|
261
|
+
{
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
FPropertyEditorModule& PropertyModule =
|
|
265
|
+
FModuleManager::GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
|
|
266
|
+
|
|
267
|
+
PropertyModule.UnregisterCustomClassLayout(
|
|
268
|
+
UMyDataAsset::StaticClass()->GetFName());
|
|
269
|
+
PropertyModule.UnregisterCustomPropertyTypeLayout(
|
|
270
|
+
FMyStruct::StaticStruct()->GetFName());
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// ---- Asset Type Actions -----------------------------------------------------
|
|
274
|
+
|
|
275
|
+
void FMyGameEditorModule::RegisterAssetTypeActions()
|
|
276
|
+
{
|
|
277
|
+
IAssetTools& AssetTools =
|
|
278
|
+
FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
|
|
279
|
+
|
|
280
|
+
TSharedPtr<FMyAssetTypeActions> Actions =
|
|
281
|
+
MakeShareable(new FMyAssetTypeActions);
|
|
282
|
+
AssetTools.RegisterAssetTypeActions(Actions.ToSharedRef());
|
|
283
|
+
RegisteredAssetTypeActions.Add(Actions);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
void FMyGameEditorModule::UnregisterAssetTypeActions()
|
|
287
|
+
{
|
|
288
|
+
if (!FModuleManager::Get().IsModuleLoaded("AssetTools"))
|
|
289
|
+
{
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
IAssetTools& AssetTools =
|
|
293
|
+
FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools").Get();
|
|
294
|
+
|
|
295
|
+
for (const TSharedPtr<IAssetTypeActions>& Action : RegisteredAssetTypeActions)
|
|
296
|
+
{
|
|
297
|
+
AssetTools.UnregisterAssetTypeActions(Action.ToSharedRef());
|
|
298
|
+
}
|
|
299
|
+
RegisteredAssetTypeActions.Empty();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// ---- Editor Modes -----------------------------------------------------------
|
|
303
|
+
|
|
304
|
+
void FMyGameEditorModule::RegisterEditorModes()
|
|
305
|
+
{
|
|
306
|
+
FEditorModeRegistry::Get().RegisterMode<FMyEditorMode>(
|
|
307
|
+
FMyEditorMode::EM_MyMode,
|
|
308
|
+
FText::FromString("My Editor Mode"),
|
|
309
|
+
FSlateIcon(FAppStyle::GetAppStyleSetName(), "LevelEditor.SelectMode"),
|
|
310
|
+
true // bVisible in the mode toolbar
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
void FMyGameEditorModule::UnregisterEditorModes()
|
|
315
|
+
{
|
|
316
|
+
FEditorModeRegistry::Get().UnregisterMode(FMyEditorMode::EM_MyMode);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// ---- Menu Extensions --------------------------------------------------------
|
|
320
|
+
|
|
321
|
+
void FMyGameEditorModule::RegisterMenuExtensions()
|
|
322
|
+
{
|
|
323
|
+
FToolMenuOwnerScoped OwnerScoped(this);
|
|
324
|
+
|
|
325
|
+
// Main menu extension
|
|
326
|
+
UToolMenu* WindowMenu =
|
|
327
|
+
UToolMenus::Get()->ExtendMenu("LevelEditor.MainMenu.Window");
|
|
328
|
+
{
|
|
329
|
+
FToolMenuSection& Section =
|
|
330
|
+
WindowMenu->FindOrAddSection("MyGameSection");
|
|
331
|
+
Section.Label = FText::FromString("My Game");
|
|
332
|
+
|
|
333
|
+
Section.AddMenuEntry(
|
|
334
|
+
"OpenMyPanel",
|
|
335
|
+
FText::FromString("My Tool Panel"),
|
|
336
|
+
FText::FromString("Open the My Game tool panel"),
|
|
337
|
+
FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.Settings"),
|
|
338
|
+
FUIAction(FExecuteAction::CreateLambda([]()
|
|
339
|
+
{
|
|
340
|
+
// GEditor->GetEditorSubsystem<UEditorUtilitySubsystem>()
|
|
341
|
+
// ->SpawnAndRegisterTab(WidgetBP);
|
|
342
|
+
}))
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## WITH_EDITOR Guards in Runtime Modules
|
|
351
|
+
|
|
352
|
+
If a Runtime module needs to reference editor-only functionality (uncommon but valid for things like editor hints):
|
|
353
|
+
|
|
354
|
+
```cpp
|
|
355
|
+
// SomeRuntimeClass.h
|
|
356
|
+
UCLASS()
|
|
357
|
+
class MYGAME_API UMyRuntimeClass : public UObject
|
|
358
|
+
{
|
|
359
|
+
GENERATED_BODY()
|
|
360
|
+
|
|
361
|
+
public:
|
|
362
|
+
#if WITH_EDITOR
|
|
363
|
+
// Editor-only virtual, e.g. for detail panel hints
|
|
364
|
+
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
|
|
365
|
+
virtual bool CanEditChange(const FProperty* InProperty) const override;
|
|
366
|
+
#endif
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
// SomeRuntimeClass.cpp
|
|
370
|
+
#if WITH_EDITOR
|
|
371
|
+
void UMyRuntimeClass::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
|
372
|
+
{
|
|
373
|
+
Super::PostEditChangeProperty(PropertyChangedEvent);
|
|
374
|
+
const FName PropertyName = PropertyChangedEvent.GetPropertyName();
|
|
375
|
+
if (PropertyName == GET_MEMBER_NAME_CHECKED(UMyRuntimeClass, Speed))
|
|
376
|
+
{
|
|
377
|
+
Speed = FMath::Clamp(Speed, 0.f, MaxSpeed);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
bool UMyRuntimeClass::CanEditChange(const FProperty* InProperty) const
|
|
382
|
+
{
|
|
383
|
+
if (!Super::CanEditChange(InProperty))
|
|
384
|
+
{
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
if (InProperty->GetFName() == GET_MEMBER_NAME_CHECKED(UMyRuntimeClass, AdvancedSetting))
|
|
388
|
+
{
|
|
389
|
+
return bEnableAdvanced;
|
|
390
|
+
}
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
#endif
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Asset Factory (UFactory) Boilerplate
|
|
399
|
+
|
|
400
|
+
Required to support "right-click > Create" in the Content Browser for a custom asset type:
|
|
401
|
+
|
|
402
|
+
```cpp
|
|
403
|
+
// MyCustomAssetFactory.h
|
|
404
|
+
#pragma once
|
|
405
|
+
#include "Factories/Factory.h"
|
|
406
|
+
#include "MyCustomAssetFactory.generated.h"
|
|
407
|
+
|
|
408
|
+
UCLASS()
|
|
409
|
+
class UMyCustomAssetFactory : public UFactory
|
|
410
|
+
{
|
|
411
|
+
GENERATED_BODY()
|
|
412
|
+
|
|
413
|
+
public:
|
|
414
|
+
UMyCustomAssetFactory();
|
|
415
|
+
|
|
416
|
+
virtual UObject* FactoryCreateNew(
|
|
417
|
+
UClass* Class,
|
|
418
|
+
UObject* InParent,
|
|
419
|
+
FName Name,
|
|
420
|
+
EObjectFlags Flags,
|
|
421
|
+
UObject* Context,
|
|
422
|
+
FFeedbackContext* Warn) override;
|
|
423
|
+
|
|
424
|
+
virtual bool ShouldShowInNewMenu() const override { return true; }
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
// MyCustomAssetFactory.cpp
|
|
428
|
+
#include "MyCustomAssetFactory.h"
|
|
429
|
+
#include "MyCustomAsset.h"
|
|
430
|
+
|
|
431
|
+
UMyCustomAssetFactory::UMyCustomAssetFactory()
|
|
432
|
+
{
|
|
433
|
+
SupportedClass = UMyCustomAsset::StaticClass();
|
|
434
|
+
bCreateNew = true;
|
|
435
|
+
bEditAfterNew = true; // open editor immediately after creation
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
UObject* UMyCustomAssetFactory::FactoryCreateNew(
|
|
439
|
+
UClass* Class,
|
|
440
|
+
UObject* InParent,
|
|
441
|
+
FName Name,
|
|
442
|
+
EObjectFlags Flags,
|
|
443
|
+
UObject* Context,
|
|
444
|
+
FFeedbackContext* Warn)
|
|
445
|
+
{
|
|
446
|
+
return NewObject<UMyCustomAsset>(InParent, Class, Name, Flags);
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
The factory is auto-discovered by the editor; no explicit registration is needed. The `UFactory` subclass must be in the editor module.
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Module Dependency Graph
|
|
455
|
+
|
|
456
|
+
```
|
|
457
|
+
MyGameEditor (Type: Editor)
|
|
458
|
+
depends on → MyGame (Type: Runtime)
|
|
459
|
+
depends on → PropertyEditor, UnrealEd, Blutility, ToolMenus, AssetTools
|
|
460
|
+
depends on → Slate, SlateCore, EditorStyle
|
|
461
|
+
|
|
462
|
+
MyGame (Type: Runtime)
|
|
463
|
+
no editor dependencies
|
|
464
|
+
uses WITH_EDITOR guards for PostEditChangeProperty etc.
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## Checklist: New Editor Module
|
|
470
|
+
|
|
471
|
+
- [ ] `"Type": "Editor"` in .uproject
|
|
472
|
+
- [ ] `"LoadingPhase": "PostEngineInit"` in .uproject
|
|
473
|
+
- [ ] `Build.cs` references `UnrealEd`, `PropertyEditor`, `ToolMenus`, `Blutility` as needed
|
|
474
|
+
- [ ] `IMPLEMENT_MODULE(FMyEditorModule, MyEditorModuleName)` in .cpp
|
|
475
|
+
- [ ] All registrations in `StartupModule`
|
|
476
|
+
- [ ] All unregistrations in `ShutdownModule` (guarded with `IsModuleLoaded` checks)
|
|
477
|
+
- [ ] Menu registrations wrapped in `UToolMenus::RegisterStartupCallback`
|
|
478
|
+
- [ ] Menu unregistration: `UnRegisterStartupCallback` + `UnregisterOwner`
|
|
479
|
+
- [ ] `NotifyCustomizationModuleChanged()` called after detail customization registration
|
|
480
|
+
- [ ] No `#include "EdMode.h"` or other editor headers pulled into Runtime module headers
|