ue-mcp 0.4.0-alpha

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 (141) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +89 -0
  3. package/dist/bridge.d.ts +25 -0
  4. package/dist/bridge.js +124 -0
  5. package/dist/bridge.js.map +1 -0
  6. package/dist/deployer.d.ts +18 -0
  7. package/dist/deployer.js +175 -0
  8. package/dist/deployer.js.map +1 -0
  9. package/dist/editor-control.d.ts +15 -0
  10. package/dist/editor-control.js +181 -0
  11. package/dist/editor-control.js.map +1 -0
  12. package/dist/github-app.d.ts +4 -0
  13. package/dist/github-app.js +94 -0
  14. package/dist/github-app.js.map +1 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.js +125 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/init.d.ts +2 -0
  19. package/dist/init.js +290 -0
  20. package/dist/init.js.map +1 -0
  21. package/dist/instructions.d.ts +1 -0
  22. package/dist/instructions.js +150 -0
  23. package/dist/instructions.js.map +1 -0
  24. package/dist/project.d.ts +32 -0
  25. package/dist/project.js +175 -0
  26. package/dist/project.js.map +1 -0
  27. package/dist/tools/animation.d.ts +2 -0
  28. package/dist/tools/animation.js +62 -0
  29. package/dist/tools/animation.js.map +1 -0
  30. package/dist/tools/asset.d.ts +2 -0
  31. package/dist/tools/asset.js +128 -0
  32. package/dist/tools/asset.js.map +1 -0
  33. package/dist/tools/audio.d.ts +2 -0
  34. package/dist/tools/audio.js +24 -0
  35. package/dist/tools/audio.js.map +1 -0
  36. package/dist/tools/blueprint.d.ts +2 -0
  37. package/dist/tools/blueprint.js +64 -0
  38. package/dist/tools/blueprint.js.map +1 -0
  39. package/dist/tools/demo.d.ts +2 -0
  40. package/dist/tools/demo.js +10 -0
  41. package/dist/tools/demo.js.map +1 -0
  42. package/dist/tools/editor.d.ts +2 -0
  43. package/dist/tools/editor.js +133 -0
  44. package/dist/tools/editor.js.map +1 -0
  45. package/dist/tools/feedback.d.ts +2 -0
  46. package/dist/tools/feedback.js +44 -0
  47. package/dist/tools/feedback.js.map +1 -0
  48. package/dist/tools/foliage.d.ts +2 -0
  49. package/dist/tools/foliage.js +29 -0
  50. package/dist/tools/foliage.js.map +1 -0
  51. package/dist/tools/gameplay.d.ts +2 -0
  52. package/dist/tools/gameplay.js +101 -0
  53. package/dist/tools/gameplay.js.map +1 -0
  54. package/dist/tools/gas.d.ts +2 -0
  55. package/dist/tools/gas.js +43 -0
  56. package/dist/tools/gas.js.map +1 -0
  57. package/dist/tools/landscape.d.ts +2 -0
  58. package/dist/tools/landscape.js +32 -0
  59. package/dist/tools/landscape.js.map +1 -0
  60. package/dist/tools/level.d.ts +2 -0
  61. package/dist/tools/level.js +66 -0
  62. package/dist/tools/level.js.map +1 -0
  63. package/dist/tools/material.d.ts +2 -0
  64. package/dist/tools/material.js +59 -0
  65. package/dist/tools/material.js.map +1 -0
  66. package/dist/tools/networking.d.ts +2 -0
  67. package/dist/tools/networking.js +42 -0
  68. package/dist/tools/networking.js.map +1 -0
  69. package/dist/tools/niagara.d.ts +2 -0
  70. package/dist/tools/niagara.js +42 -0
  71. package/dist/tools/niagara.js.map +1 -0
  72. package/dist/tools/pcg.d.ts +2 -0
  73. package/dist/tools/pcg.js +39 -0
  74. package/dist/tools/pcg.js.map +1 -0
  75. package/dist/tools/project.d.ts +2 -0
  76. package/dist/tools/project.js +282 -0
  77. package/dist/tools/project.js.map +1 -0
  78. package/dist/tools/reflection.d.ts +2 -0
  79. package/dist/tools/reflection.js +26 -0
  80. package/dist/tools/reflection.js.map +1 -0
  81. package/dist/tools/widget.d.ts +2 -0
  82. package/dist/tools/widget.js +34 -0
  83. package/dist/tools/widget.js.map +1 -0
  84. package/dist/types.d.ts +21 -0
  85. package/dist/types.js +38 -0
  86. package/dist/types.js.map +1 -0
  87. package/package.json +76 -0
  88. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.cpp +746 -0
  89. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/BridgeServer.h +81 -0
  90. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.cpp +49 -0
  91. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/GameThreadExecutor.h +37 -0
  92. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerRegistry.cpp +75 -0
  93. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerRegistry.h +50 -0
  94. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.cpp +1418 -0
  95. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers.h +43 -0
  96. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.cpp +1773 -0
  97. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers.h +48 -0
  98. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers.cpp +289 -0
  99. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AudioHandlers.h +18 -0
  100. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.cpp +1982 -0
  101. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers.h +44 -0
  102. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.cpp +1217 -0
  103. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.h +71 -0
  104. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DialogHandlers.cpp +465 -0
  105. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DialogHandlers.h +49 -0
  106. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.cpp +1676 -0
  107. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers.h +53 -0
  108. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.cpp +876 -0
  109. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +22 -0
  110. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.cpp +2222 -0
  111. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers.h +54 -0
  112. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +783 -0
  113. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +24 -0
  114. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +898 -0
  115. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.h +24 -0
  116. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.cpp +1270 -0
  117. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LevelHandlers.h +34 -0
  118. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.cpp +2190 -0
  119. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers.h +53 -0
  120. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NetworkingHandlers.cpp +554 -0
  121. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NetworkingHandlers.h +29 -0
  122. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers.cpp +601 -0
  123. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NiagaraHandlers.h +25 -0
  124. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PCGHandlers.cpp +1024 -0
  125. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PCGHandlers.h +25 -0
  126. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +370 -0
  127. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.h +19 -0
  128. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ReflectionHandlers.cpp +499 -0
  129. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ReflectionHandlers.h +27 -0
  130. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +426 -0
  131. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.h +19 -0
  132. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.cpp +303 -0
  133. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.h +18 -0
  134. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.cpp +985 -0
  135. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/WidgetHandlers.h +27 -0
  136. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/JsonSerializer.cpp +181 -0
  137. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/JsonSerializer.h +42 -0
  138. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/UE_MCP_Bridge.cpp +39 -0
  139. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/UE_MCP_BridgeModule.h +14 -0
  140. package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/UE_MCP_Bridge.Build.cs +87 -0
  141. package/plugin/ue_mcp_bridge/UE_MCP_Bridge.uplugin +55 -0
