RealWorldTerrainPrefs.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. /* INFINITY CODE */
  2. /* https://infinity-code.com */
  3. using System;
  4. using System.Collections;
  5. using System.Globalization;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Reflection;
  9. using System.Text;
  10. using System.Xml;
  11. using UnityEditor;
  12. using UnityEngine;
  13. namespace InfinityCode.RealWorldTerrain
  14. {
  15. public class RealWorldTerrainPrefs : RealWorldTerrainPrefsBase
  16. {
  17. public const string prefsFilename = "RealWorldTerrainPrefs.xml";
  18. private const string prefix = "RWT_";
  19. private static string _mapboxAccessToken;
  20. [IgnoreInXML]
  21. public bool allowChange = true;
  22. [IgnoreInXML]
  23. public Vector2 coordinatesFrom = new Vector2(-113.6438f, 36.0358f);
  24. [IgnoreInXML]
  25. public Vector2 coordinatesTo = new Vector2(-113.0670f, 35.5680f);
  26. public double leftLongitude = -113.6438;
  27. public double rightLongitude = -113.0670;
  28. public double topLatitude = 36.0358;
  29. public double bottomLatitude = 35.5680;
  30. public bool useAnchor;
  31. public double anchorLatitude;
  32. public double anchorLongitude;
  33. public bool generateBuildings;
  34. public bool generateGrass;
  35. public bool generateRivers;
  36. public bool generateRoads;
  37. public bool generateTextures = false;
  38. public bool generateTrees;
  39. public RealWorldTerrainVector2i terrainCount = RealWorldTerrainVector2i.one;
  40. [IgnoreInXML]
  41. private RealWorldTerrainTextureProviderManager.MapType _mapType;
  42. public static string mapboxAccessToken
  43. {
  44. get
  45. {
  46. if (_mapboxAccessToken == null) _mapboxAccessToken = LoadPref("MapboxAPI", "");
  47. return _mapboxAccessToken;
  48. }
  49. }
  50. public RealWorldTerrainTextureProviderManager.MapType mapType
  51. {
  52. get
  53. {
  54. if (_mapType == null)
  55. {
  56. _mapType = RealWorldTerrainTextureProviderManager.FindMapType(mapTypeID);
  57. _mapType.LoadSettings(mapTypeExtraFields);
  58. }
  59. return _mapType;
  60. }
  61. set { _mapType = value; }
  62. }
  63. public void Apply(RealWorldTerrainMonoBase target)
  64. {
  65. target.prefs = new RealWorldTerrainPrefsBase();
  66. FieldInfo[] fieldInfos = typeof(RealWorldTerrainPrefsBase).GetFields(BindingFlags.Instance | BindingFlags.Public);
  67. foreach (FieldInfo info in fieldInfos) info.SetValue(target.prefs, info.GetValue(this));
  68. target.generatedBuildings = target.generatedBuildings || generateBuildings;
  69. target.generateGrass = target.generateGrass || generateGrass;
  70. target.generateRoads = target.generateRoads || generateRoads;
  71. target.generateTextures = generateTextures;
  72. target.generateTrees = target.generateTrees || generateTrees;
  73. }
  74. private void CreateChildNode(XmlNode node, string name, object value)
  75. {
  76. if (value == null) return;
  77. if (value is string) CreateNode(node, name, value as string, true);
  78. else if (value is bool || value is int || value is long || value is short || value is Enum) CreateNode(node, name, value);
  79. else if (value is float) CreateNode(node, name, ((float)value).ToString(RealWorldTerrainCultureInfo.numberFormat));
  80. else if (value is double) CreateNode(node, name, ((double)value).ToString(RealWorldTerrainCultureInfo.numberFormat));
  81. else if (value is UnityEngine.Object) CreateNode(node, name, AssetDatabase.GetAssetPath(value as UnityEngine.Object), true);
  82. else if (value is IEnumerable)
  83. {
  84. IEnumerable v = (IEnumerable)value;
  85. XmlNode n = CreateNode(node, name);
  86. foreach (var item in v) CreateChildNode(n, "Item", item);
  87. }
  88. else
  89. {
  90. XmlNode n = CreateNode(node, name);
  91. FieldInfo[] fields = value.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
  92. foreach (FieldInfo field in fields) CreateChildNode(n, field.Name, field.GetValue(value));
  93. }
  94. }
  95. private XmlNode CreateNode(XmlNode node, string nodeName)
  96. {
  97. XmlDocument doc = node.OwnerDocument;
  98. if (doc == null) return null;
  99. XmlNode newNode = doc.CreateElement(nodeName);
  100. node.AppendChild(newNode);
  101. return newNode;
  102. }
  103. private XmlNode CreateNode(XmlNode node, string nodeName, object value)
  104. {
  105. if (value != null) return CreateNode(node, nodeName, value.ToString(), false);
  106. return null;
  107. }
  108. private XmlNode CreateNode(XmlNode node, string nodeName, string value, bool wrapCData)
  109. {
  110. XmlDocument doc = node.OwnerDocument;
  111. if (doc == null) return null;
  112. XmlNode newNode = doc.CreateElement(nodeName);
  113. if (!wrapCData) newNode.AppendChild(doc.CreateTextNode(value));
  114. else newNode.AppendChild(doc.CreateCDataSection(value));
  115. node.AppendChild(newNode);
  116. return newNode;
  117. }
  118. public static void DeletePref(string id)
  119. {
  120. EditorPrefs.DeleteKey(prefix + id);
  121. }
  122. public static RealWorldTerrainPrefs GetPrefs(RealWorldTerrainMonoBase item, bool isNew = false)
  123. {
  124. RealWorldTerrainPrefs prefs = new RealWorldTerrainPrefs
  125. {
  126. leftLongitude = item.leftLongitude,
  127. topLatitude = item.topLatitude,
  128. rightLongitude = item.rightLongitude,
  129. bottomLatitude = item.bottomLatitude,
  130. generateGrass = item.generateGrass,
  131. generateRoads = item.generateRoads,
  132. generateTextures = item.generateTextures,
  133. generateTrees = item.generateTrees,
  134. };
  135. FieldInfo[] fieldInfos = typeof(RealWorldTerrainPrefsBase).GetFields(BindingFlags.Instance | BindingFlags.Public);
  136. foreach (FieldInfo info in fieldInfos) info.SetValue(prefs, info.GetValue(item.prefs));
  137. if (item is RealWorldTerrainContainer) prefs.terrainCount = ((RealWorldTerrainContainer)item).terrainCount;
  138. else prefs.terrainCount = RealWorldTerrainVector2i.one;
  139. if (!isNew) prefs.allowChange = false;
  140. if (string.IsNullOrEmpty(prefs.mapTypeID)) prefs.mapTypeID = RealWorldTerrainTextureProviderManager.Upgrade(prefs.textureProvider);
  141. prefs.mapType = RealWorldTerrainTextureProviderManager.FindMapType(prefs.mapTypeID);
  142. prefs.mapType.LoadSettings(prefs.mapTypeExtraFields);
  143. return prefs;
  144. }
  145. public void Load()
  146. {
  147. if (!allowChange) return;
  148. LoadFromXML(prefsFilename);
  149. if (string.IsNullOrEmpty(mapTypeID)) mapTypeID = RealWorldTerrainTextureProviderManager.Upgrade(textureProvider);
  150. mapType = RealWorldTerrainTextureProviderManager.FindMapType(mapTypeID);
  151. mapType.LoadSettings(mapTypeExtraFields);
  152. }
  153. public void LoadField(FieldInfo field, object target, XmlNode node)
  154. {
  155. if (node == null) return;
  156. string value = node.InnerXml;
  157. if (string.IsNullOrEmpty(value)) return;
  158. Type type = field.FieldType;
  159. if (type == typeof(string)) field.SetValue(target, node.InnerText.Trim());
  160. else if (type.IsEnum)
  161. {
  162. try
  163. {
  164. field.SetValue(target, Enum.Parse(type, value));
  165. }
  166. catch
  167. {
  168. }
  169. }
  170. else if (type == typeof(int) || type == typeof(long) || type == typeof(short) ||
  171. type == typeof(float) || type == typeof(double) ||
  172. type == typeof(bool))
  173. {
  174. PropertyInfo[] properties = type.GetProperties();
  175. Type underlyingType = type;
  176. if (properties.Length == 2 && string.Equals(properties[0].Name, "HasValue", StringComparison.InvariantCultureIgnoreCase)) underlyingType = properties[1].PropertyType;
  177. try
  178. {
  179. MethodInfo method = underlyingType.GetMethod("Parse", new[] { typeof(string), typeof(IFormatProvider) });
  180. object obj;
  181. if (method != null) obj = method.Invoke(null, new object[] {value, RealWorldTerrainCultureInfo.numberFormat});
  182. else
  183. {
  184. method = underlyingType.GetMethod("Parse", new[] {typeof(string)});
  185. obj = method.Invoke(null, new[] {value});
  186. }
  187. field.SetValue(target, obj);
  188. }
  189. catch (Exception exception)
  190. {
  191. Debug.Log(exception.Message + "\n" + exception.StackTrace);
  192. throw;
  193. }
  194. }
  195. else if (type.IsSubclassOf(typeof(UnityEngine.Object)))
  196. {
  197. object v = AssetDatabase.LoadAssetAtPath(node.InnerText.Trim(), typeof(UnityEngine.Object));
  198. field.SetValue(target, v);
  199. }
  200. else if (type.IsArray)
  201. {
  202. Array v = Array.CreateInstance(type.GetElementType(), node.ChildNodes.Count);
  203. int index = 0;
  204. foreach (XmlNode itemNode in node.ChildNodes)
  205. {
  206. Type elementType = type.GetElementType();
  207. if (elementType == typeof(string))
  208. {
  209. v.SetValue(itemNode.FirstChild.Value, index);
  210. }
  211. else
  212. {
  213. object item = Activator.CreateInstance(elementType);
  214. FieldInfo[] fields = elementType.GetFields(BindingFlags.Public | BindingFlags.Instance);
  215. foreach (XmlNode fieldNode in itemNode.ChildNodes)
  216. {
  217. FieldInfo fieldInfo = fields.FirstOrDefault(f => f.Name == fieldNode.Name);
  218. if (fieldInfo == null)
  219. {
  220. Debug.Log("No info for " + fieldNode.Name);
  221. continue;
  222. }
  223. LoadField(fieldInfo, item, fieldNode);
  224. }
  225. v.SetValue(item, index);
  226. }
  227. index++;
  228. }
  229. field.SetValue(target, v);
  230. }
  231. else if (type.IsGenericType)
  232. {
  233. Type listType = type.GetGenericArguments()[0];
  234. object v = type.Assembly.CreateInstance(type.FullName);
  235. foreach (XmlNode itemNode in node.ChildNodes)
  236. {
  237. object item = null;
  238. if (listType.IsSubclassOf(typeof(UnityEngine.Object)))
  239. {
  240. item = AssetDatabase.LoadAssetAtPath(itemNode.FirstChild.InnerText, listType);
  241. if (item == null) continue;
  242. }
  243. else if (listType.IsValueType)
  244. {
  245. try
  246. {
  247. MethodInfo method = listType.GetMethod("Parse", new[] {typeof(string), typeof(IFormatProvider)});
  248. if (method != null) item = method.Invoke(null, new object[] { itemNode.FirstChild.InnerText, RealWorldTerrainCultureInfo.numberFormat});
  249. else
  250. {
  251. method = listType.GetMethod("Parse", new[] {typeof(string)});
  252. item = method.Invoke(null, new[] { itemNode.FirstChild.InnerText });
  253. }
  254. }
  255. catch { }
  256. }
  257. else
  258. {
  259. item = listType.Assembly.CreateInstance(listType.FullName);
  260. FieldInfo[] fields = listType.GetFields(BindingFlags.Public | BindingFlags.Instance);
  261. foreach (XmlNode fieldNode in itemNode.ChildNodes)
  262. {
  263. FieldInfo fieldInfo = fields.FirstOrDefault(f => f.Name == fieldNode.Name);
  264. if (fieldInfo == null)
  265. {
  266. Debug.Log("No info for " + fieldNode.Name);
  267. continue;
  268. }
  269. LoadField(fieldInfo, item, fieldNode);
  270. }
  271. }
  272. try
  273. {
  274. type.GetMethod("Add").Invoke(v, new[] { item });
  275. }
  276. catch (Exception exception)
  277. {
  278. Debug.LogError(exception.Message + "\n" + exception.StackTrace);
  279. }
  280. }
  281. field.SetValue(target, v);
  282. }
  283. else
  284. {
  285. try
  286. {
  287. object v = type.Assembly.CreateInstance(type.FullName);
  288. FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
  289. foreach (XmlNode childNode in node.ChildNodes)
  290. {
  291. FieldInfo fieldInfo = fields.FirstOrDefault(f => f.Name == childNode.Name);
  292. if (fieldInfo == null) continue;
  293. LoadField(fieldInfo, v, childNode);
  294. }
  295. field.SetValue(target, v);
  296. }
  297. catch (Exception)
  298. {
  299. Debug.Log(type.FullName);
  300. Debug.Log(node.Name);
  301. throw;
  302. }
  303. }
  304. }
  305. public void LoadFromXML(string filename)
  306. {
  307. if (!File.Exists(filename)) return;
  308. XmlDocument doc = new XmlDocument();
  309. doc.Load(filename);
  310. XmlNode node = doc.FirstChild;
  311. Type type = GetType();
  312. FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
  313. foreach (XmlNode childNode in node.ChildNodes)
  314. {
  315. FieldInfo field = fields.FirstOrDefault(f => f.Name == childNode.Name);
  316. if (field == null)
  317. {
  318. Debug.Log("Cannot find field: " + childNode.Name);
  319. continue;
  320. }
  321. LoadField(field, this, childNode);
  322. if (field.Name == "coordinatesFrom")
  323. {
  324. leftLongitude = coordinatesFrom.x;
  325. topLatitude = coordinatesFrom.y;
  326. }
  327. else if (field.Name == "coordinatesTo")
  328. {
  329. rightLongitude = coordinatesTo.x;
  330. bottomLatitude = coordinatesTo.y;
  331. }
  332. }
  333. }
  334. public static bool LoadPref(string id, bool defVal)
  335. {
  336. string key = prefix + id;
  337. if (EditorPrefs.HasKey(key)) return EditorPrefs.GetBool(key);
  338. return defVal;
  339. }
  340. public static int LoadPref(string id, int defVal)
  341. {
  342. string key = prefix + id;
  343. if (EditorPrefs.HasKey(key)) return EditorPrefs.GetInt(key);
  344. return defVal;
  345. }
  346. public static string LoadPref(string id, string defVal)
  347. {
  348. string key = prefix + id;
  349. if (EditorPrefs.HasKey(key)) return EditorPrefs.GetString(key);
  350. return defVal;
  351. }
  352. public void Save()
  353. {
  354. if (!allowChange) return;
  355. File.WriteAllText(prefsFilename, ToXML(new XmlDocument()).OuterXml, Encoding.UTF8);
  356. string coordsScript = "var Coords = {" + string.Format(RealWorldTerrainCultureInfo.numberFormat, "tlx: {0}, tly: {1}, brx: {2}, bry: {3}", leftLongitude, topLatitude, rightLongitude, bottomLatitude) + "};";
  357. if (POI != null)
  358. {
  359. coordsScript += "var POI = [";
  360. for (int i = 0; i < POI.Count; i++)
  361. {
  362. RealWorldTerrainPOI poi = POI[i];
  363. if (i > 0) coordsScript += ", ";
  364. coordsScript += "{x: " + poi.x.ToString(RealWorldTerrainCultureInfo.numberFormat) + ", y:" + poi.y.ToString(RealWorldTerrainCultureInfo.numberFormat) + ", title: \"" + poi.title + "\"}";
  365. }
  366. coordsScript += "];";
  367. }
  368. string coordPath = Directory.GetFiles(Application.dataPath, "RWT_Coords.jscript", SearchOption.AllDirectories)[0].Replace('\\', '/');
  369. File.WriteAllText(coordPath, coordsScript);
  370. }
  371. public static void SetPref(string id, bool val)
  372. {
  373. EditorPrefs.SetBool(prefix + id, val);
  374. }
  375. public static void SetPref(string id, int val)
  376. {
  377. EditorPrefs.SetInt(prefix + id, val);
  378. }
  379. public static void SetPref(string id, string val)
  380. {
  381. EditorPrefs.SetString(prefix + id, val);
  382. }
  383. public XmlNode ToXML(XmlDocument document)
  384. {
  385. XmlNode node = document.CreateElement("Prefs");
  386. mapTypeID = mapType.fullID;
  387. mapTypeExtraFields = mapType.GetSettings();
  388. FieldInfo[] fields = GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
  389. foreach (FieldInfo field in fields)
  390. {
  391. if (field.IsDefined(typeof(IgnoreInXMLAttribute), false)) continue;
  392. try
  393. {
  394. CreateChildNode(node, field.Name, field.GetValue(this));
  395. }
  396. catch (Exception exception)
  397. {
  398. Debug.Log(exception.Message + "\n" + exception.StackTrace);
  399. }
  400. }
  401. return node;
  402. }
  403. private class IgnoreInXMLAttribute : Attribute
  404. {
  405. }
  406. }
  407. }