This commit is contained in:
Jacobwasbeast 2024-12-24 16:28:45 +08:00 committed by GitHub
commit b2128f191c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 393 additions and 120 deletions

View file

@ -339,10 +339,9 @@ namespace Ryujinx.HLE.HOS
public void ScanAmiibo(int nfpDeviceId, string amiiboId, bool useRandomUuid)
{
if (VirtualAmiibo.ApplicationBytes.Length > 0)
if (VirtualAmiibo.VirtualAmiiboBinFile != null)
{
VirtualAmiibo.ApplicationBytes = Array.Empty<byte>();
VirtualAmiibo.InputBin = string.Empty;
VirtualAmiibo.VirtualAmiiboBinFile.SaveFile();
}
if (NfpDevices[nfpDeviceId].State == NfpDeviceState.SearchingForTag)
{
@ -353,13 +352,7 @@ namespace Ryujinx.HLE.HOS
}
public void ScanAmiiboFromBin(string path)
{
VirtualAmiibo.InputBin = path;
if (VirtualAmiibo.ApplicationBytes.Length > 0)
{
VirtualAmiibo.ApplicationBytes = Array.Empty<byte>();
}
byte[] encryptedData = File.ReadAllBytes(path);
VirtualAmiiboFile newFile = AmiiboBinReader.ReadBinFile(encryptedData);
VirtualAmiiboFile newFile = AmiiboBinReader.ReadBinFile(path);
if (SearchingForAmiibo(out int nfpDeviceId))
{
NfpDevices[nfpDeviceId].State = NfpDeviceState.TagFound;

View file

@ -19,8 +19,19 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
return (byte)(uid[3] ^ uid[4] ^ uid[5] ^ uid[6]);
}
public static VirtualAmiiboFile ReadBinFile(byte[] fileBytes)
public static VirtualAmiiboFile ReadBinFile(string filePath)
{
Logger.Info?.Print(LogClass.ServiceNfp, "Reading bin file.");
byte[] fileBytes;
try
{
fileBytes = File.ReadAllBytes(filePath);
}
catch (Exception ex)
{
Logger.Error?.Print(LogClass.ServiceNfp, $"Error reading file: {ex.Message}");
return new VirtualAmiiboFile();
}
string keyRetailBinPath = GetKeyRetailBinPath();
if (string.IsNullOrEmpty(keyRetailBinPath))
{
@ -39,6 +50,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
byte[] newFileBytes = new byte[totalBytes];
Array.Copy(fileBytes, newFileBytes, fileBytes.Length);
fileBytes = newFileBytes;
Logger.Info?.Print(LogClass.ServiceNfp, "Added 8 bytes to the end of the file.");
}
AmiiboDecryptor amiiboDecryptor = new(keyRetailBinPath);
@ -59,6 +71,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
byte[] dataFull = amiiboDump.GetData();
Logger.Debug?.Print(LogClass.ServiceNfp, $"Data Full Length: {dataFull.Length}");
byte[] uid = new byte[7];
byte[] mii = new byte[98];
Array.Copy(dataFull, 0, uid, 0, 7);
byte bcc0 = CalculateBCC0(uid);
@ -96,6 +109,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
setID[0] = pageData[2];
formData = pageData[3];
break;
case >= 40 and <= 63:
int miiOffset = (page - 40) * 4;
Array.Copy(pageData, 0, mii, miiOffset, 4);
break;
case 64:
case 65:
// Extract title ID
@ -113,7 +130,6 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
break;
}
}
string usedCharacterStr = BitConverter.ToString(usedCharacter).Replace("-", "");
string variationStr = BitConverter.ToString(variation).Replace("-", "");
string amiiboIDStr = BitConverter.ToString(amiiboID).Replace("-", "");
@ -141,14 +157,20 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
LastWriteDate = writeDateTime,
WriteCounter = writeCounterValue,
};
if (writeCounterValue > 0)
VirtualAmiiboBinFile virtualAmiiboBinFile = new VirtualAmiiboBinFile
{
VirtualAmiibo.ApplicationBytes = applicationAreas;
}
VirtualAmiibo.NickName = nickName;
ApplicationBytes = applicationAreas,
MiiBytes = mii,
InputBin = filePath,
NickName = nickName,
WriteCounter = writeCounterValue,
LastWriteDate = writeDateTime,
TagUuid = uid,
};
VirtualAmiibo.VirtualAmiiboBinFile = virtualAmiiboBinFile;
return virtualAmiiboFile;
}
public static bool SaveBinFile(string inputFile, byte[] appData)
public static bool SaveBinFile(string inputFile, VirtualAmiiboBinFile virtualAmiiboBinFile)
{
Logger.Info?.Print(LogClass.ServiceNfp, "Saving bin file.");
byte[] readBytes;
@ -168,92 +190,32 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
return false;
}
if (appData.Length != 216) // Ensure application area size is valid
if (readBytes.Length == 532)
{
// add 8 bytes to the end of the file
byte[] newFileBytes = new byte[540];
Array.Copy(readBytes, newFileBytes, readBytes.Length);
readBytes = newFileBytes;
}
AmiiboDecryptor amiiboDecryptor = new AmiiboDecryptor(keyRetailBinPath);
AmiiboDump amiiboDump = amiiboDecryptor.DecryptAmiiboDump(readBytes);
amiiboDump.AmiiboNickname = virtualAmiiboBinFile.NickName;
byte[] appData = virtualAmiiboBinFile.ApplicationBytes;
if (appData.Length != 216)
{
Logger.Error?.Print(LogClass.ServiceNfp, "Invalid application data length. Expected 216 bytes.");
return false;
}
if (readBytes.Length == 532)
{
// add 8 bytes to the end of the file
byte[] newFileBytes = new byte[540];
Array.Copy(readBytes, newFileBytes, readBytes.Length);
readBytes = newFileBytes;
}
AmiiboDecryptor amiiboDecryptor = new AmiiboDecryptor(keyRetailBinPath);
AmiiboDump amiiboDump = amiiboDecryptor.DecryptAmiiboDump(readBytes);
byte[] oldData = amiiboDump.GetData();
if (oldData.Length != 540) // Verify the expected length for NTAG215 tags
{
Logger.Error?.Print(LogClass.ServiceNfp, "Invalid tag data length. Expected 540 bytes.");
return false;
}
Array.Copy(appData, 0, oldData, 304, 216);
// apply write counter and write date change
byte[] writeCounter = BitConverter.GetBytes(virtualAmiiboBinFile.WriteCounter);
byte[] writeDate = BitConverter.GetBytes((ushort)virtualAmiiboBinFile.LastWriteDate.Day);
writeDate = BitConverter.GetBytes((ushort)(writeDate[0] | (virtualAmiiboBinFile.LastWriteDate.Month << 5) | (virtualAmiiboBinFile.LastWriteDate.Year - 2000) << 9));
Array.Copy(writeCounter, 0, oldData, 264, 2);
Array.Copy(writeDate, 0, oldData, 26, 2);
byte[] newData = new byte[oldData.Length];
Array.Copy(oldData, newData, oldData.Length);
// Replace application area with appData
int appAreaOffset = 76 * 4; // Starting page (76) times 4 bytes per page
Array.Copy(appData, 0, newData, appAreaOffset, appData.Length);
AmiiboDump encryptedDump = amiiboDecryptor.EncryptAmiiboDump(newData);
byte[] encryptedData = encryptedDump.GetData();
if (encryptedData == null || encryptedData.Length != readBytes.Length)
{
Logger.Error?.Print(LogClass.ServiceNfp, "Failed to encrypt data correctly.");
return false;
}
inputFile = inputFile.Replace("_modified", string.Empty);
// Save the encrypted data to file or return it for saving externally
string outputFilePath = Path.Combine(Path.GetDirectoryName(inputFile), Path.GetFileNameWithoutExtension(inputFile) + "_modified.bin");
try
{
File.WriteAllBytes(outputFilePath, encryptedData);
Logger.Info?.Print(LogClass.ServiceNfp, $"Modified Amiibo data saved to {outputFilePath}.");
return true;
}
catch (Exception ex)
{
Logger.Error?.Print(LogClass.ServiceNfp, $"Error saving file: {ex.Message}");
return false;
}
}
public static bool SaveBinFile(string inputFile, string newNickName)
{
Logger.Info?.Print(LogClass.ServiceNfp, "Saving bin file.");
byte[] readBytes;
try
{
readBytes = File.ReadAllBytes(inputFile);
}
catch (Exception ex)
{
Logger.Error?.Print(LogClass.ServiceNfp, $"Error reading file: {ex.Message}");
return false;
}
string keyRetailBinPath = GetKeyRetailBinPath();
if (string.IsNullOrEmpty(keyRetailBinPath))
{
Logger.Error?.Print(LogClass.ServiceNfp, "Key retail path is empty.");
return false;
}
if (readBytes.Length == 532)
{
// add 8 bytes to the end of the file
byte[] newFileBytes = new byte[540];
Array.Copy(readBytes, newFileBytes, readBytes.Length);
readBytes = newFileBytes;
}
AmiiboDecryptor amiiboDecryptor = new AmiiboDecryptor(keyRetailBinPath);
AmiiboDump amiiboDump = amiiboDecryptor.DecryptAmiiboDump(readBytes);
amiiboDump.AmiiboNickname = newNickName;
byte[] oldData = amiiboDump.GetData();
if (oldData.Length != 540) // Verify the expected length for NTAG215 tags
{
Logger.Error?.Print(LogClass.ServiceNfp, "Invalid tag data length. Expected 540 bytes.");

View file

@ -0,0 +1,257 @@
using Ryujinx.HLE.HOS.Services.Mii.Types;
using System;
using System.Text;
namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
{
internal class CharInfoBin
{
public byte MiiVersion { get; private set; }
public byte[] CreateID { get; private set; }
public bool AllowCopying { get; private set; }
public bool ProfanityFlag { get; private set; }
public int RegionLock { get; private set; }
public int CharacterSet { get; private set; }
public int PageIndex { get; private set; }
public int SlotIndex { get; private set; }
public int DeviceOrigin { get; private set; }
public ulong SystemId { get; private set; }
public uint MiiId { get; private set; }
public string CreatorMac { get; private set; }
public bool IsMale { get; private set; }
public int BirthdayMonth { get; private set; }
public int BirthdayDay { get; private set; }
public int FavoriteColor { get; private set; }
public bool FavoriteMii { get; private set; }
public string MiiName { get; private set; }
public string AuthorName { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
public bool DisableSharing { get; private set; }
public int FaceShape { get; private set; }
public int SkinColor { get; private set; }
public int Wrinkles { get; private set; }
public int Makeup { get; private set; }
public int HairStyle { get; private set; }
public int HairColor { get; private set; }
public bool FlipHair { get; private set; }
public int EyeStyle { get; private set; }
public int EyeColor { get; private set; }
public int EyeScale { get; private set; }
public int EyeYScale { get; private set; }
public int EyeRotation { get; private set; }
public int EyeXSpacing { get; private set; }
public int EyeYPosition { get; private set; }
public int EyebrowStyle { get; private set; }
public int EyebrowColor { get; private set; }
public int EyebrowScale { get; private set; }
public int EyebrowYScale { get; private set; }
public int EyebrowRotation { get; private set; }
public int EyebrowXSpacing { get; private set; }
public int EyebrowYPosition { get; private set; }
public int NoseStyle { get; private set; }
public int NoseScale { get; private set; }
public int NoseYPosition { get; private set; }
public int MouthStyle { get; private set; }
public int MouthColor { get; private set; }
public int MouthScale { get; private set; }
public int MouthYScale { get; private set; }
public int MouthYPosition { get; private set; }
public int MustacheStyle { get; private set; }
public int BeardStyle { get; private set; }
public int BeardColor { get; private set; }
public int MustacheScale { get; private set; }
public int MustacheYPosition { get; private set; }
public int GlassesStyle { get; private set; }
public int GlassesColor { get; private set; }
public int GlassesScale { get; private set; }
public int GlassesYPosition { get; private set; }
public bool MoleEnabled { get; private set; }
public int MoleScale { get; private set; }
public int MoleXPosition { get; private set; }
public int MoleYPosition { get; private set; }
public static CharInfoBin Parse(byte[] data)
{
if (data.Length < 0x5C)
throw new ArgumentException("Data too short to parse Mii data.");
var mii = new CharInfoBin();
mii.MiiVersion = data[0x0];
byte flags1 = data[0x1];
mii.AllowCopying = (flags1 & 0x1) != 0;
mii.ProfanityFlag = (flags1 & 0x2) != 0;
mii.RegionLock = (flags1 >> 2) & 0x3;
mii.CharacterSet = (flags1 >> 4) & 0x3;
// add the first 0x10 bytes to the create id
mii.CreateID = data[0x0..0x10];
byte position = data[0x2];
mii.PageIndex = position & 0xF;
mii.SlotIndex = (position >> 4) & 0xF;
byte deviceInfo = data[0x3];
mii.DeviceOrigin = (deviceInfo >> 4) & 0x7;
mii.SystemId = BitConverter.ToUInt64(data, 0x4);
mii.MiiId = BitConverter.ToUInt32(data, 0xC);
mii.CreatorMac = BitConverter.ToString(data, 0x10, 0x6).Replace("-", ":");
ushort flags2 = BitConverter.ToUInt16(data, 0x18);
mii.IsMale = (flags2 & 0x1) == 0;
mii.BirthdayMonth = (flags2 >> 1) & 0xF;
mii.BirthdayDay = (flags2 >> 5) & 0x1F;
mii.FavoriteColor = (flags2 >> 10) & 0xF;
mii.FavoriteMii = (flags2 & 0x4000) != 0;
mii.MiiName = ParseUtf16String(data, 0x1A, 20);
ushort dimensions = BitConverter.ToUInt16(data, 0x2E);
mii.Width = dimensions & 0xFF;
mii.Height = (dimensions >> 8) & 0xFF;
byte flags3 = data[0x30];
mii.DisableSharing = (flags3 & 0x1) != 0;
mii.FaceShape = (flags3 >> 1) & 0xF;
mii.SkinColor = (flags3 >> 5) & 0x7;
byte flags4 = data[0x31];
mii.Wrinkles = flags4 & 0xF;
mii.Makeup = (flags4 >> 4) & 0xF;
mii.HairStyle = data[0x32];
byte hairInfo = data[0x33];
mii.HairColor = hairInfo & 0x7;
mii.FlipHair = (hairInfo & 0x8) != 0;
uint eyeInfo = BitConverter.ToUInt32(data, 0x34);
mii.EyeStyle = (int)(eyeInfo & 0x3F);
mii.EyeColor = (int)((eyeInfo >> 6) & 0x7);
mii.EyeScale = (int)((eyeInfo >> 9) & 0xF);
mii.EyeYScale = (int)((eyeInfo >> 13) & 0x7);
mii.EyeRotation = (int)((eyeInfo >> 16) & 0x1F);
mii.EyeXSpacing = (int)((eyeInfo >> 21) & 0xF);
mii.EyeYPosition = (int)((eyeInfo >> 25) & 0x1F);
uint eyebrowInfo = BitConverter.ToUInt32(data, 0x38);
mii.EyebrowStyle = (int)(eyebrowInfo & 0x1F);
mii.EyebrowColor = (int)((eyebrowInfo >> 5) & 0x7);
mii.EyebrowScale = (int)((eyebrowInfo >> 8) & 0xF);
mii.EyebrowYScale = (int)((eyebrowInfo >> 12) & 0x7);
mii.EyebrowRotation = (int)((eyebrowInfo >> 16) & 0xF);
mii.EyebrowXSpacing = (int)((eyebrowInfo >> 21) & 0xF);
mii.EyebrowYPosition = (int)((eyebrowInfo >> 25) & 0x1F);
ushort noseInfo = BitConverter.ToUInt16(data, 0x3C);
mii.NoseStyle = noseInfo & 0x1F;
mii.NoseScale = (noseInfo >> 5) & 0xF;
mii.NoseYPosition = (noseInfo >> 9) & 0x1F;
ushort mouthInfo = BitConverter.ToUInt16(data, 0x3E);
mii.MouthStyle = mouthInfo & 0x3F;
mii.MouthColor = (mouthInfo >> 6) & 0x7;
mii.MouthScale = (mouthInfo >> 9) & 0xF;
mii.MouthYScale = (mouthInfo >> 13) & 0x7;
ushort miscInfo = BitConverter.ToUInt16(data, 0x40);
mii.MouthYPosition = miscInfo & 0x1F;
mii.MustacheStyle = (miscInfo >> 5) & 0x7;
ushort beardInfo = BitConverter.ToUInt16(data, 0x42);
mii.BeardStyle = beardInfo & 0x7;
mii.BeardColor = (beardInfo >> 3) & 0x7;
ushort mustacheInfo = BitConverter.ToUInt16(data, 0x44);
mii.MustacheScale = mustacheInfo & 0xF;
mii.MustacheYPosition = (mustacheInfo >> 4) & 0x1F;
ushort glassesInfo = BitConverter.ToUInt16(data, 0x46);
mii.GlassesStyle = glassesInfo & 0xF;
mii.GlassesColor = (glassesInfo >> 4) & 0x7;
mii.GlassesScale = (glassesInfo >> 7) & 0xF;
mii.GlassesYPosition = (glassesInfo >> 11) & 0x1F;
byte moleFlags = data[0x48];
mii.MoleEnabled = (moleFlags & 0x1) != 0;
mii.MoleScale = (moleFlags >> 1) & 0xF;
ushort moleInfo = BitConverter.ToUInt16(data, 0x46);
mii.MoleEnabled = (moleInfo & 0x1) != 0;
mii.MoleScale = (moleInfo >> 1) & 0xF; // 4 bits for scale
mii.MoleXPosition = (moleInfo >> 5) & 0x1F; // 5 bits for X position
mii.MoleYPosition = (moleInfo >> 10) & 0x1F; // 5 bits for Y position
return mii;
}
private static string ParseUtf16String(byte[] data, int offset, int maxLength)
{
int length = 0;
for (int i = 0; i < maxLength * 2; i += 2)
{
if (data[offset + i] == 0 && data[offset + i + 1] == 0)
break;
length++;
}
return Encoding.Unicode.GetString(data, offset, length * 2);
}
public CharInfo ConvertToCharInfo(CharInfo Info)
{
//UInt128 CreateId = BitConverter.ToUInt128(CreateID, 0);
//Info.CreateId = new CreateId(CreateId);
Info.Nickname = Nickname.FromString(MiiName);
Info.FavoriteColor = (byte)FavoriteColor;
Info.Gender = IsMale ? Gender.Male : Gender.Female;
Info.Height = (byte)Height;
Info.FacelineType = (FacelineType)FaceShape;
Info.FacelineColor = (FacelineColor)SkinColor;
Info.FacelineWrinkle = (FacelineWrinkle)Wrinkles;
Info.FacelineMake = (FacelineMake)Makeup;
Info.HairType = (HairType)HairStyle;
Info.HairColor = (CommonColor)HairColor;
Info.HairFlip = FlipHair ? HairFlip.Left : HairFlip.Right;
Info.EyeType = (EyeType)EyeStyle;
Info.EyeColor = (CommonColor)EyeColor;
Info.EyeScale = (byte)EyeScale;
Info.EyeAspect = (byte)EyeYScale;
Info.EyeRotate = (byte)EyeRotation;
Info.EyeX = (byte)EyeXSpacing;
Info.EyeY = (byte)EyeYPosition;
Info.EyebrowType = (EyebrowType)EyebrowStyle;
Info.EyebrowColor = (CommonColor)EyebrowColor;
Info.EyebrowScale = (byte)EyebrowScale;
Info.EyebrowAspect = (byte)EyebrowYScale;
Info.EyebrowRotate = (byte)EyebrowRotation;
Info.EyebrowX = (byte)EyebrowXSpacing;
Info.EyebrowY = (byte)EyebrowYPosition;
Info.NoseType = (NoseType)NoseStyle;
Info.NoseScale = (byte)NoseScale;
Info.NoseY = (byte)NoseYPosition;
Info.MouthType = (MouthType)MouthStyle;
Info.MouthColor = (CommonColor)MouthColor;
Info.MouthScale = (byte)MouthScale;
Info.MouthAspect = (byte)MouthYScale;
Info.MouthY = (byte)MouthYPosition;
Info.BeardType = (BeardType)BeardStyle;
Info.BeardColor = (CommonColor)BeardColor;
Info.MustacheType = (MustacheType)MustacheStyle;
Info.MustacheScale = (byte)MustacheScale;
Info.MustacheY = (byte)MustacheYPosition;
Info.GlassType = (GlassType)GlassesStyle;
Info.GlassColor = (CommonColor)GlassesColor;
Info.GlassScale = (byte)GlassesScale;
Info.GlassY = (byte)GlassesYPosition;
Info.MoleType = MoleEnabled ? MoleType.OneDot : MoleType.None;
Info.MoleScale = (byte)MoleScale;
Info.MoleX = (byte)MoleXPosition;
Info.MoleY = (byte)MoleYPosition;
return Info;
}
}
}

View file

@ -0,0 +1,68 @@
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Services.Mii;
using Ryujinx.HLE.HOS.Services.Mii.Types;
using Ryujinx.HLE.HOS.Services.Nfc.Nfp;
using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
using System;
using System.Collections.Generic;
using System.Text;
namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
{
public class VirtualAmiiboBinFile
{
public byte[] ApplicationBytes { get; set; }
public byte[] MiiBytes { get; set; }
public string InputBin { get; set; }
public string NickName { get; set; }
public int WriteCounter { get; set; }
public DateTime LastWriteDate { get; set; }
public byte[] TagUuid { get; set; }
internal RegisterInfo GetRegisterInfo(ITickSource tickSource)
{
RegisterInfo info = new RegisterInfo();
info.FirstWriteYear = (ushort)LastWriteDate.Year;
info.FirstWriteMonth = (byte)LastWriteDate.Month;
info.FirstWriteDay = (byte)LastWriteDate.Day;
byte[] nicknameBytes = Encoding.UTF8.GetBytes(NickName);
nicknameBytes.CopyTo(info.Nickname.AsSpan());
byte[] newMiiBytes = new byte[92];
Array.Copy(MiiBytes, 0, newMiiBytes, 0, 92);
CharInfoBin charInfoBin = CharInfoBin.Parse(newMiiBytes);
UtilityImpl utilityImpl = new UtilityImpl(tickSource);
CharInfo Info = new();
Info.SetFromStoreData(StoreData.BuildDefault(utilityImpl, 0));
CharInfo charInfo = charInfoBin.ConvertToCharInfo(Info);
info.MiiCharInfo = charInfo;
return info;
}
public void UpdateApplicationArea(byte[] applicationAreaData)
{
ApplicationBytes = applicationAreaData;
WriteCounter++;
LastWriteDate = DateTime.Now;
SaveFile();
}
public void UpdateNickName(string newNickName)
{
NickName = newNickName;
SaveFile();
}
public bool SaveFile()
{
try
{
AmiiboBinReader.SaveBinFile(InputBin, this);
VirtualAmiibo.VirtualAmiiboBinFile = null;
}
catch (Exception)
{
return false;
}
return true;
}
}
}

View file

@ -16,9 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
static class VirtualAmiibo
{
public static uint OpenedApplicationAreaId;
public static byte[] ApplicationBytes = Array.Empty<byte>();
public static string InputBin = string.Empty;
public static string NickName = string.Empty;
public static VirtualAmiiboBinFile VirtualAmiiboBinFile = null;
private static readonly AmiiboJsonSerializerContext _serializerContext = AmiiboJsonSerializerContext.Default;
public static byte[] GenerateUuid(string amiiboId, bool useRandomUuid)
{
@ -69,13 +67,12 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
public static RegisterInfo GetRegisterInfo(ITickSource tickSource, string amiiboId, string userName)
{
if (VirtualAmiiboBinFile!=null)
{
return VirtualAmiiboBinFile.GetRegisterInfo(tickSource);
}
VirtualAmiiboFile amiiboFile = LoadAmiiboFile(amiiboId);
string nickname = amiiboFile.NickName ?? "Ryujinx";
if (NickName != string.Empty)
{
nickname = NickName;
NickName = string.Empty;
}
UtilityImpl utilityImpl = new(tickSource);
CharInfo charInfo = new();
@ -103,20 +100,20 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
public static void UpdateNickName(string amiiboId, string newNickName)
{
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
virtualAmiiboFile.NickName = newNickName;
if (InputBin != string.Empty)
if (VirtualAmiiboBinFile != null)
{
AmiiboBinReader.SaveBinFile(InputBin, virtualAmiiboFile.NickName);
VirtualAmiiboBinFile.UpdateNickName(newNickName);
return;
}
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
virtualAmiiboFile.NickName = newNickName;
SaveAmiiboFile(virtualAmiiboFile);
}
public static bool OpenApplicationArea(string amiiboId, uint applicationAreaId)
{
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
if (ApplicationBytes.Length > 0)
if (VirtualAmiiboBinFile != null)
{
OpenedApplicationAreaId = applicationAreaId;
return true;
@ -134,11 +131,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
public static byte[] GetApplicationArea(string amiiboId)
{
if (ApplicationBytes.Length > 0)
if (VirtualAmiiboBinFile != null)
{
byte[] bytes = ApplicationBytes;
ApplicationBytes = Array.Empty<byte>();
return bytes;
return VirtualAmiiboBinFile.ApplicationBytes;
}
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
@ -175,9 +170,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
public static void SetApplicationArea(string amiiboId, byte[] applicationAreaData)
{
if (InputBin != string.Empty)
if (VirtualAmiiboBinFile != null)
{
AmiiboBinReader.SaveBinFile(InputBin, applicationAreaData);
VirtualAmiiboBinFile.UpdateApplicationArea(applicationAreaData);
return;
}
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId);
@ -241,11 +236,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
public static bool SaveFileExists(VirtualAmiiboFile virtualAmiiboFile)
{
if (InputBin != string.Empty)
if (VirtualAmiiboBinFile != null)
{
SaveAmiiboFile(virtualAmiiboFile);
return true;
return VirtualAmiiboBinFile.SaveFile();
}
return File.Exists(Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", $"{virtualAmiiboFile.AmiiboId}.json"));
}