VirtualAmiibo.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. using Ryujinx.Common.Configuration;
  2. using Ryujinx.Common.Memory;
  3. using Ryujinx.HLE.HOS.Services.Mii;
  4. using Ryujinx.HLE.HOS.Services.Mii.Types;
  5. using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Text.Json;
  12. namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
  13. {
  14. static class VirtualAmiibo
  15. {
  16. private static uint _openedApplicationAreaId;
  17. public static byte[] GenerateUuid(string amiiboId, bool useRandomUuid)
  18. {
  19. if (useRandomUuid)
  20. {
  21. return GenerateRandomUuid();
  22. }
  23. VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
  24. if (virtualAmiiboFile.TagUuid.Length == 0)
  25. {
  26. virtualAmiiboFile.TagUuid = GenerateRandomUuid();
  27. SaveAmiiboFile(virtualAmiiboFile);
  28. }
  29. return virtualAmiiboFile.TagUuid;
  30. }
  31. private static byte[] GenerateRandomUuid()
  32. {
  33. byte[] uuid = new byte[9];
  34. new Random().NextBytes(uuid);
  35. uuid[3] = (byte)(0x88 ^ uuid[0] ^ uuid[1] ^ uuid[2]);
  36. uuid[8] = (byte)(uuid[3] ^ uuid[4] ^ uuid[5] ^ uuid[6]);
  37. return uuid;
  38. }
  39. public static CommonInfo GetCommonInfo(string amiiboId)
  40. {
  41. VirtualAmiiboFile amiiboFile = LoadAmiiboFile(amiiboId);
  42. return new CommonInfo()
  43. {
  44. LastWriteYear = (ushort)amiiboFile.LastWriteDate.Year,
  45. LastWriteMonth = (byte)amiiboFile.LastWriteDate.Month,
  46. LastWriteDay = (byte)amiiboFile.LastWriteDate.Day,
  47. WriteCounter = amiiboFile.WriteCounter,
  48. Version = 1,
  49. ApplicationAreaSize = AmiiboConstants.ApplicationAreaSize,
  50. Reserved = new Array52<byte>()
  51. };
  52. }
  53. public static RegisterInfo GetRegisterInfo(string amiiboId, string nickname)
  54. {
  55. VirtualAmiiboFile amiiboFile = LoadAmiiboFile(amiiboId);
  56. UtilityImpl utilityImpl = new UtilityImpl();
  57. CharInfo charInfo = new CharInfo();
  58. charInfo.SetFromStoreData(StoreData.BuildDefault(utilityImpl, 0));
  59. charInfo.Nickname = Nickname.FromString(nickname);
  60. RegisterInfo registerInfo = new RegisterInfo()
  61. {
  62. MiiCharInfo = charInfo,
  63. FirstWriteYear = (ushort)amiiboFile.FirstWriteDate.Year,
  64. FirstWriteMonth = (byte)amiiboFile.FirstWriteDate.Month,
  65. FirstWriteDay = (byte)amiiboFile.FirstWriteDate.Day,
  66. FontRegion = 0,
  67. Reserved1 = new Array64<byte>(),
  68. Reserved2 = new Array58<byte>()
  69. };
  70. Encoding.ASCII.GetBytes("Ryujinx").CopyTo(registerInfo.Nickname.ToSpan());
  71. return registerInfo;
  72. }
  73. public static bool OpenApplicationArea(string amiiboId, uint applicationAreaId)
  74. {
  75. VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
  76. if (virtualAmiiboFile.ApplicationAreas.Any(item => item.ApplicationAreaId == applicationAreaId))
  77. {
  78. _openedApplicationAreaId = applicationAreaId;
  79. return true;
  80. }
  81. return false;
  82. }
  83. public static byte[] GetApplicationArea(string amiiboId)
  84. {
  85. VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
  86. foreach (VirtualAmiiboApplicationArea applicationArea in virtualAmiiboFile.ApplicationAreas)
  87. {
  88. if (applicationArea.ApplicationAreaId == _openedApplicationAreaId)
  89. {
  90. return applicationArea.ApplicationArea;
  91. }
  92. }
  93. return Array.Empty<byte>();
  94. }
  95. public static bool CreateApplicationArea(string amiiboId, uint applicationAreaId, byte[] applicationAreaData)
  96. {
  97. VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
  98. if (virtualAmiiboFile.ApplicationAreas.Any(item => item.ApplicationAreaId == applicationAreaId))
  99. {
  100. return false;
  101. }
  102. virtualAmiiboFile.ApplicationAreas.Add(new VirtualAmiiboApplicationArea()
  103. {
  104. ApplicationAreaId = applicationAreaId,
  105. ApplicationArea = applicationAreaData
  106. });
  107. SaveAmiiboFile(virtualAmiiboFile);
  108. return true;
  109. }
  110. public static void SetApplicationArea(string amiiboId, byte[] applicationAreaData)
  111. {
  112. VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
  113. if (virtualAmiiboFile.ApplicationAreas.Any(item => item.ApplicationAreaId == _openedApplicationAreaId))
  114. {
  115. for (int i = 0; i < virtualAmiiboFile.ApplicationAreas.Count; i++)
  116. {
  117. if (virtualAmiiboFile.ApplicationAreas[i].ApplicationAreaId == _openedApplicationAreaId)
  118. {
  119. virtualAmiiboFile.ApplicationAreas[i] = new VirtualAmiiboApplicationArea()
  120. {
  121. ApplicationAreaId = _openedApplicationAreaId,
  122. ApplicationArea = applicationAreaData
  123. };
  124. break;
  125. }
  126. }
  127. SaveAmiiboFile(virtualAmiiboFile);
  128. }
  129. }
  130. private static VirtualAmiiboFile LoadAmiiboFile(string amiiboId)
  131. {
  132. Directory.CreateDirectory(Path.Join(AppDataManager.BaseDirPath, "system", "amiibo"));
  133. string filePath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", $"{amiiboId}.json");
  134. VirtualAmiiboFile virtualAmiiboFile;
  135. if (File.Exists(filePath))
  136. {
  137. virtualAmiiboFile = JsonSerializer.Deserialize<VirtualAmiiboFile>(File.ReadAllText(filePath), new JsonSerializerOptions(JsonSerializerDefaults.General));
  138. }
  139. else
  140. {
  141. virtualAmiiboFile = new VirtualAmiiboFile()
  142. {
  143. FileVersion = 0,
  144. TagUuid = Array.Empty<byte>(),
  145. AmiiboId = amiiboId,
  146. FirstWriteDate = DateTime.Now,
  147. LastWriteDate = DateTime.Now,
  148. WriteCounter = 0,
  149. ApplicationAreas = new List<VirtualAmiiboApplicationArea>()
  150. };
  151. SaveAmiiboFile(virtualAmiiboFile);
  152. }
  153. return virtualAmiiboFile;
  154. }
  155. private static void SaveAmiiboFile(VirtualAmiiboFile virtualAmiiboFile)
  156. {
  157. string filePath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", $"{virtualAmiiboFile.AmiiboId}.json");
  158. File.WriteAllText(filePath, JsonSerializer.Serialize(virtualAmiiboFile));
  159. }
  160. }
  161. }