异步更新

This commit is contained in:
2025-10-13 19:47:39 +08:00
parent 6271171ab4
commit 41d502b239
2 changed files with 103 additions and 87 deletions

View File

@@ -4,7 +4,6 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using UnityEngine; using UnityEngine;
@@ -58,24 +57,28 @@ namespace Convention
}; };
} }
private string FullPath; private string OriginPath;
private FileSystemInfo OriginInfo; private FileSystemInfo OriginInfo;
public ToolFile(string path) public ToolFile(string path)
{ {
FullPath = Path.GetFullPath(Environment.ExpandEnvironmentVariables(path)); OriginPath = Environment.ExpandEnvironmentVariables(path).Replace('\\', '/');
Refresh(); Refresh();
} }
public override string ToString() public override string ToString()
{ {
return this.FullPath; return this.OriginPath;
} }
#region Path #region Path
public static implicit operator string(ToolFile data) => data.FullPath; public static implicit operator string(ToolFile data) => data.OriginPath;
public string GetAbsPath()
{
return Path.GetFullPath(OriginPath);
}
public string GetFullPath() public string GetFullPath()
{ {
return this.FullPath; return this.OriginPath;
} }
public string GetName(bool is_ignore_extension = false) public string GetName(bool is_ignore_extension = false)
{ {
@@ -86,13 +89,13 @@ namespace Convention
else if (OriginInfo is DirectoryInfo dinfo) else if (OriginInfo is DirectoryInfo dinfo)
return dinfo.Name; return dinfo.Name;
} }
var result = this.FullPath[..( var result = this.OriginPath[..(
(this.FullPath.Contains('.') && is_ignore_extension) (this.OriginPath.Contains('.') && is_ignore_extension)
? this.FullPath.LastIndexOf('.') ? this.OriginPath.LastIndexOf('.')
: ^0 : ^0
)] )]
[..( [..(
(this.FullPath[^1] == '/' || this.FullPath[^1] == '\\') (this.OriginPath[^1] == '/' || this.OriginPath[^1] == '\\')
? ^1 ? ^1
: ^0 : ^0
)]; )];
@@ -103,32 +106,32 @@ namespace Convention
{ {
if (IsDir()) if (IsDir())
return ""; return "";
return this.FullPath[( return this.OriginPath[(
(this.FullPath.Contains('.')) (this.OriginPath.Contains('.'))
? this.FullPath.LastIndexOf('.') ? this.OriginPath.LastIndexOf('.')
: ^0 : ^0
)..]; )..];
} }
public string GetFilename(bool is_without_extension = false) public string GetFilename(bool is_without_extension = false)
{ {
if (is_without_extension && Path.HasExtension(FullPath)) if (is_without_extension && Path.HasExtension(OriginPath))
{ {
return Path.GetFileNameWithoutExtension(FullPath); return Path.GetFileNameWithoutExtension(OriginPath);
} }
else if (FullPath.EndsWith(Path.DirectorySeparatorChar.ToString()) || FullPath.EndsWith(Path.AltDirectorySeparatorChar.ToString())) else if (OriginPath.EndsWith(Path.DirectorySeparatorChar.ToString()) || OriginPath.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
{ {
return Path.GetFileName(FullPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)); return Path.GetFileName(OriginPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
} }
else else
{ {
return Path.GetFileName(FullPath); return Path.GetFileName(OriginPath);
} }
} }
public string GetDir() public string GetDir()
{ {
return Path.GetDirectoryName(FullPath); return Path.GetDirectoryName(OriginPath);
} }
public ToolFile GetDirToolFile() public ToolFile GetDirToolFile()
@@ -138,7 +141,7 @@ namespace Convention
public string GetCurrentDirName() public string GetCurrentDirName()
{ {
return Path.GetDirectoryName(FullPath); return Path.GetDirectoryName(OriginPath);
} }
public ToolFile GetParentDir() public ToolFile GetParentDir()
@@ -150,7 +153,7 @@ namespace Convention
#region Exists #region Exists
public bool Exists() => File.Exists(FullPath) || Directory.Exists(FullPath); public bool Exists() => File.Exists(OriginPath) || Directory.Exists(OriginPath);
public static implicit operator bool(ToolFile file) => file.Exists(); public static implicit operator bool(ToolFile file) => file.Exists();
@@ -162,13 +165,13 @@ namespace Convention
OriginInfo = null; OriginInfo = null;
else if (IsDir()) else if (IsDir())
{ {
OriginInfo = new DirectoryInfo(FullPath); OriginInfo = new DirectoryInfo(OriginPath);
FullPath = Path.GetFullPath(FullPath); OriginPath = Path.GetFullPath(OriginPath);
} }
else else
{ {
OriginInfo = new FileInfo(FullPath); OriginInfo = new FileInfo(OriginPath);
FullPath = Path.GetFullPath(FullPath); OriginPath = Path.GetFullPath(OriginPath);
} }
return this; return this;
} }
@@ -181,7 +184,7 @@ namespace Convention
} }
public T LoadAsJson<T>(string key = "data") public T LoadAsJson<T>(string key = "data")
{ {
return ES3.Load<T>(key, FullPath); return ES3.Load<T>(key, OriginPath);
} }
public string LoadAsText() public string LoadAsText()
{ {
@@ -217,7 +220,7 @@ namespace Convention
if (IsFile() == false) if (IsFile() == false)
throw new InvalidOperationException("Target is not a file"); throw new InvalidOperationException("Target is not a file");
var lines = File.ReadAllLines(FullPath); var lines = File.ReadAllLines(OriginPath);
var result = new List<string[]>(); var result = new List<string[]>();
foreach (var line in lines) foreach (var line in lines)
@@ -244,11 +247,11 @@ namespace Convention
public Texture2D LoadAsImage() public Texture2D LoadAsImage()
{ {
return ES3Plugin.LoadImage(FullPath); return ES3Plugin.LoadImage(OriginPath);
} }
public IEnumerator LoadAsImage([In] Action<Texture2D> callback) public IEnumerator LoadAsImage([In] Action<Texture2D> callback)
{ {
UnityWebRequest request = UnityWebRequestTexture.GetTexture(FullPath); UnityWebRequest request = UnityWebRequestTexture.GetTexture(OriginPath);
yield return request.SendWebRequest(); yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success) if (request.result == UnityWebRequest.Result.Success)
@@ -259,11 +262,11 @@ namespace Convention
} }
public AudioClip LoadAsAudio() public AudioClip LoadAsAudio()
{ {
return ES3Plugin.LoadAudio(FullPath, GetAudioType(FullPath)); return ES3Plugin.LoadAudio(OriginPath, GetAudioType(OriginPath));
} }
public IEnumerator LoadAsAudio([In] Action<AudioClip> callback) public IEnumerator LoadAsAudio([In] Action<AudioClip> callback)
{ {
UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(FullPath, GetAudioType(FullPath)); UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(OriginPath, GetAudioType(OriginPath));
yield return request.SendWebRequest(); yield return request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success) if (request.result == UnityWebRequest.Result.Success)
@@ -274,18 +277,18 @@ namespace Convention
} }
public AssetBundle LoadAsAssetBundle() public AssetBundle LoadAsAssetBundle()
{ {
return AssetBundle.LoadFromFile(FullPath); return AssetBundle.LoadFromFile(OriginPath);
} }
public IEnumerator LoadAsAssetBundle([In] Action<AssetBundle> callback) public IEnumerator LoadAsAssetBundle([In] Action<AssetBundle> callback)
{ {
AssetBundleCreateRequest result = AssetBundle.LoadFromFileAsync(FullPath); AssetBundleCreateRequest result = AssetBundle.LoadFromFileAsync(OriginPath);
yield return result; yield return result;
callback(result.assetBundle); callback(result.assetBundle);
yield return null; yield return null;
} }
public IEnumerator LoadAsAssetBundle([In]Action<float> progress, [In] Action<AssetBundle> callback) public IEnumerator LoadAsAssetBundle([In]Action<float> progress, [In] Action<AssetBundle> callback)
{ {
AssetBundleCreateRequest result = AssetBundle.LoadFromFileAsync(FullPath); AssetBundleCreateRequest result = AssetBundle.LoadFromFileAsync(OriginPath);
while (result.isDone == false) while (result.isDone == false)
{ {
progress(result.progress); progress(result.progress);
@@ -311,11 +314,11 @@ namespace Convention
} }
public void SaveAsJson<T>(T data, string key = "data") public void SaveAsJson<T>(T data, string key = "data")
{ {
ES3.Save(key, data,FullPath); ES3.Save(key, data,OriginPath);
} }
public void SaveAsText(string data) public void SaveAsText(string data)
{ {
using var fs = new FileStream(FullPath, FileMode.CreateNew, FileAccess.Write); using var fs = new FileStream(OriginPath, FileMode.CreateNew, FileAccess.Write);
using var sw = new StreamWriter(fs); using var sw = new StreamWriter(fs);
sw.Write(data); sw.Write(data);
sw.Flush(); sw.Flush();
@@ -337,7 +340,7 @@ namespace Convention
public void SaveAsBinary(byte[] data) public void SaveAsBinary(byte[] data)
{ {
SaveDataAsBinary(FullPath, data, (OriginInfo as FileInfo).OpenWrite()); SaveDataAsBinary(OriginPath, data, (OriginInfo as FileInfo).OpenWrite());
} }
public void SaveAsCsv(List<string[]> csvData) public void SaveAsCsv(List<string[]> csvData)
@@ -346,7 +349,7 @@ namespace Convention
throw new InvalidOperationException("Target is not a file"); throw new InvalidOperationException("Target is not a file");
var lines = csvData.Select(row => string.Join(",", row)); var lines = csvData.Select(row => string.Join(",", row));
File.WriteAllLines(FullPath, lines); File.WriteAllLines(OriginPath, lines);
} }
public void SaveAsXml(string xmlData) public void SaveAsXml(string xmlData)
@@ -380,9 +383,9 @@ namespace Convention
{ {
if (Exists()) if (Exists())
{ {
return Directory.Exists(this.FullPath); return Directory.Exists(this.OriginPath);
} }
return this.FullPath[^1] == '\\' || this.FullPath[^1] == '/'; return this.OriginPath[^1] == '\\' || this.OriginPath[^1] == '/';
} }
public bool IsFile() public bool IsFile()
@@ -420,7 +423,7 @@ namespace Convention
{ {
if (IsDir()) if (IsDir())
{ {
return GetDirectorySize(FullPath); return GetDirectorySize(OriginPath);
} }
else else
{ {
@@ -458,6 +461,20 @@ namespace Convention
#region Operator #region Operator
public static ToolFile operator |(ToolFile left, string rightPath) public static ToolFile operator |(ToolFile left, string rightPath)
{
if (rightPath == null)
{
return new ToolFile(left.IsDir() ? left.GetFullPath() : $"{left.GetFullPath().Replace('\\', '/')}/");
}
string first = left.GetFullPath().Replace('\\','/');
string second = rightPath.Replace('\\', '/');
if (first == "./")
return new ToolFile(second);
else if (first == "../")
return new ToolFile($"{new ToolFile(left.GetAbsPath()).GetParentDir()}/{second}");
return new ToolFile($"{first}/{second}");
}
public static ToolFile operator |(ToolFile left, ToolFile rightPath)
{ {
string lp = left.GetFullPath(); string lp = left.GetFullPath();
return new ToolFile(Path.Combine(lp, rightPath)); return new ToolFile(Path.Combine(lp, rightPath));
@@ -467,19 +484,19 @@ namespace Convention
{ {
if (obj is ToolFile other) if (obj is ToolFile other)
{ {
return Path.GetFullPath(FullPath).Equals(Path.GetFullPath(other.FullPath), StringComparison.OrdinalIgnoreCase); return Path.GetFullPath(OriginPath).Equals(Path.GetFullPath(other.OriginPath), StringComparison.OrdinalIgnoreCase);
} }
return false; return false;
} }
public override int GetHashCode() public override int GetHashCode()
{ {
return Path.GetFullPath(FullPath).GetHashCode(); return Path.GetFullPath(OriginPath).GetHashCode();
} }
public ToolFile Open(string path) public ToolFile Open(string path)
{ {
this.FullPath = path; this.OriginPath = path;
Refresh(); Refresh();
return this; return this;
} }
@@ -492,9 +509,9 @@ namespace Convention
if (Exists() == false) if (Exists() == false)
{ {
if (IsDir()) if (IsDir())
Directory.CreateDirectory(this.FullPath); Directory.CreateDirectory(this.OriginPath);
else else
File.Create(this.FullPath).Close(); File.Create(this.OriginPath).Close();
Refresh(); Refresh();
} }
return this; return this;
@@ -511,7 +528,7 @@ namespace Convention
var file = OriginInfo as FileInfo; var file = OriginInfo as FileInfo;
file.MoveTo(newPath); file.MoveTo(newPath);
} }
FullPath = newPath; OriginPath = newPath;
return this; return this;
} }
public ToolFile Move(string path) public ToolFile Move(string path)
@@ -537,7 +554,7 @@ namespace Convention
public ToolFile Copy(string targetPath = null) public ToolFile Copy(string targetPath = null)
{ {
if (targetPath == null) if (targetPath == null)
return new ToolFile(FullPath); return new ToolFile(OriginPath);
if (!Exists()) if (!Exists())
throw new FileNotFoundException("File not found"); throw new FileNotFoundException("File not found");
@@ -547,9 +564,9 @@ namespace Convention
targetFile = targetFile | GetFilename(); targetFile = targetFile | GetFilename();
if (IsDir()) if (IsDir())
CopyDirectory(FullPath, targetFile.GetFullPath()); CopyDirectory(OriginPath, targetFile.GetFullPath());
else else
File.Copy(FullPath, targetFile.GetFullPath()); File.Copy(OriginPath, targetFile.GetFullPath());
return targetFile; return targetFile;
} }
@@ -575,9 +592,9 @@ namespace Convention
public ToolFile Delete() public ToolFile Delete()
{ {
if (IsDir()) if (IsDir())
Directory.Delete(FullPath); Directory.Delete(OriginPath);
else else
File.Delete(FullPath); File.Delete(OriginPath);
return this; return this;
} }
@@ -598,7 +615,7 @@ namespace Convention
} }
public ToolFile TryCreateParentPath() public ToolFile TryCreateParentPath()
{ {
string dirPath = Path.GetDirectoryName(FullPath); string dirPath = Path.GetDirectoryName(OriginPath);
if (!string.IsNullOrEmpty(dirPath) && !Directory.Exists(dirPath)) if (!string.IsNullOrEmpty(dirPath) && !Directory.Exists(dirPath))
{ {
Directory.CreateDirectory(dirPath); Directory.CreateDirectory(dirPath);
@@ -609,14 +626,14 @@ namespace Convention
{ {
if (!IsDir()) if (!IsDir())
throw new InvalidOperationException("Target is not a directory"); throw new InvalidOperationException("Target is not a directory");
return Directory.GetFileSystemEntries(FullPath).ToList(); return Directory.GetFileSystemEntries(OriginPath).ToList();
} }
public List<ToolFile> DirToolFileIter() public List<ToolFile> DirToolFileIter()
{ {
if (!IsDir()) if (!IsDir())
throw new InvalidOperationException("Target is not a directory"); throw new InvalidOperationException("Target is not a directory");
var result = new List<ToolFile>(); var result = new List<ToolFile>();
foreach (var entry in Directory.GetFileSystemEntries(FullPath)) foreach (var entry in Directory.GetFileSystemEntries(OriginPath))
{ {
result.Add(new ToolFile(entry)); result.Add(new ToolFile(entry));
} }
@@ -624,7 +641,7 @@ namespace Convention
} }
public ToolFile BackToParentDir() public ToolFile BackToParentDir()
{ {
FullPath = GetDir(); OriginPath = GetDir();
Refresh(); Refresh();
return this; return this;
} }
@@ -633,7 +650,7 @@ namespace Convention
if (!IsDir()) if (!IsDir())
throw new InvalidOperationException("Target is not a directory"); throw new InvalidOperationException("Target is not a directory");
var entries = Directory.GetFileSystemEntries(FullPath); var entries = Directory.GetFileSystemEntries(OriginPath);
if (ignore_folder) if (ignore_folder)
{ {
return entries.Count(entry => File.Exists(entry)); return entries.Count(entry => File.Exists(entry));
@@ -740,13 +757,13 @@ namespace Convention
{ {
if (IsDir()) if (IsDir())
{ {
ZipFile.CreateFromDirectory(FullPath, outputPath); ZipFile.CreateFromDirectory(OriginPath, outputPath);
} }
else else
{ {
using (var archive = ZipFile.Open(outputPath, ZipArchiveMode.Create)) using (var archive = ZipFile.Open(outputPath, ZipArchiveMode.Create))
{ {
archive.CreateEntryFromFile(FullPath, GetFilename()); archive.CreateEntryFromFile(OriginPath, GetFilename());
} }
} }
} }
@@ -778,7 +795,7 @@ namespace Convention
try try
{ {
ZipFile.ExtractToDirectory(FullPath, outputPath); ZipFile.ExtractToDirectory(OriginPath, outputPath);
return new ToolFile(outputPath); return new ToolFile(outputPath);
} }
catch (Exception ex) catch (Exception ex)
@@ -897,7 +914,7 @@ namespace Convention
try try
{ {
using (var hashAlgorithm = GetHashAlgorithm(algorithm)) using (var hashAlgorithm = GetHashAlgorithm(algorithm))
using (var stream = File.OpenRead(FullPath)) using (var stream = File.OpenRead(OriginPath))
{ {
byte[] hash = hashAlgorithm.ComputeHash(stream); byte[] hash = hashAlgorithm.ComputeHash(stream);
return BitConverter.ToString(hash).Replace("-", "").ToLower(); return BitConverter.ToString(hash).Replace("-", "").ToLower();
@@ -955,7 +972,7 @@ namespace Convention
// 注意:这是一个简化实现,实际的文件监控需要更复杂的实现 // 注意:这是一个简化实现,实际的文件监控需要更复杂的实现
// 可以使用 FileSystemWatcher 来实现完整功能 // 可以使用 FileSystemWatcher 来实现完整功能
var watcher = new FileSystemWatcher(FullPath) var watcher = new FileSystemWatcher(OriginPath)
{ {
IncludeSubdirectories = recursive, IncludeSubdirectories = recursive,
EnableRaisingEvents = true EnableRaisingEvents = true
@@ -1087,7 +1104,7 @@ namespace Convention
try try
{ {
var fileInfo = new FileInfo(FullPath); var fileInfo = new FileInfo(OriginPath);
var attributes = fileInfo.Attributes; var attributes = fileInfo.Attributes;
permissions["read"] = true; // 如果能获取到文件信息,说明可读 permissions["read"] = true; // 如果能获取到文件信息,说明可读
@@ -1114,7 +1131,7 @@ namespace Convention
try try
{ {
var fileInfo = new FileInfo(FullPath); var fileInfo = new FileInfo(OriginPath);
var attributes = fileInfo.Attributes; var attributes = fileInfo.Attributes;
if (write.HasValue) if (write.HasValue)

View File

@@ -262,13 +262,15 @@ namespace Convention
public IEnumerator LoadAsAssetBundle(Action<float> progress, Action<AssetBundle> onSuccess, Action<string> onError = null) public IEnumerator LoadAsAssetBundle(Action<float> progress, Action<AssetBundle> onSuccess, Action<string> onError = null)
{ {
yield return LoadAsBinaryAsync( AssetBundleCreateRequest request = null;
progress, yield return LoadAsBinaryAsync(x => progress(x * 0.5f), data => request = AssetBundle.LoadFromMemoryAsync(data), onError);
data => while (request.isDone == false)
{ {
progress(0.5f + request.progress * 0.5f);
}
try try
{ {
AssetBundle bundle = AssetBundle.LoadFromMemory(data); AssetBundle bundle = request.assetBundle;
if (bundle != null) if (bundle != null)
{ {
cachedData = bundle; cachedData = bundle;
@@ -283,9 +285,6 @@ namespace Convention
{ {
onError?.Invoke($"Failed to load AssetBundle: {e.Message}"); onError?.Invoke($"Failed to load AssetBundle: {e.Message}");
} }
},
onError
);
} }
#endregion #endregion