@mflrevan/ucp 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bridge/com.ucp.bridge/CHANGELOG.md +145 -0
- package/bridge/com.ucp.bridge/CHANGELOG.md.meta +7 -0
- package/bridge/com.ucp.bridge/Editor/Bridge/BridgeServer.cs +583 -0
- package/bridge/com.ucp.bridge/Editor/Bridge/BridgeServer.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Bridge.meta +8 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/AssetController.cs +425 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/AssetController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/AssetImportSupport.cs +355 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/AssetImportSupport.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/BuildController.cs +233 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/BuildController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/CompilationController.cs +26 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/CompilationController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/EditorController.cs +31 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/EditorController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/EditorSettingsController.cs +527 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/EditorSettingsController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/FileController.cs +141 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/FileController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/HierarchyController.cs +326 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/HierarchyController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ImporterController.cs +209 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ImporterController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/LogsController.cs +409 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/LogsController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/MaterialController.cs +354 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/MaterialController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ObjectReferenceResolver.cs +93 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ObjectReferenceResolver.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/PackagesController.cs +503 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/PackagesController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/PlayModeController.cs +188 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/PlayModeController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/PrefabController.cs +260 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/PrefabController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ProfilerController.cs +1679 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ProfilerController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/PropertyController.cs +563 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/PropertyController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/SceneChangeTracker.cs +166 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/SceneChangeTracker.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/SceneController.cs +318 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/SceneController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ScreenshotController.cs +125 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ScreenshotController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ScriptController.cs +104 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ScriptController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/SnapshotController.cs +227 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/SnapshotController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/TestRunnerController.cs +240 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/TestRunnerController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/VcsController.cs +611 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/VcsController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers.meta +8 -0
- package/bridge/com.ucp.bridge/Editor/Protocol/CommandRouter.cs +53 -0
- package/bridge/com.ucp.bridge/Editor/Protocol/CommandRouter.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Protocol/MessageTypes.cs +80 -0
- package/bridge/com.ucp.bridge/Editor/Protocol/MessageTypes.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Protocol/MiniJson.cs +358 -0
- package/bridge/com.ucp.bridge/Editor/Protocol/MiniJson.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Protocol.meta +8 -0
- package/bridge/com.ucp.bridge/Editor/Scripts/IUCPScript.cs +37 -0
- package/bridge/com.ucp.bridge/Editor/Scripts/IUCPScript.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Scripts.meta +8 -0
- package/bridge/com.ucp.bridge/Editor/UCP.Bridge.Editor.asmdef +16 -0
- package/bridge/com.ucp.bridge/Editor/UCP.Bridge.Editor.asmdef.meta +7 -0
- package/bridge/com.ucp.bridge/Editor.meta +8 -0
- package/bridge/com.ucp.bridge/Runtime/UCP.Bridge.Runtime.asmdef +14 -0
- package/bridge/com.ucp.bridge/Runtime/UCP.Bridge.Runtime.asmdef.meta +7 -0
- package/bridge/com.ucp.bridge/Runtime.meta +8 -0
- package/bridge/com.ucp.bridge/Tests/Editor/ControllerSmokeTests.cs +1085 -0
- package/bridge/com.ucp.bridge/Tests/Editor/ControllerSmokeTests.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Tests/Editor/UCP.Bridge.Editor.Tests.asmdef +12 -0
- package/bridge/com.ucp.bridge/Tests/Editor/UCP.Bridge.Editor.Tests.asmdef.meta +7 -0
- package/bridge/com.ucp.bridge/Tests/Editor.meta +8 -0
- package/bridge/com.ucp.bridge/Tests.meta +8 -0
- package/bridge/com.ucp.bridge/package.json +27 -0
- package/bridge/com.ucp.bridge/package.json.meta +7 -0
- package/package.json +2 -2
- package/scripts/install.js +4 -6
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections;
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
using System.Reflection;
|
|
5
|
+
using UnityEditor;
|
|
6
|
+
using UnityEditor.SceneManagement;
|
|
7
|
+
using UnityEngine;
|
|
8
|
+
using UnityEngine.SceneManagement;
|
|
9
|
+
|
|
10
|
+
namespace UCP.Bridge
|
|
11
|
+
{
|
|
12
|
+
public static class PropertyController
|
|
13
|
+
{
|
|
14
|
+
public static void Register(CommandRouter router)
|
|
15
|
+
{
|
|
16
|
+
router.Register("object/get-fields", HandleGetFields);
|
|
17
|
+
router.Register("object/get-property", HandleGetProperty);
|
|
18
|
+
router.Register("object/set-property", HandleSetProperty);
|
|
19
|
+
router.Register("object/set-active", HandleSetActive);
|
|
20
|
+
router.Register("object/set-name", HandleSetName);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private static object HandleGetFields(string paramsJson)
|
|
24
|
+
{
|
|
25
|
+
var p = MiniJson.Deserialize(paramsJson) as Dictionary<string, object>;
|
|
26
|
+
if (p == null || !p.TryGetValue("instanceId", out var idObj))
|
|
27
|
+
throw new ArgumentException("Missing 'instanceId' parameter");
|
|
28
|
+
|
|
29
|
+
var componentType = p.TryGetValue("component", out var cObj) ? cObj?.ToString() : null;
|
|
30
|
+
int instanceId = Convert.ToInt32(idObj);
|
|
31
|
+
var go = FindGameObject(instanceId);
|
|
32
|
+
|
|
33
|
+
if (componentType != null)
|
|
34
|
+
{
|
|
35
|
+
var comp = FindComponent(go, componentType);
|
|
36
|
+
return new Dictionary<string, object>
|
|
37
|
+
{
|
|
38
|
+
["instanceId"] = instanceId,
|
|
39
|
+
["name"] = go.name,
|
|
40
|
+
["component"] = componentType,
|
|
41
|
+
["fields"] = SerializeComponentFields(comp)
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Return fields for all components
|
|
46
|
+
var allComponents = new List<object>();
|
|
47
|
+
foreach (var c in go.GetComponents<Component>())
|
|
48
|
+
{
|
|
49
|
+
if (c == null) continue;
|
|
50
|
+
allComponents.Add(new Dictionary<string, object>
|
|
51
|
+
{
|
|
52
|
+
["type"] = c.GetType().Name,
|
|
53
|
+
["fields"] = SerializeComponentFields(c)
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return new Dictionary<string, object>
|
|
58
|
+
{
|
|
59
|
+
["instanceId"] = instanceId,
|
|
60
|
+
["name"] = go.name,
|
|
61
|
+
["components"] = allComponents
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private static object HandleGetProperty(string paramsJson)
|
|
66
|
+
{
|
|
67
|
+
var p = MiniJson.Deserialize(paramsJson) as Dictionary<string, object>;
|
|
68
|
+
if (p == null || !p.TryGetValue("instanceId", out var idObj))
|
|
69
|
+
throw new ArgumentException("Missing 'instanceId' parameter");
|
|
70
|
+
if (!p.TryGetValue("component", out var cObj) || cObj == null)
|
|
71
|
+
throw new ArgumentException("Missing 'component' parameter");
|
|
72
|
+
if (!p.TryGetValue("property", out var propObj) || propObj == null)
|
|
73
|
+
throw new ArgumentException("Missing 'property' parameter");
|
|
74
|
+
|
|
75
|
+
int instanceId = Convert.ToInt32(idObj);
|
|
76
|
+
var go = FindGameObject(instanceId);
|
|
77
|
+
var comp = FindComponent(go, cObj.ToString());
|
|
78
|
+
string propName = propObj.ToString();
|
|
79
|
+
|
|
80
|
+
var value = GetPropertyValue(comp, propName);
|
|
81
|
+
return new Dictionary<string, object>
|
|
82
|
+
{
|
|
83
|
+
["instanceId"] = instanceId,
|
|
84
|
+
["component"] = cObj.ToString(),
|
|
85
|
+
["property"] = propName,
|
|
86
|
+
["value"] = ConvertToJson(value),
|
|
87
|
+
["type"] = value != null ? value.GetType().Name : "null"
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private static object HandleSetProperty(string paramsJson)
|
|
92
|
+
{
|
|
93
|
+
var p = MiniJson.Deserialize(paramsJson) as Dictionary<string, object>;
|
|
94
|
+
if (p == null || !p.TryGetValue("instanceId", out var idObj))
|
|
95
|
+
throw new ArgumentException("Missing 'instanceId' parameter");
|
|
96
|
+
if (!p.TryGetValue("component", out var cObj) || cObj == null)
|
|
97
|
+
throw new ArgumentException("Missing 'component' parameter");
|
|
98
|
+
if (!p.TryGetValue("property", out var propObj) || propObj == null)
|
|
99
|
+
throw new ArgumentException("Missing 'property' parameter");
|
|
100
|
+
if (!p.ContainsKey("value"))
|
|
101
|
+
throw new ArgumentException("Missing 'value' parameter");
|
|
102
|
+
|
|
103
|
+
int instanceId = Convert.ToInt32(idObj);
|
|
104
|
+
var go = FindGameObject(instanceId);
|
|
105
|
+
var comp = FindComponent(go, cObj.ToString());
|
|
106
|
+
string propName = propObj.ToString();
|
|
107
|
+
|
|
108
|
+
Undo.RecordObject(comp, $"UCP Set {propName}");
|
|
109
|
+
SetPropertyValue(comp, propName, p["value"]);
|
|
110
|
+
EditorUtility.SetDirty(comp);
|
|
111
|
+
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
|
|
112
|
+
SceneChangeTracker.RecordGameObjectChange(go, comp.GetType().Name);
|
|
113
|
+
|
|
114
|
+
return new Dictionary<string, object>
|
|
115
|
+
{
|
|
116
|
+
["status"] = "ok",
|
|
117
|
+
["instanceId"] = instanceId,
|
|
118
|
+
["component"] = cObj.ToString(),
|
|
119
|
+
["property"] = propName
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private static object HandleSetActive(string paramsJson)
|
|
124
|
+
{
|
|
125
|
+
var p = MiniJson.Deserialize(paramsJson) as Dictionary<string, object>;
|
|
126
|
+
if (p == null || !p.TryGetValue("instanceId", out var idObj))
|
|
127
|
+
throw new ArgumentException("Missing 'instanceId' parameter");
|
|
128
|
+
if (!p.TryGetValue("active", out var activeObj))
|
|
129
|
+
throw new ArgumentException("Missing 'active' parameter");
|
|
130
|
+
|
|
131
|
+
int instanceId = Convert.ToInt32(idObj);
|
|
132
|
+
var go = FindGameObject(instanceId);
|
|
133
|
+
|
|
134
|
+
Undo.RecordObject(go, "UCP Set Active");
|
|
135
|
+
go.SetActive(Convert.ToBoolean(activeObj));
|
|
136
|
+
EditorUtility.SetDirty(go);
|
|
137
|
+
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
|
|
138
|
+
SceneChangeTracker.RecordGameObjectChange(go, "GameObject");
|
|
139
|
+
|
|
140
|
+
return new Dictionary<string, object>
|
|
141
|
+
{
|
|
142
|
+
["status"] = "ok",
|
|
143
|
+
["instanceId"] = instanceId,
|
|
144
|
+
["active"] = go.activeSelf
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private static object HandleSetName(string paramsJson)
|
|
149
|
+
{
|
|
150
|
+
var p = MiniJson.Deserialize(paramsJson) as Dictionary<string, object>;
|
|
151
|
+
if (p == null || !p.TryGetValue("instanceId", out var idObj))
|
|
152
|
+
throw new ArgumentException("Missing 'instanceId' parameter");
|
|
153
|
+
if (!p.TryGetValue("name", out var nameObj) || nameObj == null)
|
|
154
|
+
throw new ArgumentException("Missing 'name' parameter");
|
|
155
|
+
|
|
156
|
+
int instanceId = Convert.ToInt32(idObj);
|
|
157
|
+
var go = FindGameObject(instanceId);
|
|
158
|
+
|
|
159
|
+
Undo.RecordObject(go, "UCP Rename");
|
|
160
|
+
go.name = nameObj.ToString();
|
|
161
|
+
EditorUtility.SetDirty(go);
|
|
162
|
+
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene());
|
|
163
|
+
SceneChangeTracker.RecordGameObjectChange(go, "GameObject");
|
|
164
|
+
|
|
165
|
+
return new Dictionary<string, object>
|
|
166
|
+
{
|
|
167
|
+
["status"] = "ok",
|
|
168
|
+
["instanceId"] = instanceId,
|
|
169
|
+
["name"] = go.name
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ---- Reflection helpers ----
|
|
174
|
+
|
|
175
|
+
private static List<object> SerializeComponentFields(Component comp)
|
|
176
|
+
{
|
|
177
|
+
var fields = new List<object>();
|
|
178
|
+
var type = comp.GetType();
|
|
179
|
+
|
|
180
|
+
// Use SerializedObject for reliable Unity property enumeration
|
|
181
|
+
var so = new SerializedObject(comp);
|
|
182
|
+
var prop = so.GetIterator();
|
|
183
|
+
if (prop.NextVisible(true))
|
|
184
|
+
{
|
|
185
|
+
do
|
|
186
|
+
{
|
|
187
|
+
var fieldDict = new Dictionary<string, object>
|
|
188
|
+
{
|
|
189
|
+
["name"] = prop.name,
|
|
190
|
+
["displayName"] = prop.displayName,
|
|
191
|
+
["type"] = prop.propertyType.ToString(),
|
|
192
|
+
["editable"] = !prop.isReadOnly(true)
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
try
|
|
196
|
+
{
|
|
197
|
+
fieldDict["value"] = SerializedPropertyToValue(prop);
|
|
198
|
+
}
|
|
199
|
+
catch
|
|
200
|
+
{
|
|
201
|
+
fieldDict["value"] = "<unreadable>";
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
fields.Add(fieldDict);
|
|
205
|
+
}
|
|
206
|
+
while (prop.NextVisible(false));
|
|
207
|
+
}
|
|
208
|
+
so.Dispose();
|
|
209
|
+
|
|
210
|
+
return fields;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private static object SerializedPropertyToValue(SerializedProperty prop)
|
|
214
|
+
{
|
|
215
|
+
switch (prop.propertyType)
|
|
216
|
+
{
|
|
217
|
+
case SerializedPropertyType.Integer:
|
|
218
|
+
return prop.intValue;
|
|
219
|
+
case SerializedPropertyType.Boolean:
|
|
220
|
+
return prop.boolValue;
|
|
221
|
+
case SerializedPropertyType.Float:
|
|
222
|
+
return (double)prop.floatValue;
|
|
223
|
+
case SerializedPropertyType.String:
|
|
224
|
+
return prop.stringValue;
|
|
225
|
+
case SerializedPropertyType.Color:
|
|
226
|
+
var c = prop.colorValue;
|
|
227
|
+
return new List<object> { (double)c.r, (double)c.g, (double)c.b, (double)c.a };
|
|
228
|
+
case SerializedPropertyType.ObjectReference:
|
|
229
|
+
return ObjectReferenceResolver.Serialize(prop.objectReferenceValue);
|
|
230
|
+
case SerializedPropertyType.LayerMask:
|
|
231
|
+
return prop.intValue;
|
|
232
|
+
case SerializedPropertyType.Enum:
|
|
233
|
+
return prop.enumValueIndex < prop.enumDisplayNames.Length
|
|
234
|
+
? prop.enumDisplayNames[prop.enumValueIndex]
|
|
235
|
+
: prop.enumValueIndex.ToString();
|
|
236
|
+
case SerializedPropertyType.Vector2:
|
|
237
|
+
var v2 = prop.vector2Value;
|
|
238
|
+
return new List<object> { (double)v2.x, (double)v2.y };
|
|
239
|
+
case SerializedPropertyType.Vector3:
|
|
240
|
+
var v3 = prop.vector3Value;
|
|
241
|
+
return new List<object> { (double)v3.x, (double)v3.y, (double)v3.z };
|
|
242
|
+
case SerializedPropertyType.Vector4:
|
|
243
|
+
var v4 = prop.vector4Value;
|
|
244
|
+
return new List<object> { (double)v4.x, (double)v4.y, (double)v4.z, (double)v4.w };
|
|
245
|
+
case SerializedPropertyType.Rect:
|
|
246
|
+
var r = prop.rectValue;
|
|
247
|
+
return new Dictionary<string, object>
|
|
248
|
+
{
|
|
249
|
+
["x"] = (double)r.x,
|
|
250
|
+
["y"] = (double)r.y,
|
|
251
|
+
["width"] = (double)r.width,
|
|
252
|
+
["height"] = (double)r.height
|
|
253
|
+
};
|
|
254
|
+
case SerializedPropertyType.Bounds:
|
|
255
|
+
var b = prop.boundsValue;
|
|
256
|
+
return new Dictionary<string, object>
|
|
257
|
+
{
|
|
258
|
+
["center"] = new List<object> { (double)b.center.x, (double)b.center.y, (double)b.center.z },
|
|
259
|
+
["size"] = new List<object> { (double)b.size.x, (double)b.size.y, (double)b.size.z }
|
|
260
|
+
};
|
|
261
|
+
case SerializedPropertyType.Quaternion:
|
|
262
|
+
var q = prop.quaternionValue;
|
|
263
|
+
return new List<object> { (double)q.x, (double)q.y, (double)q.z, (double)q.w };
|
|
264
|
+
case SerializedPropertyType.AnimationCurve:
|
|
265
|
+
return "<AnimationCurve>";
|
|
266
|
+
case SerializedPropertyType.Gradient:
|
|
267
|
+
return "<Gradient>";
|
|
268
|
+
default:
|
|
269
|
+
return $"<{prop.propertyType}>";
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
private static object GetPropertyValue(Component comp, string propertyName)
|
|
274
|
+
{
|
|
275
|
+
var so = new SerializedObject(comp);
|
|
276
|
+
var prop = so.FindProperty(propertyName);
|
|
277
|
+
if (prop != null)
|
|
278
|
+
{
|
|
279
|
+
var val = SerializedPropertyToValue(prop);
|
|
280
|
+
so.Dispose();
|
|
281
|
+
return val;
|
|
282
|
+
}
|
|
283
|
+
so.Dispose();
|
|
284
|
+
|
|
285
|
+
// Fallback to reflection
|
|
286
|
+
var type = comp.GetType();
|
|
287
|
+
var fi = type.GetField(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
|
288
|
+
if (fi != null)
|
|
289
|
+
return fi.GetValue(comp);
|
|
290
|
+
|
|
291
|
+
var pi = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
|
|
292
|
+
if (pi != null && pi.CanRead)
|
|
293
|
+
return pi.GetValue(comp);
|
|
294
|
+
|
|
295
|
+
throw new ArgumentException($"Property '{propertyName}' not found on {type.Name}");
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
private static void SetPropertyValue(Component comp, string propertyName, object jsonValue)
|
|
299
|
+
{
|
|
300
|
+
var so = new SerializedObject(comp);
|
|
301
|
+
var prop = so.FindProperty(propertyName);
|
|
302
|
+
if (prop != null)
|
|
303
|
+
{
|
|
304
|
+
SetSerializedPropertyValue(prop, jsonValue);
|
|
305
|
+
so.ApplyModifiedProperties();
|
|
306
|
+
so.Dispose();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
so.Dispose();
|
|
310
|
+
|
|
311
|
+
// Fallback to reflection
|
|
312
|
+
var type = comp.GetType();
|
|
313
|
+
var fi = type.GetField(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
|
314
|
+
if (fi != null)
|
|
315
|
+
{
|
|
316
|
+
fi.SetValue(comp, ConvertFromJson(jsonValue, fi.FieldType));
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
var pi = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
|
|
321
|
+
if (pi != null && pi.CanWrite)
|
|
322
|
+
{
|
|
323
|
+
pi.SetValue(comp, ConvertFromJson(jsonValue, pi.PropertyType));
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
throw new ArgumentException($"Property '{propertyName}' not found or not writable on {type.Name}");
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
private static void SetSerializedPropertyValue(SerializedProperty prop, object value)
|
|
331
|
+
{
|
|
332
|
+
if (prop.isArray && prop.propertyType == SerializedPropertyType.Generic)
|
|
333
|
+
{
|
|
334
|
+
SetSerializedArrayValue(prop, value);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
switch (prop.propertyType)
|
|
339
|
+
{
|
|
340
|
+
case SerializedPropertyType.Integer:
|
|
341
|
+
prop.intValue = Convert.ToInt32(value);
|
|
342
|
+
break;
|
|
343
|
+
case SerializedPropertyType.Boolean:
|
|
344
|
+
prop.boolValue = Convert.ToBoolean(value);
|
|
345
|
+
break;
|
|
346
|
+
case SerializedPropertyType.Float:
|
|
347
|
+
prop.floatValue = Convert.ToSingle(value);
|
|
348
|
+
break;
|
|
349
|
+
case SerializedPropertyType.String:
|
|
350
|
+
prop.stringValue = value?.ToString() ?? "";
|
|
351
|
+
break;
|
|
352
|
+
case SerializedPropertyType.Color:
|
|
353
|
+
var cArr = value as List<object>;
|
|
354
|
+
if (cArr != null && cArr.Count >= 3)
|
|
355
|
+
prop.colorValue = new Color(
|
|
356
|
+
Convert.ToSingle(cArr[0]),
|
|
357
|
+
Convert.ToSingle(cArr[1]),
|
|
358
|
+
Convert.ToSingle(cArr[2]),
|
|
359
|
+
cArr.Count >= 4 ? Convert.ToSingle(cArr[3]) : 1f);
|
|
360
|
+
break;
|
|
361
|
+
case SerializedPropertyType.Enum:
|
|
362
|
+
if (value is string enumStr)
|
|
363
|
+
{
|
|
364
|
+
int idx = Array.IndexOf(prop.enumDisplayNames, enumStr);
|
|
365
|
+
if (idx >= 0)
|
|
366
|
+
prop.enumValueIndex = idx;
|
|
367
|
+
else if (int.TryParse(enumStr, out int enumIdx))
|
|
368
|
+
prop.enumValueIndex = enumIdx;
|
|
369
|
+
else
|
|
370
|
+
throw new ArgumentException($"Invalid enum value: {enumStr}");
|
|
371
|
+
}
|
|
372
|
+
else
|
|
373
|
+
{
|
|
374
|
+
prop.enumValueIndex = Convert.ToInt32(value);
|
|
375
|
+
}
|
|
376
|
+
break;
|
|
377
|
+
case SerializedPropertyType.Vector2:
|
|
378
|
+
var v2Arr = value as List<object>;
|
|
379
|
+
if (v2Arr != null && v2Arr.Count >= 2)
|
|
380
|
+
prop.vector2Value = new Vector2(
|
|
381
|
+
Convert.ToSingle(v2Arr[0]),
|
|
382
|
+
Convert.ToSingle(v2Arr[1]));
|
|
383
|
+
break;
|
|
384
|
+
case SerializedPropertyType.Vector3:
|
|
385
|
+
var v3Arr = value as List<object>;
|
|
386
|
+
if (v3Arr != null && v3Arr.Count >= 3)
|
|
387
|
+
prop.vector3Value = new Vector3(
|
|
388
|
+
Convert.ToSingle(v3Arr[0]),
|
|
389
|
+
Convert.ToSingle(v3Arr[1]),
|
|
390
|
+
Convert.ToSingle(v3Arr[2]));
|
|
391
|
+
break;
|
|
392
|
+
case SerializedPropertyType.Vector4:
|
|
393
|
+
var v4Arr = value as List<object>;
|
|
394
|
+
if (v4Arr != null && v4Arr.Count >= 4)
|
|
395
|
+
prop.vector4Value = new Vector4(
|
|
396
|
+
Convert.ToSingle(v4Arr[0]),
|
|
397
|
+
Convert.ToSingle(v4Arr[1]),
|
|
398
|
+
Convert.ToSingle(v4Arr[2]),
|
|
399
|
+
Convert.ToSingle(v4Arr[3]));
|
|
400
|
+
break;
|
|
401
|
+
case SerializedPropertyType.Quaternion:
|
|
402
|
+
var qArr = value as List<object>;
|
|
403
|
+
if (qArr != null && qArr.Count >= 4)
|
|
404
|
+
prop.quaternionValue = new Quaternion(
|
|
405
|
+
Convert.ToSingle(qArr[0]),
|
|
406
|
+
Convert.ToSingle(qArr[1]),
|
|
407
|
+
Convert.ToSingle(qArr[2]),
|
|
408
|
+
Convert.ToSingle(qArr[3]));
|
|
409
|
+
break;
|
|
410
|
+
case SerializedPropertyType.Rect:
|
|
411
|
+
var rDict = value as Dictionary<string, object>;
|
|
412
|
+
if (rDict != null)
|
|
413
|
+
prop.rectValue = new Rect(
|
|
414
|
+
Convert.ToSingle(rDict["x"]),
|
|
415
|
+
Convert.ToSingle(rDict["y"]),
|
|
416
|
+
Convert.ToSingle(rDict["width"]),
|
|
417
|
+
Convert.ToSingle(rDict["height"]));
|
|
418
|
+
break;
|
|
419
|
+
case SerializedPropertyType.Bounds:
|
|
420
|
+
var bDict = value as Dictionary<string, object>;
|
|
421
|
+
if (bDict != null)
|
|
422
|
+
{
|
|
423
|
+
var center = bDict["center"] as List<object>;
|
|
424
|
+
var size = bDict["size"] as List<object>;
|
|
425
|
+
if (center != null && size != null)
|
|
426
|
+
prop.boundsValue = new Bounds(
|
|
427
|
+
new Vector3(Convert.ToSingle(center[0]), Convert.ToSingle(center[1]), Convert.ToSingle(center[2])),
|
|
428
|
+
new Vector3(Convert.ToSingle(size[0]), Convert.ToSingle(size[1]), Convert.ToSingle(size[2])));
|
|
429
|
+
}
|
|
430
|
+
break;
|
|
431
|
+
case SerializedPropertyType.ObjectReference:
|
|
432
|
+
prop.objectReferenceValue = ObjectReferenceResolver.Resolve(value, prop.displayName);
|
|
433
|
+
if (value != null && prop.objectReferenceValue == null)
|
|
434
|
+
throw new ArgumentException($"Unable to assign object reference to '{prop.displayName}'");
|
|
435
|
+
break;
|
|
436
|
+
case SerializedPropertyType.LayerMask:
|
|
437
|
+
prop.intValue = Convert.ToInt32(value);
|
|
438
|
+
break;
|
|
439
|
+
default:
|
|
440
|
+
throw new ArgumentException($"Cannot set property of type {prop.propertyType}");
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
private static void SetSerializedArrayValue(SerializedProperty prop, object value)
|
|
445
|
+
{
|
|
446
|
+
if (!(value is IList items))
|
|
447
|
+
throw new ArgumentException($"Property '{prop.displayName}' expects an array value");
|
|
448
|
+
|
|
449
|
+
prop.arraySize = items.Count;
|
|
450
|
+
for (var index = 0; index < items.Count; index++)
|
|
451
|
+
{
|
|
452
|
+
var element = prop.GetArrayElementAtIndex(index);
|
|
453
|
+
SetSerializedPropertyValue(element, items[index]);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
private static object ConvertToJson(object value)
|
|
458
|
+
{
|
|
459
|
+
if (value == null) return null;
|
|
460
|
+
if (value is int || value is long || value is float || value is double ||
|
|
461
|
+
value is bool || value is string)
|
|
462
|
+
return value;
|
|
463
|
+
if (value is Vector2 v2)
|
|
464
|
+
return new List<object> { (double)v2.x, (double)v2.y };
|
|
465
|
+
if (value is Vector3 v3)
|
|
466
|
+
return new List<object> { (double)v3.x, (double)v3.y, (double)v3.z };
|
|
467
|
+
if (value is Vector4 v4)
|
|
468
|
+
return new List<object> { (double)v4.x, (double)v4.y, (double)v4.z, (double)v4.w };
|
|
469
|
+
if (value is Quaternion q)
|
|
470
|
+
return new List<object> { (double)q.x, (double)q.y, (double)q.z, (double)q.w };
|
|
471
|
+
if (value is Color c)
|
|
472
|
+
return new List<object> { (double)c.r, (double)c.g, (double)c.b, (double)c.a };
|
|
473
|
+
if (value is UnityEngine.Object uObj)
|
|
474
|
+
return ObjectReferenceResolver.Serialize(uObj);
|
|
475
|
+
return value.ToString();
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
private static object ConvertFromJson(object jsonValue, Type targetType)
|
|
479
|
+
{
|
|
480
|
+
if (jsonValue == null) return null;
|
|
481
|
+
if (targetType == typeof(int)) return Convert.ToInt32(jsonValue);
|
|
482
|
+
if (targetType == typeof(float)) return Convert.ToSingle(jsonValue);
|
|
483
|
+
if (targetType == typeof(double)) return Convert.ToDouble(jsonValue);
|
|
484
|
+
if (targetType == typeof(bool)) return Convert.ToBoolean(jsonValue);
|
|
485
|
+
if (targetType == typeof(string)) return jsonValue.ToString();
|
|
486
|
+
if (targetType == typeof(long)) return Convert.ToInt64(jsonValue);
|
|
487
|
+
|
|
488
|
+
if (targetType == typeof(Vector2) && jsonValue is List<object> v2)
|
|
489
|
+
return new Vector2(Convert.ToSingle(v2[0]), Convert.ToSingle(v2[1]));
|
|
490
|
+
if (targetType == typeof(Vector3) && jsonValue is List<object> v3)
|
|
491
|
+
return new Vector3(Convert.ToSingle(v3[0]), Convert.ToSingle(v3[1]), Convert.ToSingle(v3[2]));
|
|
492
|
+
if (targetType == typeof(Vector4) && jsonValue is List<object> v4)
|
|
493
|
+
return new Vector4(Convert.ToSingle(v4[0]), Convert.ToSingle(v4[1]), Convert.ToSingle(v4[2]), Convert.ToSingle(v4[3]));
|
|
494
|
+
if (targetType == typeof(Quaternion) && jsonValue is List<object> qv)
|
|
495
|
+
return new Quaternion(Convert.ToSingle(qv[0]), Convert.ToSingle(qv[1]), Convert.ToSingle(qv[2]), Convert.ToSingle(qv[3]));
|
|
496
|
+
if (targetType == typeof(Color) && jsonValue is List<object> cv)
|
|
497
|
+
return new Color(Convert.ToSingle(cv[0]), Convert.ToSingle(cv[1]), Convert.ToSingle(cv[2]),
|
|
498
|
+
cv.Count >= 4 ? Convert.ToSingle(cv[3]) : 1f);
|
|
499
|
+
|
|
500
|
+
return Convert.ChangeType(jsonValue, targetType);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
private static GameObject FindGameObject(int instanceId)
|
|
504
|
+
{
|
|
505
|
+
var obj = EditorUtility.EntityIdToObject(instanceId) as GameObject;
|
|
506
|
+
if (obj != null) return obj;
|
|
507
|
+
|
|
508
|
+
// Search in loaded scenes
|
|
509
|
+
for (int i = 0; i < SceneManager.sceneCount; i++)
|
|
510
|
+
{
|
|
511
|
+
var scene = SceneManager.GetSceneAt(i);
|
|
512
|
+
if (!scene.isLoaded) continue;
|
|
513
|
+
foreach (var root in scene.GetRootGameObjects())
|
|
514
|
+
{
|
|
515
|
+
var found = FindInHierarchy(root, instanceId);
|
|
516
|
+
if (found != null) return found;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
throw new ArgumentException($"GameObject not found: {instanceId}");
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
private static GameObject FindInHierarchy(GameObject go, int instanceId)
|
|
524
|
+
{
|
|
525
|
+
if (go.GetInstanceID() == instanceId) return go;
|
|
526
|
+
for (int i = 0; i < go.transform.childCount; i++)
|
|
527
|
+
{
|
|
528
|
+
var found = FindInHierarchy(go.transform.GetChild(i).gameObject, instanceId);
|
|
529
|
+
if (found != null) return found;
|
|
530
|
+
}
|
|
531
|
+
return null;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
private static Component FindComponent(GameObject go, string typeName)
|
|
535
|
+
{
|
|
536
|
+
foreach (var c in go.GetComponents<Component>())
|
|
537
|
+
{
|
|
538
|
+
if (c == null) continue;
|
|
539
|
+
if (c.GetType().Name == typeName || c.GetType().FullName == typeName)
|
|
540
|
+
return c;
|
|
541
|
+
}
|
|
542
|
+
throw new ArgumentException($"Component '{typeName}' not found on '{go.name}'");
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Extension-like helper for SerializedProperty.isReadOnly
|
|
546
|
+
// which doesn't exist as a public API in older Unity
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
internal static class SerializedPropertyExtensions
|
|
550
|
+
{
|
|
551
|
+
internal static bool isReadOnly(this SerializedProperty prop, bool includeChildren)
|
|
552
|
+
{
|
|
553
|
+
// Check if the property path suggests it's a built-in non-editable field
|
|
554
|
+
string path = prop.propertyPath;
|
|
555
|
+
if (path == "m_Script") return true;
|
|
556
|
+
if (path == "m_ObjectHideFlags") return true;
|
|
557
|
+
return false;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
|