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.
Files changed (144) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +104 -55
  3. package/agents/career/career-strategist.md +88 -0
  4. package/agents/career/cv-reviewer.md +81 -0
  5. package/agents/career/hiring-manager.md +68 -0
  6. package/agents/career/mock-interviewer.md +76 -0
  7. package/agents/freelance/client-screener.md +84 -0
  8. package/agents/freelance/discovery-call.md +65 -0
  9. package/agents/freelance/pipeline-strategist.md +99 -0
  10. package/agents/freelance/proposal-reviewer.md +82 -0
  11. package/agents/game/ue-blueprint-specialist.md +125 -0
  12. package/agents/game/ue-gas-specialist.md +133 -0
  13. package/agents/game/ue-umg-specialist.md +131 -0
  14. package/dist/cli.js +57 -13
  15. package/docs/RELEASE-SETUP.md +1 -1
  16. package/docs/SKILLS-CATALOG.md +67 -4
  17. package/docs/USER-GUIDE.md +77 -72
  18. package/docs/agent-hierarchy.md +21 -1
  19. package/docs/presentations/build_arcane_deck.py +2 -2
  20. package/docs/presentations/build_arcane_deck_12.py +2 -2
  21. package/hooks/detect-unreal.sh +90 -0
  22. package/package.json +2 -2
  23. package/profiles/freelance.yaml +43 -0
  24. package/profiles/job-hunt.yaml +5 -2
  25. package/profiles/unreal-dev.yaml +97 -0
  26. package/rules/drafter-reviewer.md +16 -3
  27. package/rules/freelance-guardrails.md +53 -0
  28. package/rules/gamedev/unreal-code.md +125 -0
  29. package/skills/career-registry/SKILL.md +95 -0
  30. package/skills/career-registry/scripts/career_registry.py +488 -0
  31. package/skills/client-screen/SKILL.md +83 -0
  32. package/skills/client-screen/references/red-flags.md +95 -0
  33. package/skills/cover-letter/SKILL.md +4 -3
  34. package/skills/cv-tailor/SKILL.md +11 -2
  35. package/skills/freelance-deliver/SKILL.md +90 -0
  36. package/skills/freelance-hunt/SKILL.md +126 -0
  37. package/skills/freelance-hunt/references/templates/Connects.md +39 -0
  38. package/skills/freelance-hunt/references/templates/Contrato.md +60 -0
  39. package/skills/freelance-hunt/references/templates/Propuesta.md +66 -0
  40. package/skills/freelance-kickoff/SKILL.md +94 -0
  41. package/skills/freelance-pipeline/SKILL.md +109 -0
  42. package/skills/freelance-pipeline/scripts/import_history.py +425 -0
  43. package/skills/freelance-profile/SKILL.md +93 -0
  44. package/skills/freelance-proposal/SKILL.md +112 -0
  45. package/skills/freelance-scan/SKILL.md +196 -0
  46. package/skills/freelance-scan/references/dedup.md +35 -0
  47. package/skills/freelance-scan/references/platforms.md +167 -0
  48. package/skills/freelance-scan/scripts/freelance_search.py +1077 -0
  49. package/skills/install-mcp/SKILL.md +135 -46
  50. package/skills/install-mcp/references/unreal-operations.md +55 -0
  51. package/skills/interview-prep/SKILL.md +11 -3
  52. package/skills/job-aplicar/SKILL.md +5 -1
  53. package/skills/job-hunt/SKILL.md +17 -0
  54. package/skills/job-outcome/SKILL.md +15 -1
  55. package/skills/job-upskill/SKILL.md +10 -2
  56. package/skills/ue-actor-component-architecture/SKILL.md +509 -0
  57. package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
  58. package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
  59. package/skills/ue-ai-navigation/SKILL.md +526 -0
  60. package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
  61. package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
  62. package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
  63. package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
  64. package/skills/ue-animation-system/SKILL.md +521 -0
  65. package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
  66. package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
  67. package/skills/ue-async-threading/SKILL.md +433 -0
  68. package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
  69. package/skills/ue-async-threading/references/threading-patterns.md +345 -0
  70. package/skills/ue-audio-system/SKILL.md +527 -0
  71. package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
  72. package/skills/ue-blueprints/SKILL.md +134 -0
  73. package/skills/ue-blueprints/references/communication.md +82 -0
  74. package/skills/ue-character-movement/SKILL.md +475 -0
  75. package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
  76. package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
  77. package/skills/ue-cpp-foundations/SKILL.md +533 -0
  78. package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
  79. package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
  80. package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
  81. package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
  82. package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
  83. package/skills/ue-data-assets-tables/SKILL.md +527 -0
  84. package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
  85. package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
  86. package/skills/ue-editor-tools/SKILL.md +523 -0
  87. package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
  88. package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
  89. package/skills/ue-game-features/SKILL.md +477 -0
  90. package/skills/ue-game-features/references/experience-system.md +222 -0
  91. package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
  92. package/skills/ue-gameplay-abilities/SKILL.md +518 -0
  93. package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
  94. package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
  95. package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
  96. package/skills/ue-gameplay-framework/SKILL.md +466 -0
  97. package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
  98. package/skills/ue-input-system/SKILL.md +394 -0
  99. package/skills/ue-input-system/references/cpp-setup.md +131 -0
  100. package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
  101. package/skills/ue-input-system/references/input-action-reference.md +731 -0
  102. package/skills/ue-mass-entity/SKILL.md +476 -0
  103. package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
  104. package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
  105. package/skills/ue-materials-rendering/SKILL.md +526 -0
  106. package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
  107. package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
  108. package/skills/ue-module-build-system/SKILL.md +487 -0
  109. package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
  110. package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
  111. package/skills/ue-naming-conventions/SKILL.md +142 -0
  112. package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
  113. package/skills/ue-naming-conventions/references/content-structure.md +83 -0
  114. package/skills/ue-networking-replication/SKILL.md +452 -0
  115. package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
  116. package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
  117. package/skills/ue-niagara-effects/SKILL.md +531 -0
  118. package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
  119. package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
  120. package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
  121. package/skills/ue-packaging/SKILL.md +116 -0
  122. package/skills/ue-physics-collision/SKILL.md +423 -0
  123. package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
  124. package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
  125. package/skills/ue-procedural-generation/SKILL.md +505 -0
  126. package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
  127. package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
  128. package/skills/ue-project-context/SKILL.md +305 -0
  129. package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
  130. package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
  131. package/skills/ue-serialization-savegames/SKILL.md +524 -0
  132. package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
  133. package/skills/ue-state-trees/SKILL.md +489 -0
  134. package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
  135. package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
  136. package/skills/ue-testing-debugging/SKILL.md +520 -0
  137. package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
  138. package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
  139. package/skills/ue-ui-umg-slate/SKILL.md +431 -0
  140. package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
  141. package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
  142. package/skills/ue-world-level-streaming/SKILL.md +518 -0
  143. package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
  144. package/templates/gamedev/unreal-project-context.md +107 -0
@@ -0,0 +1,466 @@
1
+ ---
2
+ name: ue-gameplay-framework
3
+ description: "GameMode, GameState, PlayerController, PlayerState, Pawn, HUD"
4
+ category: "gamedev"
5
+ argument-hint: "[class o flow]"
6
+ user-invocable: true
7
+ allowed-tools: Read, Glob, Grep, Bash, Write, Edit
8
+ ---
9
+
10
+ # UE Gameplay Framework
11
+
12
+ You are an expert in Unreal Engine's gameplay framework architecture.
13
+
14
+ Ask before writing: this skill edits GameMode, GameState, Controller, PlayerState and Pawn classes. Propose the change and get approval before using Write or Edit.
15
+
16
+ ## Context Check
17
+
18
+ Read `docs/unreal/project-context.md` before proceeding. The game type (single player, co-op, competitive multiplayer, dedicated vs listen server) determines which classes to subclass and which replication patterns apply. Resolve: single-player or multiplayer? Dedicated or listen server? What are you implementing?
19
+
20
+ ---
21
+
22
+ ## Class Responsibility Map
23
+
24
+ Each class exists on specific machines for specific reasons. Getting this wrong is the primary source of multiplayer bugs.
25
+
26
+ ### AGameModeBase / AGameMode — Server Only
27
+
28
+ **Exists on:** Server and standalone only. Never instantiated on clients.
29
+
30
+ **Why server-only:** GameMode is the authoritative referee. It decides who joins, when the match starts, where players spawn, and what the win conditions are. Client execution would allow cheating via local state manipulation.
31
+
32
+ **AGameMode adds** the full match-state machine (`EnteringMap` → `WaitingToStart` → `InProgress` → `WaitingPostMatch` → `LeavingMap`; `Aborted` on failure) with `ReadyToStartMatch` and `ReadyToEndMatch` hooks. Use `AGameModeBase` for lobby/simple games, `AGameMode` for match flow.
33
+
34
+ **Key API from source (GameModeBase.h):**
35
+ ```cpp
36
+ // Class assignments — set in constructor
37
+ TSubclassOf<APawn> DefaultPawnClass;
38
+ TSubclassOf<AGameStateBase> GameStateClass;
39
+ TSubclassOf<APlayerController> PlayerControllerClass;
40
+ TSubclassOf<APlayerState> PlayerStateClass;
41
+ TSubclassOf<AHUD> HUDClass;
42
+ uint32 bUseSeamlessTravel : 1;
43
+
44
+ // Server startup and player join lifecycle (server only)
45
+ virtual void InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage);
46
+ virtual void PreLogin(const FString& Options, const FString& Address,
47
+ const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage);
48
+ virtual APlayerController* Login(UPlayer* NewPlayer, ENetRole InRemoteRole,
49
+ const FString& Portal, const FString& Options,
50
+ const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage);
51
+ virtual void PostLogin(APlayerController* NewPlayer); // first safe point for RPCs (DispatchPostLogin deprecated 5.6 — override PostLogin directly)
52
+ virtual void Logout(AController* Exiting);
53
+ virtual void HandleStartingNewPlayer(APlayerController* NewPlayer);
54
+
55
+ // Spawn pipeline
56
+ virtual AActor* FindPlayerStart(AController* Player, const FString& IncomingName = TEXT(""));
57
+ virtual void RestartPlayer(AController* NewPlayer);
58
+ virtual APawn* SpawnDefaultPawnFor(AController* NewPlayer, AActor* StartSpot);
59
+
60
+ // Travel
61
+ virtual void ProcessServerTravel(const FString& URL, bool bAbsolute = false);
62
+ virtual void GetSeamlessTravelActorList(bool bToTransition, TArray<AActor*>& ActorList);
63
+ ```
64
+
65
+ ---
66
+
67
+ ### AGameStateBase / AGameState — Server + All Clients
68
+
69
+ **Exists on:** Everywhere. Fully replicated.
70
+
71
+ **Why everywhere:** Clients cannot read GameMode (it does not exist on them). Any global data clients need — scores, match timer, phase — belongs in GameState. `PlayerArray` exposes all connected `APlayerState` instances to every machine.
72
+
73
+ **Key API from source (GameStateBase.h):**
74
+ ```cpp
75
+ // All PlayerStates, always replicated
76
+ UPROPERTY(Transient, BlueprintReadOnly)
77
+ TArray<TObjectPtr<APlayerState>> PlayerArray;
78
+
79
+ // The GameMode class (not instance) replicated to clients
80
+ UPROPERTY(Transient, BlueprintReadOnly, ReplicatedUsing=OnRep_GameModeClass)
81
+ TSubclassOf<AGameModeBase> GameModeClass;
82
+
83
+ // Server-authoritative clock, automatically synced
84
+ virtual double GetServerWorldTimeSeconds() const;
85
+ virtual bool HasBegunPlay() const;
86
+ virtual bool HasMatchStarted() const;
87
+ virtual bool HasMatchEnded() const;
88
+ ```
89
+
90
+ **Custom replicated match data:**
91
+ ```cpp
92
+ UCLASS()
93
+ class AMyGameState : public AGameStateBase
94
+ {
95
+ GENERATED_BODY()
96
+ public:
97
+ UPROPERTY(Replicated, BlueprintReadOnly) int32 TeamAScore;
98
+ UPROPERTY(Replicated, BlueprintReadOnly) int32 TeamBScore;
99
+ UPROPERTY(ReplicatedUsing=OnRep_MatchTimer) float MatchTimeRemaining;
100
+
101
+ virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
102
+ };
103
+
104
+ void AMyGameState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
105
+ {
106
+ Super::GetLifetimeReplicatedProps(OutLifetimeProps);
107
+ DOREPLIFETIME(AMyGameState, TeamAScore);
108
+ DOREPLIFETIME(AMyGameState, TeamBScore);
109
+ DOREPLIFETIME(AMyGameState, MatchTimeRemaining);
110
+ }
111
+ ```
112
+
113
+ ---
114
+
115
+ ### APlayerController — Server (all) + Owning Client (own only)
116
+
117
+ **Exists on:** Server holds one per connected player. Each client holds only its own. Remote clients do not see other players' PlayerControllers.
118
+
119
+ **Why this split:** The PlayerController bridges one human to the server. Both ends run it for client-side prediction and server validation. A client has no reason to know another player's input state.
120
+
121
+ **Key API from source (PlayerController.h):**
122
+ ```cpp
123
+ TObjectPtr<APlayerCameraManager> PlayerCameraManager; // camera, local only
124
+ TObjectPtr<APawn> AcknowledgedPawn; // server-confirmed possession
125
+ TObjectPtr<AHUD> MyHUD; // local only
126
+
127
+ uint32 bShowMouseCursor : 1;
128
+ uint32 bEnableStreamingSource : 1; // drives World Partition loading for this viewport
129
+
130
+ void SetInputMode(const FInputModeDataBase& InData); // FInputModeGameOnly, UIOnly, GameAndUI
131
+ virtual void PlayerTick(float DeltaTime); // only ticked locally
132
+ virtual void SetupInputComponent() override;
133
+ ```
134
+
135
+ **`SetupInputComponent` on PlayerController** is for non-pawn input: spectator actions, UI shortcuts, or global keybinds that persist across possession changes. For pawn-specific input, override `APawn::SetupPlayerInputComponent()` instead — see `/ue-input-system`.
136
+
137
+ **Enhanced Input setup:**
138
+ ```cpp
139
+ void AMyPlayerController::BeginPlay()
140
+ {
141
+ Super::BeginPlay();
142
+ if (IsLocalController())
143
+ {
144
+ if (auto* Sub = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
145
+ Sub->AddMappingContext(DefaultMappingContext, 0);
146
+ SetInputMode(FInputModeGameOnly());
147
+ }
148
+ }
149
+ ```
150
+
151
+ **RPC patterns:**
152
+ ```cpp
153
+ UFUNCTION(Server, Reliable, WithValidation) void ServerRequestRespawn(); // client → server
154
+ UFUNCTION(Client, Reliable) void ClientNotifyMatchStart(); // server → client
155
+ ```
156
+
157
+ **Possess/UnPossess (server-authority required):**
158
+ ```cpp
159
+ // Take control of a new pawn — must run on server
160
+ PlayerController->Possess(NewPawn);
161
+ // Release the currently possessed pawn
162
+ PlayerController->UnPossess();
163
+ ```
164
+
165
+ **Listen-server dual-role:** On a listen server, the host's PlayerController is both `ROLE_Authority` and locally controlled. Guard dual-role logic with `IsLocalController()` checks. This is a common source of bugs where code assumes authority implies non-local (i.e., code written for dedicated servers runs incorrectly on a listen server host).
166
+
167
+ **ClientTravel — connect this client to a different server:**
168
+ ```cpp
169
+ PlayerController->ClientTravel(TEXT("127.0.0.1:7777"), TRAVEL_Absolute);
170
+ ```
171
+
172
+ **ServerTravel — move all players to a new map (called from GameMode, server only):**
173
+ ```cpp
174
+ GetWorld()->ServerTravel(TEXT("/Game/Maps/NewMap?listen"));
175
+ ```
176
+
177
+ ---
178
+
179
+ ### AController — Shared Base
180
+
181
+ `AController` is the base class for both `APlayerController` and `AAIController`. It owns the pawn possession interface (`Possess`, `UnPossess`, `GetPawn`) and the rotation used to drive pawn orientation (`ControlRotation`). Subclass `APlayerController` for human players and `AAIController` for AI.
182
+
183
+ ---
184
+
185
+ ### APlayerState — Server + All Clients (Always Relevant)
186
+
187
+ **Exists on:** Server and all clients. Marked always-relevant so it replicates to everyone regardless of distance.
188
+
189
+ **Why always relevant:** Scoreboards, team displays, and player lists need to show data for every player, not just nearby ones. PlayerState survives pawn death — when a pawn is destroyed and respawned, the PlayerController keeps its PlayerState, preserving accumulated stats.
190
+
191
+ ```cpp
192
+ UCLASS()
193
+ class AMyPlayerState : public APlayerState
194
+ {
195
+ GENERATED_BODY()
196
+ public:
197
+ UPROPERTY(Replicated, BlueprintReadOnly) int32 Kills;
198
+ UPROPERTY(Replicated, BlueprintReadOnly) int32 Deaths;
199
+ UPROPERTY(ReplicatedUsing=OnRep_Team) uint8 TeamIndex;
200
+ };
201
+
202
+ // Access patterns
203
+ APlayerState* PS = MyPawn->GetPlayerState();
204
+ APlayerState* PS = MyPC->PlayerState;
205
+ for (APlayerState* PS : GetGameState<AGameStateBase>()->PlayerArray) { /* all players */ }
206
+ ```
207
+
208
+ ---
209
+
210
+ ### APawn — Server + All Clients (Replicated)
211
+
212
+ **Exists on:** Server (authority) and all clients (simulated or autonomous proxy). Minimal base — no mesh, no collision component, no movement component.
213
+
214
+ **Use APawn when:** entity is not a humanoid (vehicle, turret, drone), you need a completely custom movement component, or you need zero-overhead baseline.
215
+
216
+ ```cpp
217
+ // Minimal subclass pattern
218
+ virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;
219
+ virtual void PossessedBy(AController* NewController) override;
220
+ virtual void UnPossessed() override;
221
+ ```
222
+
223
+ `ADefaultPawn` is the engine's built-in pawn with floating movement (no gravity) and a sphere collision root. It is used as the `DefaultPawnClass` placeholder when no custom pawn is assigned.
224
+
225
+ ---
226
+
227
+ ### ACharacter — Server + All Clients (Replicated with Prediction)
228
+
229
+ **Exists on:** Server (authority) and all clients. The locally controlled instance runs client-side prediction; simulated proxies interpolate from server updates.
230
+
231
+ **Why ACharacter:** Walking humanoids need capsule collision, gravity, jump, crouch, and movement prediction. ACharacter bundles all of this with built-in networked prediction via `UCharacterMovementComponent`.
232
+
233
+ **Component layout from source (Character.h):**
234
+ ```cpp
235
+ // Private, access via getters
236
+ TObjectPtr<UCapsuleComponent> CapsuleComponent; // GetCapsuleComponent() — root
237
+ TObjectPtr<USkeletalMeshComponent> Mesh; // GetMesh()
238
+ TObjectPtr<UCharacterMovementComponent> CharacterMovement; // GetCharacterMovement()
239
+ TObjectPtr<UArrowComponent> ArrowComponent; // GetArrowComponent() — editor-only direction indicator
240
+ ```
241
+
242
+ **Constructor configuration:**
243
+ ```cpp
244
+ AMyCharacter::AMyCharacter()
245
+ {
246
+ GetCapsuleComponent()->SetCapsuleHalfHeight(96.f);
247
+ GetCapsuleComponent()->SetCapsuleRadius(42.f);
248
+ GetMesh()->SetRelativeLocation(FVector(0.f, 0.f, -97.f));
249
+ GetMesh()->SetRelativeRotation(FRotator(0.f, -90.f, 0.f));
250
+
251
+ GetCharacterMovement()->MaxWalkSpeed = 600.f;
252
+ GetCharacterMovement()->JumpZVelocity = 700.f;
253
+ GetCharacterMovement()->GravityScale = 1.75f;
254
+ GetCharacterMovement()->AirControl = 0.35f;
255
+ GetCharacterMovement()->NavAgentProps.bCanCrouch = true;
256
+ }
257
+ ```
258
+
259
+ **Key ACharacter API from source:**
260
+ ```cpp
261
+ // Jump — from Character.h
262
+ virtual void Jump(); // set bPressedJump, triggers on next tick
263
+ virtual void StopJumping(); // clear bPressedJump
264
+ bool CanJump() const;
265
+
266
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated) float JumpMaxHoldTime; // variable height
267
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Replicated) int32 JumpMaxCount; // double jump
268
+
269
+ virtual void LaunchCharacter(FVector LaunchVelocity, bool bXYOverride, bool bZOverride);
270
+
271
+ // Crouch
272
+ void Crouch(bool bClientSimulation = false); // requests crouch via CharacterMovementComponent
273
+ void UnCrouch(bool bClientSimulation = false);
274
+ UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_IsCrouched) uint8 bIsCrouched : 1;
275
+
276
+ // Movement mode
277
+ // MOVE_Walking, MOVE_Falling, MOVE_Swimming, MOVE_Flying, MOVE_Custom
278
+ GetCharacterMovement()->SetMovementMode(MOVE_Flying);
279
+ ```
280
+
281
+ **Custom movement modes:** Set `MOVE_Custom` then override `PhysCustom(float deltaTime, int32 Iterations)` in your `UCharacterMovementComponent` subclass. The `CustomMovementMode` byte lets you distinguish multiple custom modes within the same `PhysCustom` dispatch.
282
+
283
+ ```cpp
284
+ // Custom movement mode: override in CMC subclass
285
+ void UMyCharacterMovement::PhysCustom(float DeltaTime, int32 Iterations)
286
+ {
287
+ if (CustomMovementMode == (uint8)ECustomMovement::Flying)
288
+ {
289
+ // Custom flying physics here
290
+ Velocity.Z += GetGravityZ() * DeltaTime;
291
+ }
292
+ Super::PhysCustom(DeltaTime, Iterations);
293
+ }
294
+ // Activate: CharMoveComp->SetMovementMode(MOVE_Custom, (uint8)ECustomMovement::Flying);
295
+ ```
296
+
297
+ **Movement replication:** Client sends `ServerMovePacked`, server validates and replies via `ClientMoveResponsePacked`. This is automatic — do not call these RPCs manually.
298
+
299
+ ---
300
+
301
+ ### UGameInstance — Process Lifetime Singleton
302
+
303
+ **Exists on:** One per process. Survives ALL level loads.
304
+
305
+ **Why:** On level travel, every actor (including GameMode, GameState, PlayerController, PlayerState) is destroyed. GameInstance is never destroyed. It holds session handles, save game references, analytics state, and any data that must span the entire application lifetime.
306
+
307
+ ```cpp
308
+ // Lifecycle overrides
309
+ virtual void Init() override; // called once at startup; subsystem init, save-game loading
310
+ virtual void OnStart() override; // called when the instance is ready, after Init
311
+ virtual void Shutdown() override; // called on application exit
312
+
313
+ // Access from actor or component
314
+ UMyGameInstance* GI = GetWorld()->GetGameInstance<UMyGameInstance>();
315
+
316
+ // Subsystems (also survive level travel)
317
+ UMySubsystem* Sub = GetGameInstance()->GetSubsystem<UMySubsystem>();
318
+ ```
319
+
320
+ ### Session Management (Online Subsystem)
321
+
322
+ ```cpp
323
+ // Access the Online Subsystem session interface from GameInstance
324
+ IOnlineSubsystem* OSS = IOnlineSubsystem::Get();
325
+ IOnlineSessionPtr Sessions = OSS ? OSS->GetSessionInterface() : nullptr;
326
+ if (!Sessions.IsValid()) return;
327
+
328
+ // Create session (host)
329
+ FOnlineSessionSettings Settings;
330
+ Settings.bIsLANMatch = false;
331
+ Settings.NumPublicConnections = 4;
332
+ Settings.bShouldAdvertise = true;
333
+ Sessions->OnCreateSessionCompleteDelegates.AddUObject(
334
+ this, &UMyGameInstance::OnCreateSessionComplete);
335
+ Sessions->CreateSession(0, NAME_GameSession, Settings);
336
+
337
+ // Find sessions (client)
338
+ TSharedRef<FOnlineSessionSearch> Search = MakeShared<FOnlineSessionSearch>();
339
+ Sessions->OnFindSessionsCompleteDelegates.AddUObject(
340
+ this, &UMyGameInstance::OnFindSessionsComplete);
341
+ Sessions->FindSessions(0, Search);
342
+
343
+ // Join a found session
344
+ Sessions->OnJoinSessionCompleteDelegates.AddUObject(
345
+ this, &UMyGameInstance::OnJoinSessionComplete);
346
+ Sessions->JoinSession(0, NAME_GameSession, Search->SearchResults[0]);
347
+ ```
348
+
349
+ The Online Subsystem abstracts platform-specific backends (Steam, EOS, Null for testing). Add `"OnlineSubsystem"` and `"OnlineSubsystemUtils"` to your Build.cs dependencies. After joining, retrieve the connect string with `GetResolvedConnectString` and call `ClientTravel`.
350
+
351
+ ---
352
+
353
+ ## GameMode: Registration and Spawn Pipeline
354
+
355
+ ```cpp
356
+ AMyGameMode::AMyGameMode()
357
+ {
358
+ DefaultPawnClass = AMyCharacter::StaticClass();
359
+ PlayerControllerClass = AMyPlayerController::StaticClass();
360
+ GameStateClass = AMyGameState::StaticClass();
361
+ PlayerStateClass = AMyPlayerState::StaticClass();
362
+ HUDClass = AMyHUD::StaticClass();
363
+ bUseSeamlessTravel = true;
364
+ }
365
+ ```
366
+
367
+ **Join sequence (server only):**
368
+ ```
369
+ InitGame() → called before any player joins; use for map-specific rules init
370
+ PreLogin() → reject here (server full, banned)
371
+ Login() → create PlayerController, assign UniqueId
372
+ PostLogin() → first safe point for server→client RPCs; assign teams here
373
+ HandleStartingNewPlayer() → triggers RestartPlayer()
374
+ RestartPlayer() → FindPlayerStart() → SpawnDefaultPawnFor() → Possess()
375
+ ```
376
+
377
+ **Match state (AGameMode only):**
378
+ ```cpp
379
+ bool AMyGameMode::ReadyToStartMatch_Implementation()
380
+ {
381
+ return GetNumPlayers() >= MinPlayersToStart;
382
+ }
383
+ bool AMyGameMode::ReadyToEndMatch_Implementation()
384
+ {
385
+ return GetGameState<AMyGameState>()->TeamAScore >= ScoreLimit;
386
+ }
387
+ ```
388
+
389
+ ---
390
+
391
+ ## Travel Patterns
392
+
393
+ | Pattern | Clients disconnect? | GameMode/GameState survive? | Use when |
394
+ |---|---|---|---|
395
+ | Non-seamless (`ServerTravel`) | Yes, reconnect | No, recreated | Map change with clean slate |
396
+ | Seamless (`bUseSeamlessTravel=true`) | No | No, recreated | Lobby→game, round change |
397
+
398
+ **Seamless travel survival:**
399
+ - Always: `UGameInstance`, `APlayerController`, `APlayerState`
400
+ - Never: `AGameMode`, `AGameState`, level actors
401
+ - Optional: actors you add in `GetSeamlessTravelActorList()`
402
+
403
+ ---
404
+
405
+ ## Common Mistakes
406
+
407
+ **GameMode on client (null crash):**
408
+ ```cpp
409
+ // WRONG
410
+ GetWorld()->GetAuthGameMode<AMyGameMode>()->EndMatch(); // nullptr on client
411
+ // RIGHT
412
+ if (HasAuthority()) { if (auto* GM = GetWorld()->GetAuthGameMode<AMyGameMode>()) GM->EndMatch(); }
413
+ ```
414
+
415
+ **Wrong class for data:**
416
+ ```
417
+ Score visible to all clients → APlayerState, NOT APlayerController
418
+ Match timer on clients → AGameState replicated property, NOT AGameMode
419
+ Data surviving level travel → UGameInstance, NOT AGameState
420
+ Input binding → PlayerController or Pawn::SetupPlayerInputComponent, NOT ACharacter body
421
+ ```
422
+
423
+ **AcknowledgedPawn vs GetPawn:**
424
+ `GetPawn()` on a PlayerController may return a pawn before the server confirms possession. Use `AcknowledgedPawn` when you need the server-confirmed pawn.
425
+
426
+ **Dedicated server guard:**
427
+ ```cpp
428
+ if (GetNetMode() != NM_DedicatedServer)
429
+ {
430
+ // HUD, camera, audio — never run these on dedicated server
431
+ }
432
+ ```
433
+
434
+ **PIE multi-player:** In PIE with multiple players, each has its own PlayerController but all share the same GameMode instance. Test multiplayer logic with PIE > Number of Players set to 2 or more.
435
+
436
+ ---
437
+
438
+ ## Related Skills
439
+
440
+ - `/ue-actor-component-architecture` — actor lifecycle, component tick, attachment
441
+ - `/ue-networking-replication` — DOREPLIFETIME conditions, RPC patterns, push model
442
+ - `/ue-input-system` — Enhanced Input mapping contexts and input actions
443
+
444
+ ## Reference Files
445
+
446
+ - `references/framework-class-map.md` — which framework class owns which responsibility, and what exists on server vs client
447
+
448
+ ---
449
+
450
+ ## Checklist
451
+
452
+ Validate before considering the work done:
453
+
454
+ - [ ] State lives in the correct class — GameState for shared, PlayerState for per-player
455
+ - [ ] Nothing authoritative lives on the Pawn, which can be destroyed and respawned
456
+ - [ ] Server and client paths were both considered for every piece of state
457
+ - [ ] Conventions in `docs/unreal/project-context.md` were read and followed
458
+ - [ ] The Common Mistakes section of this skill was reviewed against the change
459
+
460
+ **PASS** — every item holds. **CONCERNS** — the work stands but at least one item is unresolved and worth flagging to the user. **FAIL** — an item is violated in a way that breaks correctness, replication or the frame budget; fix it before handing the work over.
461
+
462
+ ## Next Steps
463
+
464
+ - `/ue-networking-replication` — replicate the framework state
465
+ - `/code-review` — architectural and quality review of the change
466
+ - `/commit` — conventional commit once the change is verified