Files
Ryujinx/src/Ryujinx.HLE/HOS/Services/Mii/MiiDatabaseManager.cs
TSRBerry 326749498b [Ryujinx.HLE] Address dotnet-format issues (#5380)
* dotnet format style --severity info

Some changes were manually reverted.

* dotnet format analyzers --serverity info

Some changes have been minimally adapted.

* Restore a few unused methods and variables

* Silence dotnet format IDE0060 warnings

* Silence dotnet format IDE0052 warnings

* Address or silence dotnet format IDE1006 warnings

* Address dotnet format CA1816 warnings

* Address or silence dotnet format CA2208 warnings

* Address or silence dotnet format CA1806 and a few CA1854 warnings

* Address dotnet format CA2211 warnings

* Address dotnet format CA1822 warnings

* Address or silence dotnet format CA1069 warnings

* Make dotnet format succeed in style mode

* Address or silence dotnet format CA2211 warnings

* Address review comments

* Address dotnet format CA2208 warnings properly

* Make ProcessResult readonly

* Address most dotnet format whitespace warnings

* Apply dotnet format whitespace formatting

A few of them have been manually reverted and the corresponding warning was silenced

* Add previously silenced warnings back

I have no clue how these disappeared

* Revert formatting changes for while and for-loops

* Format if-blocks correctly

* Run dotnet format style after rebase

* Run dotnet format whitespace after rebase

* Run dotnet format style after rebase

* Run dotnet format analyzers after rebase

* Run dotnet format after rebase and remove unused usings

- analyzers
- style
- whitespace

* Disable 'prefer switch expression' rule

* Add comments to disabled warnings

* Fix a few disabled warnings

* Fix naming rule violation, Convert shader properties to auto-property and convert values to const

* Simplify properties and array initialization, Use const when possible, Remove trailing commas

* Start working on disabled warnings

* Fix and silence a few dotnet-format warnings again

* Run dotnet format after rebase

* Use using declaration instead of block syntax

* Address IDE0251 warnings

* Address a few disabled IDE0060 warnings

* Silence IDE0060 in .editorconfig

* Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas"

This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e.

* dotnet format whitespace after rebase

* First dotnet format pass

* Fix naming rule violations

* Fix typo

* Add trailing commas, use targeted new and use array initializer

* Fix build issues

* Fix remaining build issues

* Remove SuppressMessage for CA1069 where possible

* Address dotnet format issues

* Address formatting issues

Co-authored-by: Ac_K <acoustik666@gmail.com>

* Add GetHashCode implementation for RenderingSurfaceInfo

* Explicitly silence CA1822 for every affected method in Syscall

* Address formatting issues in Demangler.cs

* Address review feedback

Co-authored-by: Ac_K <acoustik666@gmail.com>

* Revert marking service methods as static

* Next dotnet format pass

* Address review feedback

---------

Co-authored-by: Ac_K <acoustik666@gmail.com>
2023-07-16 19:31:14 +02:00

515 lines
15 KiB
C#

using LibHac;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
using LibHac.Fs.Shim;
using LibHac.Ncm;
using Ryujinx.HLE.HOS.Services.Mii.Types;
using System.Runtime.CompilerServices;
namespace Ryujinx.HLE.HOS.Services.Mii
{
class MiiDatabaseManager
{
private readonly bool _isTestModeEnabled = false;
private uint _mountCounter = 0;
private const ulong DatabaseTestSaveDataId = 0x8000000000000031;
private const ulong DatabaseSaveDataId = 0x8000000000000030;
private readonly U8String _databasePath = new("mii:/MiiDatabase.dat");
private readonly U8String _mountName = new("mii");
private NintendoFigurineDatabase _database;
private bool _isDirty;
private HorizonClient _horizonClient;
protected ulong UpdateCounter { get; private set; }
public MiiDatabaseManager()
{
_database = new NintendoFigurineDatabase();
_isDirty = false;
UpdateCounter = 0;
}
private void ResetDatabase()
{
_database = new NintendoFigurineDatabase();
_database.Format();
}
private void MarkDirty(DatabaseSessionMetadata metadata)
{
_isDirty = true;
UpdateCounter++;
metadata.UpdateCounter = UpdateCounter;
}
private bool GetAtVirtualIndex(int index, out int realIndex, out StoreData storeData)
{
realIndex = -1;
storeData = new StoreData();
int virtualIndex = 0;
for (int i = 0; i < _database.Length; i++)
{
StoreData tmp = _database.Get(i);
if (!tmp.IsSpecial())
{
if (index == virtualIndex)
{
realIndex = i;
storeData = tmp;
return true;
}
virtualIndex++;
}
}
return false;
}
private int ConvertRealIndexToVirtualIndex(int realIndex)
{
int virtualIndex = 0;
for (int i = 0; i < realIndex; i++)
{
StoreData tmp = _database.Get(i);
if (!tmp.IsSpecial())
{
virtualIndex++;
}
}
return virtualIndex;
}
public void InitializeDatabase(HorizonClient horizonClient)
{
_horizonClient = horizonClient;
// Ensure we have valid data in the database
_database.Format();
MountSave();
}
private Result MountSave()
{
if (_mountCounter != 0)
{
_mountCounter++;
return Result.Success;
}
ulong saveDataId = _isTestModeEnabled ? DatabaseTestSaveDataId : DatabaseSaveDataId;
Result result = _horizonClient.Fs.MountSystemSaveData(_mountName, SaveDataSpaceId.System, saveDataId);
if (result.IsFailure())
{
if (!ResultFs.TargetNotFound.Includes(result))
{
return result;
}
if (_isTestModeEnabled)
#pragma warning disable CS0162
{
result = _horizonClient.Fs.CreateSystemSaveData(saveDataId, 0x10000, 0x10000,
SaveDataFlags.KeepAfterResettingSystemSaveDataWithoutUserSaveData);
if (result.IsFailure())
{
return result;
}
}
#pragma warning restore CS0162
else
{
result = _horizonClient.Fs.CreateSystemSaveData(saveDataId, SystemProgramId.Ns.Value, 0x10000,
0x10000, SaveDataFlags.KeepAfterResettingSystemSaveDataWithoutUserSaveData);
if (result.IsFailure())
{
return result;
}
}
result = _horizonClient.Fs.MountSystemSaveData(_mountName, SaveDataSpaceId.System, saveDataId);
if (result.IsFailure())
{
return result;
}
}
if (result == Result.Success)
{
_mountCounter++;
}
return result;
}
public ResultCode DeleteFile()
{
ResultCode result = (ResultCode)_horizonClient.Fs.DeleteFile(_databasePath).Value;
_horizonClient.Fs.Commit(_mountName);
return result;
}
public ResultCode LoadFromFile(out bool isBroken)
{
isBroken = false;
if (_mountCounter == 0)
{
return ResultCode.InvalidArgument;
}
UpdateCounter++;
ResetDatabase();
Result result = _horizonClient.Fs.OpenFile(out FileHandle handle, _databasePath, OpenMode.Read);
if (result.IsSuccess())
{
result = _horizonClient.Fs.GetFileSize(out long fileSize, handle);
if (result.IsSuccess())
{
if (fileSize == Unsafe.SizeOf<NintendoFigurineDatabase>())
{
result = _horizonClient.Fs.ReadFile(handle, 0, _database.AsSpan());
if (result.IsSuccess())
{
if (_database.Verify() != ResultCode.Success)
{
ResetDatabase();
isBroken = true;
}
else
{
isBroken = _database.FixDatabase();
}
}
}
else
{
isBroken = true;
}
}
_horizonClient.Fs.CloseFile(handle);
return (ResultCode)result.Value;
}
else if (ResultFs.PathNotFound.Includes(result))
{
return (ResultCode)ForceSaveDatabase().Value;
}
return ResultCode.Success;
}
private Result ForceSaveDatabase()
{
Result result = _horizonClient.Fs.CreateFile(_databasePath, Unsafe.SizeOf<NintendoFigurineDatabase>());
if (result.IsSuccess() || ResultFs.PathAlreadyExists.Includes(result))
{
result = _horizonClient.Fs.OpenFile(out FileHandle handle, _databasePath, OpenMode.Write);
if (result.IsSuccess())
{
result = _horizonClient.Fs.GetFileSize(out long fileSize, handle);
if (result.IsSuccess())
{
// If the size doesn't match, recreate the file
if (fileSize != Unsafe.SizeOf<NintendoFigurineDatabase>())
{
_horizonClient.Fs.CloseFile(handle);
result = _horizonClient.Fs.DeleteFile(_databasePath);
if (result.IsSuccess())
{
result = _horizonClient.Fs.CreateFile(_databasePath, Unsafe.SizeOf<NintendoFigurineDatabase>());
if (result.IsSuccess())
{
result = _horizonClient.Fs.OpenFile(out handle, _databasePath, OpenMode.Write);
}
}
if (result.IsFailure())
{
return result;
}
}
result = _horizonClient.Fs.WriteFile(handle, 0, _database.AsReadOnlySpan(), WriteOption.Flush);
}
_horizonClient.Fs.CloseFile(handle);
}
}
if (result.IsSuccess())
{
_isDirty = false;
result = _horizonClient.Fs.Commit(_mountName);
}
return result;
}
public DatabaseSessionMetadata CreateSessionMetadata(SpecialMiiKeyCode miiKeyCode)
{
return new DatabaseSessionMetadata(UpdateCounter, miiKeyCode);
}
public void SetInterfaceVersion(DatabaseSessionMetadata metadata, uint interfaceVersion)
{
metadata.InterfaceVersion = interfaceVersion;
}
public bool IsUpdated(DatabaseSessionMetadata metadata)
{
bool result = metadata.UpdateCounter != UpdateCounter;
metadata.UpdateCounter = UpdateCounter;
return result;
}
public int GetCount(DatabaseSessionMetadata metadata)
{
if (!metadata.MiiKeyCode.IsEnabledSpecialMii())
{
int count = 0;
for (int i = 0; i < _database.Length; i++)
{
StoreData tmp = _database.Get(i);
if (!tmp.IsSpecial())
{
count++;
}
}
return count;
}
else
{
return _database.Length;
}
}
public void Get(DatabaseSessionMetadata metadata, int index, out StoreData storeData)
{
if (!metadata.MiiKeyCode.IsEnabledSpecialMii())
{
if (GetAtVirtualIndex(index, out int realIndex, out _))
{
index = realIndex;
}
else
{
index = 0;
}
}
storeData = _database.Get(index);
}
public ResultCode FindIndex(DatabaseSessionMetadata metadata, out int index, CreateId createId)
{
return FindIndex(out index, createId, metadata.MiiKeyCode.IsEnabledSpecialMii());
}
public ResultCode FindIndex(out int index, CreateId createId, bool isSpecial)
{
if (_database.GetIndexByCreatorId(out int realIndex, createId))
{
if (isSpecial)
{
index = realIndex;
return ResultCode.Success;
}
StoreData storeData = _database.Get(realIndex);
if (!storeData.IsSpecial())
{
if (realIndex < 1)
{
index = 0;
}
else
{
index = ConvertRealIndexToVirtualIndex(realIndex);
}
return ResultCode.Success;
}
}
index = -1;
return ResultCode.NotFound;
}
public ResultCode Move(DatabaseSessionMetadata metadata, int newIndex, CreateId createId)
{
if (!metadata.MiiKeyCode.IsEnabledSpecialMii())
{
if (GetAtVirtualIndex(newIndex, out int realIndex, out _))
{
newIndex = realIndex;
}
else
{
newIndex = 0;
}
}
if (_database.GetIndexByCreatorId(out int oldIndex, createId))
{
StoreData realStoreData = _database.Get(oldIndex);
if (!metadata.MiiKeyCode.IsEnabledSpecialMii() && realStoreData.IsSpecial())
{
return ResultCode.InvalidOperationOnSpecialMii;
}
ResultCode result = _database.Move(newIndex, oldIndex);
if (result == ResultCode.Success)
{
MarkDirty(metadata);
}
return result;
}
return ResultCode.NotFound;
}
public ResultCode AddOrReplace(DatabaseSessionMetadata metadata, StoreData storeData)
{
if (!storeData.IsValid())
{
return ResultCode.InvalidStoreData;
}
if (!metadata.MiiKeyCode.IsEnabledSpecialMii() && storeData.IsSpecial())
{
return ResultCode.InvalidOperationOnSpecialMii;
}
if (_database.GetIndexByCreatorId(out int index, storeData.CreateId))
{
StoreData oldStoreData = _database.Get(index);
if (oldStoreData.IsSpecial())
{
return ResultCode.InvalidOperationOnSpecialMii;
}
_database.Replace(index, storeData);
}
else
{
if (_database.IsFull())
{
return ResultCode.DatabaseFull;
}
_database.Add(storeData);
}
MarkDirty(metadata);
return ResultCode.Success;
}
public ResultCode Delete(DatabaseSessionMetadata metadata, CreateId createId)
{
if (!_database.GetIndexByCreatorId(out int index, createId))
{
return ResultCode.NotFound;
}
if (!metadata.MiiKeyCode.IsEnabledSpecialMii())
{
StoreData storeData = _database.Get(index);
if (storeData.IsSpecial())
{
return ResultCode.InvalidOperationOnSpecialMii;
}
}
_database.Delete(index);
MarkDirty(metadata);
return ResultCode.Success;
}
public ResultCode DestroyFile(DatabaseSessionMetadata metadata)
{
_database.CorruptDatabase();
MarkDirty(metadata);
ResultCode result = SaveDatabase();
ResetDatabase();
return result;
}
public ResultCode SaveDatabase()
{
if (_isDirty)
{
return (ResultCode)ForceSaveDatabase().Value;
}
else
{
return ResultCode.NotUpdated;
}
}
public void FormatDatabase(DatabaseSessionMetadata metadata)
{
_database.Format();
MarkDirty(metadata);
}
public bool IsFullDatabase()
{
return _database.IsFull();
}
}
}