ue-mcp 1.0.41 → 1.0.42

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-25T19:19:18.505Z",
30
+ "version": "1.0.42"
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.42",
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",
@@ -157,31 +157,21 @@ namespace UEMCPPIE
157
157
  }
158
158
  }
159
159
 
160
- bool FPIEFrameSampler::AttachToPIE(UWorld* PIEWorld)
160
+ void FPIEFrameSampler::DiscoverActions(APlayerController* PC, APawn* Pawn)
161
161
  {
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
162
  TSet<const UInputAction*> Seen;
163
+ for (const FTrackedAction& T : Tracked)
164
+ {
165
+ if (T.Action.IsValid()) Seen.Add(T.Action.Get());
166
+ }
167
+
177
168
  TSet<FString> Whitelist;
178
169
  for (const FString& P : Config.ActionPaths) Whitelist.Add(P);
179
170
 
180
- for (const TUniquePtr<FEnhancedInputActionEventBinding>& Bind : EIC->GetActionEventBindings())
171
+ auto TryAdd = [&](const UInputAction* Action)
181
172
  {
182
- const UInputAction* Action = Bind->GetAction();
183
- if (!Action || Seen.Contains(Action)) continue;
184
- if (!Whitelist.IsEmpty() && !Whitelist.Contains(Action->GetPathName())) continue;
173
+ if (!Action || Seen.Contains(Action)) return;
174
+ if (!Whitelist.IsEmpty() && !Whitelist.Contains(Action->GetPathName())) return;
185
175
  Seen.Add(Action);
186
176
 
187
177
  FTrackedAction T;
@@ -196,8 +186,46 @@ namespace UEMCPPIE
196
186
  Spec.Path = T.Path;
197
187
  Spec.ValueType = T.ValueType;
198
188
  Actions.Add(Spec);
189
+ };
190
+
191
+ // Event bindings (BindAction calls on the pawn's EIC).
192
+ if (UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(Pawn->InputComponent))
193
+ {
194
+ for (const TUniquePtr<FEnhancedInputActionEventBinding>& Bind : EIC->GetActionEventBindings())
195
+ {
196
+ TryAdd(Bind->GetAction());
197
+ }
199
198
  }
200
199
 
200
+ // IMC mappings: actions polled via GetActionValue() without BindAction.
201
+ ULocalPlayer* LP = PC->GetLocalPlayer();
202
+ UEnhancedInputLocalPlayerSubsystem* Sub = LP ? LP->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>() : nullptr;
203
+ UEnhancedPlayerInput* PlayerInput = Sub ? Sub->GetPlayerInput() : nullptr;
204
+ if (PlayerInput)
205
+ {
206
+ for (const FEnhancedActionKeyMapping& Mapping : PlayerInput->GetEnhancedActionMappings())
207
+ {
208
+ TryAdd(Mapping.Action);
209
+ }
210
+ }
211
+ }
212
+
213
+ bool FPIEFrameSampler::AttachToPIE(UWorld* PIEWorld)
214
+ {
215
+ if (bAttached) return true;
216
+ if (!PIEWorld) return false;
217
+ APlayerController* PC = (Config.ClientIndex > 0)
218
+ ? UGameplayStatics::GetPlayerController(PIEWorld, Config.ClientIndex)
219
+ : PIEWorld->GetFirstPlayerController();
220
+ if (!PC) return false;
221
+ APawn* Pawn = PC->GetPawn();
222
+ if (!Pawn || !Pawn->InputComponent) return false;
223
+
224
+ PawnClassPath = Pawn->GetClass()->GetPathName();
225
+ PIEWorldPath = PIEWorld->GetPathName();
226
+
227
+ DiscoverActions(PC, Pawn);
228
+
201
229
  bAttached = true;
202
230
  UE_LOG(LogMCPBridge, Log, TEXT("[PIE-SAMPLER] Attached: %d actions, %d tracked values, pawn=%s"),
203
231
  Actions.Num(), TrackedValues.Num(), *PawnClassPath);
@@ -220,37 +248,13 @@ namespace UEMCPPIE
220
248
  if (!Pawn) return Row;
221
249
 
222
250
  // Rescan for late-bound actions (IMCs added after initial attach).
223
- if (UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(Pawn->InputComponent))
224
251
  {
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())
252
+ const int32 Before = Tracked.Num();
253
+ DiscoverActions(PC, Pawn);
254
+ for (int32 i = Before; i < Tracked.Num(); ++i)
232
255
  {
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
256
  UE_LOG(LogMCPBridge, Log, TEXT("[PIE-SAMPLER] Late-discovered action: %s (%s)"),
253
- *T.Name, *Path);
257
+ *Tracked[i].Name, *Tracked[i].Path);
254
258
  }
255
259
  }
256
260
 
@@ -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;