This commit is contained in:
ALIENJACK\alien 2025-04-10 17:00:47 +08:00
commit 017026f706
12 changed files with 623 additions and 139 deletions

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 611bc182f939ea147a72b08613e2d2ba
guid: 164952f99969ca942b4761b200d7e381
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -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
}

View File

@ -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>

View File

@ -4,81 +4,94 @@ using nn.fs;
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
@ -182,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;
@ -247,25 +272,218 @@ 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
//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 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
//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 AxiNSWait_DeletePathDir DeletePathDirAsync(string filename)
{
var wait = new AxiNSWait_DeletePathDir(filename);
AxiNS.instance.wait.AddWait(wait);
return wait;
}
/// <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;
#else
@ -339,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
@ -386,5 +604,5 @@ public class AxiNSIO
return true; // 其他挂载点需根据实际需求实现
}
#endif
}
}
}

View File

@ -1,14 +1,17 @@
#if UNITY_SWITCH
using nn.account;
using static AxiHttp;
#endif
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 +50,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 +68,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 +106,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
}
}

View File

@ -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
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 21fa04ba4da10d74aafd65dd138478b7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e28ed9d2fb16c7f42b28cafb6a2ce0ac
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 46a1a776d2f9dba49b9641d8e0976861
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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();
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5e36180ba1c4a8f4db3ceed533a43999
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: