mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-08-07 22:09:38 +00:00
These changes allow players to matchmake for local wireless using a LDN server. The network implementation originates from Berry's public TCP RyuLDN fork. Logo and unrelated changes have been removed. Additionally displays LDN game status in the game selection window when RyuLDN is enabled. Functionality is only enabled while network mode is set to "RyuLDN" in the settings.
205 lines
7.0 KiB
C#
205 lines
7.0 KiB
C#
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Styling;
|
|
using Avalonia.Threading;
|
|
using FluentAvalonia.UI.Controls;
|
|
using Gommon;
|
|
using LibHac;
|
|
using LibHac.Common;
|
|
using LibHac.Fs;
|
|
using LibHac.Fs.Shim;
|
|
using Ryujinx.Ava.Common.Locale;
|
|
using Ryujinx.Ava.UI.Helpers;
|
|
using Ryujinx.Ava.UI.ViewModels;
|
|
using Ryujinx.Ava.UI.Views.User;
|
|
using Ryujinx.HLE.FileSystem;
|
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using UserId = Ryujinx.HLE.HOS.Services.Account.Acc.UserId;
|
|
using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
|
|
|
|
namespace Ryujinx.Ava.UI.Controls
|
|
{
|
|
public partial class NavigationDialogHost : UserControl
|
|
{
|
|
public AccountManager AccountManager { get; }
|
|
public ContentManager ContentManager { get; }
|
|
public VirtualFileSystem VirtualFileSystem { get; }
|
|
public HorizonClient HorizonClient { get; }
|
|
public UserProfileViewModel ViewModel { get; set; }
|
|
|
|
public NavigationDialogHost()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
public NavigationDialogHost(AccountManager accountManager, ContentManager contentManager,
|
|
VirtualFileSystem virtualFileSystem, HorizonClient horizonClient)
|
|
{
|
|
AccountManager = accountManager;
|
|
ContentManager = contentManager;
|
|
VirtualFileSystem = virtualFileSystem;
|
|
HorizonClient = horizonClient;
|
|
ViewModel = new UserProfileViewModel();
|
|
LoadProfiles();
|
|
|
|
if (contentManager.GetCurrentFirmwareVersion() != null)
|
|
Task.Run(() => UserFirmwareAvatarSelectorViewModel.PreloadAvatars(contentManager, virtualFileSystem));
|
|
|
|
InitializeComponent();
|
|
}
|
|
|
|
public void GoBack()
|
|
{
|
|
if (ContentFrame.BackStack.Count > 0)
|
|
ContentFrame.GoBack();
|
|
|
|
LoadProfiles();
|
|
}
|
|
|
|
public void Navigate(Type sourcePageType, object parameter)
|
|
=> ContentFrame.Navigate(sourcePageType, parameter);
|
|
|
|
public static async Task Show(
|
|
AccountManager ownerAccountManager,
|
|
ContentManager ownerContentManager,
|
|
VirtualFileSystem ownerVirtualFileSystem,
|
|
HorizonClient ownerHorizonClient)
|
|
{
|
|
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
|
|
ContentDialog contentDialog = new()
|
|
{
|
|
Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
|
|
PrimaryButtonText = string.Empty,
|
|
SecondaryButtonText = string.Empty,
|
|
CloseButtonText = string.Empty,
|
|
Content = content,
|
|
Padding = new Thickness(0)
|
|
};
|
|
|
|
contentDialog.Closed += (_, _) => content.ViewModel.Dispose();
|
|
|
|
Style footer = new(x => x.Name("DialogSpace").Child().OfType<Border>());
|
|
footer.Setters.Add(new Setter(IsVisibleProperty, false));
|
|
|
|
contentDialog.Styles.Add(footer);
|
|
|
|
await contentDialog.ShowAsync();
|
|
}
|
|
|
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
|
{
|
|
base.OnAttachedToVisualTree(e);
|
|
|
|
Navigate(typeof(UserSelectorViews), this);
|
|
}
|
|
|
|
public void LoadProfiles()
|
|
{
|
|
ViewModel.Profiles.Clear();
|
|
ViewModel.LostProfiles.Clear();
|
|
|
|
AccountManager.GetAllUsers()
|
|
.OrderBy(x => x.Name)
|
|
.ForEach(profile => ViewModel.Profiles.Add(new UserProfile(profile, this)));
|
|
|
|
var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account, default, saveDataId: default, index: default);
|
|
|
|
using var saveDataIterator = new UniqueRef<SaveDataIterator>();
|
|
|
|
HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref, SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
|
|
|
|
Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10];
|
|
|
|
HashSet<UserId> lostAccounts = new();
|
|
|
|
while (true)
|
|
{
|
|
saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure();
|
|
|
|
if (readCount == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
for (int i = 0; i < readCount; i++)
|
|
{
|
|
var save = saveDataInfo[i];
|
|
var id = new UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
|
|
if (ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId == id) == null)
|
|
{
|
|
lostAccounts.Add(id);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var account in lostAccounts)
|
|
{
|
|
ViewModel.LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, string.Empty, null), this));
|
|
}
|
|
|
|
ViewModel.Profiles.Add(new BaseModel());
|
|
}
|
|
|
|
public async void DeleteUser(UserProfile userProfile)
|
|
{
|
|
var lastUserId = AccountManager.LastOpenedUser.UserId;
|
|
|
|
if (userProfile.UserId == lastUserId)
|
|
{
|
|
// If we are deleting the currently open profile, then we must open something else before deleting.
|
|
var profile = ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId != lastUserId);
|
|
|
|
if (profile == null)
|
|
{
|
|
_ = Dispatcher.UIThread.InvokeAsync(async ()
|
|
=> await ContentDialogHelper.CreateErrorDialog(
|
|
LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]));
|
|
|
|
return;
|
|
}
|
|
|
|
AccountManager.OpenUser(profile.UserId);
|
|
}
|
|
|
|
var result = await ContentDialogHelper.CreateConfirmationDialog(
|
|
LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionConfirmMessage],
|
|
string.Empty,
|
|
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
|
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
|
string.Empty);
|
|
|
|
if (result == UserResult.Yes)
|
|
{
|
|
GoBack();
|
|
AccountManager.DeleteUser(userProfile.UserId);
|
|
}
|
|
|
|
LoadProfiles();
|
|
}
|
|
|
|
public void AddUser()
|
|
{
|
|
Navigate(typeof(UserEditorView), (this, (UserProfile)null, true));
|
|
}
|
|
|
|
public void EditUser(UserProfile userProfile)
|
|
{
|
|
Navigate(typeof(UserEditorView), (this, userProfile, false));
|
|
}
|
|
|
|
public void RecoverLostAccounts()
|
|
{
|
|
Navigate(typeof(UserRecovererView), this);
|
|
}
|
|
|
|
public void ManageSaves()
|
|
{
|
|
Navigate(typeof(UserSaveManagerView), (this, AccountManager, HorizonClient, VirtualFileSystem));
|
|
}
|
|
}
|
|
}
|