Compare commits

...

4 Commits

Author SHA1 Message Date
Gloria d1d94bdbe1
Merge 02e84fd59a into a23d8cb92f 2024-05-09 00:24:43 +00:00
yeah-its-gloria 02e84fd59a
Implement Cabinet applet
This implements Nickname support for Amiibos, as well as means of editing the name of an amiibo in games.
2024-05-08 20:23:59 -04:00
Marco Carvalho a23d8cb92f
Replace "List.ForEach" for "foreach" (#6783)
* Replace "List.ForEach" for "foreach"

* dotnet format

* Update Ptc.cs

* Update GpuContext.cs
2024-05-08 13:53:25 +02:00
Nicolas Abram ab12fbe963
Fix system dateTime loading in avalonia LoadCurrentConfiguration (#6676)
* Fix system dateTime loading in avalonia LoadCurrentConfiguration

* Rename local var to not use upper camel case
2024-05-02 13:33:28 +02:00
11 changed files with 249 additions and 8 deletions

View File

@ -857,8 +857,14 @@ namespace ARMeilleure.Translation.PTC
Stopwatch sw = Stopwatch.StartNew();
threads.ForEach((thread) => thread.Start());
threads.ForEach((thread) => thread.Join());
foreach (var thread in threads)
{
thread.Start();
}
foreach (var thread in threads)
{
thread.Join();
}
threads.Clear();

View File

@ -395,8 +395,14 @@ namespace Ryujinx.Graphics.Gpu
{
Renderer.CreateSync(SyncNumber, strict);
SyncActions.ForEach(action => action.SyncPreAction(syncpoint));
SyncpointActions.ForEach(action => action.SyncPreAction(syncpoint));
foreach (var action in SyncActions)
{
action.SyncPreAction(syncpoint);
}
foreach (var action in SyncpointActions)
{
action.SyncPreAction(syncpoint);
}
SyncNumber++;

View File

@ -18,6 +18,7 @@ namespace Ryujinx.HLE.HOS.Applets
{ AppletId.PlayerSelect, typeof(PlayerSelectApplet) },
{ AppletId.Controller, typeof(ControllerApplet) },
{ AppletId.SoftwareKeyboard, typeof(SoftwareKeyboardApplet) },
{ AppletId.Cabinet, typeof(CabinetApplet) },
{ AppletId.LibAppletWeb, typeof(BrowserApplet) },
{ AppletId.LibAppletShop, typeof(BrowserApplet) },
{ AppletId.LibAppletOff, typeof(BrowserApplet) },

View File

@ -0,0 +1,15 @@
using System;
namespace Ryujinx.HLE.HOS.Applets
{
[Flags]
enum AmiiboSettingsReturnFlag : byte
{
Cancel = 0,
HasTagInfo = 1 << 1,
HasRegisterInfo = 1 << 2,
HasCompleteInfo = HasTagInfo | HasRegisterInfo,
}
}

View File

@ -0,0 +1,123 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Memory;
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
using Ryujinx.HLE.HOS.Services.Nfc.Nfp;
using System;
using System.IO;
using System.Text;
namespace Ryujinx.HLE.HOS.Applets
{
internal class CabinetApplet : IApplet
{
private readonly Horizon _system;
private AppletSession _normalSession;
private StartParamForAmiiboSettings _startArguments;
public event EventHandler AppletStateChanged;
public CabinetApplet(Horizon system)
{
_system = system;
}
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
{
_normalSession = normalSession;
CommonArguments commonArguments = IApplet.ReadStruct<CommonArguments>(normalSession.Pop());
Logger.Info?.PrintMsg(LogClass.ServiceAm, $"CabinetApplet version: 0x{commonArguments.AppletVersion:x8}");
_startArguments = IApplet.ReadStruct<StartParamForAmiiboSettings>(normalSession.Pop());
switch (_startArguments.Type)
{
case StartParamForAmiiboSettingsType.NicknameAndOwnerSettings:
{
// TODO: allow changing the owning Mii
ChangeNickname();
break;
}
default:
throw new NotImplementedException($"CabinetStartType {_startArguments.Type} is not implemented.");
}
return ResultCode.Success;
}
public ResultCode GetResult()
{
return ResultCode.Success;
}
private void ChangeNickname()
{
string nickname = null;
if (_startArguments.Flags.HasFlag(AmiiboSettingsReturnFlag.HasRegisterInfo))
{
nickname = Encoding.UTF8.GetString(_startArguments.RegisterInfo.Nickname.AsSpan()).TrimEnd('\0');
}
SoftwareKeyboardUIArgs inputParameters = new()
{
HeaderText = "Enter a new nickname for this amiibo.",
GuideText = nickname,
StringLengthMin = 1,
StringLengthMax = 10,
};
bool inputResult = _system.Device.UIHandler.DisplayInputDialog(inputParameters, out string newNickname);
if (!inputResult)
{
ReturnCancel();
return;
}
VirtualAmiibo.SetNickname(_startArguments.TagInfo.Uuid.AsSpan()[..9].ToArray(), newNickname);
ReturnValueForAmiiboSettings returnValue = new()
{
Flags = AmiiboSettingsReturnFlag.HasCompleteInfo,
DeviceHandle = (ulong)_system.NfpDevices[0].Handle,
TagInfo = _startArguments.TagInfo,
RegisterInfo = _startArguments.RegisterInfo,
};
Span<byte> nicknameData = returnValue.RegisterInfo.Nickname.AsSpan();
nicknameData.Clear();
Encoding.UTF8.GetBytes(newNickname).CopyTo(nicknameData);
_normalSession.Push(BuildResponse(returnValue));
AppletStateChanged?.Invoke(this, null);
_system.ReturnFocus();
}
private void ReturnCancel()
{
_normalSession.Push(BuildResponse());
AppletStateChanged?.Invoke(this, null);
_system.ReturnFocus();
}
private static byte[] BuildResponse(ReturnValueForAmiiboSettings result)
{
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
using BinaryWriter writer = new(stream);
writer.WriteStruct(result);
return stream.ToArray();
}
private static byte[] BuildResponse()
{
return BuildResponse(new ReturnValueForAmiiboSettings { Flags = AmiiboSettingsReturnFlag.Cancel });
}
}
}

View File

@ -0,0 +1,17 @@
using Ryujinx.Common.Memory;
using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Applets
{
[StructLayout(LayoutKind.Sequential, Size = 0x188, Pack = 1)]
struct ReturnValueForAmiiboSettings
{
public AmiiboSettingsReturnFlag Flags;
public Array3<byte> Padding;
public ulong DeviceHandle;
public TagInfo TagInfo;
public RegisterInfo RegisterInfo;
public Array36<byte> Ignored;
}
}

View File

@ -0,0 +1,19 @@
using Ryujinx.Common.Memory;
using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Applets
{
[StructLayout(LayoutKind.Sequential, Size = 0x1a8)]
struct StartParamForAmiiboSettings
{
public byte Unused1;
public StartParamForAmiiboSettingsType Type;
public AmiiboSettingsReturnFlag Flags;
public Array9<byte> StartParamData1;
public TagInfo TagInfo;
public RegisterInfo RegisterInfo;
public Array32<byte> StartParamData2;
public Array36<byte> Unused2;
}
}

View File

@ -0,0 +1,10 @@
namespace Ryujinx.HLE.HOS.Applets
{
enum StartParamForAmiiboSettingsType : byte
{
NicknameAndOwnerSettings = 0,
GameDataEraser = 1,
Restorer = 2,
Formatter = 3,
}
}

View File

@ -6,6 +6,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager
struct VirtualAmiiboFile
{
public uint FileVersion { get; set; }
public string Nickname { get; set; }
public byte[] TagUuid { get; set; }
public string AmiiboId { get; set; }
public DateTime FirstWriteDate { get; set; }

View File

@ -8,6 +8,8 @@ using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
{
@ -85,7 +87,8 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
Reserved1 = new Array64<byte>(),
Reserved2 = new Array58<byte>(),
};
"Ryujinx"u8.CopyTo(registerInfo.Nickname.AsSpan());
Encoding.UTF8.GetBytes(amiiboFile.Nickname).CopyTo(registerInfo.Nickname.AsSpan());
return registerInfo;
}
@ -163,6 +166,15 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
}
}
public static void SetNickname(byte[] tagUuid, string nickname)
{
VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(tagUuid);
virtualAmiiboFile.Nickname = nickname;
SaveAmiiboFile(virtualAmiiboFile);
}
private static VirtualAmiiboFile LoadAmiiboFile(string amiiboId)
{
Directory.CreateDirectory(Path.Join(AppDataManager.BaseDirPath, "system", "amiibo"));
@ -174,12 +186,20 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
if (File.Exists(filePath))
{
virtualAmiiboFile = JsonHelper.DeserializeFromFile(filePath, _serializerContext.VirtualAmiiboFile);
if (virtualAmiiboFile.Nickname == null)
{
virtualAmiiboFile.Nickname = "Ryujinx";
SaveAmiiboFile(virtualAmiiboFile);
}
}
else
{
virtualAmiiboFile = new VirtualAmiiboFile()
{
FileVersion = 0,
Nickname = "Ryujinx",
TagUuid = Array.Empty<byte>(),
AmiiboId = amiiboId,
FirstWriteDate = DateTime.Now,
@ -194,6 +214,28 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
return virtualAmiiboFile;
}
private static VirtualAmiiboFile LoadAmiiboFile(byte[] tagUuid)
{
VirtualAmiiboFile virtualAmiiboFile;
string[] paths = Directory.GetFiles(Path.Join(AppDataManager.BaseDirPath, "system", "amiibo"), "*.json");
foreach (string path in paths)
{
if (path.EndsWith("Amiibo.json"))
{
continue;
}
virtualAmiiboFile = JsonHelper.DeserializeFromFile(path, _serializerContext.VirtualAmiiboFile);
if (virtualAmiiboFile.TagUuid.SequenceEqual(tagUuid))
{
return virtualAmiiboFile;
}
}
throw new FileNotFoundException();
}
private static void SaveAmiiboFile(VirtualAmiiboFile virtualAmiiboFile)
{
string filePath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", $"{virtualAmiiboFile.AmiiboId}.json");

View File

@ -412,10 +412,11 @@ namespace Ryujinx.Ava.UI.ViewModels
Language = (int)config.System.Language.Value;
TimeZone = config.System.TimeZone;
DateTime currentDateTime = DateTime.Now;
DateTime currentHostDateTime = DateTime.Now;
TimeSpan systemDateTimeOffset = TimeSpan.FromSeconds(config.System.SystemTimeOffset);
DateTime currentDateTime = currentHostDateTime.Add(systemDateTimeOffset);
CurrentDate = currentDateTime.Date;
CurrentTime = currentDateTime.TimeOfDay.Add(TimeSpan.FromSeconds(config.System.SystemTimeOffset));
CurrentTime = currentDateTime.TimeOfDay;
EnableVsync = config.Graphics.EnableVsync;
EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks;