PlayerDataEditorWindow.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #if UNITY_EDITOR
  2. using UnityEditor;
  3. using UnityEngine;
  4. using System.Reflection;
  5. using System.Collections.Generic;
  6. using System;
  7. using System.Collections;
  8. using System.IO;
  9. public class PlayerDataEditorWindow : EditorWindow
  10. {
  11. private AccountFileInfo.PlayerData playerData;
  12. private Vector2 scrollPos;
  13. private Dictionary<string, bool> foldoutStates = new Dictionary<string, bool>();
  14. private string DataFilePath = "/playerData.txt";
  15. [MenuItem("Tools/PlayerData 编辑器")]
  16. public static void ShowWindow()
  17. {
  18. GetWindow<PlayerDataEditorWindow>(true,"PlayerData 编辑器");
  19. }
  20. private void OnEnable()
  21. {
  22. LoadPlayerData();
  23. }
  24. private void OnGUI()
  25. {
  26. GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 14, padding = new RectOffset(5, 5, 5, 5) };
  27. GUIStyle sectionStyle = new GUIStyle(EditorStyles.helpBox) { margin = new RectOffset(5, 5, 5, 5), padding = new RectOffset(10, 10, 10, 10) };
  28. scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
  29. if (playerData == null)
  30. {
  31. EditorGUILayout.HelpBox("未加载 PlayerData!点击下方创建新数据。", MessageType.Warning);
  32. if (GUILayout.Button("创建新 PlayerData", GUILayout.Height(30)))
  33. {
  34. playerData = new AccountFileInfo.PlayerData();
  35. }
  36. EditorGUILayout.EndScrollView();
  37. return;
  38. }
  39. EditorGUILayout.LabelField("PlayerData 编辑器", headerStyle);
  40. EditorGUILayout.Space();
  41. EditorGUILayout.BeginVertical(sectionStyle);
  42. try
  43. {
  44. DrawFields(playerData, playerData.GetType(), "PlayerData.");
  45. }
  46. catch (Exception ex)
  47. {
  48. EditorGUILayout.HelpBox($"绘制字段时出错: {ex.Message}", MessageType.Error);
  49. }
  50. EditorGUILayout.EndVertical();
  51. EditorGUILayout.Space();
  52. EditorGUILayout.BeginHorizontal();
  53. if (GUILayout.Button("保存 PlayerData", GUILayout.Height(30)))
  54. {
  55. if (EditorUtility.DisplayDialog("保存确认", $"确定要保存到 {Application.persistentDataPath + DataFilePath}?\n现有文件将被覆盖。", "确定", "取消"))
  56. {
  57. SavePlayerData();
  58. }
  59. }
  60. if (GUILayout.Button("加载 PlayerData", GUILayout.Height(30)))
  61. {
  62. if (EditorUtility.DisplayDialog("加载确认", $"确定要从 {Application.persistentDataPath + DataFilePath} 加载数据?\n当前编辑的数据将被覆盖。", "确定", "取消"))
  63. {
  64. LoadPlayerData();
  65. }
  66. }
  67. EditorGUILayout.EndHorizontal();
  68. EditorGUILayout.EndScrollView();
  69. }
  70. private void DrawFields(object obj, Type type, string prefix = "")
  71. {
  72. if (obj == null)
  73. {
  74. EditorGUILayout.LabelField($"{prefix} (空)");
  75. return;
  76. }
  77. FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
  78. foreach (FieldInfo field in fields)
  79. {
  80. string fieldKey = $"{prefix}{field.Name}";
  81. object value = field.GetValue(obj);
  82. // 初始化折叠状态
  83. if (!foldoutStates.ContainsKey(fieldKey))
  84. foldoutStates[fieldKey] = false;
  85. // 处理基本类型
  86. if (field.FieldType == typeof(int))
  87. {
  88. EditorGUILayout.BeginHorizontal();
  89. EditorGUILayout.LabelField(field.Name, GUILayout.Width(200));
  90. int newValue = EditorGUILayout.IntField(value != null ? (int)value : 0);
  91. field.SetValue(obj, newValue);
  92. EditorGUILayout.EndHorizontal();
  93. }
  94. else if (field.FieldType == typeof(long))
  95. {
  96. EditorGUILayout.BeginHorizontal();
  97. EditorGUILayout.LabelField(field.Name, GUILayout.Width(200));
  98. long newValue = EditorGUILayout.LongField(value != null ? (long)value : 0);
  99. field.SetValue(obj, newValue);
  100. EditorGUILayout.EndHorizontal();
  101. }
  102. else if (field.FieldType == typeof(bool))
  103. {
  104. EditorGUILayout.BeginHorizontal();
  105. EditorGUILayout.LabelField(field.Name, GUILayout.Width(200));
  106. bool newValue = EditorGUILayout.Toggle(value != null ? (bool)value : false);
  107. field.SetValue(obj, newValue);
  108. EditorGUILayout.EndHorizontal();
  109. }
  110. else if (field.FieldType == typeof(float))
  111. {
  112. EditorGUILayout.BeginHorizontal();
  113. EditorGUILayout.LabelField(field.Name, GUILayout.Width(200));
  114. float newValue = EditorGUILayout.FloatField(value != null ? (float)value : 0f);
  115. field.SetValue(obj, newValue);
  116. EditorGUILayout.EndHorizontal();
  117. }
  118. else if (field.FieldType == typeof(string))
  119. {
  120. EditorGUILayout.BeginHorizontal();
  121. EditorGUILayout.LabelField(field.Name, GUILayout.Width(200));
  122. string newValue = EditorGUILayout.TextField(value != null ? (string)value : "");
  123. field.SetValue(obj, newValue);
  124. EditorGUILayout.EndHorizontal();
  125. }
  126. // 处理列表类型
  127. else if (field.FieldType.IsGenericType && field.FieldType.GetGenericTypeDefinition() == typeof(List<>))
  128. {
  129. Type itemType = field.FieldType.GetGenericArguments()[0];
  130. IList list = (IList)(value ?? Activator.CreateInstance(field.FieldType));
  131. EditorGUILayout.BeginHorizontal();
  132. foldoutStates[fieldKey] = EditorGUILayout.Foldout(foldoutStates[fieldKey], $"{field.Name} (列表, {list.Count} 项)", true);
  133. EditorGUILayout.EndHorizontal();
  134. if (foldoutStates[fieldKey])
  135. {
  136. EditorGUI.indentLevel++;
  137. EditorGUILayout.BeginHorizontal();
  138. EditorGUILayout.LabelField("大小", GUILayout.Width(200));
  139. int newSize = EditorGUILayout.IntField(list.Count);
  140. try
  141. {
  142. while (newSize > list.Count)
  143. {
  144. object newItem = Activator.CreateInstance(itemType);
  145. list.Add(newItem);
  146. }
  147. while (newSize < list.Count)
  148. {
  149. list.RemoveAt(list.Count - 1);
  150. }
  151. }
  152. catch (Exception ex)
  153. {
  154. EditorGUILayout.HelpBox($"修改列表大小时出错: {ex.Message}", MessageType.Error);
  155. }
  156. EditorGUILayout.EndHorizontal();
  157. for (int i = 0; i < list.Count; i++)
  158. {
  159. string itemKey = $"{fieldKey}[{i}]";
  160. if (!foldoutStates.ContainsKey(itemKey))
  161. foldoutStates[itemKey] = false;
  162. EditorGUILayout.BeginHorizontal();
  163. foldoutStates[itemKey] = EditorGUILayout.Foldout(foldoutStates[itemKey], $"{field.Name}[{i}]", true);
  164. if (GUILayout.Button("删除", GUILayout.Width(60)))
  165. {
  166. list.RemoveAt(i);
  167. foldoutStates.Remove(itemKey);
  168. break;
  169. }
  170. EditorGUILayout.EndHorizontal();
  171. if (foldoutStates[itemKey])
  172. {
  173. EditorGUI.indentLevel++;
  174. EditorGUILayout.BeginVertical(EditorStyles.helpBox);
  175. try
  176. {
  177. DrawFields(list[i], itemType, $"{prefix}{field.Name}[{i}].");
  178. }
  179. catch (Exception ex)
  180. {
  181. EditorGUILayout.HelpBox($"绘制 {itemKey} 时出错: {ex.Message}", MessageType.Error);
  182. }
  183. EditorGUILayout.EndVertical();
  184. EditorGUI.indentLevel--;
  185. }
  186. }
  187. if (GUILayout.Button($"添加新 {itemType.Name}", GUILayout.Height(25)))
  188. {
  189. try
  190. {
  191. object newItem = Activator.CreateInstance(itemType);
  192. list.Add(newItem);
  193. }
  194. catch (Exception ex)
  195. {
  196. EditorGUILayout.HelpBox($"添加新 {itemType.Name} 时出错: {ex.Message}", MessageType.Error);
  197. }
  198. }
  199. field.SetValue(obj, list);
  200. EditorGUI.indentLevel--;
  201. }
  202. }
  203. // 处理自定义类
  204. else if (field.FieldType.IsClass)
  205. {
  206. EditorGUILayout.BeginHorizontal();
  207. foldoutStates[fieldKey] = EditorGUILayout.Foldout(foldoutStates[fieldKey], $"{field.Name} ({field.FieldType.Name})", true);
  208. if (value == null && GUILayout.Button("创建", GUILayout.Width(60)))
  209. {
  210. value = Activator.CreateInstance(field.FieldType);
  211. field.SetValue(obj, value);
  212. }
  213. EditorGUILayout.EndHorizontal();
  214. if (foldoutStates[fieldKey] && value != null)
  215. {
  216. EditorGUI.indentLevel++;
  217. EditorGUILayout.BeginVertical(EditorStyles.helpBox);
  218. try
  219. {
  220. DrawFields(value, field.FieldType, $"{prefix}{field.Name}.");
  221. }
  222. catch (Exception ex)
  223. {
  224. EditorGUILayout.HelpBox($"绘制 {fieldKey} 时出错: {ex.Message}", MessageType.Error);
  225. }
  226. EditorGUILayout.EndVertical();
  227. EditorGUI.indentLevel--;
  228. }
  229. }
  230. else
  231. {
  232. EditorGUILayout.LabelField($"{field.Name} ({field.FieldType.Name})", "不支持的类型");
  233. }
  234. }
  235. }
  236. private void SavePlayerData()
  237. {
  238. try
  239. {
  240. string json = JsonUtility.ToJson(playerData, true);
  241. string path = Application.persistentDataPath + DataFilePath;
  242. File.WriteAllText(path, json);
  243. Debug.Log($"PlayerData 已保存至 {path}");
  244. EditorUtility.DisplayDialog("保存成功", $"PlayerData 已保存至 {path}", "确定");
  245. }
  246. catch (Exception ex)
  247. {
  248. EditorGUILayout.HelpBox($"保存 PlayerData 时出错: {ex.Message}", MessageType.Error);
  249. EditorUtility.DisplayDialog("保存失败", $"保存 PlayerData 时出错: {ex.Message}", "确定");
  250. }
  251. }
  252. private void LoadPlayerData()
  253. {
  254. if (!Application.isPlaying)
  255. {
  256. if(playerData == null)
  257. playerData = new AccountFileInfo.PlayerData();
  258. try
  259. {
  260. string path = Application.persistentDataPath + DataFilePath;
  261. if (File.Exists(path))
  262. {
  263. string json = File.ReadAllText(path);
  264. JsonUtility.FromJsonOverwrite(json, playerData);
  265. }
  266. else
  267. {
  268. EditorGUILayout.HelpBox($"未找到文件: {path}", MessageType.Warning);
  269. EditorUtility.DisplayDialog("加载失败", $"未找到文件: {path}", "确定");
  270. }
  271. }
  272. catch (Exception ex)
  273. {
  274. EditorGUILayout.HelpBox($"加载 PlayerData 时出错: {ex.Message}", MessageType.Error);
  275. EditorUtility.DisplayDialog("加载失败", $"加载 PlayerData 时出错: {ex.Message}", "确定");
  276. }
  277. }
  278. else
  279. {
  280. playerData = AccountFileInfo.Instance.playerData;
  281. }
  282. }
  283. }
  284. #endif