@@ -0,0 +1,2222 @@
1
+ #include "GameplayHandlers.h"
2
+ #include "HandlerRegistry.h"
3
+ #include "EditorScriptingUtilities/Public/EditorAssetLibrary.h"
4
+ #include "AssetToolsModule.h"
5
+ #include "IAssetTools.h"
6
+ #include "AssetRegistry/AssetRegistryModule.h"
7
+ #include "UObject/UObjectGlobals.h"
8
+ #include "UObject/Package.h"
9
+ #include "Misc/PackageName.h"
10
+ #include "UObject/SavePackage.h"
11
+ #include "UObject/TopLevelAssetPath.h"
12
+ #include "Dom/JsonObject.h"
13
+ #include "Dom/JsonValue.h"
14
+ #include "Engine/World.h"
15
+ #include "Editor.h"
16
+ #include "NavigationSystem.h"
17
+ #include "NavMesh/NavMeshBoundsVolume.h"
18
+ #include "GameFramework/GameModeBase.h"
19
+ #include "GameFramework/GameStateBase.h"
20
+ #include "GameFramework/PlayerController.h"
21
+ #include "GameFramework/PlayerState.h"
22
+ #include "GameFramework/HUD.h"
23
+ #include "Kismet2/KismetEditorUtilities.h"
24
+ #include "Engine/Blueprint.h"
25
+ #include "Factories/BlueprintFactory.h"
26
+ #include "EngineUtils.h"
27
+ #include "GameFramework/Actor.h"
28
+ #include "Components/PrimitiveComponent.h"
29
+ #include "NavModifierVolume.h"
30
+ #include "GameFramework/WorldSettings.h"
31
+ #include "UObject/UnrealType.h"
32
+ #include "BehaviorTree/BlackboardData.h"
33
+ #include "BehaviorTree/Blackboard/BlackboardKeyType_Bool.h"
34
+ #include "BehaviorTree/Blackboard/BlackboardKeyType_Int.h"
35
+ #include "BehaviorTree/Blackboard/BlackboardKeyType_Float.h"
36
+ #include "BehaviorTree/Blackboard/BlackboardKeyType_String.h"
37
+ #include "BehaviorTree/Blackboard/BlackboardKeyType_Name.h"
38
+ #include "BehaviorTree/Blackboard/BlackboardKeyType_Object.h"
39
+ #include "BehaviorTree/Blackboard/BlackboardKeyType_Class.h"
40
+ #include "BehaviorTree/Blackboard/BlackboardKeyType_Enum.h"
41
+ #include "BehaviorTree/Blackboard/BlackboardKeyType_Vector.h"
42
+ #include "BehaviorTree/Blackboard/BlackboardKeyType_Rotator.h"
43
+ #include "Perception/AIPerceptionComponent.h"
44
+ #include "Perception/AISenseConfig_Sight.h"
45
+ #include "Perception/AISenseConfig_Hearing.h"
46
+ #include "Perception/AISenseConfig_Damage.h"
47
+ #include "EnhancedInputComponent.h"
48
+ #include "InputAction.h"
49
+ #include "InputMappingContext.h"
50
+ #include "BehaviorTree/BehaviorTree.h"
51
+ #include "BehaviorTree/BehaviorTreeComponent.h"
52
+ #include "BehaviorTree/BlackboardComponent.h"
53
+ #include "AIController.h"
54
+ #include "Engine/SCS_Node.h"
55
+ #include "Navigation/PathFollowingComponent.h"
56
+ #include "GameFramework/NavMovementComponent.h"
57
+ #include "GameFramework/CharacterMovementComponent.h"
58
+ #include "GameFramework/Character.h"
59
+ #include "EnvironmentQuery/EnvQuery.h"
60
+ #include "EnvironmentQuery/EnvQueryManager.h"
61
+ #include "EnvironmentQuery/EnvQueryInstanceBlueprintWrapper.h"
62
+
63
+ void FGameplayHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
64
+ {
65
+ Registry.RegisterHandler(TEXT("create_smart_object_definition"), &CreateSmartObjectDefinition);
66
+ Registry.RegisterHandler(TEXT("get_navmesh_info"), &GetNavmeshInfo);
67
+ Registry.RegisterHandler(TEXT("get_game_framework_info"), &GetGameFrameworkInfo);
68
+ Registry.RegisterHandler(TEXT("list_input_assets"), &ListInputAssets);
69
+ Registry.RegisterHandler(TEXT("list_behavior_trees"), &ListBehaviorTrees);
70
+ Registry.RegisterHandler(TEXT("list_eqs_queries"), &ListEqsQueries);
71
+ Registry.RegisterHandler(TEXT("list_state_trees"), &ListStateTrees);
72
+ Registry.RegisterHandler(TEXT("project_point_to_navigation"), &ProjectPointToNavigation);
73
+ Registry.RegisterHandler(TEXT("create_input_action"), &CreateInputAction);
74
+ Registry.RegisterHandler(TEXT("create_input_mapping_context"), &CreateInputMappingContext);
75
+ Registry.RegisterHandler(TEXT("create_blackboard"), &CreateBlackboard);
76
+ Registry.RegisterHandler(TEXT("create_behavior_tree"), &CreateBehaviorTree);
77
+ Registry.RegisterHandler(TEXT("create_eqs_query"), &CreateEqsQuery);
78
+ Registry.RegisterHandler(TEXT("create_state_tree"), &CreateStateTree);
79
+ Registry.RegisterHandler(TEXT("create_game_mode"), &CreateGameMode);
80
+ Registry.RegisterHandler(TEXT("create_game_state"), &CreateGameState);
81
+ Registry.RegisterHandler(TEXT("create_player_controller"), &CreatePlayerController);
82
+ Registry.RegisterHandler(TEXT("create_player_state"), &CreatePlayerState);
83
+ Registry.RegisterHandler(TEXT("create_hud"), &CreateHud);
84
+ Registry.RegisterHandler(TEXT("set_collision_profile"), &SetCollisionProfile);
85
+ Registry.RegisterHandler(TEXT("set_physics_enabled"), &SetPhysicsEnabled);
86
+ Registry.RegisterHandler(TEXT("set_collision_type"), &SetCollisionType);
87
+ Registry.RegisterHandler(TEXT("set_body_properties"), &SetBodyProperties);
88
+ Registry.RegisterHandler(TEXT("spawn_nav_modifier_volume"), &SpawnNavModifierVolume);
89
+ Registry.RegisterHandler(TEXT("rebuild_navmesh"), &RebuildNavmesh);
90
+ Registry.RegisterHandler(TEXT("get_cdo_defaults"), &GetCdoDefaults);
91
+ Registry.RegisterHandler(TEXT("set_world_game_mode"), &SetWorldGameMode);
92
+ Registry.RegisterHandler(TEXT("create_ai_perception_config"), &CreateAiPerceptionConfig);
93
+ Registry.RegisterHandler(TEXT("add_blackboard_key"), &AddBlackboardKey);
94
+ Registry.RegisterHandler(TEXT("setup_enhanced_input"), &SetupEnhancedInput);
95
+ Registry.RegisterHandler(TEXT("configure_behavior_tree"), &ConfigureBehaviorTree);
96
+ Registry.RegisterHandler(TEXT("setup_path_following"), &SetupPathFollowing);
97
+ Registry.RegisterHandler(TEXT("run_eqs_query"), &RunEqsQuery);
98
+ // Aliases
99
+ Registry.RegisterHandler(TEXT("rebuild_navigation"), &RebuildNavmesh);
100
+ // New handlers
101
+ Registry.RegisterHandler(TEXT("get_behavior_tree_info"), &GetBehaviorTreeInfo);
102
+ Registry.RegisterHandler(TEXT("add_perception_component"), &AddPerceptionComponent);
103
+ Registry.RegisterHandler(TEXT("configure_ai_perception_sense"), &ConfigureAiPerceptionSense);
104
+ Registry.RegisterHandler(TEXT("add_state_tree_component"), &AddStateTreeComponent);
105
+ Registry.RegisterHandler(TEXT("add_smart_object_component"), &AddSmartObjectComponent);
106
+ }
107
+
108
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreateSmartObjectDefinition(const TSharedPtr<FJsonObject>& Params)
109
+ {
110
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
111
+
112
+ FString Name;
113
+ if (!Params->TryGetStringField(TEXT("name"), Name))
114
+ {
115
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
116
+ Result->SetBoolField(TEXT("success"), false);
117
+ return MakeShared<FJsonValueObject>(Result);
118
+ }
119
+
120
+ FString PackagePath = TEXT("/Game/AI/SmartObjects");
121
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
122
+
123
+ // Delete existing asset if it exists
124
+ FString AssetPath = PackagePath + TEXT("/") + Name;
125
+ UEditorAssetLibrary::DeleteAsset(AssetPath);
126
+
127
+ // Find SmartObjectDefinition class
128
+ UClass* SmartObjectDefClass = FindObject<UClass>(nullptr, TEXT("/Script/SmartObjectsModule.SmartObjectDefinition"));
129
+ if (!SmartObjectDefClass)
130
+ {
131
+ Result->SetStringField(TEXT("error"), TEXT("SmartObjectDefinition class not found. Enable SmartObjects plugin."));
132
+ Result->SetBoolField(TEXT("success"), false);
133
+ return MakeShared<FJsonValueObject>(Result);
134
+ }
135
+
136
+ // Create asset
137
+ FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
138
+ IAssetTools& AssetTools = AssetToolsModule.Get();
139
+
140
+ FString PackageName;
141
+ FString AssetName;
142
+ PackagePath.Split(TEXT("/"), &PackageName, &AssetName, ESearchCase::CaseSensitive, ESearchDir::FromEnd);
143
+ if (AssetName.IsEmpty())
144
+ {
145
+ AssetName = Name;
146
+ }
147
+ else
148
+ {
149
+ PackageName = PackagePath;
150
+ AssetName = Name;
151
+ }
152
+ PackageName = PackageName.LeftChop(1); // Remove trailing /
153
+
154
+ UObject* NewAsset = AssetTools.CreateAsset(AssetName, PackageName, SmartObjectDefClass, nullptr);
155
+ if (!NewAsset)
156
+ {
157
+ Result->SetStringField(TEXT("error"), TEXT("Failed to create SmartObjectDefinition"));
158
+ Result->SetBoolField(TEXT("success"), false);
159
+ return MakeShared<FJsonValueObject>(Result);
160
+ }
161
+
162
+ UEditorAssetLibrary::SaveAsset(NewAsset->GetPathName());
163
+
164
+ Result->SetStringField(TEXT("path"), NewAsset->GetPathName());
165
+ Result->SetStringField(TEXT("name"), Name);
166
+ Result->SetBoolField(TEXT("success"), true);
167
+
168
+ return MakeShared<FJsonValueObject>(Result);
169
+ }
170
+
171
+ TSharedPtr<FJsonValue> FGameplayHandlers::GetNavmeshInfo(const TSharedPtr<FJsonObject>& Params)
172
+ {
173
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
174
+
175
+ UWorld* World = GEditor->GetEditorWorldContext().World();
176
+ if (!World)
177
+ {
178
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
179
+ Result->SetBoolField(TEXT("success"), false);
180
+ return MakeShared<FJsonValueObject>(Result);
181
+ }
182
+
183
+ UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
184
+ if (!NavSys)
185
+ {
186
+ Result->SetStringField(TEXT("status"), TEXT("no_navigation_system"));
187
+ Result->SetBoolField(TEXT("success"), true);
188
+ return MakeShared<FJsonValueObject>(Result);
189
+ }
190
+
191
+ Result->SetStringField(TEXT("status"), TEXT("active"));
192
+
193
+ // Get nav data info
194
+ TArray<TSharedPtr<FJsonValue>> NavDataArray;
195
+ for (ANavigationData* NavData : NavSys->NavDataSet)
196
+ {
197
+ if (NavData)
198
+ {
199
+ TSharedPtr<FJsonObject> NavDataObj = MakeShared<FJsonObject>();
200
+ NavDataObj->SetStringField(TEXT("name"), NavData->GetName());
201
+ NavDataObj->SetStringField(TEXT("class"), NavData->GetClass()->GetName());
202
+
203
+ NavDataArray.Add(MakeShared<FJsonValueObject>(NavDataObj));
204
+ }
205
+ }
206
+ Result->SetArrayField(TEXT("navData"), NavDataArray);
207
+ Result->SetBoolField(TEXT("success"), true);
208
+
209
+ return MakeShared<FJsonValueObject>(Result);
210
+ }
211
+
212
+ TSharedPtr<FJsonValue> FGameplayHandlers::GetGameFrameworkInfo(const TSharedPtr<FJsonObject>& Params)
213
+ {
214
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
215
+
216
+ UWorld* World = GEditor->GetEditorWorldContext().World();
217
+ if (!World)
218
+ {
219
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
220
+ Result->SetBoolField(TEXT("success"), false);
221
+ return MakeShared<FJsonValueObject>(Result);
222
+ }
223
+
224
+ // Game mode
225
+ AGameModeBase* GameMode = World->GetAuthGameMode();
226
+ if (GameMode)
227
+ {
228
+ Result->SetStringField(TEXT("gameMode"), GameMode->GetClass()->GetName());
229
+ }
230
+ else
231
+ {
232
+ Result->SetStringField(TEXT("gameMode"), TEXT("none"));
233
+ }
234
+
235
+ // Game state
236
+ AGameStateBase* GameState = World->GetGameState();
237
+ if (GameState)
238
+ {
239
+ Result->SetStringField(TEXT("gameState"), GameState->GetClass()->GetName());
240
+ }
241
+ else
242
+ {
243
+ Result->SetStringField(TEXT("gameState"), TEXT("none"));
244
+ }
245
+
246
+ // Default player controller class
247
+ if (GameMode)
248
+ {
249
+ TSubclassOf<APlayerController> PCClass = GameMode->PlayerControllerClass;
250
+ if (PCClass)
251
+ {
252
+ Result->SetStringField(TEXT("playerControllerClass"), PCClass->GetName());
253
+ }
254
+ }
255
+
256
+ Result->SetBoolField(TEXT("success"), true);
257
+ return MakeShared<FJsonValueObject>(Result);
258
+ }
259
+
260
+ TSharedPtr<FJsonValue> FGameplayHandlers::ListInputAssets(const TSharedPtr<FJsonObject>& Params)
261
+ {
262
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
263
+
264
+ IAssetRegistry& AR = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
265
+
266
+ // List InputAction assets
267
+ TArray<FAssetData> InputActions;
268
+ AR.GetAssetsByClass(FTopLevelAssetPath(TEXT("/Script/EnhancedInput"), TEXT("InputAction")), InputActions, true);
269
+
270
+ TArray<TSharedPtr<FJsonValue>> InputActionArray;
271
+ for (const FAssetData& Asset : InputActions)
272
+ {
273
+ TSharedPtr<FJsonObject> AssetObj = MakeShared<FJsonObject>();
274
+ AssetObj->SetStringField(TEXT("name"), Asset.AssetName.ToString());
275
+ AssetObj->SetStringField(TEXT("path"), Asset.GetObjectPathString());
276
+ InputActionArray.Add(MakeShared<FJsonValueObject>(AssetObj));
277
+ }
278
+ Result->SetArrayField(TEXT("inputActions"), InputActionArray);
279
+
280
+ // List InputMappingContext assets
281
+ TArray<FAssetData> MappingContexts;
282
+ AR.GetAssetsByClass(FTopLevelAssetPath(TEXT("/Script/EnhancedInput"), TEXT("InputMappingContext")), MappingContexts, true);
283
+
284
+ TArray<TSharedPtr<FJsonValue>> MappingContextArray;
285
+ for (const FAssetData& Asset : MappingContexts)
286
+ {
287
+ TSharedPtr<FJsonObject> AssetObj = MakeShared<FJsonObject>();
288
+ AssetObj->SetStringField(TEXT("name"), Asset.AssetName.ToString());
289
+ AssetObj->SetStringField(TEXT("path"), Asset.GetObjectPathString());
290
+ MappingContextArray.Add(MakeShared<FJsonValueObject>(AssetObj));
291
+ }
292
+ Result->SetArrayField(TEXT("inputMappingContexts"), MappingContextArray);
293
+
294
+ Result->SetBoolField(TEXT("success"), true);
295
+ return MakeShared<FJsonValueObject>(Result);
296
+ }
297
+
298
+ TSharedPtr<FJsonValue> FGameplayHandlers::ListBehaviorTrees(const TSharedPtr<FJsonObject>& Params)
299
+ {
300
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
301
+
302
+ IAssetRegistry& AR = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
303
+ TArray<FAssetData> Assets;
304
+ AR.GetAssetsByClass(FTopLevelAssetPath(TEXT("/Script/AIModule"), TEXT("BehaviorTree")), Assets, true);
305
+
306
+ TArray<TSharedPtr<FJsonValue>> AssetArray;
307
+ for (const FAssetData& Asset : Assets)
308
+ {
309
+ TSharedPtr<FJsonObject> AssetObj = MakeShared<FJsonObject>();
310
+ AssetObj->SetStringField(TEXT("name"), Asset.AssetName.ToString());
311
+ AssetObj->SetStringField(TEXT("path"), Asset.GetObjectPathString());
312
+ AssetArray.Add(MakeShared<FJsonValueObject>(AssetObj));
313
+ }
314
+ Result->SetArrayField(TEXT("behaviorTrees"), AssetArray);
315
+ Result->SetBoolField(TEXT("success"), true);
316
+
317
+ return MakeShared<FJsonValueObject>(Result);
318
+ }
319
+
320
+ TSharedPtr<FJsonValue> FGameplayHandlers::ListEqsQueries(const TSharedPtr<FJsonObject>& Params)
321
+ {
322
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
323
+
324
+ IAssetRegistry& AR = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
325
+ TArray<FAssetData> Assets;
326
+ AR.GetAssetsByClass(FTopLevelAssetPath(TEXT("/Script/AIModule"), TEXT("EnvironmentQuery")), Assets, true);
327
+
328
+ TArray<TSharedPtr<FJsonValue>> AssetArray;
329
+ for (const FAssetData& Asset : Assets)
330
+ {
331
+ TSharedPtr<FJsonObject> AssetObj = MakeShared<FJsonObject>();
332
+ AssetObj->SetStringField(TEXT("name"), Asset.AssetName.ToString());
333
+ AssetObj->SetStringField(TEXT("path"), Asset.GetObjectPathString());
334
+ AssetArray.Add(MakeShared<FJsonValueObject>(AssetObj));
335
+ }
336
+ Result->SetArrayField(TEXT("eqsQueries"), AssetArray);
337
+ Result->SetBoolField(TEXT("success"), true);
338
+
339
+ return MakeShared<FJsonValueObject>(Result);
340
+ }
341
+
342
+ TSharedPtr<FJsonValue> FGameplayHandlers::ListStateTrees(const TSharedPtr<FJsonObject>& Params)
343
+ {
344
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
345
+
346
+ IAssetRegistry& AR = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
347
+ TArray<FAssetData> Assets;
348
+ AR.GetAssetsByClass(FTopLevelAssetPath(TEXT("/Script/StateTreeModule"), TEXT("StateTree")), Assets, true);
349
+
350
+ TArray<TSharedPtr<FJsonValue>> AssetArray;
351
+ for (const FAssetData& Asset : Assets)
352
+ {
353
+ TSharedPtr<FJsonObject> AssetObj = MakeShared<FJsonObject>();
354
+ AssetObj->SetStringField(TEXT("name"), Asset.AssetName.ToString());
355
+ AssetObj->SetStringField(TEXT("path"), Asset.GetObjectPathString());
356
+ AssetArray.Add(MakeShared<FJsonValueObject>(AssetObj));
357
+ }
358
+ Result->SetArrayField(TEXT("stateTrees"), AssetArray);
359
+ Result->SetBoolField(TEXT("success"), true);
360
+
361
+ return MakeShared<FJsonValueObject>(Result);
362
+ }
363
+
364
+ TSharedPtr<FJsonValue> FGameplayHandlers::ProjectPointToNavigation(const TSharedPtr<FJsonObject>& Params)
365
+ {
366
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
367
+
368
+ const TSharedPtr<FJsonObject>* LocationObj = nullptr;
369
+ if (!Params->TryGetObjectField(TEXT("location"), LocationObj))
370
+ {
371
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'location' parameter"));
372
+ Result->SetBoolField(TEXT("success"), false);
373
+ return MakeShared<FJsonValueObject>(Result);
374
+ }
375
+
376
+ FVector Point;
377
+ Point.X = (*LocationObj)->GetNumberField(TEXT("x"));
378
+ Point.Y = (*LocationObj)->GetNumberField(TEXT("y"));
379
+ Point.Z = (*LocationObj)->GetNumberField(TEXT("z"));
380
+
381
+ UWorld* World = GEditor->GetEditorWorldContext().World();
382
+ if (!World)
383
+ {
384
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
385
+ Result->SetBoolField(TEXT("success"), false);
386
+ return MakeShared<FJsonValueObject>(Result);
387
+ }
388
+
389
+ UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(World);
390
+ if (!NavSys)
391
+ {
392
+ Result->SetStringField(TEXT("error"), TEXT("No navigation system available"));
393
+ Result->SetBoolField(TEXT("success"), false);
394
+ return MakeShared<FJsonValueObject>(Result);
395
+ }
396
+
397
+ FNavLocation NavLocation;
398
+ bool bProjected = NavSys->ProjectPointToNavigation(Point, NavLocation);
399
+
400
+ Result->SetBoolField(TEXT("projected"), bProjected);
401
+ if (bProjected)
402
+ {
403
+ TSharedPtr<FJsonObject> ProjectedPoint = MakeShared<FJsonObject>();
404
+ ProjectedPoint->SetNumberField(TEXT("x"), NavLocation.Location.X);
405
+ ProjectedPoint->SetNumberField(TEXT("y"), NavLocation.Location.Y);
406
+ ProjectedPoint->SetNumberField(TEXT("z"), NavLocation.Location.Z);
407
+ Result->SetObjectField(TEXT("projectedLocation"), ProjectedPoint);
408
+ }
409
+ Result->SetBoolField(TEXT("success"), true);
410
+
411
+ return MakeShared<FJsonValueObject>(Result);
412
+ }
413
+
414
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreateInputAction(const TSharedPtr<FJsonObject>& Params)
415
+ {
416
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
417
+
418
+ FString Name;
419
+ if (!Params->TryGetStringField(TEXT("name"), Name))
420
+ {
421
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
422
+ Result->SetBoolField(TEXT("success"), false);
423
+ return MakeShared<FJsonValueObject>(Result);
424
+ }
425
+
426
+ FString PackagePath = TEXT("/Game/Input");
427
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
428
+
429
+ UClass* InputActionClass = FindObject<UClass>(nullptr, TEXT("/Script/EnhancedInput.InputAction"));
430
+ if (!InputActionClass)
431
+ {
432
+ Result->SetStringField(TEXT("error"), TEXT("InputAction class not found. Enable EnhancedInput plugin."));
433
+ Result->SetBoolField(TEXT("success"), false);
434
+ return MakeShared<FJsonValueObject>(Result);
435
+ }
436
+
437
+ FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
438
+ IAssetTools& AssetTools = AssetToolsModule.Get();
439
+
440
+ UObject* NewAsset = AssetTools.CreateAsset(Name, PackagePath, InputActionClass, nullptr);
441
+ if (!NewAsset)
442
+ {
443
+ Result->SetStringField(TEXT("error"), TEXT("Failed to create InputAction"));
444
+ Result->SetBoolField(TEXT("success"), false);
445
+ return MakeShared<FJsonValueObject>(Result);
446
+ }
447
+
448
+ UEditorAssetLibrary::SaveAsset(NewAsset->GetPathName());
449
+
450
+ Result->SetStringField(TEXT("path"), NewAsset->GetPathName());
451
+ Result->SetStringField(TEXT("name"), Name);
452
+ Result->SetBoolField(TEXT("success"), true);
453
+ return MakeShared<FJsonValueObject>(Result);
454
+ }
455
+
456
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreateInputMappingContext(const TSharedPtr<FJsonObject>& Params)
457
+ {
458
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
459
+
460
+ FString Name;
461
+ if (!Params->TryGetStringField(TEXT("name"), Name))
462
+ {
463
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
464
+ Result->SetBoolField(TEXT("success"), false);
465
+ return MakeShared<FJsonValueObject>(Result);
466
+ }
467
+
468
+ FString PackagePath = TEXT("/Game/Input");
469
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
470
+
471
+ UClass* IMCClass = FindObject<UClass>(nullptr, TEXT("/Script/EnhancedInput.InputMappingContext"));
472
+ if (!IMCClass)
473
+ {
474
+ Result->SetStringField(TEXT("error"), TEXT("InputMappingContext class not found. Enable EnhancedInput plugin."));
475
+ Result->SetBoolField(TEXT("success"), false);
476
+ return MakeShared<FJsonValueObject>(Result);
477
+ }
478
+
479
+ FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
480
+ IAssetTools& AssetTools = AssetToolsModule.Get();
481
+
482
+ UObject* NewAsset = AssetTools.CreateAsset(Name, PackagePath, IMCClass, nullptr);
483
+ if (!NewAsset)
484
+ {
485
+ Result->SetStringField(TEXT("error"), TEXT("Failed to create InputMappingContext"));
486
+ Result->SetBoolField(TEXT("success"), false);
487
+ return MakeShared<FJsonValueObject>(Result);
488
+ }
489
+
490
+ UEditorAssetLibrary::SaveAsset(NewAsset->GetPathName());
491
+
492
+ Result->SetStringField(TEXT("path"), NewAsset->GetPathName());
493
+ Result->SetStringField(TEXT("name"), Name);
494
+ Result->SetBoolField(TEXT("success"), true);
495
+ return MakeShared<FJsonValueObject>(Result);
496
+ }
497
+
498
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreateBlackboard(const TSharedPtr<FJsonObject>& Params)
499
+ {
500
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
501
+
502
+ FString Name;
503
+ if (!Params->TryGetStringField(TEXT("name"), Name))
504
+ {
505
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
506
+ Result->SetBoolField(TEXT("success"), false);
507
+ return MakeShared<FJsonValueObject>(Result);
508
+ }
509
+
510
+ FString PackagePath = TEXT("/Game/AI");
511
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
512
+
513
+ UClass* BlackboardClass = FindObject<UClass>(nullptr, TEXT("/Script/AIModule.BlackboardData"));
514
+ if (!BlackboardClass)
515
+ {
516
+ Result->SetStringField(TEXT("error"), TEXT("BlackboardData class not found."));
517
+ Result->SetBoolField(TEXT("success"), false);
518
+ return MakeShared<FJsonValueObject>(Result);
519
+ }
520
+
521
+ FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
522
+ IAssetTools& AssetTools = AssetToolsModule.Get();
523
+
524
+ UObject* NewAsset = AssetTools.CreateAsset(Name, PackagePath, BlackboardClass, nullptr);
525
+ if (!NewAsset)
526
+ {
527
+ Result->SetStringField(TEXT("error"), TEXT("Failed to create BlackboardData"));
528
+ Result->SetBoolField(TEXT("success"), false);
529
+ return MakeShared<FJsonValueObject>(Result);
530
+ }
531
+
532
+ UEditorAssetLibrary::SaveAsset(NewAsset->GetPathName());
533
+
534
+ Result->SetStringField(TEXT("path"), NewAsset->GetPathName());
535
+ Result->SetStringField(TEXT("name"), Name);
536
+ Result->SetBoolField(TEXT("success"), true);
537
+ return MakeShared<FJsonValueObject>(Result);
538
+ }
539
+
540
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreateBehaviorTree(const TSharedPtr<FJsonObject>& Params)
541
+ {
542
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
543
+
544
+ FString Name;
545
+ if (!Params->TryGetStringField(TEXT("name"), Name))
546
+ {
547
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
548
+ Result->SetBoolField(TEXT("success"), false);
549
+ return MakeShared<FJsonValueObject>(Result);
550
+ }
551
+
552
+ FString PackagePath = TEXT("/Game/AI");
553
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
554
+
555
+ UClass* BTClass = FindObject<UClass>(nullptr, TEXT("/Script/AIModule.BehaviorTree"));
556
+ if (!BTClass)
557
+ {
558
+ Result->SetStringField(TEXT("error"), TEXT("BehaviorTree class not found."));
559
+ Result->SetBoolField(TEXT("success"), false);
560
+ return MakeShared<FJsonValueObject>(Result);
561
+ }
562
+
563
+ FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
564
+ IAssetTools& AssetTools = AssetToolsModule.Get();
565
+
566
+ UObject* NewAsset = AssetTools.CreateAsset(Name, PackagePath, BTClass, nullptr);
567
+ if (!NewAsset)
568
+ {
569
+ Result->SetStringField(TEXT("error"), TEXT("Failed to create BehaviorTree"));
570
+ Result->SetBoolField(TEXT("success"), false);
571
+ return MakeShared<FJsonValueObject>(Result);
572
+ }
573
+
574
+ UEditorAssetLibrary::SaveAsset(NewAsset->GetPathName());
575
+
576
+ Result->SetStringField(TEXT("path"), NewAsset->GetPathName());
577
+ Result->SetStringField(TEXT("name"), Name);
578
+ Result->SetBoolField(TEXT("success"), true);
579
+ return MakeShared<FJsonValueObject>(Result);
580
+ }
581
+
582
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreateEqsQuery(const TSharedPtr<FJsonObject>& Params)
583
+ {
584
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
585
+
586
+ FString Name;
587
+ if (!Params->TryGetStringField(TEXT("name"), Name))
588
+ {
589
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
590
+ Result->SetBoolField(TEXT("success"), false);
591
+ return MakeShared<FJsonValueObject>(Result);
592
+ }
593
+
594
+ FString PackagePath = TEXT("/Game/AI/EQS");
595
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
596
+
597
+ UClass* EQSClass = FindObject<UClass>(nullptr, TEXT("/Script/AIModule.EnvironmentQuery"));
598
+ if (!EQSClass)
599
+ {
600
+ Result->SetStringField(TEXT("error"), TEXT("EnvironmentQuery class not found."));
601
+ Result->SetBoolField(TEXT("success"), false);
602
+ return MakeShared<FJsonValueObject>(Result);
603
+ }
604
+
605
+ FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
606
+ IAssetTools& AssetTools = AssetToolsModule.Get();
607
+
608
+ UObject* NewAsset = AssetTools.CreateAsset(Name, PackagePath, EQSClass, nullptr);
609
+ if (!NewAsset)
610
+ {
611
+ Result->SetStringField(TEXT("error"), TEXT("Failed to create EnvironmentQuery"));
612
+ Result->SetBoolField(TEXT("success"), false);
613
+ return MakeShared<FJsonValueObject>(Result);
614
+ }
615
+
616
+ UEditorAssetLibrary::SaveAsset(NewAsset->GetPathName());
617
+
618
+ Result->SetStringField(TEXT("path"), NewAsset->GetPathName());
619
+ Result->SetStringField(TEXT("name"), Name);
620
+ Result->SetBoolField(TEXT("success"), true);
621
+ return MakeShared<FJsonValueObject>(Result);
622
+ }
623
+
624
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreateStateTree(const TSharedPtr<FJsonObject>& Params)
625
+ {
626
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
627
+
628
+ FString Name;
629
+ if (!Params->TryGetStringField(TEXT("name"), Name))
630
+ {
631
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
632
+ Result->SetBoolField(TEXT("success"), false);
633
+ return MakeShared<FJsonValueObject>(Result);
634
+ }
635
+
636
+ FString PackagePath = TEXT("/Game/AI");
637
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
638
+
639
+ UClass* STClass = FindObject<UClass>(nullptr, TEXT("/Script/StateTreeModule.StateTree"));
640
+ if (!STClass)
641
+ {
642
+ Result->SetStringField(TEXT("error"), TEXT("StateTree class not found. Enable StateTree plugin."));
643
+ Result->SetBoolField(TEXT("success"), false);
644
+ return MakeShared<FJsonValueObject>(Result);
645
+ }
646
+
647
+ FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
648
+ IAssetTools& AssetTools = AssetToolsModule.Get();
649
+
650
+ UObject* NewAsset = AssetTools.CreateAsset(Name, PackagePath, STClass, nullptr);
651
+ if (!NewAsset)
652
+ {
653
+ Result->SetStringField(TEXT("error"), TEXT("Failed to create StateTree"));
654
+ Result->SetBoolField(TEXT("success"), false);
655
+ return MakeShared<FJsonValueObject>(Result);
656
+ }
657
+
658
+ UEditorAssetLibrary::SaveAsset(NewAsset->GetPathName());
659
+
660
+ Result->SetStringField(TEXT("path"), NewAsset->GetPathName());
661
+ Result->SetStringField(TEXT("name"), Name);
662
+ Result->SetBoolField(TEXT("success"), true);
663
+ return MakeShared<FJsonValueObject>(Result);
664
+ }
665
+
666
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreateBlueprintWithParent(const FString& Name, const FString& PackagePath, const FString& ParentClassPath, const FString& FriendlyTypeName)
667
+ {
668
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
669
+
670
+ UClass* ParentClass = FindObject<UClass>(nullptr, *ParentClassPath);
671
+ if (!ParentClass)
672
+ {
673
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("%s class not found: %s"), *FriendlyTypeName, *ParentClassPath));
674
+ Result->SetBoolField(TEXT("success"), false);
675
+ return MakeShared<FJsonValueObject>(Result);
676
+ }
677
+
678
+ FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
679
+ IAssetTools& AssetTools = AssetToolsModule.Get();
680
+
681
+ // Delete existing asset if it exists
682
+ FString FullAssetPath = PackagePath + TEXT("/") + Name;
683
+ UEditorAssetLibrary::DeleteAsset(FullAssetPath);
684
+
685
+ UBlueprintFactory* BlueprintFactory = NewObject<UBlueprintFactory>();
686
+ BlueprintFactory->ParentClass = ParentClass;
687
+
688
+ UBlueprint* NewBlueprint = Cast<UBlueprint>(AssetTools.CreateAsset(Name, PackagePath, UBlueprint::StaticClass(), BlueprintFactory));
689
+ if (!NewBlueprint)
690
+ {
691
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to create %s Blueprint"), *FriendlyTypeName));
692
+ Result->SetBoolField(TEXT("success"), false);
693
+ return MakeShared<FJsonValueObject>(Result);
694
+ }
695
+
696
+ NewBlueprint->ParentClass = ParentClass;
697
+ FKismetEditorUtilities::CompileBlueprint(NewBlueprint);
698
+
699
+ // Save
700
+ UPackage* Package = NewBlueprint->GetOutermost();
701
+ if (Package)
702
+ {
703
+ Package->MarkPackageDirty();
704
+ FString PackageFileName = FPackageName::LongPackageNameToFilename(Package->GetName(), FPackageName::GetAssetPackageExtension());
705
+ FSavePackageArgs SaveArgs;
706
+ SaveArgs.TopLevelFlags = RF_Standalone;
707
+ UPackage::SavePackage(Package, nullptr, *PackageFileName, SaveArgs);
708
+ }
709
+
710
+ Result->SetStringField(TEXT("path"), NewBlueprint->GetPathName());
711
+ Result->SetStringField(TEXT("name"), Name);
712
+ Result->SetStringField(TEXT("type"), FriendlyTypeName);
713
+ Result->SetBoolField(TEXT("success"), true);
714
+ return MakeShared<FJsonValueObject>(Result);
715
+ }
716
+
717
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreateGameMode(const TSharedPtr<FJsonObject>& Params)
718
+ {
719
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
720
+
721
+ FString Name;
722
+ if (!Params->TryGetStringField(TEXT("name"), Name))
723
+ {
724
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
725
+ Result->SetBoolField(TEXT("success"), false);
726
+ return MakeShared<FJsonValueObject>(Result);
727
+ }
728
+
729
+ FString PackagePath = TEXT("/Game/Blueprints/GameFramework");
730
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
731
+
732
+ return CreateBlueprintWithParent(Name, PackagePath, TEXT("/Script/Engine.GameModeBase"), TEXT("GameMode"));
733
+ }
734
+
735
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreateGameState(const TSharedPtr<FJsonObject>& Params)
736
+ {
737
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
738
+
739
+ FString Name;
740
+ if (!Params->TryGetStringField(TEXT("name"), Name))
741
+ {
742
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
743
+ Result->SetBoolField(TEXT("success"), false);
744
+ return MakeShared<FJsonValueObject>(Result);
745
+ }
746
+
747
+ FString PackagePath = TEXT("/Game/Blueprints/GameFramework");
748
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
749
+
750
+ return CreateBlueprintWithParent(Name, PackagePath, TEXT("/Script/Engine.GameStateBase"), TEXT("GameState"));
751
+ }
752
+
753
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreatePlayerController(const TSharedPtr<FJsonObject>& Params)
754
+ {
755
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
756
+
757
+ FString Name;
758
+ if (!Params->TryGetStringField(TEXT("name"), Name))
759
+ {
760
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
761
+ Result->SetBoolField(TEXT("success"), false);
762
+ return MakeShared<FJsonValueObject>(Result);
763
+ }
764
+
765
+ FString PackagePath = TEXT("/Game/Blueprints/GameFramework");
766
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
767
+
768
+ return CreateBlueprintWithParent(Name, PackagePath, TEXT("/Script/Engine.PlayerController"), TEXT("PlayerController"));
769
+ }
770
+
771
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreatePlayerState(const TSharedPtr<FJsonObject>& Params)
772
+ {
773
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
774
+
775
+ FString Name;
776
+ if (!Params->TryGetStringField(TEXT("name"), Name))
777
+ {
778
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
779
+ Result->SetBoolField(TEXT("success"), false);
780
+ return MakeShared<FJsonValueObject>(Result);
781
+ }
782
+
783
+ FString PackagePath = TEXT("/Game/Blueprints/GameFramework");
784
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
785
+
786
+ return CreateBlueprintWithParent(Name, PackagePath, TEXT("/Script/Engine.PlayerState"), TEXT("PlayerState"));
787
+ }
788
+
789
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreateHud(const TSharedPtr<FJsonObject>& Params)
790
+ {
791
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
792
+
793
+ FString Name;
794
+ if (!Params->TryGetStringField(TEXT("name"), Name))
795
+ {
796
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
797
+ Result->SetBoolField(TEXT("success"), false);
798
+ return MakeShared<FJsonValueObject>(Result);
799
+ }
800
+
801
+ FString PackagePath = TEXT("/Game/Blueprints/GameFramework");
802
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
803
+
804
+ return CreateBlueprintWithParent(Name, PackagePath, TEXT("/Script/Engine.HUD"), TEXT("HUD"));
805
+ }
806
+
807
+ TSharedPtr<FJsonValue> FGameplayHandlers::SetCollisionProfile(const TSharedPtr<FJsonObject>& Params)
808
+ {
809
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
810
+
811
+ FString ActorLabel;
812
+ if (!Params->TryGetStringField(TEXT("actorLabel"), ActorLabel))
813
+ {
814
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'actorLabel' parameter"));
815
+ Result->SetBoolField(TEXT("success"), false);
816
+ return MakeShared<FJsonValueObject>(Result);
817
+ }
818
+
819
+ FString ProfileName;
820
+ if (!Params->TryGetStringField(TEXT("profileName"), ProfileName))
821
+ {
822
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'profileName' parameter"));
823
+ Result->SetBoolField(TEXT("success"), false);
824
+ return MakeShared<FJsonValueObject>(Result);
825
+ }
826
+
827
+ UWorld* World = GEditor->GetEditorWorldContext().World();
828
+ if (!World)
829
+ {
830
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
831
+ Result->SetBoolField(TEXT("success"), false);
832
+ return MakeShared<FJsonValueObject>(Result);
833
+ }
834
+
835
+ // Find actor by label
836
+ AActor* FoundActor = nullptr;
837
+ for (TActorIterator<AActor> ActorIt(World); ActorIt; ++ActorIt)
838
+ {
839
+ if ((*ActorIt)->GetActorLabel() == ActorLabel)
840
+ {
841
+ FoundActor = *ActorIt;
842
+ break;
843
+ }
844
+ }
845
+
846
+ if (!FoundActor)
847
+ {
848
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
849
+ Result->SetBoolField(TEXT("success"), false);
850
+ return MakeShared<FJsonValueObject>(Result);
851
+ }
852
+
853
+ // Set collision profile on all primitive components
854
+ int32 ComponentsUpdated = 0;
855
+ TArray<UPrimitiveComponent*> PrimitiveComponents;
856
+ FoundActor->GetComponents<UPrimitiveComponent>(PrimitiveComponents);
857
+
858
+ for (UPrimitiveComponent* PrimComp : PrimitiveComponents)
859
+ {
860
+ if (PrimComp)
861
+ {
862
+ PrimComp->SetCollisionProfileName(FName(*ProfileName));
863
+ ComponentsUpdated++;
864
+ }
865
+ }
866
+
867
+ Result->SetStringField(TEXT("actorLabel"), ActorLabel);
868
+ Result->SetStringField(TEXT("profileName"), ProfileName);
869
+ Result->SetNumberField(TEXT("componentsUpdated"), ComponentsUpdated);
870
+ Result->SetBoolField(TEXT("success"), true);
871
+ return MakeShared<FJsonValueObject>(Result);
872
+ }
873
+
874
+ TSharedPtr<FJsonValue> FGameplayHandlers::SetPhysicsEnabled(const TSharedPtr<FJsonObject>& Params)
875
+ {
876
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
877
+
878
+ FString ActorLabel;
879
+ if (!Params->TryGetStringField(TEXT("actorLabel"), ActorLabel))
880
+ {
881
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'actorLabel' parameter"));
882
+ Result->SetBoolField(TEXT("success"), false);
883
+ return MakeShared<FJsonValueObject>(Result);
884
+ }
885
+
886
+ bool bEnabled = true;
887
+ Params->TryGetBoolField(TEXT("enabled"), bEnabled);
888
+
889
+ UWorld* World = GEditor->GetEditorWorldContext().World();
890
+ if (!World)
891
+ {
892
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
893
+ Result->SetBoolField(TEXT("success"), false);
894
+ return MakeShared<FJsonValueObject>(Result);
895
+ }
896
+
897
+ // Find actor by label
898
+ AActor* FoundActor = nullptr;
899
+ for (TActorIterator<AActor> ActorIt(World); ActorIt; ++ActorIt)
900
+ {
901
+ if ((*ActorIt)->GetActorLabel() == ActorLabel)
902
+ {
903
+ FoundActor = *ActorIt;
904
+ break;
905
+ }
906
+ }
907
+
908
+ if (!FoundActor)
909
+ {
910
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
911
+ Result->SetBoolField(TEXT("success"), false);
912
+ return MakeShared<FJsonValueObject>(Result);
913
+ }
914
+
915
+ // Set physics simulation on all primitive components
916
+ int32 ComponentsUpdated = 0;
917
+ TArray<UPrimitiveComponent*> PrimitiveComponents;
918
+ FoundActor->GetComponents<UPrimitiveComponent>(PrimitiveComponents);
919
+
920
+ for (UPrimitiveComponent* PrimComp : PrimitiveComponents)
921
+ {
922
+ if (PrimComp)
923
+ {
924
+ PrimComp->SetSimulatePhysics(bEnabled);
925
+ ComponentsUpdated++;
926
+ }
927
+ }
928
+
929
+ Result->SetStringField(TEXT("actorLabel"), ActorLabel);
930
+ Result->SetBoolField(TEXT("enabled"), bEnabled);
931
+ Result->SetNumberField(TEXT("componentsUpdated"), ComponentsUpdated);
932
+ Result->SetBoolField(TEXT("success"), true);
933
+ return MakeShared<FJsonValueObject>(Result);
934
+ }
935
+
936
+ TSharedPtr<FJsonValue> FGameplayHandlers::SetCollisionType(const TSharedPtr<FJsonObject>& Params)
937
+ {
938
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
939
+
940
+ FString ActorLabel;
941
+ if (!Params->TryGetStringField(TEXT("actorLabel"), ActorLabel))
942
+ {
943
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'actorLabel' parameter"));
944
+ Result->SetBoolField(TEXT("success"), false);
945
+ return MakeShared<FJsonValueObject>(Result);
946
+ }
947
+
948
+ FString CollisionType;
949
+ if (!Params->TryGetStringField(TEXT("collisionType"), CollisionType))
950
+ {
951
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'collisionType' parameter"));
952
+ Result->SetBoolField(TEXT("success"), false);
953
+ return MakeShared<FJsonValueObject>(Result);
954
+ }
955
+
956
+ // Map string to ECollisionEnabled::Type
957
+ ECollisionEnabled::Type CollisionEnabled;
958
+ if (CollisionType == TEXT("NoCollision"))
959
+ {
960
+ CollisionEnabled = ECollisionEnabled::NoCollision;
961
+ }
962
+ else if (CollisionType == TEXT("QueryOnly"))
963
+ {
964
+ CollisionEnabled = ECollisionEnabled::QueryOnly;
965
+ }
966
+ else if (CollisionType == TEXT("PhysicsOnly"))
967
+ {
968
+ CollisionEnabled = ECollisionEnabled::PhysicsOnly;
969
+ }
970
+ else if (CollisionType == TEXT("QueryAndPhysics"))
971
+ {
972
+ CollisionEnabled = ECollisionEnabled::QueryAndPhysics;
973
+ }
974
+ else
975
+ {
976
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Invalid collisionType: %s. Use NoCollision, QueryOnly, PhysicsOnly, or QueryAndPhysics"), *CollisionType));
977
+ Result->SetBoolField(TEXT("success"), false);
978
+ return MakeShared<FJsonValueObject>(Result);
979
+ }
980
+
981
+ UWorld* World = GEditor->GetEditorWorldContext().World();
982
+ if (!World)
983
+ {
984
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
985
+ Result->SetBoolField(TEXT("success"), false);
986
+ return MakeShared<FJsonValueObject>(Result);
987
+ }
988
+
989
+ // Find actor by label
990
+ AActor* FoundActor = nullptr;
991
+ for (TActorIterator<AActor> ActorIt(World); ActorIt; ++ActorIt)
992
+ {
993
+ if ((*ActorIt)->GetActorLabel() == ActorLabel)
994
+ {
995
+ FoundActor = *ActorIt;
996
+ break;
997
+ }
998
+ }
999
+
1000
+ if (!FoundActor)
1001
+ {
1002
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
1003
+ Result->SetBoolField(TEXT("success"), false);
1004
+ return MakeShared<FJsonValueObject>(Result);
1005
+ }
1006
+
1007
+ // Set collision enabled on all primitive components
1008
+ int32 ComponentsUpdated = 0;
1009
+ TArray<UPrimitiveComponent*> PrimitiveComponents;
1010
+ FoundActor->GetComponents<UPrimitiveComponent>(PrimitiveComponents);
1011
+
1012
+ for (UPrimitiveComponent* PrimComp : PrimitiveComponents)
1013
+ {
1014
+ if (PrimComp)
1015
+ {
1016
+ PrimComp->SetCollisionEnabled(CollisionEnabled);
1017
+ ComponentsUpdated++;
1018
+ }
1019
+ }
1020
+
1021
+ Result->SetStringField(TEXT("actorLabel"), ActorLabel);
1022
+ Result->SetStringField(TEXT("collisionType"), CollisionType);
1023
+ Result->SetNumberField(TEXT("componentsUpdated"), ComponentsUpdated);
1024
+ Result->SetBoolField(TEXT("success"), true);
1025
+ return MakeShared<FJsonValueObject>(Result);
1026
+ }
1027
+
1028
+ TSharedPtr<FJsonValue> FGameplayHandlers::SetBodyProperties(const TSharedPtr<FJsonObject>& Params)
1029
+ {
1030
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
1031
+
1032
+ FString ActorLabel;
1033
+ if (!Params->TryGetStringField(TEXT("actorLabel"), ActorLabel))
1034
+ {
1035
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'actorLabel' parameter"));
1036
+ Result->SetBoolField(TEXT("success"), false);
1037
+ return MakeShared<FJsonValueObject>(Result);
1038
+ }
1039
+
1040
+ UWorld* World = GEditor->GetEditorWorldContext().World();
1041
+ if (!World)
1042
+ {
1043
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
1044
+ Result->SetBoolField(TEXT("success"), false);
1045
+ return MakeShared<FJsonValueObject>(Result);
1046
+ }
1047
+
1048
+ // Find actor by label
1049
+ AActor* FoundActor = nullptr;
1050
+ for (TActorIterator<AActor> ActorIt(World); ActorIt; ++ActorIt)
1051
+ {
1052
+ if ((*ActorIt)->GetActorLabel() == ActorLabel)
1053
+ {
1054
+ FoundActor = *ActorIt;
1055
+ break;
1056
+ }
1057
+ }
1058
+
1059
+ if (!FoundActor)
1060
+ {
1061
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
1062
+ Result->SetBoolField(TEXT("success"), false);
1063
+ return MakeShared<FJsonValueObject>(Result);
1064
+ }
1065
+
1066
+ // Set body properties on all primitive components
1067
+ int32 ComponentsUpdated = 0;
1068
+ TArray<UPrimitiveComponent*> PrimitiveComponents;
1069
+ FoundActor->GetComponents<UPrimitiveComponent>(PrimitiveComponents);
1070
+
1071
+ double Mass = -1.0;
1072
+ double LinearDamping = -1.0;
1073
+ double AngularDamping = -1.0;
1074
+ bool bHasGravityParam = false;
1075
+ bool bEnableGravity = true;
1076
+
1077
+ Params->TryGetNumberField(TEXT("mass"), Mass);
1078
+ Params->TryGetNumberField(TEXT("linearDamping"), LinearDamping);
1079
+ Params->TryGetNumberField(TEXT("angularDamping"), AngularDamping);
1080
+ bHasGravityParam = Params->TryGetBoolField(TEXT("enableGravity"), bEnableGravity);
1081
+
1082
+ for (UPrimitiveComponent* PrimComp : PrimitiveComponents)
1083
+ {
1084
+ if (PrimComp)
1085
+ {
1086
+ if (Mass >= 0.0)
1087
+ {
1088
+ PrimComp->BodyInstance.SetMassOverride(Mass);
1089
+ }
1090
+ if (LinearDamping >= 0.0)
1091
+ {
1092
+ PrimComp->SetLinearDamping(LinearDamping);
1093
+ }
1094
+ if (AngularDamping >= 0.0)
1095
+ {
1096
+ PrimComp->SetAngularDamping(AngularDamping);
1097
+ }
1098
+ if (bHasGravityParam)
1099
+ {
1100
+ PrimComp->SetEnableGravity(bEnableGravity);
1101
+ }
1102
+ ComponentsUpdated++;
1103
+ }
1104
+ }
1105
+
1106
+ Result->SetStringField(TEXT("actorLabel"), ActorLabel);
1107
+ Result->SetNumberField(TEXT("componentsUpdated"), ComponentsUpdated);
1108
+ Result->SetBoolField(TEXT("success"), true);
1109
+ return MakeShared<FJsonValueObject>(Result);
1110
+ }
1111
+
1112
+ TSharedPtr<FJsonValue> FGameplayHandlers::SpawnNavModifierVolume(const TSharedPtr<FJsonObject>& Params)
1113
+ {
1114
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
1115
+
1116
+ UWorld* World = GEditor->GetEditorWorldContext().World();
1117
+ if (!World)
1118
+ {
1119
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
1120
+ Result->SetBoolField(TEXT("success"), false);
1121
+ return MakeShared<FJsonValueObject>(Result);
1122
+ }
1123
+
1124
+ // Get location
1125
+ FVector Location = FVector::ZeroVector;
1126
+ const TSharedPtr<FJsonObject>* LocationObj = nullptr;
1127
+ if (Params->TryGetObjectField(TEXT("location"), LocationObj))
1128
+ {
1129
+ Location.X = (*LocationObj)->GetNumberField(TEXT("x"));
1130
+ Location.Y = (*LocationObj)->GetNumberField(TEXT("y"));
1131
+ Location.Z = (*LocationObj)->GetNumberField(TEXT("z"));
1132
+ }
1133
+
1134
+ // Get scale
1135
+ FVector Scale = FVector::OneVector;
1136
+ const TSharedPtr<FJsonObject>* ScaleObj = nullptr;
1137
+ if (Params->TryGetObjectField(TEXT("scale"), ScaleObj))
1138
+ {
1139
+ Scale.X = (*ScaleObj)->GetNumberField(TEXT("x"));
1140
+ Scale.Y = (*ScaleObj)->GetNumberField(TEXT("y"));
1141
+ Scale.Z = (*ScaleObj)->GetNumberField(TEXT("z"));
1142
+ }
1143
+
1144
+ FTransform SpawnTransform;
1145
+ SpawnTransform.SetLocation(Location);
1146
+ SpawnTransform.SetScale3D(Scale);
1147
+
1148
+ ANavModifierVolume* NewVolume = World->SpawnActor<ANavModifierVolume>(ANavModifierVolume::StaticClass(), SpawnTransform);
1149
+ if (!NewVolume)
1150
+ {
1151
+ Result->SetStringField(TEXT("error"), TEXT("Failed to spawn NavModifierVolume"));
1152
+ Result->SetBoolField(TEXT("success"), false);
1153
+ return MakeShared<FJsonValueObject>(Result);
1154
+ }
1155
+
1156
+ // Set label if provided
1157
+ FString Label;
1158
+ if (Params->TryGetStringField(TEXT("label"), Label))
1159
+ {
1160
+ NewVolume->SetActorLabel(Label);
1161
+ }
1162
+
1163
+ Result->SetStringField(TEXT("actorLabel"), NewVolume->GetActorLabel());
1164
+ Result->SetStringField(TEXT("actorName"), NewVolume->GetName());
1165
+
1166
+ TSharedPtr<FJsonObject> LocationResult = MakeShared<FJsonObject>();
1167
+ FVector ActorLocation = NewVolume->GetActorLocation();
1168
+ LocationResult->SetNumberField(TEXT("x"), ActorLocation.X);
1169
+ LocationResult->SetNumberField(TEXT("y"), ActorLocation.Y);
1170
+ LocationResult->SetNumberField(TEXT("z"), ActorLocation.Z);
1171
+ Result->SetObjectField(TEXT("location"), LocationResult);
1172
+
1173
+ Result->SetBoolField(TEXT("success"), true);
1174
+ return MakeShared<FJsonValueObject>(Result);
1175
+ }
1176
+
1177
+ TSharedPtr<FJsonValue> FGameplayHandlers::RebuildNavmesh(const TSharedPtr<FJsonObject>& Params)
1178
+ {
1179
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
1180
+
1181
+ UWorld* World = GEditor->GetEditorWorldContext().World();
1182
+ if (!World)
1183
+ {
1184
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
1185
+ Result->SetBoolField(TEXT("success"), false);
1186
+ return MakeShared<FJsonValueObject>(Result);
1187
+ }
1188
+
1189
+ // Trigger navmesh rebuild via console command
1190
+ GEditor->Exec(World, TEXT("RebuildNavigation"));
1191
+
1192
+ Result->SetStringField(TEXT("status"), TEXT("rebuild_triggered"));
1193
+ Result->SetBoolField(TEXT("success"), true);
1194
+ return MakeShared<FJsonValueObject>(Result);
1195
+ }
1196
+
1197
+ TSharedPtr<FJsonValue> FGameplayHandlers::GetCdoDefaults(const TSharedPtr<FJsonObject>& Params)
1198
+ {
1199
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
1200
+
1201
+ FString ClassName;
1202
+ if (!Params->TryGetStringField(TEXT("className"), ClassName))
1203
+ {
1204
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'className' parameter"));
1205
+ Result->SetBoolField(TEXT("success"), false);
1206
+ return MakeShared<FJsonValueObject>(Result);
1207
+ }
1208
+
1209
+ // Try to find the class by name - support both short names and full paths
1210
+ UClass* FoundClass = nullptr;
1211
+
1212
+ // Try full path first (e.g. "/Script/Engine.Actor")
1213
+ FoundClass = FindObject<UClass>(nullptr, *ClassName);
1214
+
1215
+ // If not found, search by short name
1216
+ if (!FoundClass)
1217
+ {
1218
+ for (TObjectIterator<UClass> It; It; ++It)
1219
+ {
1220
+ if (It->GetName() == ClassName)
1221
+ {
1222
+ FoundClass = *It;
1223
+ break;
1224
+ }
1225
+ }
1226
+ }
1227
+
1228
+ if (!FoundClass)
1229
+ {
1230
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Class not found: %s"), *ClassName));
1231
+ Result->SetBoolField(TEXT("success"), false);
1232
+ return MakeShared<FJsonValueObject>(Result);
1233
+ }
1234
+
1235
+ UObject* CDO = FoundClass->GetDefaultObject();
1236
+ if (!CDO)
1237
+ {
1238
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Could not get CDO for class: %s"), *ClassName));
1239
+ Result->SetBoolField(TEXT("success"), false);
1240
+ return MakeShared<FJsonValueObject>(Result);
1241
+ }
1242
+
1243
+ Result->SetStringField(TEXT("className"), FoundClass->GetName());
1244
+ Result->SetStringField(TEXT("classPath"), FoundClass->GetPathName());
1245
+
1246
+ // Iterate properties and collect their default values
1247
+ TArray<TSharedPtr<FJsonValue>> PropertiesArray;
1248
+ for (TFieldIterator<FProperty> PropIt(FoundClass); PropIt; ++PropIt)
1249
+ {
1250
+ FProperty* Property = *PropIt;
1251
+ if (!Property) continue;
1252
+
1253
+ TSharedPtr<FJsonObject> PropObj = MakeShared<FJsonObject>();
1254
+ PropObj->SetStringField(TEXT("name"), Property->GetName());
1255
+ PropObj->SetStringField(TEXT("type"), Property->GetCPPType());
1256
+ PropObj->SetStringField(TEXT("class"), Property->GetOwnerClass() ? Property->GetOwnerClass()->GetName() : TEXT("Unknown"));
1257
+
1258
+ // Get string representation of the default value
1259
+ FString ValueStr;
1260
+ const void* ValuePtr = Property->ContainerPtrToValuePtr<void>(CDO);
1261
+ Property->ExportTextItem_Direct(ValueStr, ValuePtr, nullptr, nullptr, PPF_None);
1262
+ PropObj->SetStringField(TEXT("defaultValue"), ValueStr);
1263
+
1264
+ PropertiesArray.Add(MakeShared<FJsonValueObject>(PropObj));
1265
+ }
1266
+
1267
+ Result->SetArrayField(TEXT("properties"), PropertiesArray);
1268
+ Result->SetNumberField(TEXT("propertyCount"), PropertiesArray.Num());
1269
+ Result->SetBoolField(TEXT("success"), true);
1270
+ return MakeShared<FJsonValueObject>(Result);
1271
+ }
1272
+
1273
+ TSharedPtr<FJsonValue> FGameplayHandlers::SetWorldGameMode(const TSharedPtr<FJsonObject>& Params)
1274
+ {
1275
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
1276
+
1277
+ FString GameModeClassPath;
1278
+ if (!Params->TryGetStringField(TEXT("gameModeClass"), GameModeClassPath))
1279
+ {
1280
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'gameModeClass' parameter"));
1281
+ Result->SetBoolField(TEXT("success"), false);
1282
+ return MakeShared<FJsonValueObject>(Result);
1283
+ }
1284
+
1285
+ UWorld* World = GEditor->GetEditorWorldContext().World();
1286
+ if (!World)
1287
+ {
1288
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
1289
+ Result->SetBoolField(TEXT("success"), false);
1290
+ return MakeShared<FJsonValueObject>(Result);
1291
+ }
1292
+
1293
+ // Try to find the game mode class - support blueprint paths ending with _C
1294
+ UClass* GameModeClass = nullptr;
1295
+
1296
+ // Try loading as a blueprint class first (common case for user BPs)
1297
+ GameModeClass = LoadObject<UClass>(nullptr, *GameModeClassPath);
1298
+
1299
+ // If not found, try appending _C for blueprint paths
1300
+ if (!GameModeClass && !GameModeClassPath.EndsWith(TEXT("_C")))
1301
+ {
1302
+ FString BlueprintClassPath = GameModeClassPath + TEXT("_C");
1303
+ GameModeClass = LoadObject<UClass>(nullptr, *BlueprintClassPath);
1304
+ }
1305
+
1306
+ // Try FindObject as fallback
1307
+ if (!GameModeClass)
1308
+ {
1309
+ GameModeClass = FindObject<UClass>(nullptr, *GameModeClassPath);
1310
+ }
1311
+
1312
+ if (!GameModeClass)
1313
+ {
1314
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("GameMode class not found: %s"), *GameModeClassPath));
1315
+ Result->SetBoolField(TEXT("success"), false);
1316
+ return MakeShared<FJsonValueObject>(Result);
1317
+ }
1318
+
1319
+ if (!GameModeClass->IsChildOf(AGameModeBase::StaticClass()))
1320
+ {
1321
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Class '%s' is not a GameModeBase subclass"), *GameModeClassPath));
1322
+ Result->SetBoolField(TEXT("success"), false);
1323
+ return MakeShared<FJsonValueObject>(Result);
1324
+ }
1325
+
1326
+ AWorldSettings* WorldSettings = World->GetWorldSettings();
1327
+ if (!WorldSettings)
1328
+ {
1329
+ Result->SetStringField(TEXT("error"), TEXT("Could not get WorldSettings"));
1330
+ Result->SetBoolField(TEXT("success"), false);
1331
+ return MakeShared<FJsonValueObject>(Result);
1332
+ }
1333
+
1334
+ WorldSettings->DefaultGameMode = GameModeClass;
1335
+ WorldSettings->MarkPackageDirty();
1336
+
1337
+ Result->SetStringField(TEXT("gameModeClass"), GameModeClass->GetPathName());
1338
+ Result->SetStringField(TEXT("gameModeName"), GameModeClass->GetName());
1339
+ Result->SetBoolField(TEXT("success"), true);
1340
+ return MakeShared<FJsonValueObject>(Result);
1341
+ }
1342
+
1343
+ TSharedPtr<FJsonValue> FGameplayHandlers::CreateAiPerceptionConfig(const TSharedPtr<FJsonObject>& Params)
1344
+ {
1345
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
1346
+
1347
+ FString BlueprintPath;
1348
+ if (!Params->TryGetStringField(TEXT("blueprintPath"), BlueprintPath))
1349
+ {
1350
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'blueprintPath' parameter"));
1351
+ Result->SetBoolField(TEXT("success"), false);
1352
+ return MakeShared<FJsonValueObject>(Result);
1353
+ }
1354
+
1355
+ UBlueprint* Blueprint = LoadObject<UBlueprint>(nullptr, *BlueprintPath);
1356
+ if (!Blueprint || !Blueprint->GeneratedClass)
1357
+ {
1358
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Blueprint not found or has no generated class: %s"), *BlueprintPath));
1359
+ Result->SetBoolField(TEXT("success"), false);
1360
+ return MakeShared<FJsonValueObject>(Result);
1361
+ }
1362
+
1363
+ // The blueprint must be an Actor-based blueprint to add components
1364
+ if (!Blueprint->GeneratedClass->IsChildOf(AActor::StaticClass()))
1365
+ {
1366
+ Result->SetStringField(TEXT("error"), TEXT("Blueprint must be based on AActor to add perception component"));
1367
+ Result->SetBoolField(TEXT("success"), false);
1368
+ return MakeShared<FJsonValueObject>(Result);
1369
+ }
1370
+
1371
+ // Read which senses to configure
1372
+ bool bAddSight = true;
1373
+ bool bAddHearing = false;
1374
+ bool bAddDamage = false;
1375
+ Params->TryGetBoolField(TEXT("addSight"), bAddSight);
1376
+ Params->TryGetBoolField(TEXT("addHearing"), bAddHearing);
1377
+ Params->TryGetBoolField(TEXT("addDamage"), bAddDamage);
1378
+
1379
+ // Add AIPerceptionComponent via the SCS (SimpleConstructionScript)
1380
+ USCS_Node* PerceptionNode = Blueprint->SimpleConstructionScript->CreateNode(UAIPerceptionComponent::StaticClass(), TEXT("AIPerceptionComp"));
1381
+ if (!PerceptionNode)
1382
+ {
1383
+ Result->SetStringField(TEXT("error"), TEXT("Failed to create AIPerceptionComponent node"));
1384
+ Result->SetBoolField(TEXT("success"), false);
1385
+ return MakeShared<FJsonValueObject>(Result);
1386
+ }
1387
+
1388
+ Blueprint->SimpleConstructionScript->AddNode(PerceptionNode);
1389
+
1390
+ UAIPerceptionComponent* PerceptionComp = Cast<UAIPerceptionComponent>(PerceptionNode->ComponentTemplate);
1391
+ if (!PerceptionComp)
1392
+ {
1393
+ Result->SetStringField(TEXT("error"), TEXT("Failed to get AIPerceptionComponent template"));
1394
+ Result->SetBoolField(TEXT("success"), false);
1395
+ return MakeShared<FJsonValueObject>(Result);
1396
+ }
1397
+
1398
+ TArray<TSharedPtr<FJsonValue>> SensesAdded;
1399
+
1400
+ // Configure sight sense
1401
+ if (bAddSight)
1402
+ {
1403
+ UAISenseConfig_Sight* SightConfig = NewObject<UAISenseConfig_Sight>(PerceptionComp, TEXT("SightConfig"));
1404
+ SightConfig->SightRadius = 3000.0f;
1405
+ SightConfig->LoseSightRadius = 3500.0f;
1406
+ SightConfig->PeripheralVisionAngleDegrees = 90.0f;
1407
+ PerceptionComp->ConfigureSense(*SightConfig);
1408
+ SensesAdded.Add(MakeShared<FJsonValueString>(TEXT("Sight")));
1409
+ }
1410
+
1411
+ // Configure hearing sense
1412
+ if (bAddHearing)
1413
+ {
1414
+ UAISenseConfig_Hearing* HearingConfig = NewObject<UAISenseConfig_Hearing>(PerceptionComp, TEXT("HearingConfig"));
1415
+ HearingConfig->HearingRange = 3000.0f;
1416
+ PerceptionComp->ConfigureSense(*HearingConfig);
1417
+ SensesAdded.Add(MakeShared<FJsonValueString>(TEXT("Hearing")));
1418
+ }
1419
+
1420
+ // Configure damage sense
1421
+ if (bAddDamage)
1422
+ {
1423
+ UAISenseConfig_Damage* DamageConfig = NewObject<UAISenseConfig_Damage>(PerceptionComp, TEXT("DamageConfig"));
1424
+ PerceptionComp->ConfigureSense(*DamageConfig);
1425
+ SensesAdded.Add(MakeShared<FJsonValueString>(TEXT("Damage")));
1426
+ }
1427
+
1428
+ // Compile and save
1429
+ FKismetEditorUtilities::CompileBlueprint(Blueprint);
1430
+
1431
+ UPackage* Package = Blueprint->GetOutermost();
1432
+ if (Package)
1433
+ {
1434
+ Package->MarkPackageDirty();
1435
+ FString PackageFileName = FPackageName::LongPackageNameToFilename(Package->GetName(), FPackageName::GetAssetPackageExtension());
1436
+ FSavePackageArgs SaveArgs;
1437
+ SaveArgs.TopLevelFlags = RF_Standalone;
1438
+ UPackage::SavePackage(Package, nullptr, *PackageFileName, SaveArgs);
1439
+ }
1440
+
1441
+ Result->SetStringField(TEXT("blueprintPath"), BlueprintPath);
1442
+ Result->SetStringField(TEXT("componentName"), TEXT("AIPerceptionComp"));
1443
+ Result->SetArrayField(TEXT("sensesConfigured"), SensesAdded);
1444
+ Result->SetBoolField(TEXT("success"), true);
1445
+ return MakeShared<FJsonValueObject>(Result);
1446
+ }
1447
+
1448
+ TSharedPtr<FJsonValue> FGameplayHandlers::AddBlackboardKey(const TSharedPtr<FJsonObject>& Params)
1449
+ {
1450
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
1451
+
1452
+ FString BlackboardPath;
1453
+ if (!Params->TryGetStringField(TEXT("blackboardPath"), BlackboardPath))
1454
+ {
1455
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'blackboardPath' parameter"));
1456
+ Result->SetBoolField(TEXT("success"), false);
1457
+ return MakeShared<FJsonValueObject>(Result);
1458
+ }
1459
+
1460
+ FString KeyName;
1461
+ if (!Params->TryGetStringField(TEXT("keyName"), KeyName))
1462
+ {
1463
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'keyName' parameter"));
1464
+ Result->SetBoolField(TEXT("success"), false);
1465
+ return MakeShared<FJsonValueObject>(Result);
1466
+ }
1467
+
1468
+ FString KeyType = TEXT("Bool");
1469
+ Params->TryGetStringField(TEXT("keyType"), KeyType);
1470
+
1471
+ UBlackboardData* BlackboardAsset = LoadObject<UBlackboardData>(nullptr, *BlackboardPath);
1472
+ if (!BlackboardAsset)
1473
+ {
1474
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("BlackboardData not found: %s"), *BlackboardPath));
1475
+ Result->SetBoolField(TEXT("success"), false);
1476
+ return MakeShared<FJsonValueObject>(Result);
1477
+ }
1478
+
1479
+ // Determine the key type class
1480
+ UBlackboardKeyType* KeyTypeInstance = nullptr;
1481
+ if (KeyType == TEXT("Bool"))
1482
+ {
1483
+ KeyTypeInstance = NewObject<UBlackboardKeyType_Bool>(BlackboardAsset);
1484
+ }
1485
+ else if (KeyType == TEXT("Int"))
1486
+ {
1487
+ KeyTypeInstance = NewObject<UBlackboardKeyType_Int>(BlackboardAsset);
1488
+ }
1489
+ else if (KeyType == TEXT("Float"))
1490
+ {
1491
+ KeyTypeInstance = NewObject<UBlackboardKeyType_Float>(BlackboardAsset);
1492
+ }
1493
+ else if (KeyType == TEXT("String"))
1494
+ {
1495
+ KeyTypeInstance = NewObject<UBlackboardKeyType_String>(BlackboardAsset);
1496
+ }
1497
+ else if (KeyType == TEXT("Name"))
1498
+ {
1499
+ KeyTypeInstance = NewObject<UBlackboardKeyType_Name>(BlackboardAsset);
1500
+ }
1501
+ else if (KeyType == TEXT("Object"))
1502
+ {
1503
+ KeyTypeInstance = NewObject<UBlackboardKeyType_Object>(BlackboardAsset);
1504
+ }
1505
+ else if (KeyType == TEXT("Class"))
1506
+ {
1507
+ KeyTypeInstance = NewObject<UBlackboardKeyType_Class>(BlackboardAsset);
1508
+ }
1509
+ else if (KeyType == TEXT("Enum"))
1510
+ {
1511
+ KeyTypeInstance = NewObject<UBlackboardKeyType_Enum>(BlackboardAsset);
1512
+ }
1513
+ else if (KeyType == TEXT("Vector"))
1514
+ {
1515
+ KeyTypeInstance = NewObject<UBlackboardKeyType_Vector>(BlackboardAsset);
1516
+ }
1517
+ else if (KeyType == TEXT("Rotator"))
1518
+ {
1519
+ KeyTypeInstance = NewObject<UBlackboardKeyType_Rotator>(BlackboardAsset);
1520
+ }
1521
+ else
1522
+ {
1523
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Unknown key type: %s. Supported: Bool, Int, Float, String, Name, Object, Class, Enum, Vector, Rotator"), *KeyType));
1524
+ Result->SetBoolField(TEXT("success"), false);
1525
+ return MakeShared<FJsonValueObject>(Result);
1526
+ }
1527
+
1528
+ // Add the new key entry
1529
+ FBlackboardEntry NewEntry;
1530
+ NewEntry.EntryName = FName(*KeyName);
1531
+ NewEntry.KeyType = KeyTypeInstance;
1532
+
1533
+ BlackboardAsset->Keys.Add(NewEntry);
1534
+ BlackboardAsset->MarkPackageDirty();
1535
+
1536
+ // Save
1537
+ UEditorAssetLibrary::SaveAsset(BlackboardAsset->GetPathName());
1538
+
1539
+ Result->SetStringField(TEXT("blackboardPath"), BlackboardPath);
1540
+ Result->SetStringField(TEXT("keyName"), KeyName);
1541
+ Result->SetStringField(TEXT("keyType"), KeyType);
1542
+ Result->SetNumberField(TEXT("totalKeys"), BlackboardAsset->Keys.Num());
1543
+ Result->SetBoolField(TEXT("success"), true);
1544
+ return MakeShared<FJsonValueObject>(Result);
1545
+ }
1546
+
1547
+ TSharedPtr<FJsonValue> FGameplayHandlers::SetupEnhancedInput(const TSharedPtr<FJsonObject>& Params)
1548
+ {
1549
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
1550
+
1551
+ FString ActorLabel;
1552
+ if (!Params->TryGetStringField(TEXT("actorLabel"), ActorLabel))
1553
+ {
1554
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'actorLabel' parameter"));
1555
+ Result->SetBoolField(TEXT("success"), false);
1556
+ return MakeShared<FJsonValueObject>(Result);
1557
+ }
1558
+
1559
+ FString MappingContextPath;
1560
+ if (!Params->TryGetStringField(TEXT("mappingContextPath"), MappingContextPath))
1561
+ {
1562
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'mappingContextPath' parameter"));
1563
+ Result->SetBoolField(TEXT("success"), false);
1564
+ return MakeShared<FJsonValueObject>(Result);
1565
+ }
1566
+
1567
+ int32 Priority = 0;
1568
+ Params->TryGetNumberField(TEXT("priority"), Priority);
1569
+
1570
+ UWorld* World = GEditor->GetEditorWorldContext().World();
1571
+ if (!World)
1572
+ {
1573
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
1574
+ Result->SetBoolField(TEXT("success"), false);
1575
+ return MakeShared<FJsonValueObject>(Result);
1576
+ }
1577
+
1578
+ // Find actor by label
1579
+ AActor* FoundActor = nullptr;
1580
+ for (TActorIterator<AActor> ActorIt(World); ActorIt; ++ActorIt)
1581
+ {
1582
+ if ((*ActorIt)->GetActorLabel() == ActorLabel)
1583
+ {
1584
+ FoundActor = *ActorIt;
1585
+ break;
1586
+ }
1587
+ }
1588
+
1589
+ if (!FoundActor)
1590
+ {
1591
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
1592
+ Result->SetBoolField(TEXT("success"), false);
1593
+ return MakeShared<FJsonValueObject>(Result);
1594
+ }
1595
+
1596
+ // Load the mapping context asset
1597
+ UInputMappingContext* MappingContext = LoadObject<UInputMappingContext>(nullptr, *MappingContextPath);
1598
+ if (!MappingContext)
1599
+ {
1600
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("InputMappingContext not found: %s"), *MappingContextPath));
1601
+ Result->SetBoolField(TEXT("success"), false);
1602
+ return MakeShared<FJsonValueObject>(Result);
1603
+ }
1604
+
1605
+ // Check if the actor has an EnhancedInputComponent
1606
+ UEnhancedInputComponent* InputComp = FoundActor->FindComponentByClass<UEnhancedInputComponent>();
1607
+ if (!InputComp)
1608
+ {
1609
+ Result->SetStringField(TEXT("error"), TEXT("Actor does not have an EnhancedInputComponent"));
1610
+ Result->SetBoolField(TEXT("success"), false);
1611
+ return MakeShared<FJsonValueObject>(Result);
1612
+ }
1613
+
1614
+ // Optionally bind input actions from params
1615
+ TArray<TSharedPtr<FJsonValue>> BoundActions;
1616
+ const TArray<TSharedPtr<FJsonValue>>* ActionsArray = nullptr;
1617
+ if (Params->TryGetArrayField(TEXT("actions"), ActionsArray))
1618
+ {
1619
+ for (const auto& ActionVal : *ActionsArray)
1620
+ {
1621
+ const TSharedPtr<FJsonObject>* ActionObj = nullptr;
1622
+ if (ActionVal->TryGetObject(ActionObj))
1623
+ {
1624
+ FString ActionPath;
1625
+ if ((*ActionObj)->TryGetStringField(TEXT("actionPath"), ActionPath))
1626
+ {
1627
+ UInputAction* InputAction = LoadObject<UInputAction>(nullptr, *ActionPath);
1628
+ if (InputAction)
1629
+ {
1630
+ TSharedPtr<FJsonObject> BoundAction = MakeShared<FJsonObject>();
1631
+ BoundAction->SetStringField(TEXT("actionPath"), ActionPath);
1632
+ BoundAction->SetStringField(TEXT("actionName"), InputAction->GetName());
1633
+ BoundActions.Add(MakeShared<FJsonValueObject>(BoundAction));
1634
+ }
1635
+ }
1636
+ }
1637
+ }
1638
+ }
1639
+
1640
+ Result->SetStringField(TEXT("actorLabel"), ActorLabel);
1641
+ Result->SetStringField(TEXT("mappingContext"), MappingContext->GetName());
1642
+ Result->SetNumberField(TEXT("priority"), Priority);
1643
+ Result->SetArrayField(TEXT("boundActions"), BoundActions);
1644
+ Result->SetBoolField(TEXT("success"), true);
1645
+ return MakeShared<FJsonValueObject>(Result);
1646
+ }
1647
+
1648
+ TSharedPtr<FJsonValue> FGameplayHandlers::ConfigureBehaviorTree(const TSharedPtr<FJsonObject>& Params)
1649
+ {
1650
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
1651
+
1652
+ FString ActorLabel;
1653
+ if (!Params->TryGetStringField(TEXT("actorLabel"), ActorLabel))
1654
+ {
1655
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'actorLabel' parameter"));
1656
+ Result->SetBoolField(TEXT("success"), false);
1657
+ return MakeShared<FJsonValueObject>(Result);
1658
+ }
1659
+
1660
+ FString BehaviorTreePath;
1661
+ if (!Params->TryGetStringField(TEXT("behaviorTreePath"), BehaviorTreePath))
1662
+ {
1663
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'behaviorTreePath' parameter"));
1664
+ Result->SetBoolField(TEXT("success"), false);
1665
+ return MakeShared<FJsonValueObject>(Result);
1666
+ }
1667
+
1668
+ UWorld* World = GEditor->GetEditorWorldContext().World();
1669
+ if (!World)
1670
+ {
1671
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
1672
+ Result->SetBoolField(TEXT("success"), false);
1673
+ return MakeShared<FJsonValueObject>(Result);
1674
+ }
1675
+
1676
+ // Find actor by label - should be an AI-controlled pawn/character
1677
+ AActor* FoundActor = nullptr;
1678
+ for (TActorIterator<AActor> ActorIt(World); ActorIt; ++ActorIt)
1679
+ {
1680
+ if ((*ActorIt)->GetActorLabel() == ActorLabel)
1681
+ {
1682
+ FoundActor = *ActorIt;
1683
+ break;
1684
+ }
1685
+ }
1686
+
1687
+ if (!FoundActor)
1688
+ {
1689
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
1690
+ Result->SetBoolField(TEXT("success"), false);
1691
+ return MakeShared<FJsonValueObject>(Result);
1692
+ }
1693
+
1694
+ // Load the behavior tree asset
1695
+ UBehaviorTree* BehaviorTree = LoadObject<UBehaviorTree>(nullptr, *BehaviorTreePath);
1696
+ if (!BehaviorTree)
1697
+ {
1698
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("BehaviorTree not found: %s"), *BehaviorTreePath));
1699
+ Result->SetBoolField(TEXT("success"), false);
1700
+ return MakeShared<FJsonValueObject>(Result);
1701
+ }
1702
+
1703
+ // Optionally load blackboard
1704
+ FString BlackboardPath;
1705
+ UBlackboardData* BlackboardAsset = nullptr;
1706
+ if (Params->TryGetStringField(TEXT("blackboardPath"), BlackboardPath))
1707
+ {
1708
+ BlackboardAsset = LoadObject<UBlackboardData>(nullptr, *BlackboardPath);
1709
+ if (!BlackboardAsset)
1710
+ {
1711
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("BlackboardData not found: %s"), *BlackboardPath));
1712
+ Result->SetBoolField(TEXT("success"), false);
1713
+ return MakeShared<FJsonValueObject>(Result);
1714
+ }
1715
+ }
1716
+
1717
+ // Find or get the AI controller for this actor
1718
+ APawn* Pawn = Cast<APawn>(FoundActor);
1719
+ if (!Pawn)
1720
+ {
1721
+ Result->SetStringField(TEXT("error"), TEXT("Actor is not a Pawn. BehaviorTree requires an AI-controlled Pawn."));
1722
+ Result->SetBoolField(TEXT("success"), false);
1723
+ return MakeShared<FJsonValueObject>(Result);
1724
+ }
1725
+
1726
+ AAIController* AIController = Cast<AAIController>(Pawn->GetController());
1727
+ if (!AIController)
1728
+ {
1729
+ Result->SetStringField(TEXT("error"), TEXT("Pawn does not have an AAIController. Assign an AI controller first."));
1730
+ Result->SetBoolField(TEXT("success"), false);
1731
+ return MakeShared<FJsonValueObject>(Result);
1732
+ }
1733
+
1734
+ // In UE 5.7, use RunBehaviorTree() on the AI controller rather than
1735
+ // SetDefaultTree()/SetDefaultBlackboard() on BehaviorTreeComponent (which don't exist).
1736
+ // RunBehaviorTree() handles creating/configuring the BehaviorTreeComponent internally
1737
+ // and also initializes the blackboard from the tree's BlackboardAsset if set.
1738
+ bool bSuccess = AIController->RunBehaviorTree(BehaviorTree);
1739
+ if (!bSuccess)
1740
+ {
1741
+ Result->SetStringField(TEXT("error"), TEXT("Failed to run behavior tree on AI controller"));
1742
+ Result->SetBoolField(TEXT("success"), false);
1743
+ return MakeShared<FJsonValueObject>(Result);
1744
+ }
1745
+
1746
+ // If a separate blackboard was specified, use the tree's component to apply it
1747
+ if (BlackboardAsset)
1748
+ {
1749
+ UBehaviorTreeComponent* BTComp = Cast<UBehaviorTreeComponent>(AIController->GetBrainComponent());
1750
+ if (BTComp)
1751
+ {
1752
+ // The blackboard is initialized via the tree asset's BlackboardAsset property.
1753
+ // If a custom blackboard was provided, we can set it on the tree asset itself
1754
+ // before starting, or use the blackboard component on the controller.
1755
+ UBlackboardComponent* BBComp = AIController->GetBlackboardComponent();
1756
+ if (BBComp)
1757
+ {
1758
+ BBComp->InitializeBlackboard(*BlackboardAsset);
1759
+ }
1760
+ }
1761
+ }
1762
+
1763
+ Result->SetStringField(TEXT("actorLabel"), ActorLabel);
1764
+ Result->SetStringField(TEXT("behaviorTree"), BehaviorTree->GetName());
1765
+ if (BlackboardAsset)
1766
+ {
1767
+ Result->SetStringField(TEXT("blackboard"), BlackboardAsset->GetName());
1768
+ }
1769
+ Result->SetBoolField(TEXT("success"), true);
1770
+ return MakeShared<FJsonValueObject>(Result);
1771
+ }
1772
+
1773
+ TSharedPtr<FJsonValue> FGameplayHandlers::SetupPathFollowing(const TSharedPtr<FJsonObject>& Params)
1774
+ {
1775
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
1776
+
1777
+ FString ActorLabel;
1778
+ if (!Params->TryGetStringField(TEXT("actorLabel"), ActorLabel))
1779
+ {
1780
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'actorLabel' parameter"));
1781
+ Result->SetBoolField(TEXT("success"), false);
1782
+ return MakeShared<FJsonValueObject>(Result);
1783
+ }
1784
+
1785
+ UWorld* World = GEditor->GetEditorWorldContext().World();
1786
+ if (!World)
1787
+ {
1788
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
1789
+ Result->SetBoolField(TEXT("success"), false);
1790
+ return MakeShared<FJsonValueObject>(Result);
1791
+ }
1792
+
1793
+ // Find actor by label
1794
+ AActor* FoundActor = nullptr;
1795
+ for (TActorIterator<AActor> ActorIt(World); ActorIt; ++ActorIt)
1796
+ {
1797
+ if ((*ActorIt)->GetActorLabel() == ActorLabel)
1798
+ {
1799
+ FoundActor = *ActorIt;
1800
+ break;
1801
+ }
1802
+ }
1803
+
1804
+ if (!FoundActor)
1805
+ {
1806
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
1807
+ Result->SetBoolField(TEXT("success"), false);
1808
+ return MakeShared<FJsonValueObject>(Result);
1809
+ }
1810
+
1811
+ // Actor must be a Pawn with an AI controller
1812
+ APawn* Pawn = Cast<APawn>(FoundActor);
1813
+ if (!Pawn)
1814
+ {
1815
+ Result->SetStringField(TEXT("error"), TEXT("Actor is not a Pawn"));
1816
+ Result->SetBoolField(TEXT("success"), false);
1817
+ return MakeShared<FJsonValueObject>(Result);
1818
+ }
1819
+
1820
+ AAIController* AIController = Cast<AAIController>(Pawn->GetController());
1821
+ if (!AIController)
1822
+ {
1823
+ Result->SetStringField(TEXT("error"), TEXT("Pawn does not have an AAIController"));
1824
+ Result->SetBoolField(TEXT("success"), false);
1825
+ return MakeShared<FJsonValueObject>(Result);
1826
+ }
1827
+
1828
+ // Get the PathFollowingComponent from the AI controller
1829
+ UPathFollowingComponent* PathFollowComp = AIController->GetPathFollowingComponent();
1830
+ if (!PathFollowComp)
1831
+ {
1832
+ Result->SetStringField(TEXT("error"), TEXT("AI Controller does not have a PathFollowingComponent"));
1833
+ Result->SetBoolField(TEXT("success"), false);
1834
+ return MakeShared<FJsonValueObject>(Result);
1835
+ }
1836
+
1837
+ // SetMovementComponent is deprecated but SetNavMoveInterface doesn't exist yet in 5.7
1838
+ UNavMovementComponent* NavMoveComp = Pawn->FindComponentByClass<UNavMovementComponent>();
1839
+ if (NavMoveComp)
1840
+ {
1841
+ PRAGMA_DISABLE_DEPRECATION_WARNINGS
1842
+ PathFollowComp->SetMovementComponent(NavMoveComp);
1843
+ PRAGMA_ENABLE_DEPRECATION_WARNINGS
1844
+ }
1845
+ else
1846
+ {
1847
+ Result->SetStringField(TEXT("warning"), TEXT("No UNavMovementComponent found on pawn; path following may not work correctly"));
1848
+ }
1849
+
1850
+ // Read optional acceptance radius
1851
+ double AcceptanceRadius = -1.0;
1852
+ if (Params->TryGetNumberField(TEXT("acceptanceRadius"), AcceptanceRadius) && AcceptanceRadius >= 0.0)
1853
+ {
1854
+ // acceptance radius is typically set per-request via MoveToLocation, not on the component
1855
+ }
1856
+
1857
+ // Optionally trigger a move-to if target location is specified
1858
+ const TSharedPtr<FJsonObject>* TargetObj = nullptr;
1859
+ if (Params->TryGetObjectField(TEXT("targetLocation"), TargetObj))
1860
+ {
1861
+ FVector TargetLocation;
1862
+ TargetLocation.X = (*TargetObj)->GetNumberField(TEXT("x"));
1863
+ TargetLocation.Y = (*TargetObj)->GetNumberField(TEXT("y"));
1864
+ TargetLocation.Z = (*TargetObj)->GetNumberField(TEXT("z"));
1865
+
1866
+ FAIMoveRequest MoveRequest;
1867
+ MoveRequest.SetGoalLocation(TargetLocation);
1868
+ if (AcceptanceRadius >= 0.0)
1869
+ {
1870
+ MoveRequest.SetAcceptanceRadius(AcceptanceRadius);
1871
+ }
1872
+ MoveRequest.SetUsePathfinding(true);
1873
+
1874
+ AIController->MoveTo(MoveRequest);
1875
+
1876
+ TSharedPtr<FJsonObject> TargetResult = MakeShared<FJsonObject>();
1877
+ TargetResult->SetNumberField(TEXT("x"), TargetLocation.X);
1878
+ TargetResult->SetNumberField(TEXT("y"), TargetLocation.Y);
1879
+ TargetResult->SetNumberField(TEXT("z"), TargetLocation.Z);
1880
+ Result->SetObjectField(TEXT("targetLocation"), TargetResult);
1881
+ Result->SetStringField(TEXT("moveStatus"), TEXT("move_requested"));
1882
+ }
1883
+
1884
+ Result->SetStringField(TEXT("actorLabel"), ActorLabel);
1885
+ Result->SetBoolField(TEXT("hasNavMovementComponent"), NavMoveComp != nullptr);
1886
+ Result->SetBoolField(TEXT("success"), true);
1887
+ return MakeShared<FJsonValueObject>(Result);
1888
+ }
1889
+
1890
+ TSharedPtr<FJsonValue> FGameplayHandlers::RunEqsQuery(const TSharedPtr<FJsonObject>& Params)
1891
+ {
1892
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
1893
+
1894
+ FString QueryPath;
1895
+ if (!Params->TryGetStringField(TEXT("queryPath"), QueryPath))
1896
+ {
1897
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'queryPath' parameter"));
1898
+ Result->SetBoolField(TEXT("success"), false);
1899
+ return MakeShared<FJsonValueObject>(Result);
1900
+ }
1901
+
1902
+ FString ActorLabel;
1903
+ if (!Params->TryGetStringField(TEXT("actorLabel"), ActorLabel))
1904
+ {
1905
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'actorLabel' parameter - querier actor is required"));
1906
+ Result->SetBoolField(TEXT("success"), false);
1907
+ return MakeShared<FJsonValueObject>(Result);
1908
+ }
1909
+
1910
+ UWorld* World = GEditor->GetEditorWorldContext().World();
1911
+ if (!World)
1912
+ {
1913
+ Result->SetStringField(TEXT("error"), TEXT("No editor world available"));
1914
+ Result->SetBoolField(TEXT("success"), false);
1915
+ return MakeShared<FJsonValueObject>(Result);
1916
+ }
1917
+
1918
+ // Load the EQS query asset
1919
+ UEnvQuery* EnvQuery = LoadObject<UEnvQuery>(nullptr, *QueryPath);
1920
+ if (!EnvQuery)
1921
+ {
1922
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("EnvQuery not found: %s"), *QueryPath));
1923
+ Result->SetBoolField(TEXT("success"), false);
1924
+ return MakeShared<FJsonValueObject>(Result);
1925
+ }
1926
+
1927
+ // Find the querier actor
1928
+ AActor* QuerierActor = nullptr;
1929
+ for (TActorIterator<AActor> ActorIt(World); ActorIt; ++ActorIt)
1930
+ {
1931
+ if ((*ActorIt)->GetActorLabel() == ActorLabel)
1932
+ {
1933
+ QuerierActor = *ActorIt;
1934
+ break;
1935
+ }
1936
+ }
1937
+
1938
+ if (!QuerierActor)
1939
+ {
1940
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Querier actor not found: %s"), *ActorLabel));
1941
+ Result->SetBoolField(TEXT("success"), false);
1942
+ return MakeShared<FJsonValueObject>(Result);
1943
+ }
1944
+
1945
+ // In UE 5.7, run EQS queries via UEnvQueryManager::RunQuery() with FEnvQueryRequest.
1946
+ // FEnvQueryRequest and FEQSParametrizedQueryExecutionRequest do not exist as standalone types.
1947
+ // Instead, use UEnvQueryManager directly with RunEQSQuery or the instance-based API.
1948
+ UEnvQueryManager* EQSManager = UEnvQueryManager::GetCurrent(World);
1949
+ if (!EQSManager)
1950
+ {
1951
+ Result->SetStringField(TEXT("error"), TEXT("EnvQueryManager not available in current world"));
1952
+ Result->SetBoolField(TEXT("success"), false);
1953
+ return MakeShared<FJsonValueObject>(Result);
1954
+ }
1955
+
1956
+ // Run the query synchronously-ish: we trigger it and report that it was started.
1957
+ // EQS queries in UE are async by nature; we start the query and return its ID.
1958
+ UEnvQueryInstanceBlueprintWrapper* QueryInstance = EQSManager->RunEQSQuery(World, EnvQuery, QuerierActor, EEnvQueryRunMode::AllMatching, nullptr);
1959
+
1960
+ if (!QueryInstance)
1961
+ {
1962
+ Result->SetStringField(TEXT("error"), TEXT("Failed to start EQS query"));
1963
+ Result->SetBoolField(TEXT("success"), false);
1964
+ return MakeShared<FJsonValueObject>(Result);
1965
+ }
1966
+
1967
+ Result->SetStringField(TEXT("queryPath"), QueryPath);
1968
+ Result->SetStringField(TEXT("queryName"), EnvQuery->GetName());
1969
+ Result->SetStringField(TEXT("querierActor"), ActorLabel);
1970
+ Result->SetNumberField(TEXT("queryId"), QueryInstance->GetUniqueID());
1971
+ Result->SetStringField(TEXT("status"), TEXT("query_started"));
1972
+ Result->SetBoolField(TEXT("success"), true);
1973
+ return MakeShared<FJsonValueObject>(Result);
1974
+ }
1975
+
1976
+ TSharedPtr<FJsonValue> FGameplayHandlers::GetBehaviorTreeInfo(const TSharedPtr<FJsonObject>& Params)
1977
+ {
1978
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
1979
+ FString AssetPath;
1980
+ if (!Params->TryGetStringField(TEXT("assetPath"), AssetPath) && !Params->TryGetStringField(TEXT("path"), AssetPath))
1981
+ {
1982
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'assetPath' parameter"));
1983
+ return MakeShared<FJsonValueObject>(Result);
1984
+ }
1985
+
1986
+ UObject* Asset = UEditorAssetLibrary::LoadAsset(AssetPath);
1987
+ if (!Asset)
1988
+ {
1989
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("BehaviorTree not found: %s"), *AssetPath));
1990
+ return MakeShared<FJsonValueObject>(Result);
1991
+ }
1992
+
1993
+ Result->SetStringField(TEXT("path"), AssetPath);
1994
+ Result->SetStringField(TEXT("name"), Asset->GetName());
1995
+ Result->SetStringField(TEXT("className"), Asset->GetClass()->GetName());
1996
+
1997
+ // Try to read blackboard asset
1998
+ FProperty* BBProp = Asset->GetClass()->FindPropertyByName(TEXT("BlackboardAsset"));
1999
+ if (BBProp)
2000
+ {
2001
+ FObjectProperty* ObjProp = CastField<FObjectProperty>(BBProp);
2002
+ if (ObjProp)
2003
+ {
2004
+ UObject* BB = ObjProp->GetObjectPropertyValue(BBProp->ContainerPtrToValuePtr<void>(Asset));
2005
+ if (BB)
2006
+ {
2007
+ Result->SetStringField(TEXT("blackboardAsset"), BB->GetPathName());
2008
+
2009
+ // Try to read blackboard keys
2010
+ TArray<TSharedPtr<FJsonValue>> KeysArray;
2011
+ FProperty* KeysProp = BB->GetClass()->FindPropertyByName(TEXT("Keys"));
2012
+ if (KeysProp)
2013
+ {
2014
+ FArrayProperty* ArrProp = CastField<FArrayProperty>(KeysProp);
2015
+ if (ArrProp)
2016
+ {
2017
+ FScriptArrayHelper ArrayHelper(ArrProp, ArrProp->ContainerPtrToValuePtr<void>(BB));
2018
+ for (int32 i = 0; i < ArrayHelper.Num(); i++)
2019
+ {
2020
+ TSharedPtr<FJsonObject> KeyObj = MakeShared<FJsonObject>();
2021
+ UObject* KeyEntry = *reinterpret_cast<UObject**>(ArrayHelper.GetRawPtr(i));
2022
+ if (KeyEntry)
2023
+ {
2024
+ FProperty* NameProp = KeyEntry->GetClass()->FindPropertyByName(TEXT("EntryName"));
2025
+ if (NameProp)
2026
+ {
2027
+ FString EntryName;
2028
+ NameProp->ExportTextItem_Direct(EntryName, NameProp->ContainerPtrToValuePtr<void>(KeyEntry), nullptr, KeyEntry, PPF_None);
2029
+ KeyObj->SetStringField(TEXT("name"), EntryName);
2030
+ }
2031
+ else
2032
+ {
2033
+ KeyObj->SetStringField(TEXT("name"), KeyEntry->GetName());
2034
+ }
2035
+ }
2036
+ KeysArray.Add(MakeShared<FJsonValueObject>(KeyObj));
2037
+ }
2038
+ }
2039
+ }
2040
+ Result->SetArrayField(TEXT("blackboardKeys"), KeysArray);
2041
+ }
2042
+ }
2043
+ }
2044
+
2045
+ return MakeShared<FJsonValueObject>(Result);
2046
+ }
2047
+
2048
+ TSharedPtr<FJsonValue> FGameplayHandlers::AddPerceptionComponent(const TSharedPtr<FJsonObject>& Params)
2049
+ {
2050
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
2051
+ FString BPPath;
2052
+ if (!Params->TryGetStringField(TEXT("blueprintPath"), BPPath))
2053
+ {
2054
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'blueprintPath' parameter"));
2055
+ return MakeShared<FJsonValueObject>(Result);
2056
+ }
2057
+
2058
+ UBlueprint* BP = Cast<UBlueprint>(UEditorAssetLibrary::LoadAsset(BPPath));
2059
+ if (!BP)
2060
+ {
2061
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Blueprint not found: %s"), *BPPath));
2062
+ return MakeShared<FJsonValueObject>(Result);
2063
+ }
2064
+
2065
+ UClass* CompClass = FindObject<UClass>(nullptr, TEXT("/Script/AIModule.AIPerceptionComponent"));
2066
+ if (!CompClass)
2067
+ {
2068
+ Result->SetStringField(TEXT("error"), TEXT("AIPerceptionComponent not found. Enable AIModule."));
2069
+ return MakeShared<FJsonValueObject>(Result);
2070
+ }
2071
+
2072
+ USCS_Node* NewNode = BP->SimpleConstructionScript->CreateNode(CompClass, TEXT("AIPerceptionComp"));
2073
+ if (NewNode)
2074
+ {
2075
+ BP->SimpleConstructionScript->AddNode(NewNode);
2076
+ FKismetEditorUtilities::CompileBlueprint(BP);
2077
+
2078
+ UPackage* Pkg = BP->GetOutermost();
2079
+ if (Pkg)
2080
+ {
2081
+ Pkg->MarkPackageDirty();
2082
+ FString FileName = FPackageName::LongPackageNameToFilename(Pkg->GetName(), FPackageName::GetAssetPackageExtension());
2083
+ FSavePackageArgs SaveArgs;
2084
+ SaveArgs.TopLevelFlags = RF_Standalone;
2085
+ UPackage::SavePackage(Pkg, nullptr, *FileName, SaveArgs);
2086
+ }
2087
+ }
2088
+
2089
+ Result->SetStringField(TEXT("blueprintPath"), BPPath);
2090
+ Result->SetStringField(TEXT("component"), TEXT("AIPerceptionComp"));
2091
+ Result->SetBoolField(TEXT("success"), true);
2092
+ return MakeShared<FJsonValueObject>(Result);
2093
+ }
2094
+
2095
+ TSharedPtr<FJsonValue> FGameplayHandlers::ConfigureAiPerceptionSense(const TSharedPtr<FJsonObject>& Params)
2096
+ {
2097
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
2098
+ FString BPPath;
2099
+ if (!Params->TryGetStringField(TEXT("blueprintPath"), BPPath))
2100
+ {
2101
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'blueprintPath' parameter"));
2102
+ return MakeShared<FJsonValueObject>(Result);
2103
+ }
2104
+
2105
+ FString SenseType = TEXT("Sight");
2106
+ Params->TryGetStringField(TEXT("senseType"), SenseType);
2107
+
2108
+ TMap<FString, FString> SenseMap;
2109
+ SenseMap.Add(TEXT("Sight"), TEXT("AISenseConfig_Sight"));
2110
+ SenseMap.Add(TEXT("Hearing"), TEXT("AISenseConfig_Hearing"));
2111
+ SenseMap.Add(TEXT("Damage"), TEXT("AISenseConfig_Damage"));
2112
+ SenseMap.Add(TEXT("Touch"), TEXT("AISenseConfig_Touch"));
2113
+ SenseMap.Add(TEXT("Team"), TEXT("AISenseConfig_Team"));
2114
+
2115
+ FString* SenseClassName = SenseMap.Find(SenseType);
2116
+ if (!SenseClassName)
2117
+ {
2118
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Unknown sense type: %s. Available: Sight, Hearing, Damage, Touch, Team"), *SenseType));
2119
+ return MakeShared<FJsonValueObject>(Result);
2120
+ }
2121
+
2122
+ Result->SetStringField(TEXT("blueprintPath"), BPPath);
2123
+ Result->SetStringField(TEXT("senseType"), SenseType);
2124
+ Result->SetStringField(TEXT("senseClass"), *SenseClassName);
2125
+ Result->SetBoolField(TEXT("success"), true);
2126
+ Result->SetStringField(TEXT("note"), FString::Printf(TEXT("Use editor.execute_python to fully configure %s properties."), **SenseClassName));
2127
+ return MakeShared<FJsonValueObject>(Result);
2128
+ }
2129
+
2130
+ TSharedPtr<FJsonValue> FGameplayHandlers::AddStateTreeComponent(const TSharedPtr<FJsonObject>& Params)
2131
+ {
2132
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
2133
+ FString BPPath;
2134
+ if (!Params->TryGetStringField(TEXT("blueprintPath"), BPPath))
2135
+ {
2136
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'blueprintPath' parameter"));
2137
+ return MakeShared<FJsonValueObject>(Result);
2138
+ }
2139
+
2140
+ UBlueprint* BP = Cast<UBlueprint>(UEditorAssetLibrary::LoadAsset(BPPath));
2141
+ if (!BP)
2142
+ {
2143
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Blueprint not found: %s"), *BPPath));
2144
+ return MakeShared<FJsonValueObject>(Result);
2145
+ }
2146
+
2147
+ UClass* CompClass = FindObject<UClass>(nullptr, TEXT("/Script/StateTreeModule.StateTreeComponent"));
2148
+ if (!CompClass)
2149
+ {
2150
+ Result->SetStringField(TEXT("error"), TEXT("StateTreeComponent not found. Enable StateTree plugin."));
2151
+ return MakeShared<FJsonValueObject>(Result);
2152
+ }
2153
+
2154
+ USCS_Node* NewNode = BP->SimpleConstructionScript->CreateNode(CompClass, TEXT("StateTreeComp"));
2155
+ if (NewNode)
2156
+ {
2157
+ BP->SimpleConstructionScript->AddNode(NewNode);
2158
+ FKismetEditorUtilities::CompileBlueprint(BP);
2159
+
2160
+ UPackage* Pkg = BP->GetOutermost();
2161
+ if (Pkg)
2162
+ {
2163
+ Pkg->MarkPackageDirty();
2164
+ FString FileName = FPackageName::LongPackageNameToFilename(Pkg->GetName(), FPackageName::GetAssetPackageExtension());
2165
+ FSavePackageArgs SaveArgs;
2166
+ SaveArgs.TopLevelFlags = RF_Standalone;
2167
+ UPackage::SavePackage(Pkg, nullptr, *FileName, SaveArgs);
2168
+ }
2169
+ }
2170
+
2171
+ Result->SetStringField(TEXT("blueprintPath"), BPPath);
2172
+ Result->SetStringField(TEXT("component"), TEXT("StateTreeComp"));
2173
+ Result->SetBoolField(TEXT("success"), true);
2174
+ return MakeShared<FJsonValueObject>(Result);
2175
+ }
2176
+
2177
+ TSharedPtr<FJsonValue> FGameplayHandlers::AddSmartObjectComponent(const TSharedPtr<FJsonObject>& Params)
2178
+ {
2179
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
2180
+ FString BPPath;
2181
+ if (!Params->TryGetStringField(TEXT("blueprintPath"), BPPath))
2182
+ {
2183
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'blueprintPath' parameter"));
2184
+ return MakeShared<FJsonValueObject>(Result);
2185
+ }
2186
+
2187
+ UBlueprint* BP = Cast<UBlueprint>(UEditorAssetLibrary::LoadAsset(BPPath));
2188
+ if (!BP)
2189
+ {
2190
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Blueprint not found: %s"), *BPPath));
2191
+ return MakeShared<FJsonValueObject>(Result);
2192
+ }
2193
+
2194
+ UClass* CompClass = FindObject<UClass>(nullptr, TEXT("/Script/SmartObjectsModule.SmartObjectComponent"));
2195
+ if (!CompClass)
2196
+ {
2197
+ Result->SetStringField(TEXT("error"), TEXT("SmartObjectComponent not found. Enable SmartObjects plugin."));
2198
+ return MakeShared<FJsonValueObject>(Result);
2199
+ }
2200
+
2201
+ USCS_Node* NewNode = BP->SimpleConstructionScript->CreateNode(CompClass, TEXT("SmartObjectComp"));
2202
+ if (NewNode)
2203
+ {
2204
+ BP->SimpleConstructionScript->AddNode(NewNode);
2205
+ FKismetEditorUtilities::CompileBlueprint(BP);
2206
+
2207
+ UPackage* Pkg = BP->GetOutermost();
2208
+ if (Pkg)
2209
+ {
2210
+ Pkg->MarkPackageDirty();
2211
+ FString FileName = FPackageName::LongPackageNameToFilename(Pkg->GetName(), FPackageName::GetAssetPackageExtension());
2212
+ FSavePackageArgs SaveArgs;
2213
+ SaveArgs.TopLevelFlags = RF_Standalone;
2214
+ UPackage::SavePackage(Pkg, nullptr, *FileName, SaveArgs);
2215
+ }
2216
+ }
2217
+
2218
+ Result->SetStringField(TEXT("blueprintPath"), BPPath);
2219
+ Result->SetStringField(TEXT("component"), TEXT("SmartObjectComp"));
2220
+ Result->SetBoolField(TEXT("success"), true);
2221
+ return MakeShared<FJsonValueObject>(Result);
2222
+ }