VirtualAmiibo.cs 7.5 KB

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