SubMaid.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Text;
  5. using I2.Loc;
  6. using UnityEngine;
  7. using wf;
  8. namespace MaidStatus
  9. {
  10. public static class SubMaid
  11. {
  12. public static int Count
  13. {
  14. get
  15. {
  16. SubMaid.CreateData();
  17. return SubMaid.commonIdManager.idMap.Count;
  18. }
  19. }
  20. public static bool Contains(string name)
  21. {
  22. return SubMaid.commonIdManager.nameMap.ContainsKey(name);
  23. }
  24. public static bool Contains(int id)
  25. {
  26. return SubMaid.commonIdManager.idMap.ContainsKey(id);
  27. }
  28. public static int uniqueNameToId(string name)
  29. {
  30. SubMaid.CreateData();
  31. NDebug.Assert(SubMaid.commonIdManager.nameMap.ContainsKey(name), "Subメイド\nユニーク名[" + name + "]をIDに変換できませんでした");
  32. return SubMaid.commonIdManager.nameMap[name];
  33. }
  34. public static string IdToUniqueName(int id)
  35. {
  36. SubMaid.CreateData();
  37. NDebug.Assert(SubMaid.commonIdManager.idMap.ContainsKey(id), "Subメイド\nID[" + id + "]をユニーク名に変換できませんでした");
  38. return SubMaid.commonIdManager.idMap[id].Key;
  39. }
  40. public static SubMaid.Data GetData(int id)
  41. {
  42. SubMaid.CreateData();
  43. NDebug.Assert(SubMaid.basicDatas.ContainsKey(id), "Subメイド\nID[" + id + "]のデータは存在しません");
  44. return SubMaid.basicDatas[id];
  45. }
  46. public static SubMaid.Data GetData(string uniqueName)
  47. {
  48. return SubMaid.GetData(SubMaid.uniqueNameToId(uniqueName));
  49. }
  50. public static bool IsEnabled(string uniqueName)
  51. {
  52. SubMaid.CreateData();
  53. return SubMaid.commonIdManager.enabledIdList.Contains(SubMaid.uniqueNameToId(uniqueName));
  54. }
  55. public static bool IsEnabled(int id)
  56. {
  57. SubMaid.CreateData();
  58. return SubMaid.commonIdManager.enabledIdList.Contains(id);
  59. }
  60. public static List<SubMaid.Data> GetAllDatas(bool onlyEnabled)
  61. {
  62. SubMaid.CreateData();
  63. List<SubMaid.Data> list = new List<SubMaid.Data>();
  64. foreach (KeyValuePair<int, KeyValuePair<string, string>> keyValuePair in SubMaid.commonIdManager.idMap)
  65. {
  66. if (!onlyEnabled || SubMaid.commonIdManager.enabledIdList.Contains(keyValuePair.Key))
  67. {
  68. list.Add(SubMaid.basicDatas[keyValuePair.Key]);
  69. }
  70. }
  71. return list;
  72. }
  73. public static void CreateData()
  74. {
  75. if (SubMaid.commonIdManager != null)
  76. {
  77. return;
  78. }
  79. SubMaid.commonIdManager = new CsvCommonIdManager("maid_status_submaid", "Subメイド", CsvCommonIdManager.Type.IdAndUniqueName, null);
  80. SubMaid.basicDatas = new Dictionary<int, SubMaid.Data>();
  81. string[] array = new string[]
  82. {
  83. "list",
  84. "kiss_side_list"
  85. };
  86. KeyValuePair<AFileBase, CsvParser>[] array2 = new KeyValuePair<AFileBase, CsvParser>[array.Length];
  87. for (int i = 0; i < array2.Length; i++)
  88. {
  89. string text = "maid_status_submaid_" + array[i] + ".nei";
  90. AFileBase afileBase = GameUty.FileSystem.FileOpen(text);
  91. CsvParser csvParser = new CsvParser();
  92. bool condition = csvParser.Open(afileBase);
  93. NDebug.Assert(condition, text + "\nopen failed.");
  94. array2[i] = new KeyValuePair<AFileBase, CsvParser>(afileBase, csvParser);
  95. }
  96. foreach (KeyValuePair<int, KeyValuePair<string, string>> keyValuePair in SubMaid.commonIdManager.idMap)
  97. {
  98. SubMaid.basicDatas.Add(keyValuePair.Key, new SubMaid.Data(keyValuePair.Key, array2[0].Value, array2[1].Value));
  99. }
  100. foreach (KeyValuePair<AFileBase, CsvParser> keyValuePair2 in array2)
  101. {
  102. keyValuePair2.Value.Dispose();
  103. keyValuePair2.Key.Dispose();
  104. }
  105. }
  106. private const string csvTopCommonName = "maid_status_submaid";
  107. private const string typeNameForErrorLog = "Subメイド";
  108. private static CsvCommonIdManager commonIdManager;
  109. private static Dictionary<int, SubMaid.Data> basicDatas;
  110. public class Data
  111. {
  112. public Data(int id, CsvParser basicCsv, CsvParser kissSideCsv)
  113. {
  114. for (int i = 1; i < basicCsv.max_cell_y; i++)
  115. {
  116. if (basicCsv.IsCellToExistData(0, i) && basicCsv.GetCellAsInteger(0, i) == id)
  117. {
  118. int num = 1;
  119. this.id = id;
  120. this.uniqueName = basicCsv.GetCellAsString(num++, i);
  121. this.replaceText = basicCsv.GetCellAsString(num++, i);
  122. this.isEditPossible = (basicCsv.GetCellAsString(num++, i) == "〇");
  123. this.status = new SubMaid.Data.CharacterStatus(this.id, this.uniqueName, false, basicCsv, i);
  124. break;
  125. }
  126. }
  127. for (int j = 1; j < kissSideCsv.max_cell_y; j++)
  128. {
  129. if (kissSideCsv.IsCellToExistData(0, j) && kissSideCsv.GetCellAsInteger(0, j) == id)
  130. {
  131. this.secondStatus = new SubMaid.Data.CharacterStatus(this.id, this.uniqueName, true, kissSideCsv, j);
  132. break;
  133. }
  134. }
  135. }
  136. public void ApplyStatus(Status status, bool refSecondStatus)
  137. {
  138. if (status == null)
  139. {
  140. return;
  141. }
  142. SubMaid.Data.CharacterStatus characterStatus = (!refSecondStatus || this.secondStatus == null) ? this.status : this.secondStatus;
  143. status.heroineType = HeroineType.Sub;
  144. status.subCharaData = this;
  145. status.lastName = characterStatus.lastName;
  146. status.firstName = characterStatus.firstName;
  147. if (Product.supportMultiLanguage)
  148. {
  149. string translation = LocalizationManager.GetTranslation(characterStatus.lastNameTerm, true, 0, true, false, null, Product.EnumConvert.ToI2LocalizeLanguageName(Product.defaultLanguage));
  150. if (!string.IsNullOrEmpty(translation))
  151. {
  152. status.lastName = translation;
  153. }
  154. translation = LocalizationManager.GetTranslation(characterStatus.firstNameTerm, true, 0, true, false, null, Product.EnumConvert.ToI2LocalizeLanguageName(Product.defaultLanguage));
  155. if (!string.IsNullOrEmpty(translation))
  156. {
  157. status.firstName = translation;
  158. }
  159. }
  160. status.contract = characterStatus.contract;
  161. status.initSeikeiken = (status.seikeiken = characterStatus.initSeikeiken);
  162. status.likability = characterStatus.likability;
  163. status.baseLovely = characterStatus.lovely;
  164. status.baseElegance = characterStatus.elegance;
  165. status.baseCharm = characterStatus.charm;
  166. status.baseCare = characterStatus.care;
  167. status.baseReception = characterStatus.reception;
  168. status.baseCooking = characterStatus.cooking;
  169. status.baseDance = characterStatus.dance;
  170. status.baseVocal = characterStatus.vocal;
  171. status.playCountNightWork = characterStatus.playCountNightWork;
  172. int num = characterStatus.hp;
  173. status.currentHp = num;
  174. status.baseMaxHp = num;
  175. num = characterStatus.mind;
  176. status.currentMind = num;
  177. status.baseMaxMind = num;
  178. status.baseInyoku = characterStatus.inyoku;
  179. status.baseMvalue = characterStatus.mvalue;
  180. status.baseHentai = characterStatus.hentai;
  181. status.baseHousi = characterStatus.housi;
  182. status.playCountYotogi = characterStatus.playCountYotogi;
  183. }
  184. public void ApplyPreset(Maid maid, bool refSecondStatus, bool setThumCard)
  185. {
  186. if (maid == null)
  187. {
  188. return;
  189. }
  190. SubMaid.Data.CharacterStatus characterStatus = (!refSecondStatus || this.secondStatus == null) ? this.status : this.secondStatus;
  191. CharacterMgr.npcDatas[characterStatus.presetName].Apply(maid, true);
  192. maid.status.UpdateBodyParam();
  193. if (!string.IsNullOrEmpty(characterStatus.iconFileName))
  194. {
  195. Texture2D texture2D = ImportCM.CreateTexture(characterStatus.iconFileName);
  196. if (texture2D.format == TextureFormat.DXT1 || texture2D.format == TextureFormat.DXT5)
  197. {
  198. Texture2D texture2D2 = new Texture2D(texture2D.width, texture2D.height, TextureFormat.ARGB32, false);
  199. texture2D2.SetPixels(texture2D.GetPixels());
  200. texture2D2.Apply();
  201. UnityEngine.Object.Destroy(texture2D);
  202. maid.SetThumIcon(texture2D2);
  203. }
  204. else
  205. {
  206. maid.SetThumIcon(texture2D);
  207. }
  208. }
  209. else
  210. {
  211. Debug.LogError(string.Concat(new string[]
  212. {
  213. "サブメイド[",
  214. characterStatus.firstName,
  215. "]のアイコンファイル[",
  216. characterStatus.iconFileName,
  217. "]が見つかりません"
  218. }));
  219. }
  220. if (setThumCard)
  221. {
  222. if (!string.IsNullOrEmpty(characterStatus.thumbnailFileName))
  223. {
  224. Texture2D texture2D3 = ImportCM.CreateTexture(characterStatus.thumbnailFileName);
  225. if (texture2D3.format == TextureFormat.DXT1 || texture2D3.format == TextureFormat.DXT5)
  226. {
  227. Texture2D texture2D4 = new Texture2D(texture2D3.width, texture2D3.height, TextureFormat.ARGB32, false);
  228. texture2D4.SetPixels(texture2D3.GetPixels());
  229. texture2D4.Apply();
  230. UnityEngine.Object.Destroy(texture2D3);
  231. maid.SetThumCard(texture2D4);
  232. }
  233. else
  234. {
  235. maid.SetThumCard(texture2D3);
  236. }
  237. }
  238. else
  239. {
  240. Debug.LogError(string.Concat(new string[]
  241. {
  242. "サブメイド[",
  243. characterStatus.firstName,
  244. "]のアイコンファイル[",
  245. characterStatus.thumbnailFileName,
  246. "]が見つかりません"
  247. }));
  248. }
  249. }
  250. }
  251. public readonly int id;
  252. public readonly string uniqueName;
  253. public readonly string replaceText;
  254. public readonly bool isEditPossible;
  255. public readonly SubMaid.Data.CharacterStatus status;
  256. public readonly SubMaid.Data.CharacterStatus secondStatus;
  257. public class CharacterStatus
  258. {
  259. public CharacterStatus(int id, string uniqueName, bool kissSideNPC, CsvParser basicCsv, int lineY)
  260. {
  261. this.id = id;
  262. this.uniqueName = uniqueName;
  263. this.kissSideNPC = kissSideNPC;
  264. int num = 4;
  265. this.lastName = basicCsv.GetCellAsString(num++, lineY);
  266. this.firstName = basicCsv.GetCellAsString(num++, lineY);
  267. this.presetName = Path.GetFileNameWithoutExtension(basicCsv.GetCellAsString(num++, lineY));
  268. this.iconFileName = Path.GetFileNameWithoutExtension(basicCsv.GetCellAsString(num++, lineY)) + ".tex";
  269. this.thumbnailFileName = Path.GetFileNameWithoutExtension(basicCsv.GetCellAsString(num++, lineY)) + ".tex";
  270. try
  271. {
  272. this.contract = (Contract)Enum.Parse(typeof(Contract), basicCsv.GetCellAsString(num++, lineY));
  273. }
  274. catch (Exception e)
  275. {
  276. NDebug.AssertParseError("Contract", e);
  277. }
  278. this.contractText = basicCsv.GetCellAsString(num++, lineY);
  279. this.personalText = basicCsv.GetCellAsString(num++, lineY);
  280. this.relationText = basicCsv.GetCellAsString(num++, lineY);
  281. try
  282. {
  283. this.initSeikeiken = (Seikeiken)Enum.Parse(typeof(Seikeiken), basicCsv.GetCellAsString(num++, lineY));
  284. }
  285. catch (Exception e2)
  286. {
  287. NDebug.AssertParseError("Seikeiken", e2);
  288. }
  289. this.jobClassText = JobClass.GetData(basicCsv.GetCellAsString(num++, lineY)).drawName;
  290. this.jobClassLevel = basicCsv.GetCellAsInteger(num++, lineY);
  291. this.yotogiClassText = basicCsv.GetCellAsString(num++, lineY);
  292. this.yotogiClassLevel = basicCsv.GetCellAsInteger(num++, lineY);
  293. this.likability = basicCsv.GetCellAsInteger(num++, lineY);
  294. this.lovely = basicCsv.GetCellAsInteger(num++, lineY);
  295. this.elegance = basicCsv.GetCellAsInteger(num++, lineY);
  296. this.charm = basicCsv.GetCellAsInteger(num++, lineY);
  297. this.care = basicCsv.GetCellAsInteger(num++, lineY);
  298. this.reception = basicCsv.GetCellAsInteger(num++, lineY);
  299. this.cooking = basicCsv.GetCellAsInteger(num++, lineY);
  300. this.dance = basicCsv.GetCellAsInteger(num++, lineY);
  301. this.vocal = basicCsv.GetCellAsInteger(num++, lineY);
  302. this.playCountNightWork = basicCsv.GetCellAsInteger(num++, lineY);
  303. this.hp = basicCsv.GetCellAsInteger(num++, lineY);
  304. this.mind = basicCsv.GetCellAsInteger(num++, lineY);
  305. this.inyoku = basicCsv.GetCellAsInteger(num++, lineY);
  306. this.mvalue = basicCsv.GetCellAsInteger(num++, lineY);
  307. this.hentai = basicCsv.GetCellAsInteger(num++, lineY);
  308. this.housi = basicCsv.GetCellAsInteger(num++, lineY);
  309. this.playCountYotogi = basicCsv.GetCellAsInteger(num++, lineY);
  310. if (basicCsv.GetCellAsString(num++, 0) == "合計値")
  311. {
  312. this.rehireEventId = -1;
  313. }
  314. else
  315. {
  316. this.rehireEventId = ((!basicCsv.IsCellToExistData(num - 1, lineY)) ? -1 : basicCsv.GetCellAsInteger(num - 1, lineY));
  317. }
  318. }
  319. public string lastNameTerm
  320. {
  321. get
  322. {
  323. return "SubMaid/" + this.uniqueName + "/苗字";
  324. }
  325. }
  326. public string firstNameTerm
  327. {
  328. get
  329. {
  330. return "SubMaid/" + this.uniqueName + "/名前";
  331. }
  332. }
  333. public string contractTextTerm
  334. {
  335. get
  336. {
  337. return "MaidStatus/契約タイプ/" + this.contractText;
  338. }
  339. }
  340. public string personalTextTerm
  341. {
  342. get
  343. {
  344. return "SubMaid/" + this.uniqueName + "/性格";
  345. }
  346. }
  347. public string relationTextTerm
  348. {
  349. get
  350. {
  351. return "SubMaid/" + this.uniqueName + "/状態";
  352. }
  353. }
  354. public readonly int id;
  355. public readonly string uniqueName;
  356. public readonly bool kissSideNPC;
  357. public readonly string lastName;
  358. public readonly string firstName;
  359. public readonly string presetName;
  360. public readonly string iconFileName;
  361. public readonly string thumbnailFileName;
  362. public readonly Contract contract;
  363. public readonly string contractText;
  364. public readonly string personalText;
  365. public readonly string relationText;
  366. public readonly Seikeiken initSeikeiken;
  367. public readonly string jobClassText;
  368. public readonly int jobClassLevel;
  369. public readonly string yotogiClassText;
  370. public readonly int yotogiClassLevel;
  371. public readonly int likability;
  372. public readonly int lovely;
  373. public readonly int elegance;
  374. public readonly int charm;
  375. public readonly int care;
  376. public readonly int reception;
  377. public readonly int cooking;
  378. public readonly int dance;
  379. public readonly int vocal;
  380. public readonly int playCountNightWork;
  381. public readonly int hp;
  382. public readonly int mind;
  383. public readonly int inyoku;
  384. public readonly int mvalue;
  385. public readonly int hentai;
  386. public readonly int housi;
  387. public readonly int playCountYotogi;
  388. public readonly int rehireEventId;
  389. }
  390. }
  391. [Serializable]
  392. public class BackupStatus : ISerializationCallbackReceiver
  393. {
  394. private BackupStatus()
  395. {
  396. }
  397. public static SubMaid.BackupStatus CreateInstance(Maid maid)
  398. {
  399. Status status = maid.status;
  400. SubMaid.BackupStatus backupStatus = new SubMaid.BackupStatus();
  401. backupStatus.subCharaUniqueName = status.subCharaData.uniqueName;
  402. backupStatus.lastName = status.lastName;
  403. backupStatus.firstName = status.firstName;
  404. backupStatus.employmentDay = status.employmentDay;
  405. backupStatus.relation = status.relation;
  406. backupStatus.additionalRelation = status.additionalRelation;
  407. backupStatus.seikeiken = status.seikeiken;
  408. backupStatus.likability = status.likability;
  409. backupStatus.playCountNightWork = status.playCountNightWork;
  410. backupStatus.sexPlayNumberOfPeople = status.sexPlayNumberOfPeople;
  411. backupStatus.sales = status.sales;
  412. backupStatus.totalSales = status.totalSales;
  413. backupStatus.totalEvaluations = status.totalEvaluations;
  414. backupStatus.evaluation = status.evaluation;
  415. int[] keyArray = status.workDatas.GetKeyArray();
  416. MaidStatus.WorkData[] valueArray = status.workDatas.GetValueArray();
  417. backupStatus.workData = new SubMaid.BackupStatus.WorkData[valueArray.Length];
  418. for (int i = 0; i < valueArray.Length; i++)
  419. {
  420. backupStatus.workData[i] = new SubMaid.BackupStatus.WorkData();
  421. backupStatus.workData[i].key = keyArray[i];
  422. backupStatus.workData[i].id = valueArray[i].id;
  423. backupStatus.workData[i].playCount = valueArray[i].playCount;
  424. backupStatus.workData[i].level = valueArray[i].level;
  425. }
  426. backupStatus.maidFlagsKey = status.flags.GetKeyArray();
  427. backupStatus.maidFlagsValue = status.flags.GetValueArray();
  428. backupStatus.eventEndFlagsKey = status.eventEndFlags.GetKeyArray();
  429. backupStatus.eventEndFlagsValue = status.eventEndFlags.GetValueArray();
  430. backupStatus.iconBinary = maid.GetThumIcon().EncodeToPNG();
  431. backupStatus.presetBinary = GameMain.Instance.CharacterMgr.PresetSaveNotWriteFile(maid, CharacterMgr.PresetType.All);
  432. return backupStatus;
  433. }
  434. public void Apply(Status status)
  435. {
  436. status.lastName = this.lastName;
  437. status.firstName = this.firstName;
  438. status.employmentDay = this.employmentDay;
  439. status.additionalRelation = this.additionalRelation;
  440. status.relation = this.relation;
  441. status.seikeiken = this.seikeiken;
  442. status.likability = this.likability;
  443. status.playCountNightWork = this.playCountNightWork;
  444. status.sexPlayNumberOfPeople = this.sexPlayNumberOfPeople;
  445. status.sales = this.sales;
  446. status.totalSales = this.totalSales;
  447. status.totalEvaluations = this.totalEvaluations;
  448. status.evaluation = this.evaluation;
  449. Dictionary<int, MaidStatus.WorkData> dictionary = new Dictionary<int, MaidStatus.WorkData>();
  450. foreach (SubMaid.BackupStatus.WorkData workData in this.workData)
  451. {
  452. MaidStatus.WorkData workData2 = new MaidStatus.WorkData();
  453. workData2.id = workData.id;
  454. workData2.level = workData.level;
  455. workData2.playCount = workData.playCount;
  456. dictionary.Add(workData.key, workData2);
  457. }
  458. status.SetWorkData(dictionary);
  459. status.RemoveFlagAll();
  460. for (int j = 0; j < this.maidFlagsKey.Length; j++)
  461. {
  462. status.SetFlag(this.maidFlagsKey[j], this.maidFlagsValue[j]);
  463. }
  464. status.RemoveEventEndFlagAll();
  465. for (int k = 0; k < this.eventEndFlagsKey.Length; k++)
  466. {
  467. status.SetEventEndFlag(this.eventEndFlagsKey[k], this.eventEndFlagsValue[k]);
  468. }
  469. if (this.iconBinary != null && this.iconBinary.Length > 0)
  470. {
  471. Texture2D texture2D = new Texture2D(4, 4, TextureFormat.ARGB32, false);
  472. texture2D.LoadImage(this.iconBinary);
  473. status.maid.SetThumIcon(texture2D);
  474. }
  475. if (this.presetBinary != null && this.presetBinary.Length > 0)
  476. {
  477. using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(this.presetBinary), Encoding.UTF8))
  478. {
  479. CharacterMgr.Preset f_prest = GameMain.Instance.CharacterMgr.PresetLoad(binaryReader, string.Empty);
  480. GameMain.Instance.CharacterMgr.PresetSet(status.maid, f_prest, false);
  481. }
  482. }
  483. }
  484. public void OnBeforeSerialize()
  485. {
  486. this.version = 1000;
  487. }
  488. public void OnAfterDeserialize()
  489. {
  490. }
  491. private const int FixVersion = 1000;
  492. public int version = 1000;
  493. public string subCharaUniqueName;
  494. public string lastName;
  495. public string firstName;
  496. public int employmentDay;
  497. public Relation relation;
  498. private AdditionalRelation additionalRelation;
  499. public Seikeiken seikeiken;
  500. public int likability;
  501. public int playCountNightWork;
  502. public int sexPlayNumberOfPeople;
  503. public long sales;
  504. public long totalSales;
  505. public long totalEvaluations;
  506. public int evaluation;
  507. public SubMaid.BackupStatus.WorkData[] workData;
  508. public string[] maidFlagsKey;
  509. public int[] maidFlagsValue;
  510. public int[] eventEndFlagsKey;
  511. public bool[] eventEndFlagsValue;
  512. [NonSerialized]
  513. public byte[] iconBinary;
  514. [NonSerialized]
  515. public byte[] presetBinary;
  516. [Serializable]
  517. public class WorkData : ISerializationCallbackReceiver
  518. {
  519. public void OnBeforeSerialize()
  520. {
  521. this.version = 1000;
  522. }
  523. public void OnAfterDeserialize()
  524. {
  525. }
  526. public int version = 1000;
  527. public int key;
  528. public int id;
  529. public uint playCount;
  530. public int level;
  531. }
  532. }
  533. }
  534. }