mirror of
https://github.com/XCharts-Team/XCharts.git
synced 2026-05-14 20:00:09 +00:00
增加Chart的Json导出导入
This commit is contained in:
@@ -778,5 +778,27 @@ namespace XCharts.Runtime
|
||||
foreach (var component in m_Components) component.ResetStatus();
|
||||
foreach (var handler in m_SerieHandlers) handler.ForceUpdateSerieContext();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Export chart configuration and data to JSON string.
|
||||
/// ||导出图表配置和数据为JSON字符串。
|
||||
/// </summary>
|
||||
[Since("v3.16.0")]
|
||||
public string ExportToJson(bool prettyPrint = true)
|
||||
{
|
||||
return XCharts.Runtime.ChartJsonSerializer.Serialize(this, prettyPrint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Import JSON and update current chart configuration.
|
||||
/// ||导入JSON并更新当前图表配置。
|
||||
/// </summary>
|
||||
[Since("v3.16.0")]
|
||||
public void ImportFromJson(string json)
|
||||
{
|
||||
XCharts.Runtime.ChartJsonDeserializer.Deserialize(json, this);
|
||||
RefreshAllComponent();
|
||||
RefreshChart();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,5 +154,25 @@ namespace XCharts.Runtime
|
||||
}
|
||||
|
||||
protected virtual void OnThemeChanged() { }
|
||||
|
||||
/// <summary>
|
||||
/// Export UI component configuration to JSON string.
|
||||
/// </summary>
|
||||
[Since("v3.16.0")]
|
||||
public string ExportToJson(bool prettyPrint = true)
|
||||
{
|
||||
return UIComponentJsonSerializer.Serialize(this, prettyPrint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Import JSON and update current UI component configuration.
|
||||
/// </summary>
|
||||
[Since("v3.16.0")]
|
||||
public void ImportFromJson(string json)
|
||||
{
|
||||
UIComponentJsonDeserializer.Deserialize(json, this);
|
||||
RefreshAllComponent();
|
||||
RefreshGraph();
|
||||
}
|
||||
}
|
||||
}
|
||||
1562
Runtime/Utilities/ChartJsonKit.cs
Normal file
1562
Runtime/Utilities/ChartJsonKit.cs
Normal file
File diff suppressed because it is too large
Load Diff
11
Runtime/Utilities/ChartJsonKit.cs.meta
Normal file
11
Runtime/Utilities/ChartJsonKit.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 529ec33cd4fb6466784b3a682204428c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
291
Runtime/Utilities/ResourceRefHandler.cs
Normal file
291
Runtime/Utilities/ResourceRefHandler.cs
Normal file
@@ -0,0 +1,291 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
#if dUI_TextMeshPro
|
||||
using TMPro;
|
||||
#endif
|
||||
|
||||
namespace XCharts.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Portable resource reference that supports a multi-level lookup strategy:
|
||||
/// GUID → path → name → fallbackName → null/default
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ResourceRef
|
||||
{
|
||||
/// <summary>Unity AssetDatabase GUID (editor-only, same project).</summary>
|
||||
public string guid;
|
||||
/// <summary>Asset path relative to project root e.g. "Assets/Fonts/Arial.ttf".</summary>
|
||||
public string path;
|
||||
/// <summary>Asset.name used for cross-project name search.</summary>
|
||||
public string name;
|
||||
/// <summary>Optional secondary name (system font alias, built-in default, etc.).</summary>
|
||||
public string fallbackName;
|
||||
/// <summary>Optional Base64-encoded asset bytes for full portability (< 100 KB recommended).</summary>
|
||||
public string base64;
|
||||
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return string.IsNullOrEmpty(guid)
|
||||
&& string.IsNullOrEmpty(path)
|
||||
&& string.IsNullOrEmpty(name)
|
||||
&& string.IsNullOrEmpty(fallbackName)
|
||||
&& string.IsNullOrEmpty(base64);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("ResourceRef{{name={0}, path={1}, guid={2}}}", name, path, guid);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles serialization and resolution of Unity asset references for chart JSON export/import.
|
||||
/// Supports Font, TMP_FontAsset, Sprite, Material, Texture2D.
|
||||
/// </summary>
|
||||
public static class ResourceRefHandler
|
||||
{
|
||||
// ─── Serialize ─────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Serializes a Unity Object into a portable ResourceRef.
|
||||
/// </summary>
|
||||
public static ResourceRef Serialize(UnityEngine.Object asset, bool includeBase64 = false)
|
||||
{
|
||||
if (asset == null) return null;
|
||||
|
||||
var refData = new ResourceRef
|
||||
{
|
||||
name = asset.name
|
||||
};
|
||||
|
||||
#if UNITY_EDITOR
|
||||
var assetPath = AssetDatabase.GetAssetPath(asset);
|
||||
if (!string.IsNullOrEmpty(assetPath))
|
||||
{
|
||||
refData.path = assetPath;
|
||||
refData.guid = AssetDatabase.AssetPathToGUID(assetPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Optional base64 embedding for portability
|
||||
if (includeBase64)
|
||||
{
|
||||
var b64 = TryEncodeBase64(asset);
|
||||
if (!string.IsNullOrEmpty(b64))
|
||||
refData.base64 = b64;
|
||||
}
|
||||
|
||||
return refData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes a Font with a fallback name hint.
|
||||
/// </summary>
|
||||
public static ResourceRef SerializeFont(Font font, string fallbackName = null)
|
||||
{
|
||||
if (font == null) return null;
|
||||
var refData = Serialize(font) ?? new ResourceRef();
|
||||
refData.fallbackName = fallbackName ?? "Arial";
|
||||
return refData;
|
||||
}
|
||||
|
||||
#if dUI_TextMeshPro
|
||||
/// <summary>
|
||||
/// Serializes a TMP_FontAsset with a fallback name hint.
|
||||
/// </summary>
|
||||
public static ResourceRef SerializeTMPFont(TMP_FontAsset font, string fallbackName = null)
|
||||
{
|
||||
if (font == null) return null;
|
||||
var refData = Serialize(font) ?? new ResourceRef();
|
||||
refData.fallbackName = fallbackName ?? "LiberationSans SDF";
|
||||
return refData;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ─── Resolve ────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to resolve a ResourceRef back to a Unity asset using the fallback chain:<br/>
|
||||
/// GUID → path → name → fallbackName → null
|
||||
/// </summary>
|
||||
public static T TryResolve<T>(ResourceRef refData) where T : UnityEngine.Object
|
||||
{
|
||||
if (refData == null || refData.IsEmpty()) return null;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// 1. GUID lookup (same project, exact)
|
||||
if (!string.IsNullOrEmpty(refData.guid))
|
||||
{
|
||||
var guidPath = AssetDatabase.GUIDToAssetPath(refData.guid);
|
||||
if (!string.IsNullOrEmpty(guidPath))
|
||||
{
|
||||
var asset = AssetDatabase.LoadAssetAtPath<T>(guidPath);
|
||||
if (asset != null) return asset;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Path-based lookup
|
||||
if (!string.IsNullOrEmpty(refData.path))
|
||||
{
|
||||
var asset = AssetDatabase.LoadAssetAtPath<T>(refData.path);
|
||||
if (asset != null) return asset;
|
||||
}
|
||||
|
||||
// 3. Name-based search across project
|
||||
if (!string.IsNullOrEmpty(refData.name))
|
||||
{
|
||||
var found = FindAssetByName<T>(refData.name);
|
||||
if (found != null) return found;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 4. Resources.Load by name
|
||||
if (!string.IsNullOrEmpty(refData.name))
|
||||
{
|
||||
var asset = Resources.Load<T>(refData.name);
|
||||
if (asset != null) return asset;
|
||||
}
|
||||
|
||||
// 5. Fallback name
|
||||
if (!string.IsNullOrEmpty(refData.fallbackName))
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var found = FindAssetByName<T>(refData.fallbackName);
|
||||
if (found != null) return found;
|
||||
#endif
|
||||
var asset = Resources.Load<T>(refData.fallbackName);
|
||||
if (asset != null) return asset;
|
||||
}
|
||||
|
||||
// 6. Base64 decode
|
||||
if (!string.IsNullOrEmpty(refData.base64))
|
||||
{
|
||||
var decoded = TryDecodeBase64<T>(refData.base64, refData.name ?? "imported_asset");
|
||||
if (decoded != null) return decoded;
|
||||
}
|
||||
|
||||
if (!IsUnityBuiltinDefaultResourceRef(refData))
|
||||
Debug.LogWarning(string.Format("[XCharts] ResourceRefHandler: Could not resolve asset '{0}'. Using default.", refData));
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool IsUnityBuiltinDefaultResourceRef(ResourceRef refData)
|
||||
{
|
||||
if (refData == null) return false;
|
||||
|
||||
bool pathIsBuiltin = !string.IsNullOrEmpty(refData.path)
|
||||
&& refData.path.IndexOf("Library/unity default resources", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
|
||||
bool guidIsBuiltin = !string.IsNullOrEmpty(refData.guid)
|
||||
&& string.Equals(refData.guid, "0000000000000000e000000000000000", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
bool nameIsBuiltinFont = string.Equals(refData.name, "Arial", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(refData.fallbackName, "Arial", StringComparison.OrdinalIgnoreCase)
|
||||
#if dUI_TextMeshPro
|
||||
|| string.Equals(refData.name, "LiberationSans SDF", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(refData.fallbackName, "LiberationSans SDF", StringComparison.OrdinalIgnoreCase)
|
||||
#endif
|
||||
;
|
||||
|
||||
return pathIsBuiltin || guidIsBuiltin || nameIsBuiltinFont;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private static T FindAssetByName<T>(string assetName) where T : UnityEngine.Object
|
||||
{
|
||||
string typeName = typeof(T).Name;
|
||||
var guids = AssetDatabase.FindAssets(string.Format("{0} t:{1}", assetName, typeName));
|
||||
foreach (var g in guids)
|
||||
{
|
||||
var p = AssetDatabase.GUIDToAssetPath(g);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<T>(p);
|
||||
if (asset != null && asset.name == assetName)
|
||||
return asset;
|
||||
}
|
||||
// Looser match (name contains)
|
||||
foreach (var g in guids)
|
||||
{
|
||||
var p = AssetDatabase.GUIDToAssetPath(g);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<T>(p);
|
||||
if (asset != null) return asset;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ─── Base64 helpers ──────────────────────────────────────────────────────────
|
||||
|
||||
private static string TryEncodeBase64(UnityEngine.Object asset)
|
||||
{
|
||||
var texture = asset as Texture2D;
|
||||
if (texture != null)
|
||||
return Convert.ToBase64String(texture.EncodeToPNG());
|
||||
// Font/Material: not trivially serializable as bytes at runtime; skip.
|
||||
return null;
|
||||
}
|
||||
|
||||
private static T TryDecodeBase64<T>(string base64, string assetName) where T : UnityEngine.Object
|
||||
{
|
||||
try
|
||||
{
|
||||
if (typeof(T) == typeof(Texture2D) || typeof(T) == typeof(Sprite))
|
||||
{
|
||||
var bytes = Convert.FromBase64String(base64);
|
||||
var tex = new Texture2D(2, 2);
|
||||
if (tex.LoadImage(bytes))
|
||||
{
|
||||
tex.name = assetName;
|
||||
if (typeof(T) == typeof(Sprite))
|
||||
{
|
||||
var sprite = Sprite.Create(tex,
|
||||
new Rect(0, 0, tex.width, tex.height),
|
||||
new Vector2(0.5f, 0.5f));
|
||||
sprite.name = assetName;
|
||||
return sprite as T;
|
||||
}
|
||||
return tex as T;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning(string.Format("[XCharts] ResourceRefHandler: Base64 decode failed: {0}", ex.Message));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ─── Convenience overloads ───────────────────────────────────────────────────
|
||||
|
||||
public static Font TryResolveFont(ResourceRef refData)
|
||||
{
|
||||
return TryResolve<Font>(refData);
|
||||
}
|
||||
|
||||
public static Sprite TryResolveSprite(ResourceRef refData)
|
||||
{
|
||||
return TryResolve<Sprite>(refData);
|
||||
}
|
||||
|
||||
public static Material TryResolveMaterial(ResourceRef refData)
|
||||
{
|
||||
return TryResolve<Material>(refData);
|
||||
}
|
||||
|
||||
public static Texture2D TryResolveTexture(ResourceRef refData)
|
||||
{
|
||||
return TryResolve<Texture2D>(refData);
|
||||
}
|
||||
|
||||
#if dUI_TextMeshPro
|
||||
public static TMP_FontAsset TryResolveTMPFont(ResourceRef refData)
|
||||
{
|
||||
return TryResolve<TMP_FontAsset>(refData);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
11
Runtime/Utilities/ResourceRefHandler.cs.meta
Normal file
11
Runtime/Utilities/ResourceRefHandler.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9c3e7340177cb43e488f9f9547ceea7b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
299
Runtime/Utilities/UIComponentJsonKit.cs
Normal file
299
Runtime/Utilities/UIComponentJsonKit.cs
Normal file
@@ -0,0 +1,299 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace XCharts.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public class UIComponentJson
|
||||
{
|
||||
public string schemaVersion = "1.0";
|
||||
public string componentType;
|
||||
public string componentVersion;
|
||||
public string exportedAt;
|
||||
public string data;
|
||||
}
|
||||
|
||||
public static class UIComponentJsonSerializer
|
||||
{
|
||||
public static string Serialize(UIComponent component, bool prettyPrint = true)
|
||||
{
|
||||
if (component == null) throw new ArgumentNullException("component");
|
||||
|
||||
var currentJson = JsonUtility.ToJson(component);
|
||||
var defaultJson = GetDefaultInstanceJson(component.GetType());
|
||||
var dataJson = BuildDataJson(component.GetType(), currentJson, defaultJson);
|
||||
|
||||
var dto = new UIComponentJson
|
||||
{
|
||||
schemaVersion = "1.0",
|
||||
componentType = component.GetType().Name,
|
||||
componentVersion = XChartsMgr.version,
|
||||
exportedAt = DateTime.UtcNow.ToString("o"),
|
||||
data = dataJson
|
||||
};
|
||||
|
||||
var json = JsonUtility.ToJson(dto, prettyPrint);
|
||||
json = ChartJsonDataFieldCodec.ConvertEscapedDataStringToRawObject(json);
|
||||
if (prettyPrint)
|
||||
{
|
||||
object parsedJson;
|
||||
if (SimpleJson.TryParse(json, out parsedJson))
|
||||
json = SimpleJson.Stringify(parsedJson, true);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
private static string BuildDataJson(Type componentType, string currentJson, string defaultJson)
|
||||
{
|
||||
if (componentType == null)
|
||||
return JsonDiffPruner.PruneDefaults(currentJson, defaultJson);
|
||||
|
||||
if (string.Equals(componentType.Name, "UITable", StringComparison.Ordinal))
|
||||
return PruneUITableData(componentType, currentJson, defaultJson);
|
||||
|
||||
return JsonDiffPruner.PruneDefaults(currentJson, defaultJson);
|
||||
}
|
||||
|
||||
private static string PruneUITableData(Type tableType, string currentJson, string defaultJson)
|
||||
{
|
||||
object currentParsed;
|
||||
object defaultParsed;
|
||||
if (!SimpleJson.TryParse(currentJson, out currentParsed))
|
||||
return JsonDiffPruner.PruneDefaults(currentJson, defaultJson);
|
||||
if (!SimpleJson.TryParse(defaultJson, out defaultParsed))
|
||||
return JsonDiffPruner.PruneDefaults(currentJson, defaultJson);
|
||||
|
||||
var currentRoot = currentParsed as System.Collections.Generic.Dictionary<string, object>;
|
||||
var defaultRoot = defaultParsed as System.Collections.Generic.Dictionary<string, object>;
|
||||
if (currentRoot == null)
|
||||
return JsonDiffPruner.PruneDefaults(currentJson, defaultJson);
|
||||
|
||||
var prunedRootObj = JsonDiffPruner.PruneParsedDefaults(currentRoot, defaultRoot);
|
||||
var prunedRoot = prunedRootObj as System.Collections.Generic.Dictionary<string, object>;
|
||||
if (prunedRoot == null)
|
||||
prunedRoot = new System.Collections.Generic.Dictionary<string, object>();
|
||||
|
||||
object currentRowsObj;
|
||||
if (!currentRoot.TryGetValue("m_Data", out currentRowsObj))
|
||||
return SimpleJson.Stringify(prunedRoot);
|
||||
|
||||
var currentRows = currentRowsObj as System.Collections.Generic.List<object>;
|
||||
if (currentRows == null)
|
||||
return SimpleJson.Stringify(prunedRoot);
|
||||
|
||||
var rowDefaultObj = CreateDefaultParsedObject(tableType.Assembly, "XCharts.Runtime.UI.TableRow");
|
||||
if (rowDefaultObj == null)
|
||||
return JsonDiffPruner.PruneDefaults(currentJson, defaultJson);
|
||||
|
||||
var cellDefaultObj = CreateDefaultParsedObject(tableType.Assembly, "XCharts.Runtime.UI.TableCell");
|
||||
|
||||
var prunedRows = new System.Collections.Generic.List<object>(currentRows.Count);
|
||||
for (int i = 0; i < currentRows.Count; i++)
|
||||
{
|
||||
var prunedRow = PruneTableRowKeepCellShape(currentRows[i], rowDefaultObj, cellDefaultObj);
|
||||
prunedRows.Add(prunedRow ?? new System.Collections.Generic.Dictionary<string, object>());
|
||||
}
|
||||
|
||||
prunedRoot["m_Data"] = prunedRows;
|
||||
return SimpleJson.Stringify(prunedRoot);
|
||||
}
|
||||
|
||||
private static object PruneTableRowKeepCellShape(object rowObj, object rowDefaultObj, object cellDefaultObj)
|
||||
{
|
||||
var rowDict = rowObj as System.Collections.Generic.Dictionary<string, object>;
|
||||
if (rowDict == null)
|
||||
return JsonDiffPruner.PruneParsedDefaults(rowObj, rowDefaultObj);
|
||||
|
||||
object rawCells;
|
||||
rowDict.TryGetValue("m_Data", out rawCells);
|
||||
var currentCells = rawCells as System.Collections.Generic.List<object>;
|
||||
|
||||
var prunedRowObj = JsonDiffPruner.PruneParsedDefaults(rowObj, rowDefaultObj);
|
||||
var prunedRowDict = prunedRowObj as System.Collections.Generic.Dictionary<string, object>;
|
||||
if (prunedRowDict == null)
|
||||
prunedRowDict = new System.Collections.Generic.Dictionary<string, object>();
|
||||
|
||||
if (currentCells != null)
|
||||
{
|
||||
var prunedCells = new System.Collections.Generic.List<object>(currentCells.Count);
|
||||
for (int i = 0; i < currentCells.Count; i++)
|
||||
{
|
||||
var prunedCell = cellDefaultObj != null
|
||||
? JsonDiffPruner.PruneParsedDefaults(currentCells[i], cellDefaultObj)
|
||||
: JsonDiffPruner.PruneParsedDefaults(currentCells[i], null);
|
||||
prunedCells.Add(prunedCell ?? new System.Collections.Generic.Dictionary<string, object>());
|
||||
}
|
||||
prunedRowDict["m_Data"] = prunedCells;
|
||||
}
|
||||
|
||||
if (prunedRowDict.Count == 0)
|
||||
return null;
|
||||
return prunedRowDict;
|
||||
}
|
||||
|
||||
private static object CreateDefaultParsedObject(Assembly assembly, string fullTypeName)
|
||||
{
|
||||
if (assembly == null || string.IsNullOrEmpty(fullTypeName))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var type = assembly.GetType(fullTypeName);
|
||||
if (type == null)
|
||||
return null;
|
||||
|
||||
var instance = Activator.CreateInstance(type);
|
||||
if (instance == null)
|
||||
return null;
|
||||
|
||||
var json = JsonUtility.ToJson(instance);
|
||||
object parsed;
|
||||
if (!SimpleJson.TryParse(json, out parsed))
|
||||
return null;
|
||||
return parsed;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDefaultInstanceJson(Type type)
|
||||
{
|
||||
if (type == null) return "{}";
|
||||
|
||||
GameObject tempObject = null;
|
||||
try
|
||||
{
|
||||
if (typeof(MonoBehaviour).IsAssignableFrom(type))
|
||||
{
|
||||
tempObject = new GameObject("__XCharts_UIJson_Default__");
|
||||
tempObject.hideFlags = HideFlags.HideAndDontSave;
|
||||
var defaultComponent = tempObject.AddComponent(type) as UIComponent;
|
||||
if (defaultComponent != null)
|
||||
return JsonUtility.ToJson(defaultComponent);
|
||||
return "{}";
|
||||
}
|
||||
|
||||
var instance = Activator.CreateInstance(type);
|
||||
if (instance == null)
|
||||
return "{}";
|
||||
return JsonUtility.ToJson(instance);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "{}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (tempObject != null)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
UnityEngine.Object.DestroyImmediate(tempObject);
|
||||
#else
|
||||
UnityEngine.Object.Destroy(tempObject);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class UIComponentJsonDeserializer
|
||||
{
|
||||
private const string LOG_TAG = "[XCharts] UIComponentJsonDeserializer";
|
||||
|
||||
public static void Deserialize(string json, UIComponent target)
|
||||
{
|
||||
if (string.IsNullOrEmpty(json)) throw new ArgumentNullException("json");
|
||||
if (target == null) throw new ArgumentNullException("target");
|
||||
|
||||
json = ChartJsonDataFieldCodec.ConvertRawObjectDataToEscapedString(json);
|
||||
|
||||
UIComponentJson dto;
|
||||
try
|
||||
{
|
||||
dto = JsonUtility.FromJson<UIComponentJson>(json);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ArgumentException(string.Format("Invalid JSON format: {0}", ex.Message), ex);
|
||||
}
|
||||
|
||||
if (dto == null || string.IsNullOrEmpty(dto.schemaVersion))
|
||||
throw new ArgumentException("JSON does not appear to be a valid XCharts UI component export (missing schemaVersion).");
|
||||
if (!dto.schemaVersion.StartsWith("1."))
|
||||
throw new ArgumentException(string.Format("Unsupported schema version '{0}'. This version only supports '1.x'.", dto.schemaVersion));
|
||||
|
||||
ValidateComponentType(dto.componentType, target);
|
||||
|
||||
if (!string.IsNullOrEmpty(dto.data))
|
||||
JsonUtility.FromJsonOverwrite(dto.data, target);
|
||||
|
||||
target.RefreshAllComponent();
|
||||
target.RefreshGraph();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(target);
|
||||
#endif
|
||||
Debug.Log(string.Format("{0}: Import complete for '{1}'.", LOG_TAG, target.GetType().Name));
|
||||
}
|
||||
|
||||
private static void ValidateComponentType(string typeName, UIComponent target)
|
||||
{
|
||||
if (string.IsNullOrEmpty(typeName) || target == null) return;
|
||||
|
||||
var resolved = ResolveType(typeName);
|
||||
if (resolved == null) return;
|
||||
|
||||
if (!resolved.IsAssignableFrom(target.GetType()))
|
||||
throw new ArgumentException(string.Format("JSON is for UI component '{0}', target is '{1}'.", resolved.Name, target.GetType().Name));
|
||||
}
|
||||
|
||||
private static Type ResolveType(string typeName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(typeName)) return null;
|
||||
|
||||
var type = Type.GetType(typeName);
|
||||
if (type != null) return type;
|
||||
|
||||
var shortName = typeName.Split(',')[0].Trim();
|
||||
var simpleName = shortName.Contains(".") ? shortName.Substring(shortName.LastIndexOf(".") + 1) : shortName;
|
||||
|
||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
try
|
||||
{
|
||||
type = asm.GetType(shortName);
|
||||
if (type != null) return type;
|
||||
|
||||
var types = asm.GetTypes();
|
||||
for (int i = 0; i < types.Length; i++)
|
||||
{
|
||||
var candidate = types[i];
|
||||
if (candidate == null) continue;
|
||||
if (string.Equals(candidate.Name, simpleName, StringComparison.Ordinal))
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
catch (ReflectionTypeLoadException rtle)
|
||||
{
|
||||
var partialTypes = rtle.Types;
|
||||
if (partialTypes == null) continue;
|
||||
for (int i = 0; i < partialTypes.Length; i++)
|
||||
{
|
||||
var candidate = partialTypes[i];
|
||||
if (candidate == null) continue;
|
||||
if (string.Equals(candidate.Name, simpleName, StringComparison.Ordinal))
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/Utilities/UIComponentJsonKit.cs.meta
Normal file
11
Runtime/Utilities/UIComponentJsonKit.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20febe04d2ef346e196ab69da9c1d7d4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user