RealWorldTerrainTextureProviderManager.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802
  1. /* INFINITY CODE */
  2. /* https://infinity-code.com */
  3. using System;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. using UnityEngine;
  8. using Random = UnityEngine.Random;
  9. namespace InfinityCode.RealWorldTerrain
  10. {
  11. public static class RealWorldTerrainTextureProviderManager
  12. {
  13. private const string SATELLITE = "Satellite";
  14. private const string RELIEF = "Relief";
  15. private const string TERRAIN = "Terrain";
  16. private const string MAP = "Map";
  17. private static Provider[] providers;
  18. public static MapType FindMapType(string mapTypeID)
  19. {
  20. if (providers == null) InitProviders();
  21. if (string.IsNullOrEmpty(mapTypeID)) return providers[0].types[0];
  22. string[] parts = mapTypeID.Split('.');
  23. foreach (Provider provider in providers)
  24. {
  25. if (provider.id == parts[0])
  26. {
  27. if (parts.Length == 1) return provider.types[0];
  28. foreach (MapType type in provider.types)
  29. {
  30. if (type.id == parts[1]) return type;
  31. }
  32. return provider.types[0];
  33. }
  34. }
  35. return providers[0].types[0];
  36. }
  37. public static Provider[] GetProviders()
  38. {
  39. if (providers == null) InitProviders();
  40. return providers;
  41. }
  42. public static string[] GetProvidersTitle()
  43. {
  44. if (providers == null) InitProviders();
  45. return providers.Select(p => p.title).ToArray();
  46. }
  47. private static void InitProviders()
  48. {
  49. providers = new[]
  50. {
  51. new Provider("arcgis", "ArcGIS (Esri)")
  52. {
  53. url = "https://server.arcgisonline.com/ArcGIS/rest/services/{variant}/MapServer/tile/{zoom}/{y}/{x}",
  54. types = new []
  55. {
  56. new MapType("WorldImagery", "ag") { variant = "World_Imagery" },
  57. }
  58. },
  59. new Provider("DigitalGlobe")
  60. {
  61. url = "https://a.tiles.mapbox.com/v4/digitalglobe.{variant}/{zoom}/{x}/{y}.jpg?access_token={accesstoken}",
  62. types = new []
  63. {
  64. new MapType("Satellite", "dg")
  65. {
  66. variant = "nal0g75k"
  67. },
  68. },
  69. extraFields = new []
  70. {
  71. new ExtraField("Access Token", "accesstoken"),
  72. },
  73. help = new []
  74. {
  75. "1 map view = 15 tiles"
  76. }
  77. },
  78. new Provider("Mapbox")
  79. {
  80. types = new []
  81. {
  82. new MapType(SATELLITE, "mbs")
  83. {
  84. url = "https://a.tiles.mapbox.com/v4/mapbox.satellite/{zoom}/{x}/{y}.png?events=true&access_token={accesstoken}"
  85. },
  86. new MapType("Map", "mbm")
  87. {
  88. url = "https://api.mapbox.com/styles/v1/{userid}/{mapid}/tiles/256/{z}/{x}/{y}?access_token={accesstoken}",
  89. extraFields = new []
  90. {
  91. new ExtraField("User ID", "userid"),
  92. new ExtraField("Map ID", "mapid"),
  93. }
  94. },
  95. new MapType("Classic", "mbc")
  96. {
  97. url = "https://a.tiles.mapbox.com/v4/{mapid}/{zoom}/{x}/{y}.png?&events=true&access_token={accesstoken}",
  98. extraFields = new []
  99. {
  100. new ExtraField("Map ID", "mapid"),
  101. },
  102. help = new []
  103. {
  104. "Only raster tiles are supported."
  105. }
  106. }
  107. },
  108. extraFields = new []
  109. {
  110. new ExtraField("Access Token", "accesstoken"),
  111. },
  112. help = new []
  113. {
  114. "1 map view = 15 tiles"
  115. }
  116. },
  117. new Provider("MapQuest")
  118. {
  119. url = "https://a.tiles.mapbox.com/v4/{variant}/{zoom}/{x}/{y}.png?access_token={accesstoken}",
  120. types = new []
  121. {
  122. new MapType(SATELLITE, "mq")
  123. {
  124. variant = "mapquest.satellite"
  125. },
  126. },
  127. extraFields = new []
  128. {
  129. new ToggleExtraGroup("Anonymous", true, new []
  130. {
  131. new ExtraField("Access Token", "accesstoken", "pk.eyJ1IjoibWFwcXVlc3QiLCJhIjoiY2Q2N2RlMmNhY2NiZTRkMzlmZjJmZDk0NWU0ZGJlNTMifQ.mPRiEubbajc6a5y9ISgydg")
  132. })
  133. },
  134. },
  135. new Provider("mapy", "Mapy.CZ")
  136. {
  137. url = "https://m[0-4].mapserver.mapy.cz/{variant}/{zoom}-{x}-{y}",
  138. types = new []
  139. {
  140. new MapType(SATELLITE, "mcz")
  141. {
  142. variant = "ophoto-m"
  143. },
  144. }
  145. },
  146. new Provider("nokia", "Nokia Maps (here.com)")
  147. {
  148. url = "https://[1-4].{prop2}.maps.cit.api.here.com/maptile/2.1/{prop}/newest/{variant}/{zoom}/{x}/{y}/256/png8?lg={lng}&app_id={appid}&app_code={appcode}",
  149. prop = "maptile",
  150. prop2 = "base",
  151. types = new []
  152. {
  153. new MapType(SATELLITE, "n")
  154. {
  155. variant = "satellite.day",
  156. prop2 = "aerial",
  157. },
  158. },
  159. extraFields = new []
  160. {
  161. new ToggleExtraGroup("Anonymous", true, new []
  162. {
  163. new ExtraField("App ID", "appid", "xWVIueSv6JL0aJ5xqTxb"),
  164. new ExtraField("App Code", "appcode", "djPZyynKsbTjIUDOBcHZ2g"),
  165. })
  166. }
  167. },
  168. new Provider("osm", "OpenStreetMap")
  169. {
  170. types = new []
  171. {
  172. new MapType("Mapnik", "osmm")
  173. {
  174. url = "https://a.tile.openstreetmap.org/{zoom}/{x}/{y}.png"
  175. },
  176. new MapType("BlackAndWhite", "osmbw")
  177. {
  178. url = "http://a.tiles.wmflabs.org/bw-mapnik/{zoom}/{x}/{y}.png"
  179. },
  180. new MapType("DE", "osmde")
  181. {
  182. url = "http://a.tile.openstreetmap.de/tiles/osmde/{zoom}/{x}/{y}.png"
  183. },
  184. new MapType("France", "osmfr")
  185. {
  186. url = "https://a.tile.openstreetmap.fr/osmfr/{zoom}/{x}/{y}.png"
  187. },
  188. new MapType("HOT", "osmhot")
  189. {
  190. url = "https://a.tile.openstreetmap.fr/hot/{zoom}/{x}/{y}.png"
  191. },
  192. }
  193. },
  194. new Provider("sentinel2", "Sentinel-2")
  195. {
  196. types = new []
  197. {
  198. new MapType("satellite", "s2s")
  199. {
  200. url = "https://services.sentinel-hub.com/ogc/wmts/cd280189-7c51-45a6-ab05-f96a76067710?REQUEST=GetTile&TILEMATRIXSET=PopularWebMercator256&LAYER=1_TRUE_COLOR&TILEMATRIX={zoom}&TILEROW={y}&TILECOL={x}&showlogo=false"
  201. },
  202. }
  203. },
  204. new Provider("virtualearth", "Virtual Earth (Bing Maps)")
  205. {
  206. types = new []
  207. {
  208. new MapType("Aerial", "ve")
  209. {
  210. url = "https://t[0-4].ssl.ak.tiles.virtualearth.net/tiles/a{quad}.jpeg?mkt={lng}&g=1457&n=z",
  211. },
  212. }
  213. },
  214. new Provider("Custom")
  215. {
  216. types = new []
  217. {
  218. new MapType("Custom", "custom") { isCustom = true }
  219. }
  220. }
  221. };
  222. for (int i = 0; i < providers.Length; i++)
  223. {
  224. Provider provider = providers[i];
  225. provider.index = i;
  226. for (int j = 0; j < provider.types.Length; j++)
  227. {
  228. MapType type = provider.types[j];
  229. type.provider = provider;
  230. type.fullID = provider.id + "." + type.id;
  231. type.index = j;
  232. }
  233. }
  234. }
  235. public static string Upgrade(RealWorldTerrainTextureProvider providerID)
  236. {
  237. StringBuilder builder = new StringBuilder();
  238. if (providerID == RealWorldTerrainTextureProvider.arcGIS) builder.Append("arcgis");
  239. else if (providerID == RealWorldTerrainTextureProvider.google)
  240. {
  241. Debug.LogWarning("Support for Google Maps is removed, please use another provider.\nIf you really want to continue using Google Maps, you can do it using Provider - Custom.");
  242. return "arcgis";
  243. }
  244. else if (providerID == RealWorldTerrainTextureProvider.nokia) builder.Append("nokia");
  245. else if (providerID == RealWorldTerrainTextureProvider.mapQuest) builder.Append("mapquest");
  246. else if (providerID == RealWorldTerrainTextureProvider.virtualEarth) builder.Append("virtualearth");
  247. else if (providerID == RealWorldTerrainTextureProvider.openStreetMap) builder.Append("osm");
  248. else if (providerID == RealWorldTerrainTextureProvider.custom) builder.Append("custom").Append(".").Append("custom");
  249. else
  250. {
  251. Debug.LogWarning("Trying to upgrade provider failed. Please select the provider manually.");
  252. return "arcgis";
  253. }
  254. return builder.ToString();
  255. }
  256. public class Provider
  257. {
  258. /// <summary>
  259. /// ID of provider
  260. /// </summary>
  261. public readonly string id;
  262. /// <summary>
  263. /// Human-readable provider title.
  264. /// </summary>
  265. public readonly string title;
  266. /// <summary>
  267. /// Index of current provider.
  268. /// </summary>
  269. public int index;
  270. /// <summary>
  271. /// Extension. Token {ext}, that is being replaced in the URL.
  272. /// </summary>
  273. public string ext;
  274. /// <summary>
  275. /// Property. Token {prop}, that is being replaced in the URL.
  276. /// </summary>
  277. public string prop;
  278. /// <summary>
  279. /// Property. Token {prop2}, that is being replaced in the URL.
  280. /// </summary>
  281. public string prop2;
  282. public bool logUrl = false;
  283. public IExtraField[] extraFields;
  284. public string[] help;
  285. private string _url;
  286. private MapType[] _types;
  287. /// <summary>
  288. /// Array of map types available for the current provider.
  289. /// </summary>
  290. public MapType[] types
  291. {
  292. get { return _types; }
  293. set { _types = value; }
  294. }
  295. /// <summary>
  296. /// Gets / sets the URL pattern of tiles.
  297. /// </summary>
  298. public string url
  299. {
  300. get { return _url; }
  301. set
  302. {
  303. _url = value;
  304. }
  305. }
  306. public Provider(string title) : this(title.ToLower(), title)
  307. {
  308. }
  309. public Provider(string id, string title)
  310. {
  311. this.id = id.ToLower();
  312. this.title = title;
  313. }
  314. /// <summary>
  315. /// Gets map type by index.
  316. /// </summary>
  317. /// <param name="index">Index of map type.</param>
  318. /// <param name="repeat">TRUE - Repeat index value, FALSE - Clamp index value.</param>
  319. /// <returns>Instance of map type.</returns>
  320. public MapType GetByIndex(int index, bool repeat = false)
  321. {
  322. if (repeat) index = Mathf.RoundToInt(Mathf.Repeat(index, _types.Length - 1));
  323. else index = Mathf.Clamp(index, 0, _types.Length);
  324. return _types[index];
  325. }
  326. }
  327. /// <summary>
  328. /// Class of map type
  329. /// </summary>
  330. public class MapType
  331. {
  332. /// <summary>
  333. /// ID of map type
  334. /// </summary>
  335. public readonly string id;
  336. public string filePrefix;
  337. public string fullID;
  338. /// <summary>
  339. /// Human-readable map type title.
  340. /// </summary>
  341. public readonly string title;
  342. /// <summary>
  343. /// Reference to provider instance.
  344. /// </summary>
  345. public Provider provider;
  346. /// <summary>
  347. /// Index of map type
  348. /// </summary>
  349. public int index;
  350. public IExtraField[] extraFields;
  351. /// <summary>
  352. /// Indicates that this is an custom provider.
  353. /// </summary>
  354. public bool isCustom;
  355. private string _ext;
  356. private string _url;
  357. private string _variant;
  358. private string _prop;
  359. private string _prop2;
  360. private bool? _logUrl;
  361. public string[] help;
  362. /// <summary>
  363. /// Extension. Token {ext}, that is being replaced in the URL.
  364. /// </summary>
  365. public string ext
  366. {
  367. get
  368. {
  369. if (!string.IsNullOrEmpty(_ext)) return _ext;
  370. if (!string.IsNullOrEmpty(provider.ext)) return provider.ext;
  371. return string.Empty;
  372. }
  373. set { _ext = value; }
  374. }
  375. public bool logUrl
  376. {
  377. get
  378. {
  379. if (_logUrl.HasValue) return _logUrl.Value;
  380. return provider.logUrl;
  381. }
  382. set { _logUrl = value; }
  383. }
  384. /// <summary>
  385. /// Property. Token {prop}, that is being replaced in the URL.
  386. /// </summary>
  387. public string prop
  388. {
  389. get
  390. {
  391. if (!string.IsNullOrEmpty(_prop)) return _prop;
  392. return provider.prop;
  393. }
  394. set
  395. {
  396. _prop = value;
  397. }
  398. }
  399. /// <summary>
  400. /// Property. Token {prop2}, that is being replaced in the URL.
  401. /// </summary>
  402. public string prop2
  403. {
  404. get { return string.IsNullOrEmpty(_prop2) ? provider.prop2 : _prop2; }
  405. set { _prop2 = value; }
  406. }
  407. /// <summary>
  408. /// Variant. Token {variant}, that is being replaced in the URL.
  409. /// </summary>
  410. public string variant
  411. {
  412. get { return _variant; }
  413. set
  414. {
  415. _variant = value;
  416. }
  417. }
  418. /// <summary>
  419. /// Gets / sets the URL pattern of tiles.
  420. /// </summary>
  421. public string url
  422. {
  423. get
  424. {
  425. if (!string.IsNullOrEmpty(_url)) return _url;
  426. return provider.url;
  427. }
  428. set
  429. {
  430. _url = value;
  431. }
  432. }
  433. /// <summary>
  434. /// Constructor
  435. /// </summary>
  436. /// <param name="title">Human-readable map type title.</param>
  437. public MapType(string title, string filePrefix) : this(title.ToLower(), title, filePrefix)
  438. {
  439. }
  440. /// <summary>
  441. /// Constructor
  442. /// </summary>
  443. /// <param name="id">ID of map type.</param>
  444. /// <param name="title">Human-readable map type title.</param>
  445. public MapType(string id, string title, string filePrefix)
  446. {
  447. this.filePrefix = filePrefix;
  448. this.id = id;
  449. this.title = title;
  450. }
  451. public string GetSettings()
  452. {
  453. if (provider.extraFields == null) return null;
  454. StringBuilder builder = new StringBuilder();
  455. foreach (IExtraField field in provider.extraFields) field.SaveSettings(builder);
  456. return builder.ToString();
  457. }
  458. /// <summary>
  459. /// Gets the URL to download the tile texture.
  460. /// </summary>
  461. /// <param name="zoom">Tile zoom</param>
  462. /// <param name="x">Tile X</param>
  463. /// <param name="y">Tile Y</param>
  464. /// <returns>URL to tile texture.</returns>
  465. public string GetURL(int zoom, int x, int y)
  466. {
  467. return GetURL(zoom, x, y, url);
  468. }
  469. public string GetURL(int zoom, int x, int y, string url)
  470. {
  471. url = Regex.Replace(url, @"{\w+}", delegate (Match match)
  472. {
  473. string v = match.Value.ToLower().Trim('{', '}');
  474. if (v == "zoom") return zoom.ToString();
  475. if (v == "z") return zoom.ToString();
  476. if (v == "x") return x.ToString();
  477. if (v == "y") return y.ToString();
  478. if (v == "quad") return RealWorldTerrainUtils.TileToQuadKey(x, y, zoom);
  479. if (v == "ext") return ext;
  480. if (v == "prop") return prop;
  481. if (v == "prop2") return prop2;
  482. if (v == "variant") return variant;
  483. if (TryUseExtraFields(ref v)) return v;
  484. return v;
  485. });
  486. url = Regex.Replace(url, @"\[(\d+)-(\d+)\]", delegate (Match match)
  487. {
  488. int v1 = int.Parse(match.Groups[1].Value);
  489. int v2 = int.Parse(match.Groups[2].Value);
  490. return Random.Range(v1, v2 + 1).ToString();
  491. });
  492. if (logUrl) Debug.Log(url);
  493. return url;
  494. }
  495. public void LoadSettings(string settings)
  496. {
  497. IExtraField[] fields = provider.extraFields;
  498. if (fields == null || string.IsNullOrEmpty(settings)) return;
  499. int i = 0;
  500. while (i < settings.Length)
  501. {
  502. int titleLength = int.Parse(settings.Substring(i, 2));
  503. i += 2;
  504. string title = settings.Substring(i, titleLength);
  505. i += titleLength;
  506. int contentLengthSize = int.Parse(settings.Substring(i, 1));
  507. i++;
  508. int contentSize = int.Parse(settings.Substring(i, contentLengthSize));
  509. i += contentLengthSize;
  510. foreach (IExtraField field in fields) if (field.TryLoadSettings(title, settings, i, contentSize)) break;
  511. i += contentSize;
  512. }
  513. }
  514. private bool TryUseExtraFields(ref string token)
  515. {
  516. if (provider.extraFields != null)
  517. {
  518. foreach (IExtraField field in provider.extraFields)
  519. {
  520. string value;
  521. if (field.GetTokenValue(token, false, out value))
  522. {
  523. token = value;
  524. return true;
  525. }
  526. }
  527. }
  528. if (extraFields != null)
  529. {
  530. foreach (IExtraField field in extraFields)
  531. {
  532. string value;
  533. if (field.GetTokenValue(token, false, out value))
  534. {
  535. token = value;
  536. return true;
  537. }
  538. }
  539. }
  540. return false;
  541. }
  542. public override string ToString()
  543. {
  544. return fullID;
  545. }
  546. }
  547. /// <summary>
  548. /// Group of toggle extra fields
  549. /// </summary>
  550. public class ToggleExtraGroup : IExtraField
  551. {
  552. /// <summary>
  553. /// Array of extra fields
  554. /// </summary>
  555. public IExtraField[] fields;
  556. /// <summary>
  557. /// Group title
  558. /// </summary>
  559. public string title;
  560. /// <summary>
  561. /// Group value
  562. /// </summary>
  563. public bool value = false;
  564. /// <summary>
  565. /// Group ID
  566. /// </summary>
  567. public string id;
  568. public ToggleExtraGroup(string title, bool value = false)
  569. {
  570. this.title = title;
  571. this.value = value;
  572. }
  573. public ToggleExtraGroup(string title, bool value, IExtraField[] fields) : this(title, value)
  574. {
  575. this.fields = fields;
  576. }
  577. public bool GetTokenValue(string token, bool useDefaultValue, out string value)
  578. {
  579. value = null;
  580. if (fields == null) return false;
  581. foreach (IExtraField field in fields)
  582. {
  583. if (field.GetTokenValue(token, this.value || useDefaultValue, out value)) return true;
  584. }
  585. return false;
  586. }
  587. public void SaveSettings(StringBuilder builder)
  588. {
  589. int titleLength = title.Length;
  590. if (titleLength < 10) builder.Append("0");
  591. builder.Append(titleLength);
  592. builder.Append(title);
  593. StringBuilder dataBuilder = new StringBuilder();
  594. dataBuilder.Append(value ? 1 : 0);
  595. if (fields != null) foreach (IExtraField field in fields) field.SaveSettings(dataBuilder);
  596. builder.Append(dataBuilder.Length.ToString().Length);
  597. builder.Append(dataBuilder.Length);
  598. builder.Append(dataBuilder);
  599. }
  600. public bool TryLoadSettings(string title, string settings, int index, int contentSize)
  601. {
  602. if (this.title != title) return false;
  603. value = settings.Substring(index, 1) == "1";
  604. int i = index + 1;
  605. while (i < index + contentSize)
  606. {
  607. int titleLength = int.Parse(settings.Substring(i, 2));
  608. i += 2;
  609. string fieldTitle = settings.Substring(i, titleLength);
  610. i += titleLength;
  611. int contentLengthSize = int.Parse(settings.Substring(i, 1));
  612. i++;
  613. int contentLength = int.Parse(settings.Substring(i, contentLengthSize));
  614. i += contentLengthSize;
  615. foreach (IExtraField field in fields) if (field.TryLoadSettings(fieldTitle, settings, i, contentLength)) break;
  616. i += contentLength;
  617. }
  618. return true;
  619. }
  620. }
  621. /// <summary>
  622. /// Interface for extra fields tile provider
  623. /// </summary>
  624. public interface IExtraField
  625. {
  626. bool GetTokenValue(string token, bool useDefaultValue, out string value);
  627. void SaveSettings(StringBuilder builder);
  628. bool TryLoadSettings(string title, string settings, int index, int contentSize);
  629. }
  630. /// <summary>
  631. /// Class for extra field
  632. /// </summary>
  633. public class ExtraField : IExtraField
  634. {
  635. /// <summary>
  636. /// Title
  637. /// </summary>
  638. public string title;
  639. /// <summary>
  640. /// Value
  641. /// </summary>
  642. public string value;
  643. /// <summary>
  644. /// Default value
  645. /// </summary>
  646. public string defaultValue;
  647. /// <summary>
  648. /// Token (ID)
  649. /// </summary>
  650. public string token;
  651. public ExtraField(string title, string token)
  652. {
  653. this.title = title;
  654. this.token = token;
  655. }
  656. public ExtraField(string title, string token, string defaultValue) : this(title, token)
  657. {
  658. this.defaultValue = defaultValue;
  659. }
  660. public bool GetTokenValue(string token, bool useDefaultValue, out string value)
  661. {
  662. value = null;
  663. if (this.token == token)
  664. {
  665. value = useDefaultValue ? defaultValue : this.value;
  666. return true;
  667. }
  668. return false;
  669. }
  670. public void SaveSettings(StringBuilder builder)
  671. {
  672. int titleLength = title.Length;
  673. if (titleLength < 10) builder.Append("0");
  674. builder.Append(titleLength);
  675. builder.Append(title);
  676. if (string.IsNullOrEmpty(value)) builder.Append(1).Append(1).Append(0);
  677. else
  678. {
  679. StringBuilder dataBuilder = new StringBuilder();
  680. int valueLength = value.Length;
  681. dataBuilder.Append(valueLength.ToString().Length);
  682. dataBuilder.Append(valueLength);
  683. dataBuilder.Append(value);
  684. builder.Append(dataBuilder.Length.ToString().Length);
  685. builder.Append(dataBuilder.Length);
  686. builder.Append(dataBuilder);
  687. }
  688. }
  689. public bool TryLoadSettings(string title, string settings, int index, int contentSize)
  690. {
  691. if (this.title != title) return false;
  692. int lengthSize = int.Parse(settings.Substring(index, 1));
  693. if (lengthSize == 0) value = "";
  694. else
  695. {
  696. index++;
  697. int length = int.Parse(settings.Substring(index, lengthSize));
  698. index += lengthSize;
  699. value = settings.Substring(index, length);
  700. }
  701. return true;
  702. }
  703. }
  704. }
  705. }