Compare commits

...

2 Commits

Author SHA1 Message Date
WilliamWsyHK
d00754477e Add Firmware keyword in log if it is indeed firmware (#343)
Co-authored-by: LotP1 <rasmus.stilling.pedersen1@gmail.com>
2024-12-07 04:03:01 -06:00
maxdlpee
0bc1eddaeb Update Spanish translation (#332)
- Added translations for XCI trimmer
- Added translations for Cabinet applet
- Added translations for Keys installer
- Other miscellaneous translations added
2024-12-06 21:57:35 -06:00
8 changed files with 104 additions and 69 deletions

View File

@@ -26,7 +26,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
{ {
private static readonly TitleUpdateMetadataJsonSerializerContext _applicationSerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly TitleUpdateMetadataJsonSerializerContext _applicationSerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public static ProcessResult Load(this Nca nca, Switch device, Nca patchNca, Nca controlNca) public static ProcessResult Load(this Nca nca, Switch device, Nca patchNca, Nca controlNca, BlitStruct<ApplicationControlProperty>? customNacpData = null)
{ {
// Extract RomFs and ExeFs from NCA. // Extract RomFs and ExeFs from NCA.
IStorage romFs = nca.GetRomFs(device, patchNca); IStorage romFs = nca.GetRomFs(device, patchNca);
@@ -55,6 +55,10 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
{ {
nacpData = controlNca.GetNacp(device); nacpData = controlNca.GetNacp(device);
} }
else if (customNacpData != null) // if the Application doesn't provide a nacp file but the Application provides an override, use the provided nacp override
{
nacpData = (BlitStruct<ApplicationControlProperty>)customNacpData;
}
/* TODO: Rework this since it's wrong and doesn't work as it takes the DisplayVersion from a "potential" non-existent update. /* TODO: Rework this since it's wrong and doesn't work as it takes the DisplayVersion from a "potential" non-existent update.

View File

@@ -98,12 +98,12 @@ namespace Ryujinx.HLE.Loaders.Processes
return false; return false;
} }
public bool LoadNca(string path) public bool LoadNca(string path, BlitStruct<ApplicationControlProperty>? customNacpData = null)
{ {
FileStream file = new(path, FileMode.Open, FileAccess.Read); FileStream file = new(path, FileMode.Open, FileAccess.Read);
Nca nca = new(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false)); Nca nca = new(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false));
ProcessResult processResult = nca.Load(_device, null, null); ProcessResult processResult = nca.Load(_device, null, null, customNacpData);
if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult)) if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult))
{ {

View File

@@ -84,12 +84,19 @@ namespace Ryujinx.HLE.Loaders.Processes
return false; return false;
} }
bool isFirmware = ProgramId is >= 0x0100000000000819 and <= 0x010000000000081C;
bool isFirmwareApplication = ProgramId <= 0x0100000000007FFF;
string name = !isFirmware
? (isFirmwareApplication ? "Firmware Application " : "") + (!string.IsNullOrWhiteSpace(Name) ? Name : "<Unknown Name>")
: "Firmware";
// TODO: LibHac npdm currently doesn't support version field. // TODO: LibHac npdm currently doesn't support version field.
string version = ProgramId > 0x0100000000007FFF string version = !isFirmware
? DisplayVersion ? (!string.IsNullOrWhiteSpace(DisplayVersion) ? DisplayVersion : "<Unknown Version>")
: device.System.ContentManager.GetCurrentFirmwareVersion()?.VersionString ?? "?"; : device.System.ContentManager.GetCurrentFirmwareVersion()?.VersionString ?? "?";
Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {Name} v{version} [{ProgramIdText}] [{(Is64Bit ? "64-bit" : "32-bit")}]"); Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {name} v{version} [{ProgramIdText}] [{(Is64Bit ? "64-bit" : "32-bit")}]");
return true; return true;
} }

View File

@@ -1,3 +1,5 @@
using LibHac.Common;
using LibHac.Ns;
using Ryujinx.Audio.Backends.CompatLayer; using Ryujinx.Audio.Backends.CompatLayer;
using Ryujinx.Audio.Integration; using Ryujinx.Audio.Integration;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
@@ -111,7 +113,7 @@ namespace Ryujinx.HLE
public bool LoadCart(string exeFsDir, string romFsFile = null) => Processes.LoadUnpackedNca(exeFsDir, romFsFile); public bool LoadCart(string exeFsDir, string romFsFile = null) => Processes.LoadUnpackedNca(exeFsDir, romFsFile);
public bool LoadXci(string xciFile, ulong applicationId = 0) => Processes.LoadXci(xciFile, applicationId); public bool LoadXci(string xciFile, ulong applicationId = 0) => Processes.LoadXci(xciFile, applicationId);
public bool LoadNca(string ncaFile) => Processes.LoadNca(ncaFile); public bool LoadNca(string ncaFile, BlitStruct<ApplicationControlProperty>? customNacpData = null) => Processes.LoadNca(ncaFile, customNacpData);
public bool LoadNsp(string nspFile, ulong applicationId = 0) => Processes.LoadNsp(nspFile, applicationId); public bool LoadNsp(string nspFile, ulong applicationId = 0) => Processes.LoadNsp(nspFile, applicationId);
public bool LoadProgram(string fileName) => Processes.LoadNxo(fileName); public bool LoadProgram(string fileName) => Processes.LoadNxo(fileName);

View File

@@ -3,6 +3,8 @@ using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Threading; using Avalonia.Threading;
using LibHac.Common;
using LibHac.Ns;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.Dummy; using Ryujinx.Audio.Backends.Dummy;
using Ryujinx.Audio.Backends.OpenAL; using Ryujinx.Audio.Backends.OpenAL;
@@ -670,7 +672,7 @@ namespace Ryujinx.Ava
_cursorState = CursorStates.ForceChangeCursor; _cursorState = CursorStates.ForceChangeCursor;
} }
public async Task<bool> LoadGuestApplication() public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null)
{ {
InitializeSwitchInstance(); InitializeSwitchInstance();
MainWindow.UpdateGraphicsConfig(); MainWindow.UpdateGraphicsConfig();
@@ -740,7 +742,7 @@ namespace Ryujinx.Ava
{ {
Logger.Info?.Print(LogClass.Application, "Loading as Firmware Title (NCA)."); Logger.Info?.Print(LogClass.Application, "Loading as Firmware Title (NCA).");
if (!Device.LoadNca(ApplicationPath)) if (!Device.LoadNca(ApplicationPath, customNacpData))
{ {
Device.Dispose(); Device.Dispose();

View File

@@ -1,7 +1,7 @@
{ {
"Language": "Español (ES)", "Language": "Español (ES)",
"MenuBarFileOpenApplet": "Abrir applet", "MenuBarFileOpenApplet": "Abrir applet",
"MenuBarFileOpenAppletOpenMiiApplet": "Mii Edit Applet", "MenuBarFileOpenAppletOpenMiiApplet": "Applet Editor Mii",
"MenuBarFileOpenAppletOpenMiiAppletToolTip": "Abre el editor de Mii en modo autónomo", "MenuBarFileOpenAppletOpenMiiAppletToolTip": "Abre el editor de Mii en modo autónomo",
"SettingsTabInputDirectMouseAccess": "Acceso directo al ratón", "SettingsTabInputDirectMouseAccess": "Acceso directo al ratón",
"SettingsTabSystemMemoryManagerMode": "Modo del administrador de memoria:", "SettingsTabSystemMemoryManagerMode": "Modo del administrador de memoria:",
@@ -32,12 +32,12 @@
"MenuBarFileToolsInstallFirmwareFromFile": "Instalar firmware desde un archivo XCI o ZIP", "MenuBarFileToolsInstallFirmwareFromFile": "Instalar firmware desde un archivo XCI o ZIP",
"MenuBarFileToolsInstallFirmwareFromDirectory": "Instalar firmware desde una carpeta", "MenuBarFileToolsInstallFirmwareFromDirectory": "Instalar firmware desde una carpeta",
"MenuBarToolsInstallKeys": "Install Keys", "MenuBarToolsInstallKeys": "Install Keys",
"MenuBarFileToolsInstallKeysFromFile": "Install keys from KEYS or ZIP", "MenuBarFileToolsInstallKeysFromFile": "Instalar keys de KEYS o ZIP",
"MenuBarFileToolsInstallKeysFromFolder": "Install keys from a directory", "MenuBarFileToolsInstallKeysFromFolder": "Instalar keys de un directorio",
"MenuBarToolsManageFileTypes": "Administrar tipos de archivo", "MenuBarToolsManageFileTypes": "Administrar tipos de archivo",
"MenuBarToolsInstallFileTypes": "Instalar tipos de archivo", "MenuBarToolsInstallFileTypes": "Instalar tipos de archivo",
"MenuBarToolsUninstallFileTypes": "Desinstalar tipos de archivo", "MenuBarToolsUninstallFileTypes": "Desinstalar tipos de archivo",
"MenuBarToolsXCITrimmer": "Trim XCI Files", "MenuBarToolsXCITrimmer": "Recortar archivos XCI",
"MenuBarView": "_View", "MenuBarView": "_View",
"MenuBarViewWindow": "Tamaño Ventana", "MenuBarViewWindow": "Tamaño Ventana",
"MenuBarViewWindow720": "720p", "MenuBarViewWindow720": "720p",
@@ -89,11 +89,11 @@
"GameListContextMenuOpenModsDirectoryToolTip": "Abre el directorio que contiene los Mods de la Aplicación.", "GameListContextMenuOpenModsDirectoryToolTip": "Abre el directorio que contiene los Mods de la Aplicación.",
"GameListContextMenuOpenSdModsDirectory": "Abrir Directorio de Mods de Atmosphere\n\n\n\n\n\n", "GameListContextMenuOpenSdModsDirectory": "Abrir Directorio de Mods de Atmosphere\n\n\n\n\n\n",
"GameListContextMenuOpenSdModsDirectoryToolTip": "Abre el directorio alternativo de la tarjeta SD de Atmosphere que contiene los Mods de la Aplicación. Útil para los mods que están empaquetados para el hardware real.", "GameListContextMenuOpenSdModsDirectoryToolTip": "Abre el directorio alternativo de la tarjeta SD de Atmosphere que contiene los Mods de la Aplicación. Útil para los mods que están empaquetados para el hardware real.",
"GameListContextMenuTrimXCI": "Check and Trim XCI File", "GameListContextMenuTrimXCI": "Verificar y recortar archivo XCI",
"GameListContextMenuTrimXCIToolTip": "Check and Trim XCI File to Save Disk Space", "GameListContextMenuTrimXCIToolTip": "Verificar y recortar archivo XCI para ahorrar espacio en disco",
"StatusBarGamesLoaded": "{0}/{1} juegos cargados", "StatusBarGamesLoaded": "{0}/{1} juegos cargados",
"StatusBarSystemVersion": "Versión del sistema: {0}", "StatusBarSystemVersion": "Versión del sistema: {0}",
"StatusBarXCIFileTrimming": "Trimming XCI File '{0}'", "StatusBarXCIFileTrimming": "Recortando el siguiente archivo XCI: '{0}'",
"LinuxVmMaxMapCountDialogTitle": "Límite inferior para mapeos de memoria detectado", "LinuxVmMaxMapCountDialogTitle": "Límite inferior para mapeos de memoria detectado",
"LinuxVmMaxMapCountDialogTextPrimary": "¿Quieres aumentar el valor de vm.max_map_count a {0}?", "LinuxVmMaxMapCountDialogTextPrimary": "¿Quieres aumentar el valor de vm.max_map_count a {0}?",
"LinuxVmMaxMapCountDialogTextSecondary": "Algunos juegos podrían intentar crear más mapeos de memoria de los permitidos. Ryujinx se bloqueará tan pronto como se supere este límite.", "LinuxVmMaxMapCountDialogTextSecondary": "Algunos juegos podrían intentar crear más mapeos de memoria de los permitidos. Ryujinx se bloqueará tan pronto como se supere este límite.",
@@ -480,7 +480,7 @@
"DialogUninstallFileTypesSuccessMessage": "¡Tipos de archivos desinstalados con éxito!", "DialogUninstallFileTypesSuccessMessage": "¡Tipos de archivos desinstalados con éxito!",
"DialogUninstallFileTypesErrorMessage": "No se pudo desinstalar los tipos de archivo.", "DialogUninstallFileTypesErrorMessage": "No se pudo desinstalar los tipos de archivo.",
"DialogOpenSettingsWindowLabel": "Abrir ventana de opciones", "DialogOpenSettingsWindowLabel": "Abrir ventana de opciones",
"DialogOpenXCITrimmerWindowLabel": "XCI Trimmer Window", "DialogOpenXCITrimmerWindowLabel": "Ventana recortador XCI",
"DialogControllerAppletTitle": "Applet de mandos", "DialogControllerAppletTitle": "Applet de mandos",
"DialogMessageDialogErrorExceptionMessage": "Error al mostrar cuadro de diálogo: {0}", "DialogMessageDialogErrorExceptionMessage": "Error al mostrar cuadro de diálogo: {0}",
"DialogSoftwareKeyboardErrorExceptionMessage": "Error al mostrar teclado de software: {0}", "DialogSoftwareKeyboardErrorExceptionMessage": "Error al mostrar teclado de software: {0}",
@@ -509,13 +509,13 @@
"DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n¿Continuar?", "DialogFirmwareInstallerFirmwareInstallConfirmMessage": "\n\n¿Continuar?",
"DialogFirmwareInstallerFirmwareInstallWaitMessage": "Instalando firmware...", "DialogFirmwareInstallerFirmwareInstallWaitMessage": "Instalando firmware...",
"DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Versión de sistema {0} instalada con éxito.", "DialogFirmwareInstallerFirmwareInstallSuccessMessage": "Versión de sistema {0} instalada con éxito.",
"DialogKeysInstallerKeysNotFoundErrorMessage": "An invalid Keys file was found in {0}", "DialogKeysInstallerKeysNotFoundErrorMessage": "Se halló un archivo Keys inválido en {0}",
"DialogKeysInstallerKeysInstallTitle": "Install Keys", "DialogKeysInstallerKeysInstallTitle": "Instalar Keys",
"DialogKeysInstallerKeysInstallMessage": "New Keys file will be installed.", "DialogKeysInstallerKeysInstallMessage": "Un nuevo archivo Keys será instalado.",
"DialogKeysInstallerKeysInstallSubMessage": "\n\nThis may replace some of the current installed Keys.", "DialogKeysInstallerKeysInstallSubMessage": "\n\nEsto puede reemplazar algunas de las Keys actualmente instaladas.",
"DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDo you want to continue?", "DialogKeysInstallerKeysInstallConfirmMessage": "\n\nDeseas continuar?",
"DialogKeysInstallerKeysInstallWaitMessage": "Installing Keys...", "DialogKeysInstallerKeysInstallWaitMessage": "Instalando Keys...",
"DialogKeysInstallerKeysInstallSuccessMessage": "New Keys file successfully installed.", "DialogKeysInstallerKeysInstallSuccessMessage": "Nuevo archivo Keys instalado con éxito.",
"DialogUserProfileDeletionWarningMessage": "Si eliminas el perfil seleccionado no quedará ningún otro perfil", "DialogUserProfileDeletionWarningMessage": "Si eliminas el perfil seleccionado no quedará ningún otro perfil",
"DialogUserProfileDeletionConfirmMessage": "¿Quieres eliminar el perfil seleccionado?", "DialogUserProfileDeletionConfirmMessage": "¿Quieres eliminar el perfil seleccionado?",
"DialogUserProfileUnsavedChangesTitle": "Advertencia - Cambios sin guardar", "DialogUserProfileUnsavedChangesTitle": "Advertencia - Cambios sin guardar",
@@ -688,23 +688,23 @@
"OpenSetupGuideMessage": "Abrir la guía de instalación", "OpenSetupGuideMessage": "Abrir la guía de instalación",
"NoUpdate": "No actualizado", "NoUpdate": "No actualizado",
"TitleUpdateVersionLabel": "Versión {0} - {1}", "TitleUpdateVersionLabel": "Versión {0} - {1}",
"TitleBundledUpdateVersionLabel": "Bundled: Version {0}", "TitleBundledUpdateVersionLabel": "Incorporado: Versión {0}",
"TitleBundledDlcLabel": "Bundled:", "TitleBundledDlcLabel": "Incorporado:",
"TitleXCIStatusPartialLabel": "Partial", "TitleXCIStatusPartialLabel": "Parcial",
"TitleXCIStatusTrimmableLabel": "Untrimmed", "TitleXCIStatusTrimmableLabel": "Sin recortar",
"TitleXCIStatusUntrimmableLabel": "Trimmed", "TitleXCIStatusUntrimmableLabel": "Recortado",
"TitleXCIStatusFailedLabel": "(Failed)", "TitleXCIStatusFailedLabel": "(Fallido)",
"TitleXCICanSaveLabel": "Save {0:n0} Mb", "TitleXCICanSaveLabel": "Ahorra {0:n0} Mb",
"TitleXCISavingLabel": "Saved {0:n0} Mb", "TitleXCISavingLabel": "{0:n0} Mb ahorrado(s)",
"RyujinxInfo": "Ryujinx - Info", "RyujinxInfo": "Ryujinx - Info",
"RyujinxConfirm": "Ryujinx - Confirmación", "RyujinxConfirm": "Ryujinx - Confirmación",
"FileDialogAllTypes": "Todos los tipos", "FileDialogAllTypes": "Todos los tipos",
"Never": "Nunca", "Never": "Nunca",
"SwkbdMinCharacters": "Debe tener al menos {0} caracteres", "SwkbdMinCharacters": "Debe tener al menos {0} caracteres",
"SwkbdMinRangeCharacters": "Debe tener {0}-{1} caracteres", "SwkbdMinRangeCharacters": "Debe tener {0}-{1} caracteres",
"CabinetTitle": "Cabinet Dialog", "CabinetTitle": "Diálogo Gabinete",
"CabinetDialog": "Enter your Amiibo's new name", "CabinetDialog": "Ingresa el nuevo nombre de tu Amiibo",
"CabinetScanDialog": "Please scan your Amiibo now.", "CabinetScanDialog": "Escanea tu Amiibo ahora.",
"SoftwareKeyboard": "Teclado de software", "SoftwareKeyboard": "Teclado de software",
"SoftwareKeyboardModeNumeric": "Debe ser sólo 0-9 o '.'", "SoftwareKeyboardModeNumeric": "Debe ser sólo 0-9 o '.'",
"SoftwareKeyboardModeAlphabet": "Solo deben ser caracteres no CJK", "SoftwareKeyboardModeAlphabet": "Solo deben ser caracteres no CJK",
@@ -750,39 +750,39 @@
"SelectDlcDialogTitle": "Selecciona archivo(s) de DLC", "SelectDlcDialogTitle": "Selecciona archivo(s) de DLC",
"SelectUpdateDialogTitle": "Selecciona archivo(s) de actualización", "SelectUpdateDialogTitle": "Selecciona archivo(s) de actualización",
"SelectModDialogTitle": "Seleccionar un directorio de Mods", "SelectModDialogTitle": "Seleccionar un directorio de Mods",
"TrimXCIFileDialogTitle": "Check and Trim XCI File", "TrimXCIFileDialogTitle": "Verificar y recortar archivo XCI",
"TrimXCIFileDialogPrimaryText": "This function will first check the empty space and then trim the XCI File to save disk space.", "TrimXCIFileDialogPrimaryText": "Esta función verificará el espacio vacío y después recortará el archivo XCI para ahorrar espacio en disco",
"TrimXCIFileDialogSecondaryText": "Current File Size: {0:n} MB\nGame Data Size: {1:n} MB\nDisk Space Savings: {2:n} MB", "TrimXCIFileDialogSecondaryText": "Tamaño de archivo actual: {0:n} MB\nTamaño de datos de juego: {1:n} MB\nAhorro de espacio en disco: {2:n} MB",
"TrimXCIFileNoTrimNecessary": "XCI File does not need to be trimmed. Check logs for further details", "TrimXCIFileNoTrimNecessary": "El archivo XCI no necesita ser recortado. Verifica los logs para más detalles.",
"TrimXCIFileNoUntrimPossible": "XCI File cannot be untrimmed. Check logs for further details", "TrimXCIFileNoUntrimPossible": "El recorte del archivo XCI no puede ser deshecho. Verifica los registros para más detalles.",
"TrimXCIFileReadOnlyFileCannotFix": "XCI File is Read Only and could not be made writable. Check logs for further details", "TrimXCIFileReadOnlyFileCannotFix": "El archivo XCI es de solo Lectura y no se le puede escribir. Lee el registro para más información.",
"TrimXCIFileFileSizeChanged": "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.", "TrimXCIFileFileSizeChanged": "El archivo XCI ha cambiado de tamaño desde que fue escaneado. Verifica que no se esté escribiendo al archivo y vuelve a intentarlo.",
"TrimXCIFileFreeSpaceCheckFailed": "XCI File has data in the free space area, it is not safe to trim", "TrimXCIFileFreeSpaceCheckFailed": "El archivo XCI tiene datos en el área de espacio libre, no es seguro recortar.",
"TrimXCIFileInvalidXCIFile": "XCI File contains invalid data. Check logs for further details", "TrimXCIFileInvalidXCIFile": "El archivo XCI contiene datos inválidos. Lee el registro para más información.",
"TrimXCIFileFileIOWriteError": "XCI File could not be opened for writing. Check logs for further details", "TrimXCIFileFileIOWriteError": "El archivo XCI no se puede abrir para escribirlo. Lee el registro para más información.",
"TrimXCIFileFailedPrimaryText": "Trimming of the XCI file failed", "TrimXCIFileFailedPrimaryText": "El recorte del archivo XCI falló",
"TrimXCIFileCancelled": "The operation was cancelled", "TrimXCIFileCancelled": "La operación fue cancelada",
"TrimXCIFileFileUndertermined": "No operation was performed", "TrimXCIFileFileUndertermined": "No se realizó ninguna operación",
"UserProfileWindowTitle": "Administrar perfiles de usuario", "UserProfileWindowTitle": "Administrar perfiles de usuario",
"CheatWindowTitle": "Administrar cheats", "CheatWindowTitle": "Administrar cheats",
"DlcWindowTitle": "Administrar contenido descargable", "DlcWindowTitle": "Administrar contenido descargable",
"ModWindowTitle": "Administrar Mods para {0} ({1})", "ModWindowTitle": "Administrar Mods para {0} ({1})",
"UpdateWindowTitle": "Administrar actualizaciones", "UpdateWindowTitle": "Administrar actualizaciones",
"XCITrimmerWindowTitle": "XCI File Trimmer", "XCITrimmerWindowTitle": "Recortador de archivos XCI",
"XCITrimmerTitleStatusCount": "{0} of {1} Title(s) Selected", "XCITrimmerTitleStatusCount": "{0} de {1} Título(s) seleccionado(s)",
"XCITrimmerTitleStatusCountWithFilter": "{0} of {1} Title(s) Selected ({2} displayed)", "XCITrimmerTitleStatusCountWithFilter": "{0} de {1} Título(s) seleccionado(s) ({2} mostrado(s))",
"XCITrimmerTitleStatusTrimming": "Trimming {0} Title(s)...", "XCITrimmerTitleStatusTrimming": "Recortando {0} Título(s)...",
"XCITrimmerTitleStatusUntrimming": "Untrimming {0} Title(s)...", "XCITrimmerTitleStatusUntrimming": "Deshaciendo recorte de {0} Título(s)...",
"XCITrimmerTitleStatusFailed": "Failed", "XCITrimmerTitleStatusFailed": "Fallido",
"XCITrimmerPotentialSavings": "Potential Savings", "XCITrimmerPotentialSavings": "Ahorro potencial",
"XCITrimmerActualSavings": "Actual Savings", "XCITrimmerActualSavings": "Ahorro real",
"XCITrimmerSavingsMb": "{0:n0} Mb", "XCITrimmerSavingsMb": "{0:n0} Mb",
"XCITrimmerSelectDisplayed": "Select Shown", "XCITrimmerSelectDisplayed": "Seleccionar mostrado(s)",
"XCITrimmerDeselectDisplayed": "Deselect Shown", "XCITrimmerDeselectDisplayed": "Deseleccionar mostrado(s)",
"XCITrimmerSortName": "Title", "XCITrimmerSortName": "Título",
"XCITrimmerSortSaved": "Space Savings", "XCITrimmerSortSaved": "Ahorro de espacio",
"XCITrimmerTrim": "Trim", "XCITrimmerTrim": "Recortar",
"XCITrimmerUntrim": "Untrim", "XCITrimmerUntrim": "Deshacer recorte",
"UpdateWindowUpdateAddedMessage": "{0} nueva(s) actualización(es) agregada(s)", "UpdateWindowUpdateAddedMessage": "{0} nueva(s) actualización(es) agregada(s)",
"UpdateWindowBundledContentNotice": "Las actualizaciones agrupadas no pueden ser eliminadas, solamente deshabilitadas.", "UpdateWindowBundledContentNotice": "Las actualizaciones agrupadas no pueden ser eliminadas, solamente deshabilitadas.",
"CheatWindowHeading": "Cheats disponibles para {0} [{1}]", "CheatWindowHeading": "Cheats disponibles para {0} [{1}]",
@@ -795,7 +795,7 @@
"AutoloadUpdateRemovedMessage": "Se eliminaron {0} actualización(es) faltantes", "AutoloadUpdateRemovedMessage": "Se eliminaron {0} actualización(es) faltantes",
"ModWindowHeading": "{0} Mod(s)", "ModWindowHeading": "{0} Mod(s)",
"UserProfilesEditProfile": "Editar selección", "UserProfilesEditProfile": "Editar selección",
"Continue": "Continue", "Continue": "Continuar",
"Cancel": "Cancelar", "Cancel": "Cancelar",
"Save": "Guardar", "Save": "Guardar",
"Discard": "Descartar", "Discard": "Descartar",

View File

@@ -10,6 +10,7 @@ using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using LibHac.Common; using LibHac.Common;
using LibHac.Ns;
using Ryujinx.Ava.Common; using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Input; using Ryujinx.Ava.Input;
@@ -1897,7 +1898,7 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public async Task LoadApplication(ApplicationData application, bool startFullscreen = false) public async Task LoadApplication(ApplicationData application, bool startFullscreen = false, BlitStruct<ApplicationControlProperty>? customNacpData = null)
{ {
if (AppHost != null) if (AppHost != null)
{ {
@@ -1935,7 +1936,7 @@ namespace Ryujinx.Ava.UI.ViewModels
this, this,
TopLevel); TopLevel);
if (!await AppHost.LoadGuestApplication()) if (!await AppHost.LoadGuestApplication(customNacpData))
{ {
AppHost.DisposeContext(); AppHost.DisposeContext();
AppHost = null; AppHost = null;

View File

@@ -3,7 +3,9 @@ using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Threading; using Avalonia.Threading;
using Gommon; using Gommon;
using LibHac.Common;
using LibHac.Ncm; using LibHac.Ncm;
using LibHac.Ns;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
@@ -19,6 +21,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
namespace Ryujinx.Ava.UI.Views.Main namespace Ryujinx.Ava.UI.Views.Main
{ {
@@ -123,18 +126,34 @@ namespace Ryujinx.Ava.UI.Views.Main
public async void OpenMiiApplet(object sender, RoutedEventArgs e) public async void OpenMiiApplet(object sender, RoutedEventArgs e)
{ {
string contentPath = ViewModel.ContentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program); const string name = "miiEdit";
const ulong programId = 0x0100000000001009;
string contentPath = ViewModel.ContentManager.GetInstalledContentPath(programId, StorageId.BuiltInSystem, NcaContentType.Program);
if (!string.IsNullOrEmpty(contentPath)) if (!string.IsNullOrEmpty(contentPath))
{ {
ApplicationData applicationData = new() ApplicationData applicationData = new()
{ {
Name = "miiEdit", Name = name,
Id = 0x0100000000001009, Id = programId,
Path = contentPath, Path = contentPath,
}; };
await ViewModel.LoadApplication(applicationData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen); string version = "1.0.0";
var nacpData = new BlitStruct<ApplicationControlProperty>(1);
//version buffer
Encoding.ASCII.GetBytes(version).AsSpan().CopyTo(nacpData.ByteSpan.Slice(0x3060));
//name and distributor buffer
//repeat once for each locale (the ApplicationControlProperty has 16 locales)
for (int i = 0; i < 0x10; i++)
{
Encoding.ASCII.GetBytes(name).AsSpan().CopyTo(nacpData.ByteSpan.Slice(i * 0x300));
"Ryujinx"u8.ToArray().AsSpan().CopyTo(nacpData.ByteSpan.Slice(i * 0x300 + 0x200));
}
await ViewModel.LoadApplication(applicationData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);
} }
} }