VirtualAmiibo.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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 nickname)
  55. {
  56. VirtualAmiiboFile amiiboFile = LoadAmiiboFile(amiiboId);
  57. UtilityImpl utilityImpl = new UtilityImpl(tickSource);
  58. CharInfo charInfo = new CharInfo();
  59. charInfo.SetFromStoreData(StoreData.BuildDefault(utilityImpl, 0));
  60. charInfo.Nickname = Nickname.FromString(nickname);
  61. RegisterInfo registerInfo = new RegisterInfo()
  62. {
  63. MiiCharInfo = charInfo,
  64. FirstWriteYear = (ushort)amiiboFile.FirstWriteDate.Year,
  65. FirstWriteMonth = (byte)amiiboFile.FirstWriteDate.Month,
  66. FirstWriteDay = (byte)amiiboFile.FirstWriteDate.Day,
  67. FontRegion = 0,
  68. Reserved1 = new Array64<byte>(),
  69. Reserved2 = new Array58<byte>()
  70. };
  71. "Ryujinx"u8.CopyTo(registerInfo.Nickname.AsSpan());
  72. return registerInfo;
  73. }
  74. public static bool OpenApplicationArea(string amiiboId, uint applicationAreaId)
  75. {
  76. VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
  77. if (virtualAmiiboFile.ApplicationAreas.Any(item => item.ApplicationAreaId == applicationAreaId))
  78. {
  79. _openedApplicationAreaId = applicationAreaId;
  80. return true;
  81. }
  82. return false;
  83. }
  84. public static byte[] GetApplicationArea(string amiiboId)
  85. {
  86. VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
  87. foreach (VirtualAmiiboApplicationArea applicationArea in virtualAmiiboFile.ApplicationAreas)
  88. {
  89. if (applicationArea.ApplicationAreaId == _openedApplicationAreaId)
  90. {
  91. return applicationArea.ApplicationArea;
  92. }
  93. }
  94. return Array.Empty<byte>();
  95. }
  96. public static bool CreateApplicationArea(string amiiboId, uint applicationAreaId, byte[] applicationAreaData)
  97. {
  98. VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
  99. if (virtualAmiiboFile.ApplicationAreas.Any(item => item.ApplicationAreaId == applicationAreaId))
  100. {
  101. return false;
  102. }
  103. virtualAmiiboFile.ApplicationAreas.Add(new VirtualAmiiboApplicationArea()
  104. {
  105. ApplicationAreaId = applicationAreaId,
  106. ApplicationArea = applicationAreaData
  107. });
  108. SaveAmiiboFile(virtualAmiiboFile);
  109. return true;
  110. }
  111. public static void SetApplicationArea(string amiiboId, byte[] applicationAreaData)
  112. {
  113. VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
  114. if (virtualAmiiboFile.ApplicationAreas.Any(item => item.ApplicationAreaId == _openedApplicationAreaId))
  115. {
  116. for (int i = 0; i < virtualAmiiboFile.ApplicationAreas.Count; i++)
  117. {
  118. if (virtualAmiiboFile.ApplicationAreas[i].ApplicationAreaId == _openedApplicationAreaId)
  119. {
  120. virtualAmiiboFile.ApplicationAreas[i] = new VirtualAmiiboApplicationArea()
  121. {
  122. ApplicationAreaId = _openedApplicationAreaId,
  123. ApplicationArea = applicationAreaData
  124. };
  125. break;
  126. }
  127. }
  128. SaveAmiiboFile(virtualAmiiboFile);
  129. }
  130. }
  131. private static VirtualAmiiboFile LoadAmiiboFile(string amiiboId)
  132. {
  133. Directory.CreateDirectory(Path.Join(AppDataManager.BaseDirPath, "system", "amiibo"));
  134. string filePath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", $"{amiiboId}.json");
  135. VirtualAmiiboFile virtualAmiiboFile;
  136. if (File.Exists(filePath))
  137. {
  138. virtualAmiiboFile = JsonHelper.DeserializeFromFile(filePath, SerializerContext.VirtualAmiiboFile);
  139. }
  140. else
  141. {
  142. virtualAmiiboFile = new VirtualAmiiboFile()
  143. {
  144. FileVersion = 0,
  145. TagUuid = Array.Empty<byte>(),
  146. AmiiboId = amiiboId,
  147. FirstWriteDate = DateTime.Now,
  148. LastWriteDate = DateTime.Now,
  149. WriteCounter = 0,
  150. ApplicationAreas = new List<VirtualAmiiboApplicationArea>()
  151. };
  152. SaveAmiiboFile(virtualAmiiboFile);
  153. }
  154. return virtualAmiiboFile;
  155. }
  156. private static void SaveAmiiboFile(VirtualAmiiboFile virtualAmiiboFile)
  157. {
  158. string filePath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", $"{virtualAmiiboFile.AmiiboId}.json");
  159. JsonHelper.SerializeToFile(filePath, virtualAmiiboFile, SerializerContext.VirtualAmiiboFile);
  160. }
  161. }
  162. }