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
+ }
+
+ ///
+ /// 递归删除目录
+ ///
+ ///
+ ///
+ 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
+ }
+
+ ///
+ /// 递归删除情况
+ ///
+ ///
+ ///
+ 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();
}
///
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
- ///
- /// 检查Path是否存在
- ///
- ///
- ///
- public bool CheckPathExists(string filePath)
- {
+ ///
+ /// 检查Path是否存在
+ ///
+ ///
+ ///
+ 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
- }
- ///
- /// 检查Path是否不存在
- ///
- ///
- ///
- public bool CheckPathNotFound(string filePath)
- {
+ }
+ ///
+ /// 检查Path是否不存在
+ ///
+ ///
+ ///
+ 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
- }
- ///
- /// 创建目录,目录存在也会返回true
- ///
- ///
- ///
- public bool CreateDir(string filePath)
- {
+ }
+ ///
+ /// 创建目录,目录存在也会返回true
+ ///
+ ///
+ ///
+ 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
- }
- ///
- /// 保存并创建文件(如果目录不存在回先自动创建目录)
- ///
- ///
- ///
- ///
- public bool FileToSaveWithCreate(string filePath, System.IO.MemoryStream ms)
- {
- return FileToSaveWithCreate(filePath, ms.ToArray());
- }
- ///
- /// 保存并创建文件(如果目录不存在回先自动创建目录)
- ///
- ///
- ///
- ///
- public bool FileToSaveWithCreate(string filePath, byte[] data)
- {
+ }
+
+ ///
+ /// 保存并创建文件(如果目录不存在回先自动创建目录)
+ ///
+ ///
+ ///
+ ///
+ public bool FileToSaveWithCreate(string filePath, System.IO.MemoryStream ms)
+ {
+ return FileToSaveWithCreate(filePath, ms.ToArray());
+ }
+ ///
+ /// 保存并创建文件(如果目录不存在回先自动创建目录)
+ ///
+ ///
+ ///
+ ///
+ public AxiNSWait_FileToSaveByMSWithCreate FileToSaveWithCreateAsync(string filePath, System.IO.MemoryStream ms)
+ {
+ var wait = new AxiNSWait_FileToSaveByMSWithCreate(filePath, ms);
+ AxiNS.instance.wait.AddWait(wait);
+ return wait;
+ }
+ ///
+ /// 保存并创建文件(如果目录不存在回先自动创建目录)
+ ///
+ ///
+ ///
+ ///
+ 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)
- {
+ }
+ ///
+ /// 保存并创建文件(如果目录不存在回先自动创建目录)
+ ///
+ ///
+ ///
+ ///
+ 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;
+ }
///
/// 递归删除目录
@@ -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
- }
- ///
- /// 检查指定挂载点是否可访问
- ///
- /// 路径前缀,例如 "save:/" 或 "sd:/"
- /// 挂载点是否可访问
- bool IsMountPointAccessible(string pathPrefix)
- {
+ }
+ ///
+ /// 检查指定挂载点是否可访问
+ ///
+ /// 路径前缀,例如 "save:/" 或 "sd:/"
+ /// 挂载点是否可访问
+ 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 m_QueueReady = new Queue();
+ static Queue m_QueueWork = new Queue();
+ 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: