ue-mcp 1.0.41 → 1.0.43

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.
@@ -26,6 +26,6 @@
26
26
  "statetree": 35,
27
27
  "plugins": 2
28
28
  },
29
- "generatedAt": "2026-05-25T18:39:43.608Z",
30
- "version": "1.0.41"
29
+ "generatedAt": "2026-05-25T23:08:00.321Z",
30
+ "version": "1.0.43"
31
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ue-mcp",
3
- "version": "1.0.41",
3
+ "version": "1.0.43",
4
4
  "description": "Unreal Engine MCP server - 21 tools, 556+ actions for AI-driven editor control",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -6,6 +6,8 @@
6
6
  #include "EnhancedInputComponent.h"
7
7
  #include "EnhancedInputSubsystems.h"
8
8
  #include "EnhancedPlayerInput.h"
9
+ #include "InputAction.h"
10
+ #include "UObject/UObjectIterator.h"
9
11
  #include "GameFramework/PlayerController.h"
10
12
  #include "GameFramework/Pawn.h"
11
13
  #include "GameFramework/Character.h"
@@ -157,31 +159,21 @@ namespace UEMCPPIE
157
159
  }
158
160
  }
159
161
 
160
- bool FPIEFrameSampler::AttachToPIE(UWorld* PIEWorld)
162
+ void FPIEFrameSampler::DiscoverActions(APlayerController* PC, APawn* Pawn)
161
163
  {
162
- if (bAttached) return true;
163
- if (!PIEWorld) return false;
164
- APlayerController* PC = (Config.ClientIndex > 0)
165
- ? UGameplayStatics::GetPlayerController(PIEWorld, Config.ClientIndex)
166
- : PIEWorld->GetFirstPlayerController();
167
- if (!PC) return false;
168
- APawn* Pawn = PC->GetPawn();
169
- if (!Pawn || !Pawn->InputComponent) return false;
170
- UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(Pawn->InputComponent);
171
- if (!EIC) return false;
172
-
173
- PawnClassPath = Pawn->GetClass()->GetPathName();
174
- PIEWorldPath = PIEWorld->GetPathName();
175
-
176
164
  TSet<const UInputAction*> Seen;
165
+ for (const FTrackedAction& T : Tracked)
166
+ {
167
+ if (T.Action.IsValid()) Seen.Add(T.Action.Get());
168
+ }
169
+
177
170
  TSet<FString> Whitelist;
178
171
  for (const FString& P : Config.ActionPaths) Whitelist.Add(P);
179
172
 
180
- for (const TUniquePtr<FEnhancedInputActionEventBinding>& Bind : EIC->GetActionEventBindings())
173
+ auto TryAdd = [&](const UInputAction* Action)
181
174
  {
182
- const UInputAction* Action = Bind->GetAction();
183
- if (!Action || Seen.Contains(Action)) continue;
184
- if (!Whitelist.IsEmpty() && !Whitelist.Contains(Action->GetPathName())) continue;
175
+ if (!Action || Seen.Contains(Action)) return;
176
+ if (!Whitelist.IsEmpty() && !Whitelist.Contains(Action->GetPathName())) return;
185
177
  Seen.Add(Action);
186
178
 
187
179
  FTrackedAction T;
@@ -196,7 +188,51 @@ namespace UEMCPPIE
196
188
  Spec.Path = T.Path;
197
189
  Spec.ValueType = T.ValueType;
198
190
  Actions.Add(Spec);
191
+ };
192
+
193
+ // Event bindings (BindAction calls on the pawn's EIC).
194
+ if (UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(Pawn->InputComponent))
195
+ {
196
+ for (const TUniquePtr<FEnhancedInputActionEventBinding>& Bind : EIC->GetActionEventBindings())
197
+ {
198
+ TryAdd(Bind->GetAction());
199
+ }
200
+ }
201
+
202
+ // IMC-mapped actions: walk all loaded UInputAction assets and check
203
+ // which ones have active instance data in the player input. This
204
+ // catches actions polled via GetActionValue() without BindAction.
205
+ ULocalPlayer* LP = PC->GetLocalPlayer();
206
+ UEnhancedInputLocalPlayerSubsystem* Sub = LP ? LP->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>() : nullptr;
207
+ UEnhancedPlayerInput* PlayerInput = Sub ? Sub->GetPlayerInput() : nullptr;
208
+ if (PlayerInput)
209
+ {
210
+ for (TObjectIterator<UInputAction> It; It; ++It)
211
+ {
212
+ const UInputAction* Action = *It;
213
+ if (Action && PlayerInput->FindActionInstanceData(Action))
214
+ {
215
+ TryAdd(Action);
216
+ }
217
+ }
199
218
  }
219
+ }
220
+
221
+ bool FPIEFrameSampler::AttachToPIE(UWorld* PIEWorld)
222
+ {
223
+ if (bAttached) return true;
224
+ if (!PIEWorld) return false;
225
+ APlayerController* PC = (Config.ClientIndex > 0)
226
+ ? UGameplayStatics::GetPlayerController(PIEWorld, Config.ClientIndex)
227
+ : PIEWorld->GetFirstPlayerController();
228
+ if (!PC) return false;
229
+ APawn* Pawn = PC->GetPawn();
230
+ if (!Pawn || !Pawn->InputComponent) return false;
231
+
232
+ PawnClassPath = Pawn->GetClass()->GetPathName();
233
+ PIEWorldPath = PIEWorld->GetPathName();
234
+
235
+ DiscoverActions(PC, Pawn);
200
236
 
201
237
  bAttached = true;
202
238
  UE_LOG(LogMCPBridge, Log, TEXT("[PIE-SAMPLER] Attached: %d actions, %d tracked values, pawn=%s"),
@@ -220,37 +256,13 @@ namespace UEMCPPIE
220
256
  if (!Pawn) return Row;
221
257
 
222
258
  // Rescan for late-bound actions (IMCs added after initial attach).
223
- if (UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(Pawn->InputComponent))
224
259
  {
225
- TSet<FString> Known;
226
- for (const FTrackedAction& T : Tracked) Known.Add(T.Path);
227
-
228
- TSet<FString> Whitelist;
229
- for (const FString& P : Config.ActionPaths) Whitelist.Add(P);
230
-
231
- for (const TUniquePtr<FEnhancedInputActionEventBinding>& Bind : EIC->GetActionEventBindings())
260
+ const int32 Before = Tracked.Num();
261
+ DiscoverActions(PC, Pawn);
262
+ for (int32 i = Before; i < Tracked.Num(); ++i)
232
263
  {
233
- const UInputAction* Action = Bind->GetAction();
234
- if (!Action) continue;
235
- const FString Path = Action->GetPathName();
236
- if (Known.Contains(Path)) continue;
237
- if (!Whitelist.IsEmpty() && !Whitelist.Contains(Path)) continue;
238
- Known.Add(Path);
239
-
240
- FTrackedAction T;
241
- T.Action = Action;
242
- T.Name = Action->GetName();
243
- T.Path = Path;
244
- T.ValueType = ConvertValueType(Action->ValueType);
245
- Tracked.Add(T);
246
-
247
- FActionSpec Spec;
248
- Spec.Name = T.Name;
249
- Spec.Path = Path;
250
- Spec.ValueType = T.ValueType;
251
- Actions.Add(Spec);
252
264
  UE_LOG(LogMCPBridge, Log, TEXT("[PIE-SAMPLER] Late-discovered action: %s (%s)"),
253
- *T.Name, *Path);
265
+ *Tracked[i].Name, *Tracked[i].Path);
254
266
  }
255
267
  }
256
268
 
@@ -86,6 +86,8 @@ namespace UEMCPPIE
86
86
  bool bWasActive = false;
87
87
  };
88
88
 
89
+ void DiscoverActions(APlayerController* PC, APawn* Pawn);
90
+
89
91
  FConfig Config;
90
92
  bool bAttached = false;
91
93
  FString PawnClassPath;