From 57c4947623afc0e2e56f7ba23df1f7838319f79f Mon Sep 17 00:00:00 2001 From: sin365 <353374337@qq.com> Date: Mon, 18 Aug 2025 22:12:40 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=95=E5=85=A5=E6=9C=80=E6=96=B0=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E7=9A=84AxiNSApi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/Plugins/AxiNSApi/AxiNS.cs | 5 + .../Assets/Plugins/AxiNSApi/AxiNSIO.cs | 457 ++++++++++-------- .../Assets/Plugins/AxiNSApi/AxiNSMono.cs | 41 ++ .../Assets/Plugins/AxiNSApi/AxiNSMono.cs.meta | 11 + .../AxiNSWaitHandle/AxiNSWaitHandle.Data.cs | 15 + .../AxiNSWaitHandle/AxiNSWaitHandle.cs | 69 ++- 6 files changed, 384 insertions(+), 214 deletions(-) create mode 100644 AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMono.cs create mode 100644 AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMono.cs.meta diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNS.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNS.cs index e39ca58e..e30ef88b 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNS.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNS.cs @@ -15,6 +15,11 @@ public class AxiNS } } + /// + /// 延迟提交是否使用多线程 + /// + public static bool usedmultithreading = false; + public AxiNSUser user; public AxiNSMount mount; public AxiNSIO io; diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSIO.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSIO.cs index 6baa6d0b..9ad3c4a9 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSIO.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSIO.cs @@ -7,20 +7,20 @@ using System.Text.RegularExpressions; 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 - static object commitLock = new object(); + static object commitLock = new object(); - static bool bDirty = false; + static bool bDirty = false; - bool CommitSave() - { - lock (commitLock) - { + bool CommitSave() + { + lock (commitLock) + { #if UNITY_SWITCH && !UNITY_EDITOR // 阻止用户在保存时,退出游戏 Switch 条例 0080 @@ -39,41 +39,41 @@ public class AxiNSIO bDirty = false; return true; #else - return false; + return false; #endif - } + } - } + } - void SetCommitDirty() - { - lock (commitLock) - { - bDirty = true; - } - } + void SetCommitDirty() + { + lock (commitLock) + { + bDirty = true; + } + } - public void ApplyAutoCommit() - { - bool temp; - lock (commitLock) - { - temp = bDirty; - } + public void ApplyAutoCommit() + { + bool temp; + lock (commitLock) + { + temp = bDirty; + } - if (temp) - { - CommitSave(); - } - } + if (temp) + { + CommitSave(); + } + } - /// - /// 检查Path是否存在 - /// - /// - /// - public bool CheckPathExists(string filePath) - { + /// + /// 检查Path是否存在 + /// + /// + /// + public bool CheckPathExists(string filePath) + { #if !UNITY_SWITCH return false; #else @@ -86,14 +86,14 @@ public class AxiNSIO //return nn.fs.FileSystem.ResultPathAlreadyExists.Includes(result); return !nn.fs.FileSystem.ResultPathNotFound.Includes(result); #endif - } - /// - /// 检查Path是否不存在 - /// - /// - /// - public bool CheckPathNotFound(string filePath) - { + } + /// + /// 检查Path是否不存在 + /// + /// + /// + public bool CheckPathNotFound(string filePath) + { #if !UNITY_SWITCH return false; #else @@ -102,16 +102,16 @@ public class AxiNSIO //这个异常捕获。真的别扭 return nn.fs.FileSystem.ResultPathNotFound.Includes(result); #endif - } - /// - /// 创建目录,目录存在也会返回true - /// - /// - /// - public bool CreateDir(string filePath) - { - lock (commitLock) - { + } + /// + /// 创建目录,目录存在也会返回true + /// + /// + /// + public bool CreateDir(string filePath) + { + lock (commitLock) + { #if !UNITY_SWITCH return false; @@ -124,43 +124,43 @@ public class AxiNSIO } return true; #endif - } - } + } + } - /// - /// 保存并创建文件(如果目录不存在回先自动创建目录) - /// - /// - /// - /// - 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, 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; + } - /// - /// 保存并创建文件(如果目录不存在回先自动创建目录) - /// - /// - /// - /// 是否立即Commit到物理存储 - /// - public bool FileToSaveWithCreate(string filePath, byte[] data, bool immediatelyCommit = true) - { - lock (commitLock) - { + /// + /// 保存并创建文件(如果目录不存在回先自动创建目录) + /// + /// + /// + /// 是否立即Commit到物理存储 + /// + public bool FileToSaveWithCreate(string filePath, byte[] data, bool immediatelyCommit = true) + { + lock (commitLock) + { #if !UNITY_SWITCH return false; #else @@ -293,42 +293,45 @@ public class AxiNSIO return true; } #endif - } - } - /// - /// 保存并创建文件(如果目录不存在回先自动创建目录) - /// - /// - /// - /// - public AxiNSWait_FileToSaveWithCreate FileToSaveWithCreateAsync(string filePath, byte[] data) - { - var wait = new AxiNSWait_FileToSaveWithCreate(filePath, data); - AxiNS.instance.wait.AddWait(wait); - return wait; - } - public byte[] LoadSwitchDataFile(string filename) - { - LoadSwitchDataFile(filename, out byte[] outputData); - return outputData; - } - 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 byte[] LoadSwitchDataFile(string filename) + { + byte[] outputData; + LoadSwitchDataFile(filename, out outputData); + return outputData; + } + + public bool LoadSwitchDataFile(string filename, ref System.IO.MemoryStream ms) + { + byte[] outputData; + if (LoadSwitchDataFile(filename, out 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 || UNITY_EDITOR - outputData = null; - return false; + outputData = null; + return false; #else outputData = null; if (!AxiNS.instance.mount.SaveIsMount) @@ -376,32 +379,34 @@ public class AxiNSIO outputData = loadedData; return true; #endif - } - public AxiNSWait_LoadSwitchDataFile LoadSwitchDataFileAsync(string filename) - { - var wait = new AxiNSWait_LoadSwitchDataFile(filename); - AxiNS.instance.wait.AddWait(wait); - return wait; - } - public bool GetDirectoryFiles(string path, out string[] entrys) - { + } + public AxiNSWait_LoadSwitchDataFile LoadSwitchDataFileAsync(string filename) + { + var wait = new AxiNSWait_LoadSwitchDataFile(filename); + AxiNS.instance.wait.AddWait(wait); + return wait; + } + + public bool GetDirectoryFiles(string path, out string[] entrys) + { #if !UNITY_SWITCH || UNITY_EDITOR - entrys = null; - return false; + entrys = null; + return false; #else return GetDirectoryEntrys(path,nn.fs.OpenDirectoryMode.File,out entrys); #endif - } - public bool GetDirectoryDirs(string path, out string[] entrys) - { + } + + public bool GetDirectoryDirs(string path, out string[] entrys) + { #if !UNITY_SWITCH || UNITY_EDITOR - entrys = null; - return false; + entrys = null; + return false; #else return GetDirectoryEntrys(path, nn.fs.OpenDirectoryMode.Directory, out entrys); #endif - } + } #if UNITY_SWITCH public bool GetDirectoryEntrys(string path, nn.fs.OpenDirectoryMode type, out string[] entrys) @@ -430,8 +435,9 @@ public class AxiNSIO } #endif - public bool GetDirectoryEntrysFullRecursion(string path, out string[] entrys) - { + + public bool GetDirectoryEntrysFullRecursion(string path, out string[] entrys) + { #if UNITY_SWITCH nn.fs.DirectoryHandle eHandle = new nn.fs.DirectoryHandle(); @@ -462,15 +468,15 @@ public class AxiNSIO entrys = temp.ToArray(); return true; #else - entrys = default; + entrys = null; return false; #endif - } + } - public IEnumerable EnumerateFiles(string path, string searchPattern) - { + public IEnumerable EnumerateFiles(string path, string searchPattern) + { #if !UNITY_SWITCH || UNITY_EDITOR - yield break; + yield break; #else // 将通配符转换为正则表达式(支持*和?) var regexPattern = "^" + @@ -494,10 +500,10 @@ public class AxiNSIO } } #endif - } + } - public bool DeletePathFile(string filename) - { + public bool DeletePathFile(string filename) + { #if !UNITY_SWITCH return false; #else @@ -526,15 +532,15 @@ public class AxiNSIO return CommitSave(); #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) - { + } + 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 @@ -561,15 +567,15 @@ public class AxiNSIO #endif return CommitSave(); #endif - } - public AxiNSWait_DeletePathDir DeletePathDirAsync(string filename) - { - var wait = new AxiNSWait_DeletePathDir(filename); - AxiNS.instance.wait.AddWait(wait); - return wait; - } - public bool DeletePathDirRecursively(string filename) - { + } + public AxiNSWait_DeletePathDir DeletePathDirAsync(string filename) + { + var wait = new AxiNSWait_DeletePathDir(filename); + AxiNS.instance.wait.AddWait(wait); + return wait; + } + public bool DeletePathDirRecursively(string filename) + { #if !UNITY_SWITCH return false; #else @@ -596,19 +602,86 @@ public class AxiNSIO #endif return CommitSave(); #endif - } + } + public AxiNSWait_DeletePathDirRecursively DeletePathDirRecursivelyAsync(string filename) + { + var wait = new AxiNSWait_DeletePathDirRecursively(filename); + AxiNS.instance.wait.AddWait(wait); + return wait; + } -#if UNITY_SWITCH - public AxiNSWait_DeletePathDirRecursively DeletePathDirRecursivelyAsync(string filename) - { - var wait = new AxiNSWait_DeletePathDirRecursively(filename); - AxiNS.instance.wait.AddWait(wait); - return wait; - } + /// + /// 递归删除目录 + /// + /// + /// + 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 - public bool RenameDir(string oldpath, string newpath) - { + 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; + } + +#if UNITY_SWITCH && !UNITY_EDITOR + // End preventing the user from quitting the game while saving. + UnityEngine.Switch.Notification.LeaveExitRequestHandlingSection(); +#endif + return CommitSave(); +#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; + } + +#if UNITY_SWITCH && !UNITY_EDITOR + // End preventing the user from quitting the game while saving. + UnityEngine.Switch.Notification.LeaveExitRequestHandlingSection(); +#endif + return CommitSave(); +#endif + } + + public bool RenameDir(string oldpath, string newpath) + { #if !UNITY_SWITCH return false; #else @@ -637,9 +710,9 @@ public class AxiNSIO return CommitSave(); #endif - } - bool EnsureParentDirectory(string filePath, bool bAutoCreateDir = true) - { + } + bool EnsureParentDirectory(string filePath, bool bAutoCreateDir = true) + { #if !UNITY_SWITCH return false; #else @@ -715,14 +788,14 @@ public class AxiNSIO return true; #endif - } - /// - /// 检查指定挂载点是否可访问 - /// - /// 路径前缀,例如 "save:/" 或 "sd:/" - /// 挂载点是否可访问 - bool IsMountPointAccessible(string pathPrefix) - { + } + /// + /// 检查指定挂载点是否可访问 + /// + /// 路径前缀,例如 "save:/" 或 "sd:/" + /// 挂载点是否可访问 + bool IsMountPointAccessible(string pathPrefix) + { #if !UNITY_SWITCH return false; #else @@ -760,5 +833,5 @@ public class AxiNSIO return true; // 其他挂载点需根据实际需求实现 } #endif - } + } } diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMono.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMono.cs new file mode 100644 index 00000000..bc6f96bd --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMono.cs @@ -0,0 +1,41 @@ +锘縰sing System; +using UnityEngine; + +public class AxiNSMono : MonoBehaviour +{ + Action act; + float waittime; + float lastinvokeTime; + + public static void SetInvoke(Action _act, int _waitsec) + { + GameObject gobj = GameObject.Find($"[{nameof(AxiNSMono)}]"); + if (gobj == null) + { + gobj = new GameObject(); + gobj.name = $"[{nameof(AxiNSMono)}]"; + GameObject.DontDestroyOnLoad(gobj); + } + AxiNSMono com = gobj.GetComponent(); + if (com == null) + { + com = gobj.AddComponent(); + } + com.act = _act; + com.waittime = _waitsec; + } + + public void OnEnable() + { + Debug.Log("AxiNSMono Enable"); + } + + public void Update() + { + if (Time.time - lastinvokeTime < waittime) + return; + lastinvokeTime = Time.time; + if (act != null) + act.Invoke(); + } +} \ No newline at end of file diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMono.cs.meta b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMono.cs.meta new file mode 100644 index 00000000..4a4f0ae6 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSMono.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 23d5745b8989af04d8a871b5c7b65d50 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + 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 index 009b93e8..5c8a4a7d 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.Data.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.Data.cs @@ -116,4 +116,19 @@ public class AxiNSWait_DeletePathDir : AxiNSWaitBase { result = AxiNS.instance.io.DeletePathDir(req.filePath); } +} + +public class AxiNSWait_DeletePathDirRecursively : AxiNSWaitBase +{ + S_NSWAIT_Path req; + public bool result; + public AxiNSWait_DeletePathDirRecursively(string filePath) + { + req = new S_NSWAIT_Path() { filePath = filePath }; + } + + public override void Invoke() + { + result = AxiNS.instance.io.DeletePathDirRecursively(req.filePath); + } } \ No newline at end of file diff --git a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.cs b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.cs index a8ba35f0..027edaeb 100644 --- a/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.cs +++ b/AxibugEmuOnline.Client/Assets/Plugins/AxiNSApi/AxiNSWaitHandle/AxiNSWaitHandle.cs @@ -4,21 +4,30 @@ 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(); + + if (AxiNS.usedmultithreading) + { + InitInternalThread(); + autoEvent.Set(); + } + else + { + InitMonoInit(); + } } + #region 多线程实现 + static AutoResetEvent autoEvent = new AutoResetEvent(false); + static Thread waitThread = new Thread(Loop); + static bool bSingleInit = false; static void InitInternalThread() { if (bSingleInit) return; @@ -30,27 +39,43 @@ public class AxiNSWaitHandle { while (autoEvent.WaitOne()) { - lock (m_QueueReady) + Do(); + } + } + #endregion + + #region 主线程时间间隔实现 + static bool bMonoInit = false; + static void InitMonoInit() + { + if (bMonoInit) return; + AxiNSMono.SetInvoke(Do,15); + bMonoInit = true; + } + #endregion + + static void Do() + { + lock (m_QueueReady) + { + while (m_QueueReady.Count > 0) { - while (m_QueueReady.Count > 0) - { - m_QueueWork.Enqueue(m_QueueReady.Dequeue()); - } + m_QueueWork.Enqueue(m_QueueReady.Dequeue()); } - while (m_QueueWork.Count > 0) + } + while (m_QueueWork.Count > 0) + { + AxiNSWaitBase wait = m_QueueWork.Dequeue(); + try { - AxiNSWaitBase wait = m_QueueWork.Dequeue(); - try - { - wait.Invoke(); - } - catch (Exception ex) - { - wait.errmsg = ex.ToString(); - UnityEngine.Debug.Log(ex.ToString()); - } - wait.SetDone(); + wait.Invoke(); } + catch (Exception ex) + { + wait.errmsg = ex.ToString(); + UnityEngine.Debug.Log(ex.ToString()); + } + wait.SetDone(); } } } \ No newline at end of file