ue-mcp 1.2.1 → 1.2.2

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 (54) hide show
  1. package/dist/context-cli.js +16 -16
  2. package/dist/engine-observer.js +68 -68
  3. package/dist/flow/guard.d.ts +26 -37
  4. package/dist/flow/guard.js +40 -25
  5. package/dist/flow/guard.js.map +1 -1
  6. package/dist/flow/guarded-bridge.d.ts +0 -10
  7. package/dist/flow/guarded-bridge.js +18 -23
  8. package/dist/flow/guarded-bridge.js.map +1 -1
  9. package/dist/flow/schema.d.ts +276 -16
  10. package/dist/flow/task-guards.d.ts +1 -1
  11. package/dist/flow/task-guards.js +44 -68
  12. package/dist/flow/task-guards.js.map +1 -1
  13. package/dist/instructions.js +130 -130
  14. package/dist/plugin-cli.js +299 -299
  15. package/dist/tool-counts.json +2 -2
  16. package/package.json +2 -2
  17. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/EngineStatusHooks.cpp +76 -76
  18. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/EngineStatusHooks.h +27 -27
  19. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerRegistry.cpp +128 -128
  20. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerRegistry.h +63 -63
  21. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRig.cpp +230 -230
  22. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Struct.cpp +323 -323
  23. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Internal.h +20 -20
  24. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ChooserHandlers_Nested.cpp +537 -537
  25. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.h +77 -77
  26. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +353 -353
  27. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +18 -18
  28. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_InputRuntime.cpp +246 -246
  29. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +597 -597
  30. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +51 -51
  31. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +878 -878
  32. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +449 -449
  33. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Function.cpp +275 -275
  34. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Graph.cpp +551 -551
  35. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NetworkingHandlers.cpp +531 -531
  36. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NetworkingHandlers.h +28 -28
  37. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +677 -677
  38. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +822 -822
  39. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.h +22 -22
  40. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.cpp +218 -218
  41. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.h +17 -17
  42. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/VolumeHelpers_Internal.cpp +46 -46
  43. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/VolumeHelpers_Internal.h +23 -23
  44. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/MCPExternalRegistry.cpp +83 -83
  45. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/UE_MCP_BridgeModule.h +14 -14
  46. package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/UE_MCP_BridgeStatusModule.cpp +37 -37
  47. package/dist/manifest-signature.d.ts +0 -1
  48. package/dist/manifest-signature.js +0 -53
  49. package/dist/manifest-signature.js.map +0 -1
  50. package/dist/pie/schema.d.ts +0 -791
  51. package/dist/pie/schema.js +0 -151
  52. package/dist/pie/schema.js.map +0 -1
  53. package/dist/watch-cli.js.map +0 -1
  54. /package/plugin/ue_mcp_bridge/{ue_mcp_bridge.uplugin → UE_MCP_Bridge.uplugin} +0 -0
@@ -1,531 +1,531 @@
1
- #include "NetworkingHandlers.h"
2
- #include "HandlerRegistry.h"
3
- #include "HandlerUtils.h"
4
- #include "Engine/Blueprint.h"
5
- #include "GameFramework/Actor.h"
6
- #include "Kismet2/KismetEditorUtilities.h"
7
- #include "Kismet2/BlueprintEditorUtils.h"
8
- #include "UObject/UObjectGlobals.h"
9
- #include "UObject/Package.h"
10
- #include "Misc/PackageName.h"
11
- #include "UObject/SavePackage.h"
12
- #include "Dom/JsonObject.h"
13
- #include "Dom/JsonValue.h"
14
- #include "UObject/UnrealType.h"
15
- #include "EditorScriptingUtilities/Public/EditorAssetLibrary.h"
16
-
17
- void FNetworkingHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
18
- {
19
- Registry.RegisterHandler(TEXT("get_networking_info"), &GetNetworkingInfo);
20
- Registry.RegisterHandler(TEXT("set_replicates"), &SetReplicates);
21
- Registry.RegisterHandler(TEXT("configure_net_update_frequency"), &ConfigureNetUpdateFrequency);
22
- Registry.RegisterHandler(TEXT("set_net_dormancy"), &SetNetDormancy);
23
- Registry.RegisterHandler(TEXT("set_always_relevant"), &SetAlwaysRelevant);
24
- Registry.RegisterHandler(TEXT("set_net_priority"), &SetNetPriority);
25
- Registry.RegisterHandler(TEXT("set_replicate_movement"), &SetReplicateMovement);
26
- Registry.RegisterHandler(TEXT("set_property_replicated"), &SetVariableReplication);
27
- Registry.RegisterHandler(TEXT("set_only_relevant_to_owner"), &SetOwnerOnlyRelevant);
28
- // New handlers
29
- Registry.RegisterHandler(TEXT("set_net_load_on_client"), &SetNetLoadOnClient);
30
- Registry.RegisterHandler(TEXT("configure_net_cull_distance"), &ConfigureNetCullDistance);
31
- }
32
-
33
- AActor* FNetworkingHandlers::LoadBlueprintCDO(const FString& BlueprintPath, TSharedPtr<FJsonObject>& OutResult)
34
- {
35
- // Thin adapter over the shared ::LoadBlueprintCDO<T> helper in HandlerUtils.h.
36
- // Translates the helper's TSharedPtr<FJsonValue> error into the OutResult-style
37
- // {success:false, error:...} object the networking call sites accumulate into.
38
- TSharedPtr<FJsonValue> Err;
39
- AActor* CDO = ::LoadBlueprintCDO<AActor>(BlueprintPath, Err);
40
- if (!CDO)
41
- {
42
- FString ErrMsg = TEXT("Failed to load blueprint CDO");
43
- if (Err.IsValid())
44
- {
45
- if (TSharedPtr<FJsonObject> ErrObj = Err->AsObject())
46
- {
47
- ErrObj->TryGetStringField(TEXT("error"), ErrMsg);
48
- }
49
- }
50
- OutResult->SetStringField(TEXT("error"), ErrMsg);
51
- OutResult->SetBoolField(TEXT("success"), false);
52
- }
53
- return CDO;
54
- }
55
-
56
- void FNetworkingHandlers::SaveBlueprint(UBlueprint* Blueprint)
57
- {
58
- if (!Blueprint) return;
59
- FKismetEditorUtilities::CompileBlueprint(Blueprint);
60
- SaveAssetPackage(Blueprint);
61
- }
62
-
63
- TSharedPtr<FJsonValue> FNetworkingHandlers::GetNetworkingInfo(const TSharedPtr<FJsonObject>& Params)
64
- {
65
- FString BlueprintPath;
66
- if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
67
-
68
- TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
69
- AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
70
- if (!CDO) return MCPResult(Result);
71
-
72
- Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
73
- Result->SetBoolField(TEXT("replicates"), CDO->GetIsReplicated());
74
- #if UE_MCP_HAS_5_5_API
75
- Result->SetNumberField(TEXT("netUpdateFrequency"), CDO->GetNetUpdateFrequency());
76
- Result->SetNumberField(TEXT("minNetUpdateFrequency"), CDO->GetMinNetUpdateFrequency());
77
- #else
78
- Result->SetNumberField(TEXT("netUpdateFrequency"), CDO->NetUpdateFrequency);
79
- Result->SetNumberField(TEXT("minNetUpdateFrequency"), CDO->MinNetUpdateFrequency);
80
- #endif
81
- Result->SetNumberField(TEXT("netPriority"), CDO->NetPriority);
82
- Result->SetBoolField(TEXT("alwaysRelevant"), CDO->bAlwaysRelevant);
83
- Result->SetBoolField(TEXT("replicateMovement"), CDO->IsReplicatingMovement());
84
- Result->SetNumberField(TEXT("netDormancy"), (int32)CDO->NetDormancy);
85
- Result->SetBoolField(TEXT("success"), true);
86
-
87
- return MCPResult(Result);
88
- }
89
-
90
- TSharedPtr<FJsonValue> FNetworkingHandlers::SetReplicates(const TSharedPtr<FJsonObject>& Params)
91
- {
92
- FString BlueprintPath;
93
- if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
94
-
95
- TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
96
- AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
97
- if (!CDO) return MCPResult(Result);
98
-
99
- bool bReplicates = OptionalBool(Params, TEXT("replicates"), false);
100
- const bool bPrev = CDO->GetIsReplicated();
101
-
102
- Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
103
- Result->SetBoolField(TEXT("replicates"), bReplicates);
104
- Result->SetBoolField(TEXT("success"), true);
105
-
106
- if (bPrev == bReplicates)
107
- {
108
- MCPSetExisted(Result);
109
- Result->SetBoolField(TEXT("updated"), false);
110
- return MCPResult(Result);
111
- }
112
-
113
- CDO->SetReplicates(bReplicates);
114
- UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
115
- SaveBlueprint(Blueprint);
116
-
117
- MCPSetUpdated(Result);
118
- TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
119
- Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
120
- Payload->SetBoolField(TEXT("replicates"), bPrev);
121
- MCPSetRollback(Result, TEXT("set_replicates"), Payload);
122
- return MCPResult(Result);
123
- }
124
-
125
- TSharedPtr<FJsonValue> FNetworkingHandlers::ConfigureNetUpdateFrequency(const TSharedPtr<FJsonObject>& Params)
126
- {
127
- FString BlueprintPath;
128
- if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
129
-
130
- TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
131
- AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
132
- if (!CDO) return MCPResult(Result);
133
-
134
- double NetUpdateFrequency = 0;
135
- if (Params->TryGetNumberField(TEXT("netUpdateFrequency"), NetUpdateFrequency))
136
- {
137
- #if UE_MCP_HAS_5_5_API
138
- CDO->SetNetUpdateFrequency((float)NetUpdateFrequency);
139
- #else
140
- CDO->NetUpdateFrequency = (float)NetUpdateFrequency;
141
- #endif
142
- }
143
- double MinNetUpdateFrequency = 0;
144
- if (Params->TryGetNumberField(TEXT("minNetUpdateFrequency"), MinNetUpdateFrequency))
145
- {
146
- #if UE_MCP_HAS_5_5_API
147
- CDO->SetMinNetUpdateFrequency((float)MinNetUpdateFrequency);
148
- #else
149
- CDO->MinNetUpdateFrequency = (float)MinNetUpdateFrequency;
150
- #endif
151
- }
152
-
153
- UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
154
- SaveBlueprint(Blueprint);
155
-
156
- Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
157
- #if UE_MCP_HAS_5_5_API
158
- Result->SetNumberField(TEXT("netUpdateFrequency"), CDO->GetNetUpdateFrequency());
159
- Result->SetNumberField(TEXT("minNetUpdateFrequency"), CDO->GetMinNetUpdateFrequency());
160
- #else
161
- Result->SetNumberField(TEXT("netUpdateFrequency"), CDO->NetUpdateFrequency);
162
- Result->SetNumberField(TEXT("minNetUpdateFrequency"), CDO->MinNetUpdateFrequency);
163
- #endif
164
- Result->SetBoolField(TEXT("success"), true);
165
- return MCPResult(Result);
166
- }
167
-
168
- static FString DormancyToString(ENetDormancy D)
169
- {
170
- switch (D)
171
- {
172
- case DORM_Never: return TEXT("DORM_Never");
173
- case DORM_Awake: return TEXT("DORM_Awake");
174
- case DORM_DormantAll: return TEXT("DORM_DormantAll");
175
- case DORM_DormantPartial: return TEXT("DORM_DormantPartial");
176
- case DORM_Initial: return TEXT("DORM_Initial");
177
- default: return TEXT("DORM_Awake");
178
- }
179
- }
180
-
181
- TSharedPtr<FJsonValue> FNetworkingHandlers::SetNetDormancy(const TSharedPtr<FJsonObject>& Params)
182
- {
183
- FString BlueprintPath;
184
- if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
185
-
186
- TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
187
- AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
188
- if (!CDO) return MCPResult(Result);
189
-
190
- FString Dormancy = OptionalString(Params, TEXT("dormancy"));
191
- const ENetDormancy PrevDormancy = CDO->NetDormancy;
192
- const FString PrevDormStr = DormancyToString(PrevDormancy);
193
- ENetDormancy NewDormancy = PrevDormancy;
194
- if (!Dormancy.IsEmpty())
195
- {
196
- if (Dormancy == TEXT("DORM_Never")) NewDormancy = DORM_Never;
197
- else if (Dormancy == TEXT("DORM_Awake")) NewDormancy = DORM_Awake;
198
- else if (Dormancy == TEXT("DORM_DormantAll")) NewDormancy = DORM_DormantAll;
199
- else if (Dormancy == TEXT("DORM_DormantPartial")) NewDormancy = DORM_DormantPartial;
200
- else if (Dormancy == TEXT("DORM_Initial")) NewDormancy = DORM_Initial;
201
- }
202
-
203
- Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
204
- Result->SetNumberField(TEXT("netDormancy"), (int32)NewDormancy);
205
- Result->SetBoolField(TEXT("success"), true);
206
-
207
- if (NewDormancy == PrevDormancy)
208
- {
209
- MCPSetExisted(Result);
210
- Result->SetBoolField(TEXT("updated"), false);
211
- return MCPResult(Result);
212
- }
213
-
214
- CDO->NetDormancy = NewDormancy;
215
- UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
216
- SaveBlueprint(Blueprint);
217
-
218
- MCPSetUpdated(Result);
219
- TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
220
- Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
221
- Payload->SetStringField(TEXT("dormancy"), PrevDormStr);
222
- MCPSetRollback(Result, TEXT("set_net_dormancy"), Payload);
223
- return MCPResult(Result);
224
- }
225
-
226
- TSharedPtr<FJsonValue> FNetworkingHandlers::SetAlwaysRelevant(const TSharedPtr<FJsonObject>& Params)
227
- {
228
- FString BlueprintPath;
229
- if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
230
-
231
- TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
232
- AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
233
- if (!CDO) return MCPResult(Result);
234
-
235
- bool bAlwaysRelevant = OptionalBool(Params, TEXT("alwaysRelevant"), false);
236
- const bool bPrev = CDO->bAlwaysRelevant;
237
-
238
- Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
239
- Result->SetBoolField(TEXT("alwaysRelevant"), bAlwaysRelevant);
240
- Result->SetBoolField(TEXT("success"), true);
241
-
242
- if (bPrev == bAlwaysRelevant)
243
- {
244
- MCPSetExisted(Result);
245
- Result->SetBoolField(TEXT("updated"), false);
246
- return MCPResult(Result);
247
- }
248
-
249
- CDO->bAlwaysRelevant = bAlwaysRelevant;
250
- UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
251
- SaveBlueprint(Blueprint);
252
-
253
- MCPSetUpdated(Result);
254
- TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
255
- Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
256
- Payload->SetBoolField(TEXT("alwaysRelevant"), bPrev);
257
- MCPSetRollback(Result, TEXT("set_always_relevant"), Payload);
258
- return MCPResult(Result);
259
- }
260
-
261
- TSharedPtr<FJsonValue> FNetworkingHandlers::SetNetPriority(const TSharedPtr<FJsonObject>& Params)
262
- {
263
- FString BlueprintPath;
264
- if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
265
-
266
- TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
267
- AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
268
- if (!CDO) return MCPResult(Result);
269
-
270
- double NetPriority = OptionalNumber(Params, TEXT("netPriority"), 1.0);
271
- const float fPrev = CDO->NetPriority;
272
-
273
- Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
274
- Result->SetNumberField(TEXT("netPriority"), NetPriority);
275
- Result->SetBoolField(TEXT("success"), true);
276
-
277
- if (FMath::IsNearlyEqual(fPrev, (float)NetPriority))
278
- {
279
- MCPSetExisted(Result);
280
- Result->SetBoolField(TEXT("updated"), false);
281
- return MCPResult(Result);
282
- }
283
-
284
- CDO->NetPriority = (float)NetPriority;
285
- UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
286
- SaveBlueprint(Blueprint);
287
-
288
- MCPSetUpdated(Result);
289
- TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
290
- Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
291
- Payload->SetNumberField(TEXT("netPriority"), fPrev);
292
- MCPSetRollback(Result, TEXT("set_net_priority"), Payload);
293
- return MCPResult(Result);
294
- }
295
-
296
- TSharedPtr<FJsonValue> FNetworkingHandlers::SetReplicateMovement(const TSharedPtr<FJsonObject>& Params)
297
- {
298
- FString BlueprintPath;
299
- if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
300
-
301
- TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
302
- AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
303
- if (!CDO) return MCPResult(Result);
304
-
305
- bool bReplicateMovement = OptionalBool(Params, TEXT("replicateMovement"), false);
306
- const bool bPrev = CDO->IsReplicatingMovement();
307
-
308
- Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
309
- Result->SetBoolField(TEXT("replicateMovement"), bReplicateMovement);
310
- Result->SetBoolField(TEXT("success"), true);
311
-
312
- if (bPrev == bReplicateMovement)
313
- {
314
- MCPSetExisted(Result);
315
- Result->SetBoolField(TEXT("updated"), false);
316
- return MCPResult(Result);
317
- }
318
-
319
- CDO->SetReplicatingMovement(bReplicateMovement);
320
- UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
321
- SaveBlueprint(Blueprint);
322
-
323
- MCPSetUpdated(Result);
324
- TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
325
- Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
326
- Payload->SetBoolField(TEXT("replicateMovement"), bPrev);
327
- MCPSetRollback(Result, TEXT("set_replicate_movement"), Payload);
328
- return MCPResult(Result);
329
- }
330
-
331
- TSharedPtr<FJsonValue> FNetworkingHandlers::SetVariableReplication(const TSharedPtr<FJsonObject>& Params)
332
- {
333
- FString BlueprintPath;
334
- if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
335
-
336
- FString VariableName;
337
- if (auto Err = RequireString(Params, TEXT("variableName"), VariableName)) return Err;
338
-
339
- FString ReplicationType = OptionalString(Params, TEXT("replicationType"), TEXT("None"));
340
-
341
- UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
342
- if (!Blueprint)
343
- {
344
- return MCPError(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintPath));
345
- }
346
-
347
- // Find the variable in the blueprint
348
- FName VarFName(*VariableName);
349
- FBPVariableDescription* VarDesc = nullptr;
350
- for (FBPVariableDescription& Var : Blueprint->NewVariables)
351
- {
352
- if (Var.VarName == VarFName)
353
- {
354
- VarDesc = &Var;
355
- break;
356
- }
357
- }
358
-
359
- if (!VarDesc)
360
- {
361
- return MCPError(FString::Printf(TEXT("Variable '%s' not found in blueprint"), *VariableName));
362
- }
363
-
364
- // Capture previous state
365
- const bool bWasNet = (VarDesc->PropertyFlags & CPF_Net) != 0;
366
- const bool bWasRepNotify = (VarDesc->PropertyFlags & CPF_RepNotify) != 0;
367
- FString PrevType = TEXT("None");
368
- if (bWasNet && bWasRepNotify) PrevType = TEXT("RepNotify");
369
- else if (bWasNet) PrevType = TEXT("Replicated");
370
-
371
- auto Result = MCPSuccess();
372
- Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
373
- Result->SetStringField(TEXT("variableName"), VariableName);
374
- Result->SetStringField(TEXT("replicationType"), ReplicationType);
375
-
376
- if (PrevType == ReplicationType)
377
- {
378
- MCPSetExisted(Result);
379
- Result->SetBoolField(TEXT("updated"), false);
380
- return MCPResult(Result);
381
- }
382
-
383
- // Set the replication condition
384
- if (ReplicationType == TEXT("Replicated"))
385
- {
386
- VarDesc->PropertyFlags |= CPF_Net;
387
- VarDesc->PropertyFlags &= ~CPF_RepNotify;
388
- VarDesc->ReplicationCondition = COND_None;
389
- }
390
- else if (ReplicationType == TEXT("RepNotify"))
391
- {
392
- VarDesc->PropertyFlags |= CPF_Net;
393
- VarDesc->PropertyFlags |= CPF_RepNotify;
394
- VarDesc->ReplicationCondition = COND_None;
395
- }
396
- else // "None"
397
- {
398
- VarDesc->PropertyFlags &= ~CPF_Net;
399
- VarDesc->PropertyFlags &= ~CPF_RepNotify;
400
- }
401
-
402
- SaveBlueprint(Blueprint);
403
-
404
- MCPSetUpdated(Result);
405
- TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
406
- Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
407
- Payload->SetStringField(TEXT("variableName"), VariableName);
408
- Payload->SetStringField(TEXT("replicationType"), PrevType);
409
- MCPSetRollback(Result, TEXT("set_variable_replication"), Payload);
410
- return MCPResult(Result);
411
- }
412
-
413
- TSharedPtr<FJsonValue> FNetworkingHandlers::SetOwnerOnlyRelevant(const TSharedPtr<FJsonObject>& Params)
414
- {
415
- FString BlueprintPath;
416
- if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
417
-
418
- TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
419
- AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
420
- if (!CDO) return MCPResult(Result);
421
-
422
- bool bOnlyRelevantToOwner = OptionalBool(Params, TEXT("onlyRelevantToOwner"), false);
423
- const bool bPrev = CDO->bOnlyRelevantToOwner;
424
-
425
- Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
426
- Result->SetBoolField(TEXT("onlyRelevantToOwner"), bOnlyRelevantToOwner);
427
- Result->SetBoolField(TEXT("success"), true);
428
-
429
- if (bPrev == bOnlyRelevantToOwner)
430
- {
431
- MCPSetExisted(Result);
432
- Result->SetBoolField(TEXT("updated"), false);
433
- return MCPResult(Result);
434
- }
435
-
436
- CDO->bOnlyRelevantToOwner = bOnlyRelevantToOwner;
437
- UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
438
- SaveBlueprint(Blueprint);
439
-
440
- MCPSetUpdated(Result);
441
- TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
442
- Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
443
- Payload->SetBoolField(TEXT("onlyRelevantToOwner"), bPrev);
444
- MCPSetRollback(Result, TEXT("set_owner_only_relevant"), Payload);
445
- return MCPResult(Result);
446
- }
447
-
448
- TSharedPtr<FJsonValue> FNetworkingHandlers::SetNetLoadOnClient(const TSharedPtr<FJsonObject>& Params)
449
- {
450
- FString BlueprintPath;
451
- if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
452
-
453
- TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
454
- AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
455
- if (!CDO) return MCPResult(Result);
456
-
457
- bool bLoadOnClient = OptionalBool(Params, TEXT("loadOnClient"), true);
458
- bool bPrev = bLoadOnClient;
459
-
460
- FProperty* Prop = CDO->GetClass()->FindPropertyByName(TEXT("bNetLoadOnClient"));
461
- if (Prop)
462
- {
463
- bool* ValPtr = Prop->ContainerPtrToValuePtr<bool>(CDO);
464
- if (ValPtr)
465
- {
466
- bPrev = *ValPtr;
467
- }
468
- }
469
-
470
- Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
471
- Result->SetBoolField(TEXT("loadOnClient"), bLoadOnClient);
472
- Result->SetBoolField(TEXT("success"), true);
473
-
474
- if (bPrev == bLoadOnClient)
475
- {
476
- MCPSetExisted(Result);
477
- Result->SetBoolField(TEXT("updated"), false);
478
- return MCPResult(Result);
479
- }
480
-
481
- if (Prop)
482
- {
483
- bool* ValPtr = Prop->ContainerPtrToValuePtr<bool>(CDO);
484
- if (ValPtr) { *ValPtr = bLoadOnClient; }
485
- }
486
-
487
- UBlueprint* BP = Cast<UBlueprint>(UEditorAssetLibrary::LoadAsset(BlueprintPath));
488
- if (BP) SaveBlueprint(BP);
489
-
490
- MCPSetUpdated(Result);
491
- TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
492
- Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
493
- Payload->SetBoolField(TEXT("loadOnClient"), bPrev);
494
- MCPSetRollback(Result, TEXT("set_net_load_on_client"), Payload);
495
- return MCPResult(Result);
496
- }
497
-
498
- TSharedPtr<FJsonValue> FNetworkingHandlers::ConfigureNetCullDistance(const TSharedPtr<FJsonObject>& Params)
499
- {
500
- FString BlueprintPath;
501
- if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
502
-
503
- TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
504
- AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
505
- if (!CDO) return MCPResult(Result);
506
-
507
- double Distance = OptionalNumber(Params, TEXT("netCullDistanceSquared"), 225000000.0);
508
-
509
- FProperty* Prop = CDO->GetClass()->FindPropertyByName(TEXT("NetCullDistanceSquared"));
510
- if (Prop)
511
- {
512
- FFloatProperty* FloatProp = CastField<FFloatProperty>(Prop);
513
- FDoubleProperty* DoubleProp = CastField<FDoubleProperty>(Prop);
514
- if (FloatProp)
515
- {
516
- FloatProp->SetPropertyValue_InContainer(CDO, static_cast<float>(Distance));
517
- }
518
- else if (DoubleProp)
519
- {
520
- DoubleProp->SetPropertyValue_InContainer(CDO, Distance);
521
- }
522
- }
523
-
524
- UBlueprint* BP = Cast<UBlueprint>(UEditorAssetLibrary::LoadAsset(BlueprintPath));
525
- if (BP) SaveBlueprint(BP);
526
-
527
- Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
528
- Result->SetNumberField(TEXT("netCullDistanceSquared"), Distance);
529
- Result->SetBoolField(TEXT("success"), true);
530
- return MCPResult(Result);
531
- }
1
+ #include "NetworkingHandlers.h"
2
+ #include "HandlerRegistry.h"
3
+ #include "HandlerUtils.h"
4
+ #include "Engine/Blueprint.h"
5
+ #include "GameFramework/Actor.h"
6
+ #include "Kismet2/KismetEditorUtilities.h"
7
+ #include "Kismet2/BlueprintEditorUtils.h"
8
+ #include "UObject/UObjectGlobals.h"
9
+ #include "UObject/Package.h"
10
+ #include "Misc/PackageName.h"
11
+ #include "UObject/SavePackage.h"
12
+ #include "Dom/JsonObject.h"
13
+ #include "Dom/JsonValue.h"
14
+ #include "UObject/UnrealType.h"
15
+ #include "EditorScriptingUtilities/Public/EditorAssetLibrary.h"
16
+
17
+ void FNetworkingHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
18
+ {
19
+ Registry.RegisterHandler(TEXT("get_networking_info"), &GetNetworkingInfo);
20
+ Registry.RegisterHandler(TEXT("set_replicates"), &SetReplicates);
21
+ Registry.RegisterHandler(TEXT("configure_net_update_frequency"), &ConfigureNetUpdateFrequency);
22
+ Registry.RegisterHandler(TEXT("set_net_dormancy"), &SetNetDormancy);
23
+ Registry.RegisterHandler(TEXT("set_always_relevant"), &SetAlwaysRelevant);
24
+ Registry.RegisterHandler(TEXT("set_net_priority"), &SetNetPriority);
25
+ Registry.RegisterHandler(TEXT("set_replicate_movement"), &SetReplicateMovement);
26
+ Registry.RegisterHandler(TEXT("set_property_replicated"), &SetVariableReplication);
27
+ Registry.RegisterHandler(TEXT("set_only_relevant_to_owner"), &SetOwnerOnlyRelevant);
28
+ // New handlers
29
+ Registry.RegisterHandler(TEXT("set_net_load_on_client"), &SetNetLoadOnClient);
30
+ Registry.RegisterHandler(TEXT("configure_net_cull_distance"), &ConfigureNetCullDistance);
31
+ }
32
+
33
+ AActor* FNetworkingHandlers::LoadBlueprintCDO(const FString& BlueprintPath, TSharedPtr<FJsonObject>& OutResult)
34
+ {
35
+ // Thin adapter over the shared ::LoadBlueprintCDO<T> helper in HandlerUtils.h.
36
+ // Translates the helper's TSharedPtr<FJsonValue> error into the OutResult-style
37
+ // {success:false, error:...} object the networking call sites accumulate into.
38
+ TSharedPtr<FJsonValue> Err;
39
+ AActor* CDO = ::LoadBlueprintCDO<AActor>(BlueprintPath, Err);
40
+ if (!CDO)
41
+ {
42
+ FString ErrMsg = TEXT("Failed to load blueprint CDO");
43
+ if (Err.IsValid())
44
+ {
45
+ if (TSharedPtr<FJsonObject> ErrObj = Err->AsObject())
46
+ {
47
+ ErrObj->TryGetStringField(TEXT("error"), ErrMsg);
48
+ }
49
+ }
50
+ OutResult->SetStringField(TEXT("error"), ErrMsg);
51
+ OutResult->SetBoolField(TEXT("success"), false);
52
+ }
53
+ return CDO;
54
+ }
55
+
56
+ void FNetworkingHandlers::SaveBlueprint(UBlueprint* Blueprint)
57
+ {
58
+ if (!Blueprint) return;
59
+ FKismetEditorUtilities::CompileBlueprint(Blueprint);
60
+ SaveAssetPackage(Blueprint);
61
+ }
62
+
63
+ TSharedPtr<FJsonValue> FNetworkingHandlers::GetNetworkingInfo(const TSharedPtr<FJsonObject>& Params)
64
+ {
65
+ FString BlueprintPath;
66
+ if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
67
+
68
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
69
+ AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
70
+ if (!CDO) return MCPResult(Result);
71
+
72
+ Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
73
+ Result->SetBoolField(TEXT("replicates"), CDO->GetIsReplicated());
74
+ #if UE_MCP_HAS_5_5_API
75
+ Result->SetNumberField(TEXT("netUpdateFrequency"), CDO->GetNetUpdateFrequency());
76
+ Result->SetNumberField(TEXT("minNetUpdateFrequency"), CDO->GetMinNetUpdateFrequency());
77
+ #else
78
+ Result->SetNumberField(TEXT("netUpdateFrequency"), CDO->NetUpdateFrequency);
79
+ Result->SetNumberField(TEXT("minNetUpdateFrequency"), CDO->MinNetUpdateFrequency);
80
+ #endif
81
+ Result->SetNumberField(TEXT("netPriority"), CDO->NetPriority);
82
+ Result->SetBoolField(TEXT("alwaysRelevant"), CDO->bAlwaysRelevant);
83
+ Result->SetBoolField(TEXT("replicateMovement"), CDO->IsReplicatingMovement());
84
+ Result->SetNumberField(TEXT("netDormancy"), (int32)CDO->NetDormancy);
85
+ Result->SetBoolField(TEXT("success"), true);
86
+
87
+ return MCPResult(Result);
88
+ }
89
+
90
+ TSharedPtr<FJsonValue> FNetworkingHandlers::SetReplicates(const TSharedPtr<FJsonObject>& Params)
91
+ {
92
+ FString BlueprintPath;
93
+ if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
94
+
95
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
96
+ AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
97
+ if (!CDO) return MCPResult(Result);
98
+
99
+ bool bReplicates = OptionalBool(Params, TEXT("replicates"), false);
100
+ const bool bPrev = CDO->GetIsReplicated();
101
+
102
+ Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
103
+ Result->SetBoolField(TEXT("replicates"), bReplicates);
104
+ Result->SetBoolField(TEXT("success"), true);
105
+
106
+ if (bPrev == bReplicates)
107
+ {
108
+ MCPSetExisted(Result);
109
+ Result->SetBoolField(TEXT("updated"), false);
110
+ return MCPResult(Result);
111
+ }
112
+
113
+ CDO->SetReplicates(bReplicates);
114
+ UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
115
+ SaveBlueprint(Blueprint);
116
+
117
+ MCPSetUpdated(Result);
118
+ TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
119
+ Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
120
+ Payload->SetBoolField(TEXT("replicates"), bPrev);
121
+ MCPSetRollback(Result, TEXT("set_replicates"), Payload);
122
+ return MCPResult(Result);
123
+ }
124
+
125
+ TSharedPtr<FJsonValue> FNetworkingHandlers::ConfigureNetUpdateFrequency(const TSharedPtr<FJsonObject>& Params)
126
+ {
127
+ FString BlueprintPath;
128
+ if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
129
+
130
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
131
+ AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
132
+ if (!CDO) return MCPResult(Result);
133
+
134
+ double NetUpdateFrequency = 0;
135
+ if (Params->TryGetNumberField(TEXT("netUpdateFrequency"), NetUpdateFrequency))
136
+ {
137
+ #if UE_MCP_HAS_5_5_API
138
+ CDO->SetNetUpdateFrequency((float)NetUpdateFrequency);
139
+ #else
140
+ CDO->NetUpdateFrequency = (float)NetUpdateFrequency;
141
+ #endif
142
+ }
143
+ double MinNetUpdateFrequency = 0;
144
+ if (Params->TryGetNumberField(TEXT("minNetUpdateFrequency"), MinNetUpdateFrequency))
145
+ {
146
+ #if UE_MCP_HAS_5_5_API
147
+ CDO->SetMinNetUpdateFrequency((float)MinNetUpdateFrequency);
148
+ #else
149
+ CDO->MinNetUpdateFrequency = (float)MinNetUpdateFrequency;
150
+ #endif
151
+ }
152
+
153
+ UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
154
+ SaveBlueprint(Blueprint);
155
+
156
+ Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
157
+ #if UE_MCP_HAS_5_5_API
158
+ Result->SetNumberField(TEXT("netUpdateFrequency"), CDO->GetNetUpdateFrequency());
159
+ Result->SetNumberField(TEXT("minNetUpdateFrequency"), CDO->GetMinNetUpdateFrequency());
160
+ #else
161
+ Result->SetNumberField(TEXT("netUpdateFrequency"), CDO->NetUpdateFrequency);
162
+ Result->SetNumberField(TEXT("minNetUpdateFrequency"), CDO->MinNetUpdateFrequency);
163
+ #endif
164
+ Result->SetBoolField(TEXT("success"), true);
165
+ return MCPResult(Result);
166
+ }
167
+
168
+ static FString DormancyToString(ENetDormancy D)
169
+ {
170
+ switch (D)
171
+ {
172
+ case DORM_Never: return TEXT("DORM_Never");
173
+ case DORM_Awake: return TEXT("DORM_Awake");
174
+ case DORM_DormantAll: return TEXT("DORM_DormantAll");
175
+ case DORM_DormantPartial: return TEXT("DORM_DormantPartial");
176
+ case DORM_Initial: return TEXT("DORM_Initial");
177
+ default: return TEXT("DORM_Awake");
178
+ }
179
+ }
180
+
181
+ TSharedPtr<FJsonValue> FNetworkingHandlers::SetNetDormancy(const TSharedPtr<FJsonObject>& Params)
182
+ {
183
+ FString BlueprintPath;
184
+ if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
185
+
186
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
187
+ AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
188
+ if (!CDO) return MCPResult(Result);
189
+
190
+ FString Dormancy = OptionalString(Params, TEXT("dormancy"));
191
+ const ENetDormancy PrevDormancy = CDO->NetDormancy;
192
+ const FString PrevDormStr = DormancyToString(PrevDormancy);
193
+ ENetDormancy NewDormancy = PrevDormancy;
194
+ if (!Dormancy.IsEmpty())
195
+ {
196
+ if (Dormancy == TEXT("DORM_Never")) NewDormancy = DORM_Never;
197
+ else if (Dormancy == TEXT("DORM_Awake")) NewDormancy = DORM_Awake;
198
+ else if (Dormancy == TEXT("DORM_DormantAll")) NewDormancy = DORM_DormantAll;
199
+ else if (Dormancy == TEXT("DORM_DormantPartial")) NewDormancy = DORM_DormantPartial;
200
+ else if (Dormancy == TEXT("DORM_Initial")) NewDormancy = DORM_Initial;
201
+ }
202
+
203
+ Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
204
+ Result->SetNumberField(TEXT("netDormancy"), (int32)NewDormancy);
205
+ Result->SetBoolField(TEXT("success"), true);
206
+
207
+ if (NewDormancy == PrevDormancy)
208
+ {
209
+ MCPSetExisted(Result);
210
+ Result->SetBoolField(TEXT("updated"), false);
211
+ return MCPResult(Result);
212
+ }
213
+
214
+ CDO->NetDormancy = NewDormancy;
215
+ UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
216
+ SaveBlueprint(Blueprint);
217
+
218
+ MCPSetUpdated(Result);
219
+ TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
220
+ Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
221
+ Payload->SetStringField(TEXT("dormancy"), PrevDormStr);
222
+ MCPSetRollback(Result, TEXT("set_net_dormancy"), Payload);
223
+ return MCPResult(Result);
224
+ }
225
+
226
+ TSharedPtr<FJsonValue> FNetworkingHandlers::SetAlwaysRelevant(const TSharedPtr<FJsonObject>& Params)
227
+ {
228
+ FString BlueprintPath;
229
+ if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
230
+
231
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
232
+ AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
233
+ if (!CDO) return MCPResult(Result);
234
+
235
+ bool bAlwaysRelevant = OptionalBool(Params, TEXT("alwaysRelevant"), false);
236
+ const bool bPrev = CDO->bAlwaysRelevant;
237
+
238
+ Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
239
+ Result->SetBoolField(TEXT("alwaysRelevant"), bAlwaysRelevant);
240
+ Result->SetBoolField(TEXT("success"), true);
241
+
242
+ if (bPrev == bAlwaysRelevant)
243
+ {
244
+ MCPSetExisted(Result);
245
+ Result->SetBoolField(TEXT("updated"), false);
246
+ return MCPResult(Result);
247
+ }
248
+
249
+ CDO->bAlwaysRelevant = bAlwaysRelevant;
250
+ UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
251
+ SaveBlueprint(Blueprint);
252
+
253
+ MCPSetUpdated(Result);
254
+ TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
255
+ Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
256
+ Payload->SetBoolField(TEXT("alwaysRelevant"), bPrev);
257
+ MCPSetRollback(Result, TEXT("set_always_relevant"), Payload);
258
+ return MCPResult(Result);
259
+ }
260
+
261
+ TSharedPtr<FJsonValue> FNetworkingHandlers::SetNetPriority(const TSharedPtr<FJsonObject>& Params)
262
+ {
263
+ FString BlueprintPath;
264
+ if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
265
+
266
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
267
+ AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
268
+ if (!CDO) return MCPResult(Result);
269
+
270
+ double NetPriority = OptionalNumber(Params, TEXT("netPriority"), 1.0);
271
+ const float fPrev = CDO->NetPriority;
272
+
273
+ Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
274
+ Result->SetNumberField(TEXT("netPriority"), NetPriority);
275
+ Result->SetBoolField(TEXT("success"), true);
276
+
277
+ if (FMath::IsNearlyEqual(fPrev, (float)NetPriority))
278
+ {
279
+ MCPSetExisted(Result);
280
+ Result->SetBoolField(TEXT("updated"), false);
281
+ return MCPResult(Result);
282
+ }
283
+
284
+ CDO->NetPriority = (float)NetPriority;
285
+ UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
286
+ SaveBlueprint(Blueprint);
287
+
288
+ MCPSetUpdated(Result);
289
+ TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
290
+ Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
291
+ Payload->SetNumberField(TEXT("netPriority"), fPrev);
292
+ MCPSetRollback(Result, TEXT("set_net_priority"), Payload);
293
+ return MCPResult(Result);
294
+ }
295
+
296
+ TSharedPtr<FJsonValue> FNetworkingHandlers::SetReplicateMovement(const TSharedPtr<FJsonObject>& Params)
297
+ {
298
+ FString BlueprintPath;
299
+ if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
300
+
301
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
302
+ AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
303
+ if (!CDO) return MCPResult(Result);
304
+
305
+ bool bReplicateMovement = OptionalBool(Params, TEXT("replicateMovement"), false);
306
+ const bool bPrev = CDO->IsReplicatingMovement();
307
+
308
+ Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
309
+ Result->SetBoolField(TEXT("replicateMovement"), bReplicateMovement);
310
+ Result->SetBoolField(TEXT("success"), true);
311
+
312
+ if (bPrev == bReplicateMovement)
313
+ {
314
+ MCPSetExisted(Result);
315
+ Result->SetBoolField(TEXT("updated"), false);
316
+ return MCPResult(Result);
317
+ }
318
+
319
+ CDO->SetReplicatingMovement(bReplicateMovement);
320
+ UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
321
+ SaveBlueprint(Blueprint);
322
+
323
+ MCPSetUpdated(Result);
324
+ TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
325
+ Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
326
+ Payload->SetBoolField(TEXT("replicateMovement"), bPrev);
327
+ MCPSetRollback(Result, TEXT("set_replicate_movement"), Payload);
328
+ return MCPResult(Result);
329
+ }
330
+
331
+ TSharedPtr<FJsonValue> FNetworkingHandlers::SetVariableReplication(const TSharedPtr<FJsonObject>& Params)
332
+ {
333
+ FString BlueprintPath;
334
+ if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
335
+
336
+ FString VariableName;
337
+ if (auto Err = RequireString(Params, TEXT("variableName"), VariableName)) return Err;
338
+
339
+ FString ReplicationType = OptionalString(Params, TEXT("replicationType"), TEXT("None"));
340
+
341
+ UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
342
+ if (!Blueprint)
343
+ {
344
+ return MCPError(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintPath));
345
+ }
346
+
347
+ // Find the variable in the blueprint
348
+ FName VarFName(*VariableName);
349
+ FBPVariableDescription* VarDesc = nullptr;
350
+ for (FBPVariableDescription& Var : Blueprint->NewVariables)
351
+ {
352
+ if (Var.VarName == VarFName)
353
+ {
354
+ VarDesc = &Var;
355
+ break;
356
+ }
357
+ }
358
+
359
+ if (!VarDesc)
360
+ {
361
+ return MCPError(FString::Printf(TEXT("Variable '%s' not found in blueprint"), *VariableName));
362
+ }
363
+
364
+ // Capture previous state
365
+ const bool bWasNet = (VarDesc->PropertyFlags & CPF_Net) != 0;
366
+ const bool bWasRepNotify = (VarDesc->PropertyFlags & CPF_RepNotify) != 0;
367
+ FString PrevType = TEXT("None");
368
+ if (bWasNet && bWasRepNotify) PrevType = TEXT("RepNotify");
369
+ else if (bWasNet) PrevType = TEXT("Replicated");
370
+
371
+ auto Result = MCPSuccess();
372
+ Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
373
+ Result->SetStringField(TEXT("variableName"), VariableName);
374
+ Result->SetStringField(TEXT("replicationType"), ReplicationType);
375
+
376
+ if (PrevType == ReplicationType)
377
+ {
378
+ MCPSetExisted(Result);
379
+ Result->SetBoolField(TEXT("updated"), false);
380
+ return MCPResult(Result);
381
+ }
382
+
383
+ // Set the replication condition
384
+ if (ReplicationType == TEXT("Replicated"))
385
+ {
386
+ VarDesc->PropertyFlags |= CPF_Net;
387
+ VarDesc->PropertyFlags &= ~CPF_RepNotify;
388
+ VarDesc->ReplicationCondition = COND_None;
389
+ }
390
+ else if (ReplicationType == TEXT("RepNotify"))
391
+ {
392
+ VarDesc->PropertyFlags |= CPF_Net;
393
+ VarDesc->PropertyFlags |= CPF_RepNotify;
394
+ VarDesc->ReplicationCondition = COND_None;
395
+ }
396
+ else // "None"
397
+ {
398
+ VarDesc->PropertyFlags &= ~CPF_Net;
399
+ VarDesc->PropertyFlags &= ~CPF_RepNotify;
400
+ }
401
+
402
+ SaveBlueprint(Blueprint);
403
+
404
+ MCPSetUpdated(Result);
405
+ TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
406
+ Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
407
+ Payload->SetStringField(TEXT("variableName"), VariableName);
408
+ Payload->SetStringField(TEXT("replicationType"), PrevType);
409
+ MCPSetRollback(Result, TEXT("set_variable_replication"), Payload);
410
+ return MCPResult(Result);
411
+ }
412
+
413
+ TSharedPtr<FJsonValue> FNetworkingHandlers::SetOwnerOnlyRelevant(const TSharedPtr<FJsonObject>& Params)
414
+ {
415
+ FString BlueprintPath;
416
+ if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
417
+
418
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
419
+ AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
420
+ if (!CDO) return MCPResult(Result);
421
+
422
+ bool bOnlyRelevantToOwner = OptionalBool(Params, TEXT("onlyRelevantToOwner"), false);
423
+ const bool bPrev = CDO->bOnlyRelevantToOwner;
424
+
425
+ Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
426
+ Result->SetBoolField(TEXT("onlyRelevantToOwner"), bOnlyRelevantToOwner);
427
+ Result->SetBoolField(TEXT("success"), true);
428
+
429
+ if (bPrev == bOnlyRelevantToOwner)
430
+ {
431
+ MCPSetExisted(Result);
432
+ Result->SetBoolField(TEXT("updated"), false);
433
+ return MCPResult(Result);
434
+ }
435
+
436
+ CDO->bOnlyRelevantToOwner = bOnlyRelevantToOwner;
437
+ UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
438
+ SaveBlueprint(Blueprint);
439
+
440
+ MCPSetUpdated(Result);
441
+ TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
442
+ Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
443
+ Payload->SetBoolField(TEXT("onlyRelevantToOwner"), bPrev);
444
+ MCPSetRollback(Result, TEXT("set_owner_only_relevant"), Payload);
445
+ return MCPResult(Result);
446
+ }
447
+
448
+ TSharedPtr<FJsonValue> FNetworkingHandlers::SetNetLoadOnClient(const TSharedPtr<FJsonObject>& Params)
449
+ {
450
+ FString BlueprintPath;
451
+ if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
452
+
453
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
454
+ AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
455
+ if (!CDO) return MCPResult(Result);
456
+
457
+ bool bLoadOnClient = OptionalBool(Params, TEXT("loadOnClient"), true);
458
+ bool bPrev = bLoadOnClient;
459
+
460
+ FProperty* Prop = CDO->GetClass()->FindPropertyByName(TEXT("bNetLoadOnClient"));
461
+ if (Prop)
462
+ {
463
+ bool* ValPtr = Prop->ContainerPtrToValuePtr<bool>(CDO);
464
+ if (ValPtr)
465
+ {
466
+ bPrev = *ValPtr;
467
+ }
468
+ }
469
+
470
+ Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
471
+ Result->SetBoolField(TEXT("loadOnClient"), bLoadOnClient);
472
+ Result->SetBoolField(TEXT("success"), true);
473
+
474
+ if (bPrev == bLoadOnClient)
475
+ {
476
+ MCPSetExisted(Result);
477
+ Result->SetBoolField(TEXT("updated"), false);
478
+ return MCPResult(Result);
479
+ }
480
+
481
+ if (Prop)
482
+ {
483
+ bool* ValPtr = Prop->ContainerPtrToValuePtr<bool>(CDO);
484
+ if (ValPtr) { *ValPtr = bLoadOnClient; }
485
+ }
486
+
487
+ UBlueprint* BP = Cast<UBlueprint>(UEditorAssetLibrary::LoadAsset(BlueprintPath));
488
+ if (BP) SaveBlueprint(BP);
489
+
490
+ MCPSetUpdated(Result);
491
+ TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
492
+ Payload->SetStringField(TEXT("blueprintPath"), BlueprintPath);
493
+ Payload->SetBoolField(TEXT("loadOnClient"), bPrev);
494
+ MCPSetRollback(Result, TEXT("set_net_load_on_client"), Payload);
495
+ return MCPResult(Result);
496
+ }
497
+
498
+ TSharedPtr<FJsonValue> FNetworkingHandlers::ConfigureNetCullDistance(const TSharedPtr<FJsonObject>& Params)
499
+ {
500
+ FString BlueprintPath;
501
+ if (auto Err = RequireString(Params, TEXT("blueprintPath"), BlueprintPath)) return Err;
502
+
503
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
504
+ AActor* CDO = LoadBlueprintCDO(BlueprintPath, Result);
505
+ if (!CDO) return MCPResult(Result);
506
+
507
+ double Distance = OptionalNumber(Params, TEXT("netCullDistanceSquared"), 225000000.0);
508
+
509
+ FProperty* Prop = CDO->GetClass()->FindPropertyByName(TEXT("NetCullDistanceSquared"));
510
+ if (Prop)
511
+ {
512
+ FFloatProperty* FloatProp = CastField<FFloatProperty>(Prop);
513
+ FDoubleProperty* DoubleProp = CastField<FDoubleProperty>(Prop);
514
+ if (FloatProp)
515
+ {
516
+ FloatProp->SetPropertyValue_InContainer(CDO, static_cast<float>(Distance));
517
+ }
518
+ else if (DoubleProp)
519
+ {
520
+ DoubleProp->SetPropertyValue_InContainer(CDO, Distance);
521
+ }
522
+ }
523
+
524
+ UBlueprint* BP = Cast<UBlueprint>(UEditorAssetLibrary::LoadAsset(BlueprintPath));
525
+ if (BP) SaveBlueprint(BP);
526
+
527
+ Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
528
+ Result->SetNumberField(TEXT("netCullDistanceSquared"), Distance);
529
+ Result->SetBoolField(TEXT("success"), true);
530
+ return MCPResult(Result);
531
+ }