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,985 @@
1
+ #include "WidgetHandlers.h"
2
+ #include "HandlerRegistry.h"
3
+ #include "AssetRegistry/AssetRegistryModule.h"
4
+ #include "AssetToolsModule.h"
5
+ #include "IAssetTools.h"
6
+ #include "UObject/UObjectGlobals.h"
7
+ #include "UObject/Package.h"
8
+ #include "Misc/PackageName.h"
9
+ #include "UObject/SavePackage.h"
10
+ #include "EditorScriptingUtilities/Public/EditorAssetLibrary.h"
11
+ #include "WidgetBlueprint.h"
12
+ #include "WidgetBlueprintFactory.h"
13
+ #include "Blueprint/UserWidget.h"
14
+ #include "Blueprint/WidgetTree.h"
15
+ #include "Components/Widget.h"
16
+ #include "Components/PanelWidget.h"
17
+ #include "Components/TextBlock.h"
18
+ #include "Components/Image.h"
19
+ #include "Components/Button.h"
20
+ #include "Components/ProgressBar.h"
21
+ #include "Components/CheckBox.h"
22
+ #include "Components/Slider.h"
23
+ #include "Components/EditableTextBox.h"
24
+ #include "Components/ComboBoxString.h"
25
+ #include "Animation/WidgetAnimation.h"
26
+ #include "MovieScene.h"
27
+ #include "MovieScenePossessable.h"
28
+ #include "MovieSceneSpawnable.h"
29
+ #include "Dom/JsonObject.h"
30
+ #include "Dom/JsonValue.h"
31
+ #include "UObject/UnrealType.h"
32
+ #include "Editor.h"
33
+ #include "EditorUtilitySubsystem.h"
34
+ #include "EditorUtilityWidget.h"
35
+ #include "EditorUtilityWidgetBlueprint.h"
36
+ #include "EditorUtilityBlueprint.h"
37
+
38
+ void FWidgetHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
39
+ {
40
+ Registry.RegisterHandler(TEXT("list_widget_blueprints"), &ListWidgetBlueprints);
41
+ Registry.RegisterHandler(TEXT("create_widget_blueprint"), &CreateWidgetBlueprint);
42
+ Registry.RegisterHandler(TEXT("read_widget_tree"), &ReadWidgetTree);
43
+ Registry.RegisterHandler(TEXT("create_editor_utility_widget"), &CreateEditorUtilityWidget);
44
+ Registry.RegisterHandler(TEXT("create_editor_utility_blueprint"), &CreateEditorUtilityBlueprint);
45
+ Registry.RegisterHandler(TEXT("search_widget_by_name"), &SearchWidgetByName);
46
+ Registry.RegisterHandler(TEXT("get_widget_properties"), &GetWidgetProperties);
47
+ Registry.RegisterHandler(TEXT("get_widget_details"), &GetWidgetProperties);
48
+ Registry.RegisterHandler(TEXT("set_widget_property"), &SetWidgetProperty);
49
+ Registry.RegisterHandler(TEXT("read_widget_animations"), &ReadWidgetAnimations);
50
+ Registry.RegisterHandler(TEXT("run_editor_utility_widget"), &RunEditorUtilityWidget);
51
+ Registry.RegisterHandler(TEXT("run_editor_utility_blueprint"), &RunEditorUtilityBlueprint);
52
+ }
53
+
54
+ UWidget* FWidgetHandlers::FindWidgetByNameRecursive(UWidget* Root, const FString& WidgetName)
55
+ {
56
+ if (!Root) return nullptr;
57
+
58
+ if (Root->GetName() == WidgetName)
59
+ {
60
+ return Root;
61
+ }
62
+
63
+ UPanelWidget* PanelWidget = Cast<UPanelWidget>(Root);
64
+ if (PanelWidget)
65
+ {
66
+ for (int32 i = 0; i < PanelWidget->GetChildrenCount(); ++i)
67
+ {
68
+ UWidget* Child = PanelWidget->GetChildAt(i);
69
+ UWidget* Found = FindWidgetByNameRecursive(Child, WidgetName);
70
+ if (Found)
71
+ {
72
+ return Found;
73
+ }
74
+ }
75
+ }
76
+
77
+ return nullptr;
78
+ }
79
+
80
+ TSharedPtr<FJsonValue> FWidgetHandlers::ListWidgetBlueprints(const TSharedPtr<FJsonObject>& Params)
81
+ {
82
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
83
+
84
+ bool bRecursive = true;
85
+ Params->TryGetBoolField(TEXT("recursive"), bRecursive);
86
+
87
+ IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry")).Get();
88
+
89
+ TArray<FAssetData> AssetDataList;
90
+ AssetRegistry.GetAssetsByClass(FTopLevelAssetPath(TEXT("/Script/UMGEditor"), TEXT("WidgetBlueprint")), AssetDataList, bRecursive);
91
+
92
+ TArray<TSharedPtr<FJsonValue>> AssetsArray;
93
+ for (const FAssetData& AssetData : AssetDataList)
94
+ {
95
+ TSharedPtr<FJsonObject> AssetObj = MakeShared<FJsonObject>();
96
+ AssetObj->SetStringField(TEXT("name"), AssetData.AssetName.ToString());
97
+ AssetObj->SetStringField(TEXT("path"), AssetData.GetObjectPathString());
98
+ AssetObj->SetStringField(TEXT("packagePath"), AssetData.PackagePath.ToString());
99
+ AssetsArray.Add(MakeShared<FJsonValueObject>(AssetObj));
100
+ }
101
+
102
+ Result->SetArrayField(TEXT("assets"), AssetsArray);
103
+ Result->SetNumberField(TEXT("count"), AssetsArray.Num());
104
+ Result->SetBoolField(TEXT("success"), true);
105
+
106
+ return MakeShared<FJsonValueObject>(Result);
107
+ }
108
+
109
+ TSharedPtr<FJsonValue> FWidgetHandlers::CreateWidgetBlueprint(const TSharedPtr<FJsonObject>& Params)
110
+ {
111
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
112
+
113
+ FString Name;
114
+ if (!Params->TryGetStringField(TEXT("name"), Name))
115
+ {
116
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'name' parameter"));
117
+ Result->SetBoolField(TEXT("success"), false);
118
+ return MakeShared<FJsonValueObject>(Result);
119
+ }
120
+
121
+ FString PackagePath = TEXT("/Game/UI/Widgets");
122
+ Params->TryGetStringField(TEXT("packagePath"), PackagePath);
123
+
124
+ // Delete existing asset if it exists
125
+ FString FullAssetPath = PackagePath + TEXT("/") + Name;
126
+ UEditorAssetLibrary::DeleteAsset(FullAssetPath);
127
+
128
+ FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
129
+ IAssetTools& AssetTools = AssetToolsModule.Get();
130
+
131
+ UWidgetBlueprintFactory* WidgetFactory = NewObject<UWidgetBlueprintFactory>();
132
+ WidgetFactory->ParentClass = UUserWidget::StaticClass();
133
+
134
+ UObject* NewAsset = AssetTools.CreateAsset(Name, PackagePath, UWidgetBlueprint::StaticClass(), WidgetFactory);
135
+ if (!NewAsset)
136
+ {
137
+ Result->SetStringField(TEXT("error"), TEXT("Failed to create WidgetBlueprint"));
138
+ Result->SetBoolField(TEXT("success"), false);
139
+ return MakeShared<FJsonValueObject>(Result);
140
+ }
141
+
142
+ UEditorAssetLibrary::SaveAsset(NewAsset->GetPathName());
143
+
144
+ Result->SetStringField(TEXT("path"), NewAsset->GetPathName());
145
+ Result->SetStringField(TEXT("name"), Name);
146
+ Result->SetBoolField(TEXT("success"), true);
147
+
148
+ return MakeShared<FJsonValueObject>(Result);
149
+ }
150
+
151
+ TSharedPtr<FJsonValue> FWidgetHandlers::ReadWidgetTree(const TSharedPtr<FJsonObject>& Params)
152
+ {
153
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
154
+
155
+ FString AssetPath;
156
+ if (!Params->TryGetStringField(TEXT("assetPath"), AssetPath) && !Params->TryGetStringField(TEXT("path"), AssetPath))
157
+ {
158
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'path' or 'assetPath' parameter"));
159
+ Result->SetBoolField(TEXT("success"), false);
160
+ return MakeShared<FJsonValueObject>(Result);
161
+ }
162
+
163
+ UObject* LoadedAsset = UEditorAssetLibrary::LoadAsset(AssetPath);
164
+ UWidgetBlueprint* WidgetBP = Cast<UWidgetBlueprint>(LoadedAsset);
165
+ if (!WidgetBP)
166
+ {
167
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load WidgetBlueprint at '%s'"), *AssetPath));
168
+ Result->SetBoolField(TEXT("success"), false);
169
+ return MakeShared<FJsonValueObject>(Result);
170
+ }
171
+
172
+ // Recursive lambda to build widget hierarchy
173
+ TFunction<TSharedPtr<FJsonObject>(UWidget*)> BuildWidgetJson = [&](UWidget* Widget) -> TSharedPtr<FJsonObject>
174
+ {
175
+ if (!Widget) return nullptr;
176
+
177
+ TSharedPtr<FJsonObject> WidgetObj = MakeShared<FJsonObject>();
178
+ WidgetObj->SetStringField(TEXT("name"), Widget->GetName());
179
+ WidgetObj->SetStringField(TEXT("class"), Widget->GetClass()->GetName());
180
+ WidgetObj->SetBoolField(TEXT("isVisible"), Widget->IsVisible());
181
+
182
+ // If it's a panel widget, recurse into children
183
+ UPanelWidget* PanelWidget = Cast<UPanelWidget>(Widget);
184
+ if (PanelWidget)
185
+ {
186
+ TArray<TSharedPtr<FJsonValue>> ChildrenArray;
187
+ for (int32 i = 0; i < PanelWidget->GetChildrenCount(); ++i)
188
+ {
189
+ UWidget* Child = PanelWidget->GetChildAt(i);
190
+ TSharedPtr<FJsonObject> ChildObj = BuildWidgetJson(Child);
191
+ if (ChildObj.IsValid())
192
+ {
193
+ ChildrenArray.Add(MakeShared<FJsonValueObject>(ChildObj));
194
+ }
195
+ }
196
+ WidgetObj->SetArrayField(TEXT("children"), ChildrenArray);
197
+ }
198
+
199
+ return WidgetObj;
200
+ };
201
+
202
+ // Get the root widget from the WidgetTree
203
+ UWidget* RootWidget = WidgetBP->WidgetTree ? WidgetBP->WidgetTree->RootWidget : nullptr;
204
+ if (RootWidget)
205
+ {
206
+ TSharedPtr<FJsonObject> TreeObj = BuildWidgetJson(RootWidget);
207
+ Result->SetObjectField(TEXT("widgetTree"), TreeObj);
208
+ }
209
+ else
210
+ {
211
+ Result->SetStringField(TEXT("widgetTree"), TEXT("empty"));
212
+ }
213
+
214
+ Result->SetBoolField(TEXT("success"), true);
215
+
216
+ return MakeShared<FJsonValueObject>(Result);
217
+ }
218
+
219
+ TSharedPtr<FJsonValue> FWidgetHandlers::CreateEditorUtilityWidget(const TSharedPtr<FJsonObject>& Params)
220
+ {
221
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
222
+
223
+ FString Path;
224
+ if (!Params->TryGetStringField(TEXT("path"), Path) && !Params->TryGetStringField(TEXT("assetPath"), Path))
225
+ {
226
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'path' or 'assetPath' parameter"));
227
+ Result->SetBoolField(TEXT("success"), false);
228
+ return MakeShared<FJsonValueObject>(Result);
229
+ }
230
+
231
+ // Split path into package path and asset name
232
+ FString PackagePath;
233
+ FString AssetName;
234
+ Path.Split(TEXT("/"), &PackagePath, &AssetName, ESearchCase::CaseSensitive, ESearchDir::FromEnd);
235
+ if (AssetName.IsEmpty())
236
+ {
237
+ Result->SetStringField(TEXT("error"), TEXT("Invalid path format. Expected '/Game/.../AssetName'"));
238
+ Result->SetBoolField(TEXT("success"), false);
239
+ return MakeShared<FJsonValueObject>(Result);
240
+ }
241
+
242
+ // Find EditorUtilityWidgetBlueprint class
243
+ UClass* EUWBClass = FindObject<UClass>(nullptr, TEXT("/Script/Blutility.EditorUtilityWidgetBlueprint"));
244
+ if (!EUWBClass)
245
+ {
246
+ Result->SetStringField(TEXT("error"), TEXT("EditorUtilityWidgetBlueprint class not found. Enable Blutility plugin."));
247
+ Result->SetBoolField(TEXT("success"), false);
248
+ return MakeShared<FJsonValueObject>(Result);
249
+ }
250
+
251
+ // Delete existing asset if it exists
252
+ UEditorAssetLibrary::DeleteAsset(Path);
253
+
254
+ FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
255
+ IAssetTools& AssetTools = AssetToolsModule.Get();
256
+
257
+ UWidgetBlueprintFactory* WidgetFactory = NewObject<UWidgetBlueprintFactory>();
258
+ WidgetFactory->ParentClass = UUserWidget::StaticClass();
259
+ WidgetFactory->BlueprintType = BPTYPE_Normal;
260
+
261
+ UObject* NewAsset = AssetTools.CreateAsset(AssetName, PackagePath, EUWBClass, WidgetFactory);
262
+ if (!NewAsset)
263
+ {
264
+ Result->SetStringField(TEXT("error"), TEXT("Failed to create EditorUtilityWidgetBlueprint"));
265
+ Result->SetBoolField(TEXT("success"), false);
266
+ return MakeShared<FJsonValueObject>(Result);
267
+ }
268
+
269
+ UEditorAssetLibrary::SaveAsset(NewAsset->GetPathName());
270
+
271
+ Result->SetStringField(TEXT("path"), NewAsset->GetPathName());
272
+ Result->SetStringField(TEXT("name"), AssetName);
273
+ Result->SetBoolField(TEXT("success"), true);
274
+
275
+ return MakeShared<FJsonValueObject>(Result);
276
+ }
277
+
278
+ TSharedPtr<FJsonValue> FWidgetHandlers::CreateEditorUtilityBlueprint(const TSharedPtr<FJsonObject>& Params)
279
+ {
280
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
281
+
282
+ FString Path;
283
+ if (!Params->TryGetStringField(TEXT("path"), Path) && !Params->TryGetStringField(TEXT("assetPath"), Path))
284
+ {
285
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'path' or 'assetPath' parameter"));
286
+ Result->SetBoolField(TEXT("success"), false);
287
+ return MakeShared<FJsonValueObject>(Result);
288
+ }
289
+
290
+ // Split path into package path and asset name
291
+ FString PackagePath;
292
+ FString AssetName;
293
+ Path.Split(TEXT("/"), &PackagePath, &AssetName, ESearchCase::CaseSensitive, ESearchDir::FromEnd);
294
+ if (AssetName.IsEmpty())
295
+ {
296
+ Result->SetStringField(TEXT("error"), TEXT("Invalid path format. Expected '/Game/.../AssetName'"));
297
+ Result->SetBoolField(TEXT("success"), false);
298
+ return MakeShared<FJsonValueObject>(Result);
299
+ }
300
+
301
+ // Find EditorUtilityBlueprint class
302
+ UClass* EUBClass = FindObject<UClass>(nullptr, TEXT("/Script/Blutility.EditorUtilityBlueprint"));
303
+ if (!EUBClass)
304
+ {
305
+ Result->SetStringField(TEXT("error"), TEXT("EditorUtilityBlueprint class not found. Enable Blutility plugin."));
306
+ Result->SetBoolField(TEXT("success"), false);
307
+ return MakeShared<FJsonValueObject>(Result);
308
+ }
309
+
310
+ // Delete existing asset if it exists
311
+ UEditorAssetLibrary::DeleteAsset(Path);
312
+
313
+ FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
314
+ IAssetTools& AssetTools = AssetToolsModule.Get();
315
+
316
+ UObject* NewAsset = AssetTools.CreateAsset(AssetName, PackagePath, EUBClass, nullptr);
317
+ if (!NewAsset)
318
+ {
319
+ Result->SetStringField(TEXT("error"), TEXT("Failed to create EditorUtilityBlueprint"));
320
+ Result->SetBoolField(TEXT("success"), false);
321
+ return MakeShared<FJsonValueObject>(Result);
322
+ }
323
+
324
+ UEditorAssetLibrary::SaveAsset(NewAsset->GetPathName());
325
+
326
+ Result->SetStringField(TEXT("path"), NewAsset->GetPathName());
327
+ Result->SetStringField(TEXT("name"), AssetName);
328
+ Result->SetBoolField(TEXT("success"), true);
329
+
330
+ return MakeShared<FJsonValueObject>(Result);
331
+ }
332
+
333
+ TSharedPtr<FJsonValue> FWidgetHandlers::SearchWidgetByName(const TSharedPtr<FJsonObject>& Params)
334
+ {
335
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
336
+
337
+ FString AssetPath;
338
+ if (!Params->TryGetStringField(TEXT("assetPath"), AssetPath) && !Params->TryGetStringField(TEXT("path"), AssetPath))
339
+ {
340
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'path' or 'assetPath' parameter"));
341
+ Result->SetBoolField(TEXT("success"), false);
342
+ return MakeShared<FJsonValueObject>(Result);
343
+ }
344
+
345
+ FString WidgetName;
346
+ if (!Params->TryGetStringField(TEXT("widgetName"), WidgetName))
347
+ {
348
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'widgetName' parameter"));
349
+ Result->SetBoolField(TEXT("success"), false);
350
+ return MakeShared<FJsonValueObject>(Result);
351
+ }
352
+
353
+ UObject* LoadedAsset = UEditorAssetLibrary::LoadAsset(AssetPath);
354
+ UWidgetBlueprint* WidgetBP = Cast<UWidgetBlueprint>(LoadedAsset);
355
+ if (!WidgetBP)
356
+ {
357
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load WidgetBlueprint at '%s'"), *AssetPath));
358
+ Result->SetBoolField(TEXT("success"), false);
359
+ return MakeShared<FJsonValueObject>(Result);
360
+ }
361
+
362
+ if (!WidgetBP->WidgetTree)
363
+ {
364
+ Result->SetStringField(TEXT("error"), TEXT("WidgetTree is null"));
365
+ Result->SetBoolField(TEXT("success"), false);
366
+ return MakeShared<FJsonValueObject>(Result);
367
+ }
368
+
369
+ // Search recursively from root
370
+ UWidget* RootWidget = WidgetBP->WidgetTree->RootWidget;
371
+ UWidget* FoundWidget = FindWidgetByNameRecursive(RootWidget, WidgetName);
372
+
373
+ // Also search all widgets in the tree (handles named widgets not in visual tree)
374
+ if (!FoundWidget)
375
+ {
376
+ WidgetBP->WidgetTree->ForEachWidget([&](UWidget* Widget)
377
+ {
378
+ if (Widget && Widget->GetName() == WidgetName)
379
+ {
380
+ FoundWidget = Widget;
381
+ }
382
+ });
383
+ }
384
+
385
+ if (!FoundWidget)
386
+ {
387
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Widget not found: '%s'"), *WidgetName));
388
+ Result->SetBoolField(TEXT("success"), false);
389
+ return MakeShared<FJsonValueObject>(Result);
390
+ }
391
+
392
+ TSharedPtr<FJsonObject> WidgetObj = MakeShared<FJsonObject>();
393
+ WidgetObj->SetStringField(TEXT("name"), FoundWidget->GetName());
394
+ WidgetObj->SetStringField(TEXT("class"), FoundWidget->GetClass()->GetName());
395
+ WidgetObj->SetBoolField(TEXT("isVisible"), FoundWidget->IsVisible());
396
+
397
+ // Check if it has a parent
398
+ UPanelWidget* Parent = FoundWidget->GetParent();
399
+ if (Parent)
400
+ {
401
+ WidgetObj->SetStringField(TEXT("parent"), Parent->GetName());
402
+ WidgetObj->SetStringField(TEXT("parentClass"), Parent->GetClass()->GetName());
403
+ }
404
+
405
+ // Check if it's a panel and report child count
406
+ UPanelWidget* AsPanel = Cast<UPanelWidget>(FoundWidget);
407
+ if (AsPanel)
408
+ {
409
+ WidgetObj->SetNumberField(TEXT("childCount"), AsPanel->GetChildrenCount());
410
+ }
411
+
412
+ Result->SetObjectField(TEXT("widget"), WidgetObj);
413
+ Result->SetBoolField(TEXT("success"), true);
414
+
415
+ return MakeShared<FJsonValueObject>(Result);
416
+ }
417
+
418
+ TSharedPtr<FJsonValue> FWidgetHandlers::GetWidgetProperties(const TSharedPtr<FJsonObject>& Params)
419
+ {
420
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
421
+
422
+ FString AssetPath;
423
+ if (!Params->TryGetStringField(TEXT("assetPath"), AssetPath) && !Params->TryGetStringField(TEXT("path"), AssetPath))
424
+ {
425
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'path' or 'assetPath' parameter"));
426
+ Result->SetBoolField(TEXT("success"), false);
427
+ return MakeShared<FJsonValueObject>(Result);
428
+ }
429
+
430
+ FString WidgetName;
431
+ if (!Params->TryGetStringField(TEXT("widgetName"), WidgetName))
432
+ {
433
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'widgetName' parameter"));
434
+ Result->SetBoolField(TEXT("success"), false);
435
+ return MakeShared<FJsonValueObject>(Result);
436
+ }
437
+
438
+ UObject* LoadedAsset = UEditorAssetLibrary::LoadAsset(AssetPath);
439
+ UWidgetBlueprint* WidgetBP = Cast<UWidgetBlueprint>(LoadedAsset);
440
+ if (!WidgetBP)
441
+ {
442
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load WidgetBlueprint at '%s'"), *AssetPath));
443
+ Result->SetBoolField(TEXT("success"), false);
444
+ return MakeShared<FJsonValueObject>(Result);
445
+ }
446
+
447
+ if (!WidgetBP->WidgetTree)
448
+ {
449
+ Result->SetStringField(TEXT("error"), TEXT("WidgetTree is null"));
450
+ Result->SetBoolField(TEXT("success"), false);
451
+ return MakeShared<FJsonValueObject>(Result);
452
+ }
453
+
454
+ // Find the widget
455
+ UWidget* FoundWidget = nullptr;
456
+ WidgetBP->WidgetTree->ForEachWidget([&](UWidget* Widget)
457
+ {
458
+ if (Widget && Widget->GetName() == WidgetName)
459
+ {
460
+ FoundWidget = Widget;
461
+ }
462
+ });
463
+
464
+ if (!FoundWidget)
465
+ {
466
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Widget not found: '%s'"), *WidgetName));
467
+ Result->SetBoolField(TEXT("success"), false);
468
+ return MakeShared<FJsonValueObject>(Result);
469
+ }
470
+
471
+ TSharedPtr<FJsonObject> PropsObj = MakeShared<FJsonObject>();
472
+ PropsObj->SetStringField(TEXT("name"), FoundWidget->GetName());
473
+ PropsObj->SetStringField(TEXT("class"), FoundWidget->GetClass()->GetName());
474
+ PropsObj->SetBoolField(TEXT("isVisible"), FoundWidget->IsVisible());
475
+
476
+ // Type-specific properties
477
+ if (UTextBlock* TextBlock = Cast<UTextBlock>(FoundWidget))
478
+ {
479
+ PropsObj->SetStringField(TEXT("text"), TextBlock->GetText().ToString());
480
+ PropsObj->SetStringField(TEXT("widgetType"), TEXT("TextBlock"));
481
+
482
+ // Font info
483
+ FSlateFontInfo FontInfo = TextBlock->GetFont();
484
+ PropsObj->SetStringField(TEXT("fontFamily"), FontInfo.FontObject ? FontInfo.FontObject->GetName() : TEXT(""));
485
+ PropsObj->SetNumberField(TEXT("fontSize"), FontInfo.Size);
486
+
487
+ // Color
488
+ FLinearColor Color = TextBlock->GetColorAndOpacity().GetSpecifiedColor();
489
+ TSharedPtr<FJsonObject> ColorObj = MakeShared<FJsonObject>();
490
+ ColorObj->SetNumberField(TEXT("r"), Color.R);
491
+ ColorObj->SetNumberField(TEXT("g"), Color.G);
492
+ ColorObj->SetNumberField(TEXT("b"), Color.B);
493
+ ColorObj->SetNumberField(TEXT("a"), Color.A);
494
+ PropsObj->SetObjectField(TEXT("color"), ColorObj);
495
+ }
496
+ else if (UImage* Image = Cast<UImage>(FoundWidget))
497
+ {
498
+ PropsObj->SetStringField(TEXT("widgetType"), TEXT("Image"));
499
+
500
+ // Brush info
501
+ const FSlateBrush& Brush = Image->GetBrush();
502
+ TSharedPtr<FJsonObject> BrushObj = MakeShared<FJsonObject>();
503
+ BrushObj->SetStringField(TEXT("resourceName"), Brush.GetResourceName().ToString());
504
+ BrushObj->SetNumberField(TEXT("imageSizeX"), Brush.ImageSize.X);
505
+ BrushObj->SetNumberField(TEXT("imageSizeY"), Brush.ImageSize.Y);
506
+ BrushObj->SetStringField(TEXT("drawAs"), StaticEnum<ESlateBrushDrawType::Type>()->GetNameStringByValue((int64)Brush.DrawAs));
507
+ BrushObj->SetStringField(TEXT("tiling"), StaticEnum<ESlateBrushTileType::Type>()->GetNameStringByValue((int64)Brush.Tiling));
508
+ PropsObj->SetObjectField(TEXT("brush"), BrushObj);
509
+
510
+ // Color tint
511
+ FLinearColor Tint = Image->GetColorAndOpacity();
512
+ TSharedPtr<FJsonObject> TintObj = MakeShared<FJsonObject>();
513
+ TintObj->SetNumberField(TEXT("r"), Tint.R);
514
+ TintObj->SetNumberField(TEXT("g"), Tint.G);
515
+ TintObj->SetNumberField(TEXT("b"), Tint.B);
516
+ TintObj->SetNumberField(TEXT("a"), Tint.A);
517
+ PropsObj->SetObjectField(TEXT("colorAndOpacity"), TintObj);
518
+ }
519
+ else if (UButton* Button = Cast<UButton>(FoundWidget))
520
+ {
521
+ PropsObj->SetStringField(TEXT("widgetType"), TEXT("Button"));
522
+
523
+ // Button style
524
+ const FButtonStyle& Style = Button->GetStyle();
525
+ TSharedPtr<FJsonObject> StyleObj = MakeShared<FJsonObject>();
526
+
527
+ // Normal brush
528
+ StyleObj->SetStringField(TEXT("normalResourceName"), Style.Normal.GetResourceName().ToString());
529
+ StyleObj->SetStringField(TEXT("hoveredResourceName"), Style.Hovered.GetResourceName().ToString());
530
+ StyleObj->SetStringField(TEXT("pressedResourceName"), Style.Pressed.GetResourceName().ToString());
531
+
532
+ PropsObj->SetObjectField(TEXT("style"), StyleObj);
533
+
534
+ // Color
535
+ FLinearColor BtnColor = Button->GetColorAndOpacity();
536
+ TSharedPtr<FJsonObject> BtnColorObj = MakeShared<FJsonObject>();
537
+ BtnColorObj->SetNumberField(TEXT("r"), BtnColor.R);
538
+ BtnColorObj->SetNumberField(TEXT("g"), BtnColor.G);
539
+ BtnColorObj->SetNumberField(TEXT("b"), BtnColor.B);
540
+ BtnColorObj->SetNumberField(TEXT("a"), BtnColor.A);
541
+ PropsObj->SetObjectField(TEXT("colorAndOpacity"), BtnColorObj);
542
+ }
543
+ else if (UProgressBar* ProgressBar = Cast<UProgressBar>(FoundWidget))
544
+ {
545
+ PropsObj->SetStringField(TEXT("widgetType"), TEXT("ProgressBar"));
546
+ PropsObj->SetNumberField(TEXT("percent"), ProgressBar->GetPercent());
547
+
548
+ // Fill color
549
+ FLinearColor FillColor = ProgressBar->GetFillColorAndOpacity();
550
+ TSharedPtr<FJsonObject> FillObj = MakeShared<FJsonObject>();
551
+ FillObj->SetNumberField(TEXT("r"), FillColor.R);
552
+ FillObj->SetNumberField(TEXT("g"), FillColor.G);
553
+ FillObj->SetNumberField(TEXT("b"), FillColor.B);
554
+ FillObj->SetNumberField(TEXT("a"), FillColor.A);
555
+ PropsObj->SetObjectField(TEXT("fillColor"), FillObj);
556
+ }
557
+ else if (UCheckBox* CheckBox = Cast<UCheckBox>(FoundWidget))
558
+ {
559
+ PropsObj->SetStringField(TEXT("widgetType"), TEXT("CheckBox"));
560
+ PropsObj->SetBoolField(TEXT("isChecked"), CheckBox->IsChecked());
561
+ }
562
+ else if (USlider* Slider = Cast<USlider>(FoundWidget))
563
+ {
564
+ PropsObj->SetStringField(TEXT("widgetType"), TEXT("Slider"));
565
+ PropsObj->SetNumberField(TEXT("value"), Slider->GetValue());
566
+ PropsObj->SetNumberField(TEXT("minValue"), Slider->GetMinValue());
567
+ PropsObj->SetNumberField(TEXT("maxValue"), Slider->GetMaxValue());
568
+ }
569
+ else if (UEditableTextBox* EditableText = Cast<UEditableTextBox>(FoundWidget))
570
+ {
571
+ PropsObj->SetStringField(TEXT("widgetType"), TEXT("EditableTextBox"));
572
+ PropsObj->SetStringField(TEXT("text"), EditableText->GetText().ToString());
573
+ PropsObj->SetStringField(TEXT("hintText"), EditableText->GetHintText().ToString());
574
+ }
575
+ else if (UComboBoxString* ComboBox = Cast<UComboBoxString>(FoundWidget))
576
+ {
577
+ PropsObj->SetStringField(TEXT("widgetType"), TEXT("ComboBoxString"));
578
+ PropsObj->SetStringField(TEXT("selectedOption"), ComboBox->GetSelectedOption());
579
+ PropsObj->SetNumberField(TEXT("optionCount"), ComboBox->GetOptionCount());
580
+
581
+ TArray<TSharedPtr<FJsonValue>> OptionsArray;
582
+ for (int32 i = 0; i < ComboBox->GetOptionCount(); ++i)
583
+ {
584
+ OptionsArray.Add(MakeShared<FJsonValueString>(ComboBox->GetOptionAtIndex(i)));
585
+ }
586
+ PropsObj->SetArrayField(TEXT("options"), OptionsArray);
587
+ }
588
+ else
589
+ {
590
+ PropsObj->SetStringField(TEXT("widgetType"), FoundWidget->GetClass()->GetName());
591
+ }
592
+
593
+ // Common slot info via reflection
594
+ UPanelWidget* ParentWidget = FoundWidget->GetParent();
595
+ if (ParentWidget)
596
+ {
597
+ PropsObj->SetStringField(TEXT("parentName"), ParentWidget->GetName());
598
+ PropsObj->SetStringField(TEXT("parentClass"), ParentWidget->GetClass()->GetName());
599
+ }
600
+
601
+ Result->SetObjectField(TEXT("properties"), PropsObj);
602
+ Result->SetBoolField(TEXT("success"), true);
603
+
604
+ return MakeShared<FJsonValueObject>(Result);
605
+ }
606
+
607
+ TSharedPtr<FJsonValue> FWidgetHandlers::SetWidgetProperty(const TSharedPtr<FJsonObject>& Params)
608
+ {
609
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
610
+
611
+ FString AssetPath;
612
+ if (!Params->TryGetStringField(TEXT("assetPath"), AssetPath) && !Params->TryGetStringField(TEXT("path"), AssetPath))
613
+ {
614
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'path' or 'assetPath' parameter"));
615
+ Result->SetBoolField(TEXT("success"), false);
616
+ return MakeShared<FJsonValueObject>(Result);
617
+ }
618
+
619
+ FString WidgetName;
620
+ if (!Params->TryGetStringField(TEXT("widgetName"), WidgetName))
621
+ {
622
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'widgetName' parameter"));
623
+ Result->SetBoolField(TEXT("success"), false);
624
+ return MakeShared<FJsonValueObject>(Result);
625
+ }
626
+
627
+ FString PropertyName;
628
+ if (!Params->TryGetStringField(TEXT("propertyName"), PropertyName))
629
+ {
630
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'propertyName' parameter"));
631
+ Result->SetBoolField(TEXT("success"), false);
632
+ return MakeShared<FJsonValueObject>(Result);
633
+ }
634
+
635
+ FString PropertyValue;
636
+ if (!Params->TryGetStringField(TEXT("propertyValue"), PropertyValue) && !Params->TryGetStringField(TEXT("value"), PropertyValue))
637
+ {
638
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'propertyValue' or 'value' parameter"));
639
+ Result->SetBoolField(TEXT("success"), false);
640
+ return MakeShared<FJsonValueObject>(Result);
641
+ }
642
+
643
+ UObject* LoadedAsset = UEditorAssetLibrary::LoadAsset(AssetPath);
644
+ UWidgetBlueprint* WidgetBP = Cast<UWidgetBlueprint>(LoadedAsset);
645
+ if (!WidgetBP)
646
+ {
647
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load WidgetBlueprint at '%s'"), *AssetPath));
648
+ Result->SetBoolField(TEXT("success"), false);
649
+ return MakeShared<FJsonValueObject>(Result);
650
+ }
651
+
652
+ if (!WidgetBP->WidgetTree)
653
+ {
654
+ Result->SetStringField(TEXT("error"), TEXT("WidgetTree is null"));
655
+ Result->SetBoolField(TEXT("success"), false);
656
+ return MakeShared<FJsonValueObject>(Result);
657
+ }
658
+
659
+ // Find the widget
660
+ UWidget* FoundWidget = nullptr;
661
+ WidgetBP->WidgetTree->ForEachWidget([&](UWidget* Widget)
662
+ {
663
+ if (Widget && Widget->GetName() == WidgetName)
664
+ {
665
+ FoundWidget = Widget;
666
+ }
667
+ });
668
+
669
+ if (!FoundWidget)
670
+ {
671
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Widget not found: '%s'"), *WidgetName));
672
+ Result->SetBoolField(TEXT("success"), false);
673
+ return MakeShared<FJsonValueObject>(Result);
674
+ }
675
+
676
+ bool bPropertySet = false;
677
+
678
+ // Handle well-known properties by type
679
+ if (UTextBlock* TextBlock = Cast<UTextBlock>(FoundWidget))
680
+ {
681
+ if (PropertyName == TEXT("text") || PropertyName == TEXT("Text"))
682
+ {
683
+ TextBlock->SetText(FText::FromString(PropertyValue));
684
+ bPropertySet = true;
685
+ }
686
+ else if (PropertyName == TEXT("fontSize"))
687
+ {
688
+ FSlateFontInfo FontInfo = TextBlock->GetFont();
689
+ FontInfo.Size = FCString::Atoi(*PropertyValue);
690
+ TextBlock->SetFont(FontInfo);
691
+ bPropertySet = true;
692
+ }
693
+ }
694
+ else if (UImage* Image = Cast<UImage>(FoundWidget))
695
+ {
696
+ if (PropertyName == TEXT("colorAndOpacity") || PropertyName == TEXT("tint"))
697
+ {
698
+ // Expect "R,G,B,A" format
699
+ TArray<FString> Components;
700
+ PropertyValue.ParseIntoArray(Components, TEXT(","));
701
+ if (Components.Num() >= 3)
702
+ {
703
+ float R = FCString::Atof(*Components[0]);
704
+ float G = FCString::Atof(*Components[1]);
705
+ float B = FCString::Atof(*Components[2]);
706
+ float A = Components.Num() >= 4 ? FCString::Atof(*Components[3]) : 1.0f;
707
+ Image->SetColorAndOpacity(FLinearColor(R, G, B, A));
708
+ bPropertySet = true;
709
+ }
710
+ }
711
+ }
712
+ else if (UProgressBar* ProgressBar = Cast<UProgressBar>(FoundWidget))
713
+ {
714
+ if (PropertyName == TEXT("percent") || PropertyName == TEXT("Percent"))
715
+ {
716
+ ProgressBar->SetPercent(FCString::Atof(*PropertyValue));
717
+ bPropertySet = true;
718
+ }
719
+ else if (PropertyName == TEXT("fillColor") || PropertyName == TEXT("FillColorAndOpacity"))
720
+ {
721
+ TArray<FString> Components;
722
+ PropertyValue.ParseIntoArray(Components, TEXT(","));
723
+ if (Components.Num() >= 3)
724
+ {
725
+ float R = FCString::Atof(*Components[0]);
726
+ float G = FCString::Atof(*Components[1]);
727
+ float B = FCString::Atof(*Components[2]);
728
+ float A = Components.Num() >= 4 ? FCString::Atof(*Components[3]) : 1.0f;
729
+ ProgressBar->SetFillColorAndOpacity(FLinearColor(R, G, B, A));
730
+ bPropertySet = true;
731
+ }
732
+ }
733
+ }
734
+ else if (UCheckBox* CheckBox = Cast<UCheckBox>(FoundWidget))
735
+ {
736
+ if (PropertyName == TEXT("isChecked") || PropertyName == TEXT("IsChecked"))
737
+ {
738
+ bool bChecked = PropertyValue.ToBool();
739
+ CheckBox->SetIsChecked(bChecked);
740
+ bPropertySet = true;
741
+ }
742
+ }
743
+ else if (USlider* Slider = Cast<USlider>(FoundWidget))
744
+ {
745
+ if (PropertyName == TEXT("value") || PropertyName == TEXT("Value"))
746
+ {
747
+ Slider->SetValue(FCString::Atof(*PropertyValue));
748
+ bPropertySet = true;
749
+ }
750
+ }
751
+ else if (UEditableTextBox* EditableText = Cast<UEditableTextBox>(FoundWidget))
752
+ {
753
+ if (PropertyName == TEXT("text") || PropertyName == TEXT("Text"))
754
+ {
755
+ EditableText->SetText(FText::FromString(PropertyValue));
756
+ bPropertySet = true;
757
+ }
758
+ }
759
+
760
+ // Fallback: try to set via UObject reflection
761
+ if (!bPropertySet)
762
+ {
763
+ FProperty* Prop = FoundWidget->GetClass()->FindPropertyByName(FName(*PropertyName));
764
+ if (Prop)
765
+ {
766
+ void* ValuePtr = Prop->ContainerPtrToValuePtr<void>(FoundWidget);
767
+ if (Prop->ImportText_Direct(*PropertyValue, ValuePtr, FoundWidget, PPF_None))
768
+ {
769
+ bPropertySet = true;
770
+ }
771
+ }
772
+ }
773
+
774
+ if (bPropertySet)
775
+ {
776
+ // Mark package dirty and save
777
+ WidgetBP->MarkPackageDirty();
778
+ UEditorAssetLibrary::SaveAsset(AssetPath);
779
+
780
+ Result->SetStringField(TEXT("widgetName"), WidgetName);
781
+ Result->SetStringField(TEXT("propertyName"), PropertyName);
782
+ Result->SetStringField(TEXT("propertyValue"), PropertyValue);
783
+ Result->SetBoolField(TEXT("success"), true);
784
+ }
785
+ else
786
+ {
787
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to set property '%s' on widget '%s'. Property not found or value format invalid."), *PropertyName, *WidgetName));
788
+ Result->SetBoolField(TEXT("success"), false);
789
+ }
790
+
791
+ return MakeShared<FJsonValueObject>(Result);
792
+ }
793
+
794
+ TSharedPtr<FJsonValue> FWidgetHandlers::ReadWidgetAnimations(const TSharedPtr<FJsonObject>& Params)
795
+ {
796
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
797
+
798
+ FString AssetPath;
799
+ if (!Params->TryGetStringField(TEXT("assetPath"), AssetPath) && !Params->TryGetStringField(TEXT("path"), AssetPath))
800
+ {
801
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'path' or 'assetPath' parameter"));
802
+ Result->SetBoolField(TEXT("success"), false);
803
+ return MakeShared<FJsonValueObject>(Result);
804
+ }
805
+
806
+ UObject* LoadedAsset = UEditorAssetLibrary::LoadAsset(AssetPath);
807
+ UWidgetBlueprint* WidgetBP = Cast<UWidgetBlueprint>(LoadedAsset);
808
+ if (!WidgetBP)
809
+ {
810
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load WidgetBlueprint at '%s'"), *AssetPath));
811
+ Result->SetBoolField(TEXT("success"), false);
812
+ return MakeShared<FJsonValueObject>(Result);
813
+ }
814
+
815
+ TArray<TSharedPtr<FJsonValue>> AnimationsArray;
816
+
817
+ for (UWidgetAnimation* Animation : WidgetBP->Animations)
818
+ {
819
+ if (!Animation) continue;
820
+
821
+ TSharedPtr<FJsonObject> AnimObj = MakeShared<FJsonObject>();
822
+ AnimObj->SetStringField(TEXT("name"), Animation->GetName());
823
+ AnimObj->SetStringField(TEXT("displayName"), Animation->GetDisplayLabel().IsEmpty() ? Animation->GetName() : Animation->GetDisplayLabel());
824
+
825
+ UMovieScene* MovieScene = Animation->GetMovieScene();
826
+ if (MovieScene)
827
+ {
828
+ // Duration / range
829
+ FFrameRate TickResolution = MovieScene->GetTickResolution();
830
+ FFrameRate DisplayRate = MovieScene->GetDisplayRate();
831
+ TRange<FFrameNumber> PlaybackRange = MovieScene->GetPlaybackRange();
832
+
833
+ if (PlaybackRange.HasLowerBound() && PlaybackRange.HasUpperBound())
834
+ {
835
+ double StartSeconds = TickResolution.AsSeconds(PlaybackRange.GetLowerBoundValue());
836
+ double EndSeconds = TickResolution.AsSeconds(PlaybackRange.GetUpperBoundValue());
837
+ AnimObj->SetNumberField(TEXT("startTime"), StartSeconds);
838
+ AnimObj->SetNumberField(TEXT("endTime"), EndSeconds);
839
+ AnimObj->SetNumberField(TEXT("duration"), EndSeconds - StartSeconds);
840
+ }
841
+
842
+ AnimObj->SetNumberField(TEXT("displayRate"), DisplayRate.Numerator);
843
+
844
+ // Tracks (bindings)
845
+ TArray<TSharedPtr<FJsonValue>> BindingsArray;
846
+ const UMovieScene* ConstMovieScene = MovieScene;
847
+ const TArray<FMovieSceneBinding>& Bindings = ConstMovieScene->GetBindings();
848
+ for (const FMovieSceneBinding& Binding : Bindings)
849
+ {
850
+ TSharedPtr<FJsonObject> BindingObj = MakeShared<FJsonObject>();
851
+
852
+ // FMovieSceneBinding::GetName() is deprecated; look up the name from possessable/spawnable instead
853
+ FGuid ObjectGuid = Binding.GetObjectGuid();
854
+ FString BindingName;
855
+ FMovieScenePossessable* Possessable = MovieScene->FindPossessable(ObjectGuid);
856
+ if (Possessable)
857
+ {
858
+ BindingName = Possessable->GetName();
859
+ }
860
+ else
861
+ {
862
+ FMovieSceneSpawnable* Spawnable = MovieScene->FindSpawnable(ObjectGuid);
863
+ if (Spawnable)
864
+ {
865
+ BindingName = Spawnable->GetName();
866
+ }
867
+ }
868
+
869
+ BindingObj->SetStringField(TEXT("name"), BindingName);
870
+ BindingObj->SetStringField(TEXT("id"), ObjectGuid.ToString());
871
+
872
+ TArray<TSharedPtr<FJsonValue>> TracksArray;
873
+ for (UMovieSceneTrack* Track : Binding.GetTracks())
874
+ {
875
+ if (!Track) continue;
876
+ TSharedPtr<FJsonObject> TrackObj = MakeShared<FJsonObject>();
877
+ TrackObj->SetStringField(TEXT("name"), Track->GetDisplayName().ToString());
878
+ TrackObj->SetStringField(TEXT("class"), Track->GetClass()->GetName());
879
+ TrackObj->SetNumberField(TEXT("sectionCount"), Track->GetAllSections().Num());
880
+ TracksArray.Add(MakeShared<FJsonValueObject>(TrackObj));
881
+ }
882
+ BindingObj->SetArrayField(TEXT("tracks"), TracksArray);
883
+
884
+ BindingsArray.Add(MakeShared<FJsonValueObject>(BindingObj));
885
+ }
886
+ AnimObj->SetArrayField(TEXT("bindings"), BindingsArray);
887
+
888
+ // Master tracks (non-bound tracks)
889
+ TArray<TSharedPtr<FJsonValue>> MasterTracksArray;
890
+ for (UMovieSceneTrack* Track : MovieScene->GetTracks())
891
+ {
892
+ if (!Track) continue;
893
+ TSharedPtr<FJsonObject> TrackObj = MakeShared<FJsonObject>();
894
+ TrackObj->SetStringField(TEXT("name"), Track->GetDisplayName().ToString());
895
+ TrackObj->SetStringField(TEXT("class"), Track->GetClass()->GetName());
896
+ MasterTracksArray.Add(MakeShared<FJsonValueObject>(TrackObj));
897
+ }
898
+ AnimObj->SetArrayField(TEXT("masterTracks"), MasterTracksArray);
899
+ }
900
+
901
+ AnimationsArray.Add(MakeShared<FJsonValueObject>(AnimObj));
902
+ }
903
+
904
+ Result->SetArrayField(TEXT("animations"), AnimationsArray);
905
+ Result->SetNumberField(TEXT("count"), AnimationsArray.Num());
906
+ Result->SetBoolField(TEXT("success"), true);
907
+
908
+ return MakeShared<FJsonValueObject>(Result);
909
+ }
910
+
911
+ TSharedPtr<FJsonValue> FWidgetHandlers::RunEditorUtilityWidget(const TSharedPtr<FJsonObject>& Params)
912
+ {
913
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
914
+
915
+ FString AssetPath;
916
+ if (!Params->TryGetStringField(TEXT("assetPath"), AssetPath) && !Params->TryGetStringField(TEXT("path"), AssetPath))
917
+ {
918
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'path' or 'assetPath' parameter"));
919
+ Result->SetBoolField(TEXT("success"), false);
920
+ return MakeShared<FJsonValueObject>(Result);
921
+ }
922
+
923
+ UObject* LoadedAsset = UEditorAssetLibrary::LoadAsset(AssetPath);
924
+ UEditorUtilityWidgetBlueprint* EUWidget = Cast<UEditorUtilityWidgetBlueprint>(LoadedAsset);
925
+ if (!EUWidget)
926
+ {
927
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load EditorUtilityWidgetBlueprint at '%s'"), *AssetPath));
928
+ Result->SetBoolField(TEXT("success"), false);
929
+ return MakeShared<FJsonValueObject>(Result);
930
+ }
931
+
932
+ UEditorUtilitySubsystem* Subsystem = GEditor->GetEditorSubsystem<UEditorUtilitySubsystem>();
933
+ if (!Subsystem)
934
+ {
935
+ Result->SetStringField(TEXT("error"), TEXT("EditorUtilitySubsystem not available"));
936
+ Result->SetBoolField(TEXT("success"), false);
937
+ return MakeShared<FJsonValueObject>(Result);
938
+ }
939
+
940
+ Subsystem->SpawnAndRegisterTab(EUWidget);
941
+
942
+ Result->SetStringField(TEXT("assetPath"), AssetPath);
943
+ Result->SetStringField(TEXT("name"), EUWidget->GetName());
944
+ Result->SetBoolField(TEXT("success"), true);
945
+
946
+ return MakeShared<FJsonValueObject>(Result);
947
+ }
948
+
949
+ TSharedPtr<FJsonValue> FWidgetHandlers::RunEditorUtilityBlueprint(const TSharedPtr<FJsonObject>& Params)
950
+ {
951
+ TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
952
+
953
+ FString AssetPath;
954
+ if (!Params->TryGetStringField(TEXT("assetPath"), AssetPath) && !Params->TryGetStringField(TEXT("path"), AssetPath))
955
+ {
956
+ Result->SetStringField(TEXT("error"), TEXT("Missing 'path' or 'assetPath' parameter"));
957
+ Result->SetBoolField(TEXT("success"), false);
958
+ return MakeShared<FJsonValueObject>(Result);
959
+ }
960
+
961
+ UObject* LoadedAsset = UEditorAssetLibrary::LoadAsset(AssetPath);
962
+ UEditorUtilityBlueprint* EUBlueprint = Cast<UEditorUtilityBlueprint>(LoadedAsset);
963
+ if (!EUBlueprint)
964
+ {
965
+ Result->SetStringField(TEXT("error"), FString::Printf(TEXT("Failed to load EditorUtilityBlueprint at '%s'"), *AssetPath));
966
+ Result->SetBoolField(TEXT("success"), false);
967
+ return MakeShared<FJsonValueObject>(Result);
968
+ }
969
+
970
+ UEditorUtilitySubsystem* Subsystem = GEditor->GetEditorSubsystem<UEditorUtilitySubsystem>();
971
+ if (!Subsystem)
972
+ {
973
+ Result->SetStringField(TEXT("error"), TEXT("EditorUtilitySubsystem not available"));
974
+ Result->SetBoolField(TEXT("success"), false);
975
+ return MakeShared<FJsonValueObject>(Result);
976
+ }
977
+
978
+ Subsystem->TryRun(LoadedAsset);
979
+
980
+ Result->SetStringField(TEXT("assetPath"), AssetPath);
981
+ Result->SetStringField(TEXT("name"), EUBlueprint->GetName());
982
+ Result->SetBoolField(TEXT("success"), true);
983
+
984
+ return MakeShared<FJsonValueObject>(Result);
985
+ }