From 6111319ad4d388e712e37e10990aae41d417b5ac Mon Sep 17 00:00:00 2001 From: sin365 <353374337@qq.com> Date: Tue, 8 Apr 2025 10:36:07 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=BC=95=E5=85=A5=20AxiNSApi=20=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=20=E8=A1=A5=E5=AE=8CSwitch=E8=87=AA=E5=8A=A8=E6=89=93?= =?UTF-8?q?=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/AxiProjectTools/AxiNSPack.meta | 2 +- .../AxiNSPack/Editors/AxibugNSPTools.cs | 66 +++--- .../Assets/Plugins/AxiNSApi/AxiNSIO.cs | 190 +++++++++++++++++- .../Assets/Plugins/AxiNSApi/AxiNSMount.cs | 58 +++--- .../Assets/Plugins/AxiNSApi/AxiNSSDCard.cs | 23 +++ .../Plugins/AxiNSApi/AxiNSSDCard.cs.meta | 11 + 6 files changed, 293 insertions(+), 57 deletions(-) create mode 100644 AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSSDCard.cs create mode 100644 AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSSDCard.cs.meta diff --git a/AxibugEmuOnline.Client/Assets/AxiProjectTools/AxiNSPack.meta b/AxibugEmuOnline.Client/Assets/AxiProjectTools/AxiNSPack.meta index 7182dbd8..b3e69672 100644 --- a/AxibugEmuOnline.Client/Assets/AxiProjectTools/AxiNSPack.meta +++ b/AxibugEmuOnline.Client/Assets/AxiProjectTools/AxiNSPack.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 611bc182f939ea147a72b08613e2d2ba +guid: 164952f99969ca942b4761b200d7e381 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/AxibugEmuOnline.Client/Assets/AxiProjectTools/AxiNSPack/Editors/AxibugNSPTools.cs b/AxibugEmuOnline.Client/Assets/AxiProjectTools/AxiNSPack/Editors/AxibugNSPTools.cs index c9e192f0..e623c351 100644 --- a/AxibugEmuOnline.Client/Assets/AxiProjectTools/AxiNSPack/Editors/AxibugNSPTools.cs +++ b/AxibugEmuOnline.Client/Assets/AxiProjectTools/AxiNSPack/Editors/AxibugNSPTools.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using UnityEditor; @@ -82,7 +83,7 @@ namespace AxibugEmuOnline.Editors { BuildReport report = BuildPipeline.BuildPlayer(options); } - catch(Exception ex) + catch (Exception ex) { Debug.LogError($"[AxibugNSPTools] Unity Build NSP ����:{ex.ToString()}"); return; @@ -147,13 +148,13 @@ namespace AxibugEmuOnline.Editors #region ������ʱĿ¼ CleanDirectory(Path.Combine(nspParentDir, "repacker_extract")); CleanDirectory(Path.Combine(Path.GetTempPath(), "NCA")); - CleanDirectory(Path.Combine(WorkRoot, "hacpack_backup")); + CleanDirectory(Path.Combine(nspParentDir, "hacpack_backup")); #endregion EditorUtility.DisplayProgressBar("AxibugNSPTools", $"���NSP�ļ�", 0.2f); #region ���NSP�ļ� string extractPath = Path.Combine(nspParentDir, "repacker_extract"); - ExecuteCommand($"{tools["authoringTool"]} extract -o \"{extractPath}\" \"{nspFilePath}\""); + ExecuteCommand($"{tools["authoringTool"]} extract -o \"{extractPath}\" \"{nspFilePath}\"", nspParentDir); string controlPath = null; string programPath = null; @@ -167,34 +168,43 @@ namespace AxibugEmuOnline.Editors #region �ؽ�NCA/NSP string tmpPath = Path.Combine(Path.GetTempPath(), "NCA"); - EditorUtility.DisplayProgressBar("AxibugNSPTools", $"�ؽ�NCA", 0.6f); - string programNCA = BuildProgramNCA(tmpPath, titleID, programPath); - EditorUtility.DisplayProgressBar("AxibugNSPTools", $"�ؽ�NCA", 0.7f); - string controlNCA = BuildControlNCA(tmpPath, titleID, controlPath); - EditorUtility.DisplayProgressBar("AxibugNSPTools", $"�ؽ�NCA", 0.8f); - BuildMetaNCA(tmpPath, titleID, programNCA, controlNCA); + EditorUtility.DisplayProgressBar("AxibugNSPTools", $"�ؽ� Program NCA", 0.3f); + string programNCA = BuildProgramNCA(tmpPath, titleID, programPath, nspParentDir); + EditorUtility.DisplayProgressBar("AxibugNSPTools", $"�ؽ� Control NCA", 0.4f); + string controlNCA = BuildControlNCA(tmpPath, titleID, controlPath, nspParentDir); + EditorUtility.DisplayProgressBar("AxibugNSPTools", $"�ؽ� Meta NCA", 0.5f); + BuildMetaNCA(tmpPath, titleID, programNCA, controlNCA, nspParentDir); + EditorUtility.DisplayProgressBar("AxibugNSPTools", $"�ؽ�NSP", 0.6f); + string outputNSP = BuildFinalNSP(nspFilePath, nspParentDir, tmpPath, titleID, nspParentDir); EditorUtility.DisplayProgressBar("AxibugNSPTools", $"�ؽ�NSP", 0.9f); - string outputNSP = BuildFinalNSP(nspFilePath, nspParentDir, tmpPath, titleID); - EditorUtility.DisplayProgressBar("AxibugNSPTools", $"�ؽ�NSP", 1f); Debug.Log($"[AxibugNSPTools]Repacking completed: {outputNSP}"); - EditorUtility.ClearProgressBar(); - #endregion + + #endregion + + EditorUtility.DisplayProgressBar("AxibugNSPTools", $"������ʱĿ¼", 1); + #region ������ʱĿ¼ + CleanDirectory(Path.Combine(nspParentDir, "repacker_extract")); + CleanDirectory(Path.Combine(Path.GetTempPath(), "NCA")); + CleanDirectory(Path.Combine(nspParentDir, "hacpack_backup")); + #endregion + System.Diagnostics.Process.Start("explorer", "/select,\"" + outputNSP.Trim() + "\""); + EditorUtility.ClearProgressBar(); } + + #region �������� static string GetUserInput() { Console.Write("Enter the NSP filepath: "); return Console.ReadLine(); } - static string ExtractTitleID(string path) { var match = Regex.Match(path, @"0100[\dA-Fa-f]{12}"); return match.Success ? match.Value : null; } - static void CleanDirectory(string path) { if (Directory.Exists(path)) @@ -215,8 +225,9 @@ namespace AxibugEmuOnline.Editors } } - static string ExecuteCommand(string command) + static string ExecuteCommand(string command, string workdir) { + Debug.Log($"����cmd=>{command}"); var process = new System.Diagnostics.Process() { StartInfo = new System.Diagnostics.ProcessStartInfo @@ -228,7 +239,8 @@ namespace AxibugEmuOnline.Editors UseShellExecute = false, CreateNoWindow = true, StandardOutputEncoding = Encoding.UTF8, // ��ȷָ������ - StandardErrorEncoding = Encoding.UTF8 + StandardErrorEncoding = Encoding.UTF8, + WorkingDirectory = workdir } }; @@ -275,36 +287,36 @@ namespace AxibugEmuOnline.Editors #endregion #region NCA������ - static string BuildProgramNCA(string tmpPath, string titleID, string programDir) + static string BuildProgramNCA(string tmpPath, string titleID, string programDir, string workdir) { string args = $"-k \"{prodKeysPath}\" -o \"{tmpPath}\" --titleid {titleID} " + $"--type nca --ncatype program --exefsdir \"{programDir}/fs0\" " + $"--romfsdir \"{programDir}/fs1\" --logodir \"{programDir}/fs2\""; - string output = ExecuteCommand($"{tools["hacPack"]} {args}"); + string output = ExecuteCommand($"{tools["hacPack"]} {args}", workdir); return ParseNCAOutput(output, "Program"); } - static string BuildControlNCA(string tmpPath, string titleID, string controlDir) + static string BuildControlNCA(string tmpPath, string titleID, string controlDir, string workdir) { string args = $"-k \"{prodKeysPath}\" -o \"{tmpPath}\" --titleid {titleID} " + $"--type nca --ncatype control --romfsdir \"{controlDir}/fs0\""; - string output = ExecuteCommand($"{tools["hacPack"]} {args}"); + string output = ExecuteCommand($"{tools["hacPack"]} {args}", workdir); return ParseNCAOutput(output, "Control"); } - static void BuildMetaNCA(string tmpPath, string titleID, string programNCA, string controlNCA) + static void BuildMetaNCA(string tmpPath, string titleID, string programNCA, string controlNCA, string workdir) { string args = $"-k \"{prodKeysPath}\" -o \"{tmpPath}\" --titleid {titleID} " + $"--type nca --ncatype meta --titletype application " + $"--programnca \"{programNCA}\" --controlnca \"{controlNCA}\""; - ExecuteCommand($"{tools["hacPack"]} {args}"); + ExecuteCommand($"{tools["hacPack"]} {args}", workdir); } - static string BuildFinalNSP(string origPath, string parentDir, string tmpPath, string titleID) + static string BuildFinalNSP(string origPath, string parentDir, string tmpPath, string titleID, string workdir) { string outputPath = origPath.Replace(".nsp", "_repacked.nsp"); if (File.Exists(outputPath)) File.Delete(outputPath); @@ -312,7 +324,7 @@ namespace AxibugEmuOnline.Editors string args = $"-k \"{prodKeysPath}\" -o \"{parentDir}\" --titleid {titleID} " + $"--type nsp --ncadir \"{tmpPath}\""; - ExecuteCommand($"{tools["hacPack"]} {args}"); + ExecuteCommand($"{tools["hacPack"]} {args}", workdir); File.Move(Path.Combine(parentDir, $"{titleID}.nsp"), outputPath); return outputPath; } @@ -321,7 +333,9 @@ namespace AxibugEmuOnline.Editors { var line = output.Split('\n') .FirstOrDefault(l => l.Contains($"Created {type} NCA:")); - return line?.Split(':').Last().Trim(); + //return line?.Split(':').Last().Trim(); + return line?.Substring(line.IndexOf("NCA:") + "NCA:".Length).Trim(); + } #endregion } diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSIO.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSIO.cs index 6431408c..7e20444b 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSIO.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSIO.cs @@ -1,5 +1,7 @@ #if UNITY_SWITCH using nn.fs; +using System.Security.Cryptography; + #endif public class AxiNSIO @@ -253,18 +255,194 @@ public class AxiNSIO #if !UNITY_SWITCH return false; #else - //TODO + + +#if UNITY_SWITCH && !UNITY_EDITOR + // This next line prevents the user from quitting the game while saving. + // This is required for Nintendo Switch Guideline 0080 + UnityEngine.Switch.Notification.EnterExitRequestHandlingSection(); #endif - } - public bool DeletePathDir(string filename) + + if (CheckPathNotFound(filename)) + return false; + nn.Result result; + result = nn.fs.File.Delete(filename); + if (result.IsSuccess() == false) + { + UnityEngine.Debug.LogError($"nn.fs.File.Delete ʧ�� {filename} : result=>{result.GetErrorInfo()}"); + return false; + } + result = nn.fs.FileSystem.Commit(save_name); + if (!result.IsSuccess()) + { + UnityEngine.Debug.LogError($"FileSystem.Commit({save_name}) ʧ��: " + result.GetErrorInfo()); + return false; + } + return true; + +#if UNITY_SWITCH && !UNITY_EDITOR + // End preventing the user from quitting the game while saving. + UnityEngine.Switch.Notification.LeaveExitRequestHandlingSection(); +#endif + +#endif + } + public bool DeletePathDir(string filename) { #if !UNITY_SWITCH return false; #else - //TODO + +#if UNITY_SWITCH && !UNITY_EDITOR + // This next line prevents the user from quitting the game while saving. + // This is required for Nintendo Switch Guideline 0080 + UnityEngine.Switch.Notification.EnterExitRequestHandlingSection(); #endif - } - bool EnsureParentDirectory(string filePath, bool bAutoCreateDir = true) + + if (CheckPathNotFound(filename)) + return false; + nn.Result result; + result = nn.fs.Directory.Delete(filename); + if (result.IsSuccess() == false) + { + UnityEngine.Debug.LogError($"nn.fs.File.Delete ʧ�� {filename} : result=>{result.GetErrorInfo()}"); + return false; + } + result = nn.fs.FileSystem.Commit(save_name); + if (!result.IsSuccess()) + { + UnityEngine.Debug.LogError($"FileSystem.Commit({save_name}) ʧ��: " + result.GetErrorInfo()); + return false; + } + return true; + +#if UNITY_SWITCH && !UNITY_EDITOR + // End preventing the user from quitting the game while saving. + UnityEngine.Switch.Notification.LeaveExitRequestHandlingSection(); +#endif +#endif + } + + /// <summary> + /// �ݹ�ɾ��Ŀ¼ + /// </summary> + /// <param name="filename"></param> + /// <returns></returns> + public bool DeleteRecursivelyPathDir(string filename) + { +#if !UNITY_SWITCH + return false; +#else + +#if UNITY_SWITCH && !UNITY_EDITOR + // This next line prevents the user from quitting the game while saving. + // This is required for Nintendo Switch Guideline 0080 + UnityEngine.Switch.Notification.EnterExitRequestHandlingSection(); +#endif + + if (CheckPathNotFound(filename)) + return false; + nn.Result result; + result = nn.fs.Directory.DeleteRecursively(filename); + if (result.IsSuccess() == false) + { + UnityEngine.Debug.LogError($"nn.fs.File.DeleteRecursively ʧ�� {filename} : result=>{result.GetErrorInfo()}"); + return false; + } + result = nn.fs.FileSystem.Commit(save_name); + if (!result.IsSuccess()) + { + UnityEngine.Debug.LogError($"FileSystem.Commit({save_name}) ʧ��: " + result.GetErrorInfo()); + return false; + } + return true; + +#if UNITY_SWITCH && !UNITY_EDITOR + // End preventing the user from quitting the game while saving. + UnityEngine.Switch.Notification.LeaveExitRequestHandlingSection(); +#endif +#endif + } + + /// <summary> + /// �ݹ�ɾ����� + /// </summary> + /// <param name="filename"></param> + /// <returns></returns> + public bool CleanRecursivelyPathDir(string filename) + { +#if !UNITY_SWITCH + return false; +#else + +#if UNITY_SWITCH && !UNITY_EDITOR + // This next line prevents the user from quitting the game while saving. + // This is required for Nintendo Switch Guideline 0080 + UnityEngine.Switch.Notification.EnterExitRequestHandlingSection(); +#endif + + if (CheckPathNotFound(filename)) + return false; + nn.Result result; + result = nn.fs.Directory.CleanRecursively(filename); + if (result.IsSuccess() == false) + { + UnityEngine.Debug.LogError($"nn.fs.File.DeleteRecursively ʧ�� {filename} : result=>{result.GetErrorInfo()}"); + return false; + } + result = nn.fs.FileSystem.Commit(save_name); + if (!result.IsSuccess()) + { + UnityEngine.Debug.LogError($"FileSystem.Commit({save_name}) ʧ��: " + result.GetErrorInfo()); + return false; + } + return true; + +#if UNITY_SWITCH && !UNITY_EDITOR + // End preventing the user from quitting the game while saving. + UnityEngine.Switch.Notification.LeaveExitRequestHandlingSection(); +#endif +#endif + } + + + public bool RenameDir(string oldpath,string newpath) + { +#if !UNITY_SWITCH + return false; +#else + +#if UNITY_SWITCH && !UNITY_EDITOR + // This next line prevents the user from quitting the game while saving. + // This is required for Nintendo Switch Guideline 0080 + UnityEngine.Switch.Notification.EnterExitRequestHandlingSection(); +#endif + + if (CheckPathNotFound(oldpath)) + return false; + + nn.Result result; + result = nn.fs.Directory.Rename(oldpath, newpath); + if (result.IsSuccess() == false) + { + UnityEngine.Debug.LogError($"nn.fs.File.Rename ʧ�� {oldpath} to {newpath} : result=>{result.GetErrorInfo()}"); + return false; + } + result = nn.fs.FileSystem.Commit(save_name); + if (!result.IsSuccess()) + { + UnityEngine.Debug.LogError($"FileSystem.Commit({save_name}) ʧ��: " + result.GetErrorInfo()); + return false; + } + return true; + +#if UNITY_SWITCH && !UNITY_EDITOR + // End preventing the user from quitting the game while saving. + UnityEngine.Switch.Notification.LeaveExitRequestHandlingSection(); +#endif +#endif + } + bool EnsureParentDirectory(string filePath, bool bAutoCreateDir = true) { #if !UNITY_SWITCH return false; diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMount.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMount.cs index 0d1bae7c..a634a432 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMount.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMount.cs @@ -5,10 +5,12 @@ public class AxiNSMount { static bool bInMount = false; internal static string m_SaveMountName; - static bool bInMountForDebug = false; - internal static string m_SaveMountForDebugName; + static bool bInSdCardMount = false; + internal static string m_SdCardMountName; + static bool bInSdCardDebugMount = false; + internal static string m_SdCardDebugMountName; - public bool SaveIsMount => bInMount; + public bool SaveIsMount => bInMount; public string SaveMountName { get @@ -47,14 +49,14 @@ public class AxiNSMount bInMount = true; return true; } - #endif +#endif - public bool MountSDForDebug(string mountName = "sd") + public bool MountSDForDebug(string mountName = "dbgsd") { #if !UNITY_SWITCH return false; #else - if (bInMountForDebug) + if (bInSdCardDebugMount) return true; nn.Result result; result = nn.fs.SdCard.MountForDebug(mountName); @@ -65,35 +67,31 @@ public class AxiNSMount return false; } UnityEngine.Debug.Log($"nn_fs_MountSdCardForDebug->����{mountName}:/ �ɹ� "); - m_SaveMountForDebugName = mountName; - bInMountForDebug = true; + m_SdCardDebugMountName = mountName; + bInSdCardDebugMount = true; return true; #endif } - public bool MountSD(string mountName = "sd") { #if !UNITY_SWITCH return false; #else - if (bInMountForDebug) + if (bInSdCardMount) return true; nn.Result result; - result = nn.fs.SdCard.Mount(mountName); - //result.abortUnlessSuccess(); + result = AxiNSSDCard.Mount(mountName); if (!result.IsSuccess()) { UnityEngine.Debug.LogError($"nn_fs_MountSdCard->����{mountName}:/ ʧ��: " + result.ToString()); return false; } UnityEngine.Debug.Log($"nn_fs_MountSdCard->����{mountName}:/ �ɹ� "); - m_SaveMountForDebugName = mountName; - bInMountForDebug = true; + m_SdCardMountName = mountName; + bInSdCardMount = true; return true; #endif } - - public void UnmountSave() { #if UNITY_SWITCH @@ -107,18 +105,30 @@ public class AxiNSMount bInMount = false; #endif } - - public void UnmountSaveForDebug() + public void UnmountSDCardForDebug() { #if UNITY_SWITCH - if (!bInMountForDebug) + if (!bInSdCardDebugMount) { - UnityEngine.Debug.LogError($"{m_SaveMountForDebugName}:/ û�б����أ�����ж��"); + UnityEngine.Debug.LogError($"{m_SdCardDebugMountName}:/ û�б����أ�����ж��"); return; } - nn.fs.FileSystem.Unmount(m_SaveMountForDebugName); - UnityEngine.Debug.LogError($"UnmountSaveForDebufa->��ж��{m_SaveMountForDebugName}:/ "); - bInMountForDebug = false; + nn.fs.FileSystem.Unmount(m_SdCardDebugMountName); + UnityEngine.Debug.LogError($"UnmountSDCardForDebug->��ж��{m_SdCardDebugMountName}:/ "); + bInSdCardDebugMount = false; #endif - } + } + public void UnmountSDCard() + { +#if UNITY_SWITCH + if (!bInSdCardMount) + { + UnityEngine.Debug.LogError($"{m_SdCardMountName}:/ û�б����أ�����ж��"); + return; + } + nn.fs.FileSystem.Unmount(m_SdCardMountName); + UnityEngine.Debug.LogError($"UnmountSDCard->��ж��{m_SdCardMountName}:/ "); + bInSdCardMount = false; +#endif + } } \ No newline at end of file diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSSDCard.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSSDCard.cs new file mode 100644 index 00000000..f1fe28e6 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSSDCard.cs @@ -0,0 +1,23 @@ +#if UNITY_SWITCH +using nn.account; +#endif +public class AxiNSSDCard +{ +#if UNITY_SWITCH + +#if DEVELOPMENT_BUILD || NN_FS_SD_CARD_FOR_DEBUG_ENABLE + [DllImport(Nn.DllName, + CallingConvention = CallingConvention.Cdecl, + EntryPoint = "nn_fs_MountSdCard")] + public static extern nn.Result Mount(string name); +#else + + public static nn.Result Mount(string name) + { + return new nn.Result(); + } +#endif + + +#endif +} \ No newline at end of file diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSSDCard.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSSDCard.cs.meta new file mode 100644 index 00000000..1b9591a5 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSSDCard.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21fa04ba4da10d74aafd65dd138478b7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 5aabda7c3766143d923c5b546f02e786d562634e Mon Sep 17 00:00:00 2001 From: sin365 <353374337@qq.com> Date: Wed, 9 Apr 2025 00:48:15 +0800 Subject: [PATCH 2/2] =?UTF-8?q?Switch=E6=96=87=E4=BB=B6=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E5=BC=82=E6=AD=A5=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/Plugins/AxiNSApi/AxiNS.cs | 2 + .../Assets/Plugins/AxiNSApi/AxiNSIO.cs | 214 +++++++++++------- .../Assets/Plugins/AxiNSApi/AxiNSMount.cs | 1 + .../Plugins/AxiNSApi/AxiNSWaitHandle.meta | 8 + .../AxiNSWaitHandle/AxiNSWaitHandle.Data.cs | 119 ++++++++++ .../AxiNSWaitHandle.Data.cs.meta | 11 + .../AxiNSWaitHandle/AxiNSWaitHandle.cs | 56 +++++ .../AxiNSWaitHandle/AxiNSWaitHandle.cs.meta | 11 + 8 files changed, 335 insertions(+), 87 deletions(-) create mode 100644 AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle.meta create mode 100644 AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.Data.cs create mode 100644 AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.Data.cs.meta create mode 100644 AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.cs create mode 100644 AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.cs.meta diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNS.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNS.cs index 648bbd62..e39ca58e 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNS.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNS.cs @@ -18,11 +18,13 @@ public class AxiNS public AxiNSUser user; public AxiNSMount mount; public AxiNSIO io; + public AxiNSWaitHandle wait; AxiNS() { user = new AxiNSUser(); mount = new AxiNSMount(); io = new AxiNSIO(); + wait = new AxiNSWaitHandle(); } /// <summary> diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSIO.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSIO.cs index 7e20444b..9e3fe02e 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSIO.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSIO.cs @@ -1,86 +1,97 @@ #if UNITY_SWITCH using nn.fs; -using System.Security.Cryptography; - #endif public class AxiNSIO { - string save_name => AxiNS.instance.mount.SaveMountName; - public string save_path => $"{save_name}:/"; + string save_name => AxiNS.instance.mount.SaveMountName; + public string save_path => $"{save_name}:/"; #if UNITY_SWITCH private FileHandle fileHandle = new nn.fs.FileHandle(); #endif - /// <summary> - /// ���Path�Ƿ���� - /// </summary> - /// <param name="filePath"></param> - /// <returns></returns> - public bool CheckPathExists(string filePath) - { + /// <summary> + /// ���Path�Ƿ���� + /// </summary> + /// <param name="filePath"></param> + /// <returns></returns> + public bool CheckPathExists(string filePath) + { #if !UNITY_SWITCH return false; #else - nn.fs.EntryType entryType = 0; + nn.fs.EntryType entryType = 0; nn.Result result = nn.fs.FileSystem.GetEntryType(ref entryType, filePath); //result.abortUnlessSuccess(); //����쳣������ı�Ť return nn.fs.FileSystem.ResultPathAlreadyExists.Includes(result); #endif - } - /// <summary> - /// ���Path�Ƿ��� - /// </summary> - /// <param name="filePath"></param> - /// <returns></returns> - public bool CheckPathNotFound(string filePath) - { + } + /// <summary> + /// ���Path�Ƿ��� + /// </summary> + /// <param name="filePath"></param> + /// <returns></returns> + public bool CheckPathNotFound(string filePath) + { #if !UNITY_SWITCH return false; #else - nn.fs.EntryType entryType = 0; + nn.fs.EntryType entryType = 0; nn.Result result = nn.fs.FileSystem.GetEntryType(ref entryType, filePath); //����쳣������ı�Ť return nn.fs.FileSystem.ResultPathNotFound.Includes(result); #endif - } - /// <summary> - /// ����Ŀ¼��Ŀ¼����Ҳ�᷵��true - /// </summary> - /// <param name="filePath"></param> - /// <returns></returns> - public bool CreateDir(string filePath) - { + } + /// <summary> + /// ����Ŀ¼��Ŀ¼����Ҳ�᷵��true + /// </summary> + /// <param name="filePath"></param> + /// <returns></returns> + public bool CreateDir(string filePath) + { #if !UNITY_SWITCH return false; #else - // ʹ�÷�װ�������ʹ�����Ŀ¼ - if (!EnsureParentDirectory(filePath, true)) - { - UnityEngine.Debug.LogError($"��ȷ����Ŀ¼���ļ�д��ȡ��: {filePath}"); - return false; - } + // ʹ�÷�װ�������ʹ�����Ŀ¼ + if (!EnsureParentDirectory(filePath, true)) + { + UnityEngine.Debug.LogError($"��ȷ����Ŀ¼���ļ�д��ȡ��: {filePath}"); + return false; + } return true; #endif - } - /// <summary> - /// ���沢�����ļ������Ŀ¼�����ڻ����Զ�����Ŀ¼�� - /// </summary> - /// <param name="filePath"></param> - /// <param name="bw"></param> - /// <returns></returns> - public bool FileToSaveWithCreate(string filePath, System.IO.MemoryStream ms) - { - return FileToSaveWithCreate(filePath, ms.ToArray()); - } - /// <summary> - /// ���沢�����ļ������Ŀ¼�����ڻ����Զ�����Ŀ¼�� - /// </summary> - /// <param name="filePath"></param> - /// <param name="data"></param> - /// <returns></returns> - public bool FileToSaveWithCreate(string filePath, byte[] data) - { + } + + /// <summary> + /// ���沢�����ļ������Ŀ¼�����ڻ����Զ�����Ŀ¼�� + /// </summary> + /// <param name="filePath"></param> + /// <param name="bw"></param> + /// <returns></returns> + public bool FileToSaveWithCreate(string filePath, System.IO.MemoryStream ms) + { + return FileToSaveWithCreate(filePath, ms.ToArray()); + } + /// <summary> + /// ���沢�����ļ������Ŀ¼�����ڻ����Զ�����Ŀ¼�� + /// </summary> + /// <param name="filePath"></param> + /// <param name="data"></param> + /// <returns></returns> + public AxiNSWait_FileToSaveByMSWithCreate FileToSaveWithCreateAsync(string filePath, System.IO.MemoryStream ms) + { + var wait = new AxiNSWait_FileToSaveByMSWithCreate(filePath, ms); + AxiNS.instance.wait.AddWait(wait); + return wait; + } + /// <summary> + /// ���沢�����ļ������Ŀ¼�����ڻ����Զ�����Ŀ¼�� + /// </summary> + /// <param name="filePath"></param> + /// <param name="data"></param> + /// <returns></returns> + public bool FileToSaveWithCreate(string filePath, byte[] data) + { #if !UNITY_SWITCH return false; #else @@ -184,21 +195,33 @@ public class AxiNSIO return true; #endif - } - public bool LoadSwitchDataFile(string filename, ref System.IO.MemoryStream ms) - { - if (LoadSwitchDataFile(filename, out byte[] outputData)) - { - using (System.IO.BinaryWriter writer = new System.IO.BinaryWriter(ms)) - { - writer.Write(outputData); - } - return true; - } - return false; - } - public bool LoadSwitchDataFile(string filename, out byte[] outputData) - { + } + /// <summary> + /// ���沢�����ļ������Ŀ¼�����ڻ����Զ�����Ŀ¼�� + /// </summary> + /// <param name="filePath"></param> + /// <param name="data"></param> + /// <returns></returns> + public AxiNSWait_FileToSaveWithCreate FileToSaveWithCreateAsync(string filePath, byte[] data) + { + var wait = new AxiNSWait_FileToSaveWithCreate(filePath, data); + AxiNS.instance.wait.AddWait(wait); + return wait; + } + public bool LoadSwitchDataFile(string filename, ref System.IO.MemoryStream ms) + { + if (LoadSwitchDataFile(filename, out byte[] outputData)) + { + using (System.IO.BinaryWriter writer = new System.IO.BinaryWriter(ms)) + { + writer.Write(outputData); + } + return true; + } + return false; + } + public bool LoadSwitchDataFile(string filename, out byte[] outputData) + { #if !UNITY_SWITCH outputData = null; return false; @@ -249,9 +272,15 @@ public class AxiNSIO outputData = loadedData; return true; #endif - } - public bool DeletePathFile(string filename) - { + } + public AxiNSWait_LoadSwitchDataFile LoadSwitchDataFileAsync(string filename) + { + var wait = new AxiNSWait_LoadSwitchDataFile(filename); + AxiNS.instance.wait.AddWait(wait); + return wait; + } + public bool DeletePathFile(string filename) + { #if !UNITY_SWITCH return false; #else @@ -270,7 +299,7 @@ public class AxiNSIO if (result.IsSuccess() == false) { UnityEngine.Debug.LogError($"nn.fs.File.Delete ʧ�� {filename} : result=>{result.GetErrorInfo()}"); - return false; + return false; } result = nn.fs.FileSystem.Commit(save_name); if (!result.IsSuccess()) @@ -287,8 +316,14 @@ public class AxiNSIO #endif } + public AxiNSWait_DeletePathFile DeletePathFileAsync(string filename) + { + var wait = new AxiNSWait_DeletePathFile(filename); + AxiNS.instance.wait.AddWait(wait); + return wait; + } public bool DeletePathDir(string filename) - { + { #if !UNITY_SWITCH return false; #else @@ -322,6 +357,12 @@ public class AxiNSIO #endif #endif } + public AxiNSWait_DeletePathDir DeletePathDirAsync(string filename) + { + var wait = new AxiNSWait_DeletePathDir(filename); + AxiNS.instance.wait.AddWait(wait); + return wait; + } /// <summary> /// �ݹ�ɾ��Ŀ¼ @@ -405,8 +446,7 @@ public class AxiNSIO #endif } - - public bool RenameDir(string oldpath,string newpath) + public bool RenameDir(string oldpath, string newpath) { #if !UNITY_SWITCH return false; @@ -443,7 +483,7 @@ public class AxiNSIO #endif } bool EnsureParentDirectory(string filePath, bool bAutoCreateDir = true) - { + { #if !UNITY_SWITCH return false; #else @@ -517,16 +557,16 @@ public class AxiNSIO // ·����������Ŀ¼ UnityEngine.Debug.Log($"��Ŀ¼ {fullDirectoryPath} �Ѵ�������Ч"); return true; - + #endif - } - /// <summary> - /// ���ָ�����ص��Ƿ�ɷ��� - /// </summary> - /// <param name="pathPrefix">·��ǰ������ "save:/" �� "sd:/"</param> - /// <returns>���ص��Ƿ�ɷ���</returns> - bool IsMountPointAccessible(string pathPrefix) - { + } + /// <summary> + /// ���ָ�����ص��Ƿ�ɷ��� + /// </summary> + /// <param name="pathPrefix">·��ǰ������ "save:/" �� "sd:/"</param> + /// <returns>���ص��Ƿ�ɷ���</returns> + bool IsMountPointAccessible(string pathPrefix) + { #if !UNITY_SWITCH return false; #else @@ -564,5 +604,5 @@ public class AxiNSIO return true; // �������ص������ʵ������ʵ�� } #endif - } + } } diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMount.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMount.cs index a634a432..8b32a30b 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMount.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMount.cs @@ -1,5 +1,6 @@ #if UNITY_SWITCH using nn.account; +using static AxiHttp; #endif public class AxiNSMount { diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle.meta b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle.meta new file mode 100644 index 00000000..99d60f26 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e28ed9d2fb16c7f42b28cafb6a2ce0ac +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.Data.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.Data.cs new file mode 100644 index 00000000..009b93e8 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.Data.cs @@ -0,0 +1,119 @@ +public abstract class AxiNSWaitBase : UnityEngine.CustomYieldInstruction +{ + protected bool IsDone; + public abstract void Invoke(); + public string errmsg = string.Empty; + public AxiNSWaitBase() + { + this.IsDone = false; + } + + public void SetDone() + { + this.IsDone = true; + } + + ~AxiNSWaitBase() + { + } + + public override bool keepWaiting + { + get { return !IsDone; } + } +} + + + +public struct S_NSWAIT_PathWithBytes +{ + public string filePath; + public byte[] data; +} + +public class AxiNSWait_FileToSaveWithCreate : AxiNSWaitBase +{ + S_NSWAIT_PathWithBytes req; + public bool result; + public AxiNSWait_FileToSaveWithCreate(string filePath, byte[] data) + { + req = new S_NSWAIT_PathWithBytes() { filePath = filePath, data = data }; + } + + public override void Invoke() + { + result = AxiNS.instance.io.FileToSaveWithCreate(req.filePath, req.data); + } +} + +public struct S_NSWAIT_PathWithMS +{ + public string filePath; + public System.IO.MemoryStream ms; +} + +public class AxiNSWait_FileToSaveByMSWithCreate : AxiNSWaitBase +{ + S_NSWAIT_PathWithMS req; + public bool result; + public AxiNSWait_FileToSaveByMSWithCreate(string filePath, System.IO.MemoryStream ms) + { + req = new S_NSWAIT_PathWithMS() { filePath = filePath, ms = ms }; + } + + public override void Invoke() + { + result = AxiNS.instance.io.FileToSaveWithCreate(req.filePath, req.ms); + } +} + +public struct S_NSWAIT_Path +{ + public string filePath; +} + +public class AxiNSWait_LoadSwitchDataFile : AxiNSWaitBase +{ + S_NSWAIT_Path req; + public bool result; + public byte[] outputData; + public AxiNSWait_LoadSwitchDataFile(string filePath) + { + req = new S_NSWAIT_Path() { filePath = filePath}; + } + + public override void Invoke() + { + result = AxiNS.instance.io.LoadSwitchDataFile(req.filePath, out outputData); + } +} + +public class AxiNSWait_DeletePathFile : AxiNSWaitBase +{ + S_NSWAIT_Path req; + public bool result; + public AxiNSWait_DeletePathFile(string filePath) + { + req = new S_NSWAIT_Path() { filePath = filePath }; + } + + public override void Invoke() + { + result = AxiNS.instance.io.DeletePathFile(req.filePath); + } +} + +public class AxiNSWait_DeletePathDir : AxiNSWaitBase +{ + S_NSWAIT_Path req; + public bool result; + public AxiNSWait_DeletePathDir(string filePath) + { + req = new S_NSWAIT_Path() { filePath = filePath }; + } + + public override void Invoke() + { + result = AxiNS.instance.io.DeletePathDir(req.filePath); + } +} \ No newline at end of file diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.Data.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.Data.cs.meta new file mode 100644 index 00000000..ff72499f --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.Data.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 46a1a776d2f9dba49b9641d8e0976861 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.cs new file mode 100644 index 00000000..a8ba35f0 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +public class AxiNSWaitHandle +{ + static AutoResetEvent autoEvent = new AutoResetEvent(false); + static Thread waitThread = new Thread(Loop); + static bool bSingleInit = false; + static Queue<AxiNSWaitBase> m_QueueReady = new Queue<AxiNSWaitBase>(); + static Queue<AxiNSWaitBase> m_QueueWork = new Queue<AxiNSWaitBase>(); + public void AddWait(AxiNSWaitBase wait) + { + InitInternalThread(); + lock (m_QueueReady) + { + m_QueueReady.Enqueue(wait); + } + autoEvent.Set(); + } + + static void InitInternalThread() + { + if (bSingleInit) return; + waitThread.Start(); + bSingleInit = true; + } + + static void Loop() + { + while (autoEvent.WaitOne()) + { + lock (m_QueueReady) + { + while (m_QueueReady.Count > 0) + { + m_QueueWork.Enqueue(m_QueueReady.Dequeue()); + } + } + while (m_QueueWork.Count > 0) + { + AxiNSWaitBase wait = m_QueueWork.Dequeue(); + try + { + wait.Invoke(); + } + catch (Exception ex) + { + wait.errmsg = ex.ToString(); + UnityEngine.Debug.Log(ex.ToString()); + } + wait.SetDone(); + } + } + } +} \ No newline at end of file diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.cs.meta new file mode 100644 index 00000000..46fa015c --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5e36180ba1c4a8f4db3ceed533a43999 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: