ue-mcp 1.0.40 → 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.
- package/dist/tool-counts.json +2 -2
- package/package.json +1 -1
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/PIE/PIEFrameSampler.cpp +74 -21
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/PIE/PIEFrameSampler.h +3 -0
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/PIE/PIEInputRecorder.cpp +14 -0
package/dist/tool-counts.json
CHANGED
package/package.json
CHANGED
|
@@ -146,6 +146,7 @@ namespace UEMCPPIE
|
|
|
146
146
|
TrackedValues.Reset();
|
|
147
147
|
Tracked.Reset();
|
|
148
148
|
PendingMarkerLabels.Reset();
|
|
149
|
+
PrevPawnLocation = FVector::ZeroVector;
|
|
149
150
|
// Re-seed TrackedValues from config in case the caller calls AttachToPIE again.
|
|
150
151
|
for (const FString& P : Config.TrackedValuePaths)
|
|
151
152
|
{
|
|
@@ -156,31 +157,21 @@ namespace UEMCPPIE
|
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
|
|
159
|
-
|
|
160
|
+
void FPIEFrameSampler::DiscoverActions(APlayerController* PC, APawn* Pawn)
|
|
160
161
|
{
|
|
161
|
-
if (bAttached) return true;
|
|
162
|
-
if (!PIEWorld) return false;
|
|
163
|
-
APlayerController* PC = (Config.ClientIndex > 0)
|
|
164
|
-
? UGameplayStatics::GetPlayerController(PIEWorld, Config.ClientIndex)
|
|
165
|
-
: PIEWorld->GetFirstPlayerController();
|
|
166
|
-
if (!PC) return false;
|
|
167
|
-
APawn* Pawn = PC->GetPawn();
|
|
168
|
-
if (!Pawn || !Pawn->InputComponent) return false;
|
|
169
|
-
UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(Pawn->InputComponent);
|
|
170
|
-
if (!EIC) return false;
|
|
171
|
-
|
|
172
|
-
PawnClassPath = Pawn->GetClass()->GetPathName();
|
|
173
|
-
PIEWorldPath = PIEWorld->GetPathName();
|
|
174
|
-
|
|
175
162
|
TSet<const UInputAction*> Seen;
|
|
163
|
+
for (const FTrackedAction& T : Tracked)
|
|
164
|
+
{
|
|
165
|
+
if (T.Action.IsValid()) Seen.Add(T.Action.Get());
|
|
166
|
+
}
|
|
167
|
+
|
|
176
168
|
TSet<FString> Whitelist;
|
|
177
169
|
for (const FString& P : Config.ActionPaths) Whitelist.Add(P);
|
|
178
170
|
|
|
179
|
-
|
|
171
|
+
auto TryAdd = [&](const UInputAction* Action)
|
|
180
172
|
{
|
|
181
|
-
|
|
182
|
-
if (!
|
|
183
|
-
if (!Whitelist.IsEmpty() && !Whitelist.Contains(Action->GetPathName())) continue;
|
|
173
|
+
if (!Action || Seen.Contains(Action)) return;
|
|
174
|
+
if (!Whitelist.IsEmpty() && !Whitelist.Contains(Action->GetPathName())) return;
|
|
184
175
|
Seen.Add(Action);
|
|
185
176
|
|
|
186
177
|
FTrackedAction T;
|
|
@@ -195,7 +186,45 @@ namespace UEMCPPIE
|
|
|
195
186
|
Spec.Path = T.Path;
|
|
196
187
|
Spec.ValueType = T.ValueType;
|
|
197
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
|
+
}
|
|
198
|
+
}
|
|
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
|
+
}
|
|
198
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);
|
|
199
228
|
|
|
200
229
|
bAttached = true;
|
|
201
230
|
UE_LOG(LogMCPBridge, Log, TEXT("[PIE-SAMPLER] Attached: %d actions, %d tracked values, pawn=%s"),
|
|
@@ -218,6 +247,17 @@ namespace UEMCPPIE
|
|
|
218
247
|
APawn* Pawn = PC->GetPawn();
|
|
219
248
|
if (!Pawn) return Row;
|
|
220
249
|
|
|
250
|
+
// Rescan for late-bound actions (IMCs added after initial attach).
|
|
251
|
+
{
|
|
252
|
+
const int32 Before = Tracked.Num();
|
|
253
|
+
DiscoverActions(PC, Pawn);
|
|
254
|
+
for (int32 i = Before; i < Tracked.Num(); ++i)
|
|
255
|
+
{
|
|
256
|
+
UE_LOG(LogMCPBridge, Log, TEXT("[PIE-SAMPLER] Late-discovered action: %s (%s)"),
|
|
257
|
+
*Tracked[i].Name, *Tracked[i].Path);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
221
261
|
if (Config.bCapturePawnState)
|
|
222
262
|
{
|
|
223
263
|
Row.PawnLocation = Pawn->GetActorLocation();
|
|
@@ -232,8 +272,21 @@ namespace UEMCPPIE
|
|
|
232
272
|
}
|
|
233
273
|
else
|
|
234
274
|
{
|
|
235
|
-
|
|
236
|
-
|
|
275
|
+
FVector Vel = Pawn->GetVelocity();
|
|
276
|
+
if (Vel.IsNearlyZero())
|
|
277
|
+
{
|
|
278
|
+
if (UPrimitiveComponent* Root = Cast<UPrimitiveComponent>(Pawn->GetRootComponent()))
|
|
279
|
+
{
|
|
280
|
+
Vel = Root->GetPhysicsLinearVelocity();
|
|
281
|
+
}
|
|
282
|
+
if (Vel.IsNearlyZero() && FrameNumber > 0)
|
|
283
|
+
{
|
|
284
|
+
Vel = (Pawn->GetActorLocation() - PrevPawnLocation) / FMath::Max(DeltaTime, 0.001);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
PrevPawnLocation = Pawn->GetActorLocation();
|
|
288
|
+
Row.PawnVelocity = Vel;
|
|
289
|
+
Row.Speed2D = Vel.Size2D();
|
|
237
290
|
}
|
|
238
291
|
}
|
|
239
292
|
|
|
@@ -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;
|
|
@@ -94,5 +96,6 @@ namespace UEMCPPIE
|
|
|
94
96
|
TArray<FTrackedValueSpec> TrackedValues;
|
|
95
97
|
TArray<FTrackedAction> Tracked;
|
|
96
98
|
TArray<FString> PendingMarkerLabels;
|
|
99
|
+
FVector PrevPawnLocation = FVector::ZeroVector;
|
|
97
100
|
};
|
|
98
101
|
}
|
|
@@ -242,6 +242,20 @@ namespace UEMCPPIE
|
|
|
242
242
|
ActorRows.Add(MoveTemp(AR));
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
+
// Detect late-discovered actions and rebuild CSV header.
|
|
246
|
+
const TArray<FActionSpec>& CurrentActions = Sampler.GetActions();
|
|
247
|
+
if (CurrentActions.Num() != CSVHdr.Actions.Num())
|
|
248
|
+
{
|
|
249
|
+
CSVHdr.Actions = CurrentActions;
|
|
250
|
+
CSVHdr.TrackedValues = Sampler.GetTrackedValues();
|
|
251
|
+
CSVHeader = BuildCSVHeader(CSVHdr);
|
|
252
|
+
CSVBody.Reset();
|
|
253
|
+
for (const FCSVRow& Prev : Rows)
|
|
254
|
+
{
|
|
255
|
+
AppendCSVRow(CSVBody, Prev, CSVHdr);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
245
259
|
AppendCSVRow(CSVBody, Row, CSVHdr);
|
|
246
260
|
Rows.Add(MoveTemp(Row));
|
|
247
261
|
}
|