BS 0.0.1
This commit is contained in:
@@ -32,9 +32,7 @@ namespace Convention
|
||||
return MainThreadID == Thread.CurrentThread.ManagedThreadId;
|
||||
}
|
||||
|
||||
//var filePath = Environment.ExpandEnvironmentVariables(@"%USERPROFILE%\AppData\Local\Temp");
|
||||
|
||||
public static string CompanyName = "DefaultCom";
|
||||
public static string CompanyName = "DefaultCompany";
|
||||
|
||||
public static string ProductName = "DefaultProject";
|
||||
|
||||
|
416
Convention/Runtime/File.cs
Normal file
416
Convention/Runtime/File.cs
Normal file
@@ -0,0 +1,416 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Convention
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class ToolFile
|
||||
{
|
||||
private string FullPath;
|
||||
private FileSystemInfo OriginInfo;
|
||||
private FileStream OriginControlStream;
|
||||
public ToolFile(string path)
|
||||
{
|
||||
FullPath = path;
|
||||
Refresh();
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return this.FullPath;
|
||||
}
|
||||
|
||||
#region Path
|
||||
|
||||
public static implicit operator string(ToolFile data) => data.FullPath;
|
||||
public string GetFullPath()
|
||||
{
|
||||
return this.FullPath;
|
||||
}
|
||||
public string GetName(bool is_ignore_extension = false)
|
||||
{
|
||||
return this.FullPath[..(
|
||||
(this.FullPath.Contains('.') && is_ignore_extension)
|
||||
? this.FullPath.LastIndexOf('.')
|
||||
: ^0
|
||||
)]
|
||||
[..(
|
||||
(this.FullPath[^1] == '/' || this.FullPath[^1] == '\\')
|
||||
? ^1
|
||||
: ^0
|
||||
)];
|
||||
}
|
||||
public string GetExtension()
|
||||
{
|
||||
if (IsDir())
|
||||
return "";
|
||||
return this.FullPath[(
|
||||
(this.FullPath.Contains('.'))
|
||||
? this.FullPath.LastIndexOf('.')
|
||||
: ^0
|
||||
)..];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Exists
|
||||
|
||||
public bool Exists() => File.Exists(FullPath) || Directory.Exists(FullPath);
|
||||
|
||||
public static implicit operator bool(ToolFile file) => file.Exists();
|
||||
|
||||
#endregion
|
||||
|
||||
public ToolFile Refresh()
|
||||
{
|
||||
if (Exists() == false)
|
||||
OriginInfo = null;
|
||||
else if (IsDir())
|
||||
OriginInfo = new DirectoryInfo(FullPath);
|
||||
else
|
||||
OriginInfo = new FileInfo(FullPath);
|
||||
return this;
|
||||
}
|
||||
|
||||
#region Load
|
||||
|
||||
public T LoadAsRawJson<T>()
|
||||
{
|
||||
return JsonSerializer.Deserialize<T>(LoadAsText());
|
||||
}
|
||||
public T LoadAsJson<T>(string key = "data")
|
||||
{
|
||||
return EasySave.EasySave.Load<T>(key, FullPath);
|
||||
}
|
||||
public string LoadAsText()
|
||||
{
|
||||
if (IsFile() == false)
|
||||
throw new InvalidOperationException("Target is not a file");
|
||||
string result = "";
|
||||
using (var fs = (this.OriginInfo as FileInfo).OpenText())
|
||||
{
|
||||
result = fs.ReadToEnd();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public byte[] LoadAsBinary()
|
||||
{
|
||||
if (IsFile() == false)
|
||||
throw new InvalidOperationException("Target is not a file");
|
||||
var file = this.OriginInfo as FileInfo;
|
||||
const int BlockSize = 1024;
|
||||
long FileSize = file.Length;
|
||||
byte[] result = new byte[FileSize];
|
||||
long offset = 0;
|
||||
using (var fs = file.OpenRead())
|
||||
{
|
||||
fs.ReadAsync(result[(int)(offset)..(int)(offset + BlockSize)], 0, (int)(offset + BlockSize) - (int)(offset));
|
||||
offset += BlockSize;
|
||||
offset = System.Math.Min(offset, FileSize);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Save
|
||||
|
||||
public void SaveAsRawJson<T>(T data)
|
||||
{
|
||||
SaveAsText(JsonSerializer.Serialize<T>(data));
|
||||
}
|
||||
public void SaveAsJson<T>(T data, string key)
|
||||
{
|
||||
EasySave.EasySave.Save(key, data,FullPath);
|
||||
}
|
||||
private void SaveAsText(string data)
|
||||
{
|
||||
if (OriginControlStream != null && OriginControlStream.CanWrite)
|
||||
{
|
||||
using var sw = new StreamWriter(OriginControlStream);
|
||||
sw.Write(data);
|
||||
sw.Flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
using var fs = new FileStream(FullPath, FileMode.CreateNew, FileAccess.Write);
|
||||
using var sw = new StreamWriter(fs);
|
||||
sw.Write(data);
|
||||
sw.Flush();
|
||||
}
|
||||
}
|
||||
public static void SaveDataAsBinary(string path, byte[] outdata, FileStream Stream = null)
|
||||
{
|
||||
if (Stream != null && Stream.CanWrite)
|
||||
{
|
||||
Stream.Write(outdata, 0, outdata.Length);
|
||||
Stream.Flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
using var fs = new FileStream(path, FileMode.CreateNew, FileAccess.Write);
|
||||
fs.Write(outdata, 0, outdata.Length);
|
||||
fs.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveAsBinary(byte[] data)
|
||||
{
|
||||
SaveDataAsBinary(FullPath, data, OriginControlStream);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IsFileType
|
||||
|
||||
public bool IsDir()
|
||||
{
|
||||
if (Exists())
|
||||
{
|
||||
return Directory.Exists(this.FullPath);
|
||||
}
|
||||
return this.FullPath[^1] == '\\' || this.FullPath[^1] == '/';
|
||||
}
|
||||
|
||||
public bool IsFile()
|
||||
{
|
||||
return !IsDir();
|
||||
}
|
||||
|
||||
public bool IsFileEmpty()
|
||||
{
|
||||
if (IsFile())
|
||||
return (this.OriginInfo as FileInfo).Length == 0;
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Operator
|
||||
|
||||
public static ToolFile operator |(ToolFile left, string rightPath)
|
||||
{
|
||||
string lp = left.GetFullPath();
|
||||
return new ToolFile(Path.Combine(lp, rightPath));
|
||||
}
|
||||
public ToolFile Open(string path)
|
||||
{
|
||||
this.FullPath = path;
|
||||
Refresh();
|
||||
return this;
|
||||
}
|
||||
public ToolFile Open(FileMode mode)
|
||||
{
|
||||
this.Close();
|
||||
OriginControlStream = new FileStream(this.FullPath, mode);
|
||||
return this;
|
||||
}
|
||||
public ToolFile Close()
|
||||
{
|
||||
OriginControlStream?.Close();
|
||||
return this;
|
||||
}
|
||||
public ToolFile Create()
|
||||
{
|
||||
if (Exists() == false)
|
||||
{
|
||||
if (IsDir())
|
||||
Directory.CreateDirectory(this.FullPath);
|
||||
else
|
||||
File.Create(this.FullPath);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public ToolFile Rename(string newPath)
|
||||
{
|
||||
if(IsDir())
|
||||
{
|
||||
var dir = OriginInfo as DirectoryInfo;
|
||||
dir.MoveTo(newPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
var file = OriginInfo as FileInfo;
|
||||
file.MoveTo(newPath);
|
||||
}
|
||||
FullPath = newPath;
|
||||
return this;
|
||||
}
|
||||
public ToolFile Move(string path)
|
||||
{
|
||||
Rename(path);
|
||||
return this;
|
||||
}
|
||||
public ToolFile Copy(string path,out ToolFile copyTo)
|
||||
{
|
||||
if (IsDir())
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
else
|
||||
{
|
||||
var file = OriginInfo as FileInfo;
|
||||
file.CopyTo(path);
|
||||
copyTo = new(path);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public ToolFile Delete()
|
||||
{
|
||||
if (IsDir())
|
||||
Directory.Delete(FullPath);
|
||||
else
|
||||
File.Delete(FullPath);
|
||||
return this;
|
||||
}
|
||||
public ToolFile Remove() => Delete();
|
||||
public ToolFile MustExistsPath()
|
||||
{
|
||||
this.Close();
|
||||
this.TryCreateParentPath();
|
||||
this.Create();
|
||||
return this;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Dir
|
||||
|
||||
public ToolFile TryCreateParentPath()
|
||||
{
|
||||
if (this.GetName().Contains('/') || this.GetName().Contains('\\'))
|
||||
{
|
||||
var parent = new ToolFile(this.GetParentDir());
|
||||
if (parent.Exists())
|
||||
{
|
||||
parent.Create();
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<string> DirIter()
|
||||
{
|
||||
if (this.IsDir())
|
||||
{
|
||||
var dir = new DirectoryInfo(FullPath);
|
||||
var result = dir.GetDirectories().ToList().ConvertAll(x => x.FullName);
|
||||
result.AddRange(dir.GetFiles().ToList().ConvertAll(x => x.FullName));
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ToolFile> DirToolFileIter()
|
||||
{
|
||||
if (this.IsDir())
|
||||
{
|
||||
return DirIter().ConvertAll(x => new ToolFile(x));
|
||||
}
|
||||
throw new DirectoryNotFoundException(FullPath);
|
||||
}
|
||||
|
||||
public ToolFile BackToParentDir()
|
||||
{
|
||||
var file = new ToolFile(this.GetParentDir());
|
||||
this.Close();
|
||||
this.FullPath = file.FullPath;
|
||||
this.OriginInfo = file.OriginInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ToolFile GetParentDir()
|
||||
{
|
||||
if (IsDir())
|
||||
return new ToolFile((this.OriginInfo as DirectoryInfo).Parent.FullName);
|
||||
else
|
||||
return new ToolFile((this.OriginInfo as FileInfo).DirectoryName);
|
||||
}
|
||||
|
||||
public int DirCount()
|
||||
{
|
||||
if (IsDir())
|
||||
return Directory.EnumerateFiles(FullPath).Count();
|
||||
return -1;
|
||||
}
|
||||
|
||||
public ToolFile DirClear()
|
||||
{
|
||||
if (IsDir())
|
||||
{
|
||||
foreach (var file in DirIter())
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
}
|
||||
throw new DirectoryNotFoundException();
|
||||
}
|
||||
|
||||
public ToolFile MakeFileInside(string source, bool isDeleteSource = false)
|
||||
{
|
||||
if (this.IsDir() == false)
|
||||
throw new DirectoryNotFoundException(FullPath);
|
||||
string target = this | source;
|
||||
if (isDeleteSource)
|
||||
File.Move(target, source);
|
||||
else
|
||||
File.Copy(target, source);
|
||||
return this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static string[] SelectMultipleFiles(string filter = "所有文件|*.*", string title = "选择文件")
|
||||
{
|
||||
if (PlatformIndicator.IsPlatformWindows)
|
||||
return WindowsKit.SelectMultipleFiles(filter, title);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static string SelectFile(string filter = "所有文件|*.*", string title = "选择文件")
|
||||
{
|
||||
if (PlatformIndicator.IsPlatformWindows)
|
||||
{
|
||||
var results = WindowsKit.SelectMultipleFiles(filter, title);
|
||||
if (results != null && results.Length > 0)
|
||||
return results[0];
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static string SaveFile(string filter = "所有文件|*.*", string title = "保存文件")
|
||||
{
|
||||
if (PlatformIndicator.IsPlatformWindows)
|
||||
return WindowsKit.SaveFile(filter, title);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static string SelectFolder(string description = "请选择文件夹")
|
||||
{
|
||||
if (PlatformIndicator.IsPlatformWindows)
|
||||
return WindowsKit.SelectFolder(description);
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public DateTime GetTimestamp()
|
||||
{
|
||||
return File.GetLastWriteTime(FullPath).ToUniversalTime();
|
||||
}
|
||||
|
||||
public static string BrowseFile(params string[] extensions)
|
||||
{
|
||||
string filter = "";
|
||||
foreach (var ext in extensions)
|
||||
{
|
||||
filter += "*." + ext + ";";
|
||||
}
|
||||
string result = SelectFile("所有文件|" + filter);
|
||||
return result;
|
||||
}
|
||||
public static ToolFile BrowseToolFile(params string[] extensions)
|
||||
{
|
||||
return new ToolFile(BrowseFile(extensions));
|
||||
}
|
||||
}
|
||||
}
|
248
Convention/Runtime/GlobalConfig.cs
Normal file
248
Convention/Runtime/GlobalConfig.cs
Normal file
@@ -0,0 +1,248 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Convention
|
||||
{
|
||||
public class GlobalConfig : IEnumerable<KeyValuePair<string, object>>
|
||||
{
|
||||
public static string ConstConfigFile = "config.json";
|
||||
|
||||
public static void InitExtensionEnv()
|
||||
{
|
||||
ConstConfigFile = "config.json";
|
||||
ProjectConfig.InitExtensionEnv();
|
||||
}
|
||||
|
||||
public static void GenerateEmptyConfigJson(ToolFile file)
|
||||
{
|
||||
file.Open(System.IO.FileMode.CreateNew);
|
||||
file.SaveAsRawJson<Dictionary<string, object>>(new()
|
||||
{
|
||||
{ "properties",new Dictionary<string, object>() }
|
||||
});
|
||||
}
|
||||
|
||||
private int configLogging_tspace = "Property not found".Length;
|
||||
|
||||
private ToolFile DataDir;
|
||||
private Dictionary<string, object> data_pair = new();
|
||||
|
||||
public GlobalConfig(string dataDir, bool isTryCreateDataDir = false, bool isLoad = true)
|
||||
: this(new ToolFile(dataDir), isTryCreateDataDir, isLoad) { }
|
||||
public GlobalConfig(ToolFile dataDir, bool isTryCreateDataDir = false, bool isLoad = true)
|
||||
{
|
||||
// build up data folder
|
||||
dataDir ??= new ToolFile("./");
|
||||
this.DataDir = dataDir;
|
||||
if (this.DataDir.IsDir() == false)
|
||||
this.DataDir.BackToParentDir();
|
||||
if (this.DataDir.Exists() == false)
|
||||
{
|
||||
if (isTryCreateDataDir)
|
||||
this.DataDir.MustExistsPath();
|
||||
else
|
||||
throw new Exception($"Data dir not found: {this.DataDir}");
|
||||
}
|
||||
// build up init data file
|
||||
var configFile = this.ConfigFile;
|
||||
if (configFile.Exists() == false)
|
||||
GenerateEmptyConfigJson(configFile);
|
||||
else if (isLoad)
|
||||
this.LoadProperties();
|
||||
}
|
||||
~GlobalConfig()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ToolFile GetConfigFile() => DataDir | ConstConfigFile;
|
||||
public ToolFile ConfigFile => GetConfigFile();
|
||||
|
||||
public ToolFile GetFile(string path, bool isMustExist = false)
|
||||
{
|
||||
var file = DataDir | path;
|
||||
if (isMustExist)
|
||||
file.MustExistsPath();
|
||||
return file;
|
||||
}
|
||||
public bool EraseFile(string path)
|
||||
{
|
||||
var file = DataDir | path;
|
||||
if (file.Exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
file.Open(System.IO.FileMode.Create);
|
||||
return true;
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public bool RemoveFile(string path)
|
||||
{
|
||||
var file = DataDir | path;
|
||||
if (file.Exists())
|
||||
{
|
||||
try
|
||||
{
|
||||
file.Delete();
|
||||
return true;
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public bool CreateFile(string path)
|
||||
{
|
||||
var file = DataDir | path;
|
||||
if (file.Exists())
|
||||
return false;
|
||||
if (file.GetParentDir().Exists() == false)
|
||||
return false;
|
||||
file.Create();
|
||||
return true;
|
||||
}
|
||||
|
||||
public object this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
return data_pair[key];
|
||||
}
|
||||
set
|
||||
{
|
||||
data_pair[key] = value;
|
||||
}
|
||||
}
|
||||
public bool Contains(string key) => data_pair.ContainsKey(key);
|
||||
public bool Remove(string key)
|
||||
{
|
||||
if (data_pair.ContainsKey(key))
|
||||
{
|
||||
data_pair.Remove(key);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<KeyValuePair<string, object>>)this.data_pair).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable)this.data_pair).GetEnumerator();
|
||||
}
|
||||
public int DataSize() => data_pair.Count;
|
||||
|
||||
public GlobalConfig SaveProperties()
|
||||
{
|
||||
var configFile = this.ConfigFile;
|
||||
configFile.SaveAsRawJson<Dictionary<string, Dictionary<string, object>>>(new()
|
||||
{
|
||||
{ "properties", data_pair }
|
||||
});
|
||||
return this;
|
||||
}
|
||||
public GlobalConfig LoadProperties()
|
||||
{
|
||||
var configFile = this.ConfigFile;
|
||||
if (configFile.Exists() == false)
|
||||
{
|
||||
data_pair = new();
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = configFile.LoadAsRawJson<Dictionary<string, Dictionary<string, object>>>();
|
||||
if (data.TryGetValue("properties", out data_pair) == false)
|
||||
{
|
||||
throw new Exception($"Can't find properties not found in config file");
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ToolFile GetLogFile()
|
||||
{
|
||||
return this.GetFile(ConfigFile.GetName(true) + "_log.txt", true);
|
||||
}
|
||||
public ToolFile LogFile => GetLogFile();
|
||||
|
||||
private Action<string> MyDefaultLogger;
|
||||
public Action<string> DefaultLogger
|
||||
{
|
||||
get
|
||||
{
|
||||
return MyDefaultLogger ?? Console.WriteLine;
|
||||
}
|
||||
set
|
||||
{
|
||||
MyDefaultLogger = value;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Log(string messageType, string message, Action<string> logger)
|
||||
{
|
||||
configLogging_tspace = Math.Max(configLogging_tspace, messageType.Length);
|
||||
(logger ?? DefaultLogger)($"[{Utility.NowFormat()}]{new string(' ', configLogging_tspace / 2)}{messageType}{new string(' ', configLogging_tspace - configLogging_tspace / 2)}: {message}");
|
||||
}
|
||||
public void Log(string messageType, string message) => Log(messageType, message, null);
|
||||
public void LogPropertyNotFound(string message, Action<string> logger, object @default = null)
|
||||
{
|
||||
if (@default != null)
|
||||
{
|
||||
message = $"{message} (default: {@default})";
|
||||
}
|
||||
Log("Property not found", message);
|
||||
}
|
||||
public void LogPropertyNotFound(string message, object @default = null)
|
||||
{
|
||||
if (@default != null)
|
||||
{
|
||||
message = $"{message} (default: {@default})";
|
||||
}
|
||||
Log("Property not found", message);
|
||||
}
|
||||
public void LogMessageOfPleaseCompleteConfiguration()
|
||||
{
|
||||
var message = "Please complete configuration";
|
||||
Log("Error", message);
|
||||
}
|
||||
|
||||
public object FindItem(string key, object @default = null)
|
||||
{
|
||||
if (Contains(key))
|
||||
{
|
||||
return this[key];
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPropertyNotFound(key, @default);
|
||||
return @default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ProjectConfig : GlobalConfig
|
||||
{
|
||||
private static string ProjectConfigFileFocus = "Assets/";
|
||||
|
||||
public static new void InitExtensionEnv()
|
||||
{
|
||||
ProjectConfigFileFocus = "Assets/";
|
||||
}
|
||||
|
||||
public ProjectConfig(bool isLoad = true) : base(ProjectConfigFileFocus, true, isLoad) { }
|
||||
|
||||
public static void SetProjectConfigFileFocus(string path)
|
||||
{
|
||||
ProjectConfigFileFocus = path;
|
||||
}
|
||||
public static string GetProjectConfigFileFocus()
|
||||
{
|
||||
return ProjectConfigFileFocus;
|
||||
}
|
||||
}
|
||||
}
|
6
Convention/Runtime/Math.cs
Normal file
6
Convention/Runtime/Math.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Convention
|
||||
{
|
||||
|
||||
}
|
200
Convention/Runtime/Plugins/Plugin.cs
Normal file
200
Convention/Runtime/Plugins/Plugin.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Convention
|
||||
{
|
||||
public class PriorityQueue<T> where T : IComparable<T>
|
||||
{
|
||||
private int _size;
|
||||
private int _capacity;
|
||||
private T[] _elements;
|
||||
public readonly IComparer<T> _comparer = null;
|
||||
public readonly Func<T, T, int> _comparer_func = null;
|
||||
public readonly Comparator _comparator = Comparator.less;
|
||||
|
||||
public int Size => _size;
|
||||
public int Capacity => _capacity;
|
||||
public int Count => _size;
|
||||
public bool IsEmpty => _size == 0;
|
||||
public T Top => _elements[0];
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Array.Clear(_elements, 0, _size);
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
public PriorityQueue(Comparator comparator = Comparator.less, int capacity = 1)
|
||||
{
|
||||
_size = 0;
|
||||
_capacity = Math.Max(1, capacity);
|
||||
_comparator = comparator;
|
||||
_elements = new T[_capacity];
|
||||
}
|
||||
public PriorityQueue(IComparer<T> comparer, int capacity = 1)
|
||||
{
|
||||
_size = 0;
|
||||
_capacity = Math.Max(1, capacity);
|
||||
_comparer = comparer;
|
||||
_elements = new T[_capacity];
|
||||
}
|
||||
public PriorityQueue(Func<T, T, int> comparer, int capacity = 1)
|
||||
{
|
||||
_size = 0;
|
||||
_capacity = Math.Max(1, capacity);
|
||||
_comparer_func = comparer;
|
||||
_elements = new T[_capacity];
|
||||
}
|
||||
|
||||
private int Compare(T x, T y)
|
||||
{
|
||||
if (_comparer != null)
|
||||
{
|
||||
return _comparer.Compare(x, y) * (int)_comparator;
|
||||
}
|
||||
else if (_comparer_func != null)
|
||||
{
|
||||
return _comparer_func(x, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
return x.CompareTo(y) * (int)_comparator;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShiftDown()
|
||||
{
|
||||
int cur = 0;
|
||||
int child = 1;
|
||||
while (child < _size)
|
||||
{
|
||||
if (child + 1 < _size && Compare(_elements[child + 1], _elements[child]) < 0)
|
||||
child++;
|
||||
if (Compare(_elements[child], _elements[cur]) < 0)
|
||||
{
|
||||
Swap(ref _elements[child], ref _elements[cur]);
|
||||
cur = child;
|
||||
child = 2 * cur + 1;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShiftUp()
|
||||
{
|
||||
int cur = _size - 1;
|
||||
int parent = (cur - 1) / 2;
|
||||
while (cur > 0)
|
||||
{
|
||||
if (Compare(_elements[cur], _elements[parent]) < 0)
|
||||
{
|
||||
Swap(ref _elements[cur], ref _elements[parent]);
|
||||
cur = parent;
|
||||
parent = (cur - 1) / 2;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ExpandCapacity()
|
||||
{
|
||||
int newCapacity = Math.Max(_capacity * 2, 4);
|
||||
T[] temp = new T[newCapacity];
|
||||
Array.Copy(_elements, temp, _size);
|
||||
_elements = temp;
|
||||
_capacity = newCapacity;
|
||||
}
|
||||
|
||||
public void EnsureCapacity(int minCapacity)
|
||||
{
|
||||
if (_capacity < minCapacity)
|
||||
{
|
||||
int newCapacity = Math.Max(_capacity * 2, minCapacity);
|
||||
T[] temp = new T[newCapacity];
|
||||
Array.Copy(_elements, temp, _size);
|
||||
_elements = temp;
|
||||
_capacity = newCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
public T Peek()
|
||||
{
|
||||
if (_size == 0)
|
||||
throw new InvalidOperationException("Queue is empty");
|
||||
return _elements[0];
|
||||
}
|
||||
|
||||
public T Dequeue()
|
||||
{
|
||||
if (_size == 0)
|
||||
throw new InvalidOperationException("Queue is empty");
|
||||
|
||||
T result = _elements[0];
|
||||
Swap(ref _elements[0], ref _elements[_size - 1]);
|
||||
_size--;
|
||||
ShiftDown();
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool TryDequeue(out T result)
|
||||
{
|
||||
if (_size == 0)
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
result = Dequeue();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Enqueue(T value)
|
||||
{
|
||||
if (_size == _capacity)
|
||||
ExpandCapacity();
|
||||
_elements[_size++] = value;
|
||||
ShiftUp();
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
for (int i = 0; i < _size; i++)
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(_elements[i], item))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public T[] ToArray()
|
||||
{
|
||||
T[] result = new T[_size];
|
||||
Array.Copy(_elements, result, _size);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void TrimExcess()
|
||||
{
|
||||
if (_size < _capacity * 0.9)
|
||||
{
|
||||
T[] temp = new T[_size];
|
||||
Array.Copy(_elements, temp, _size);
|
||||
_elements = temp;
|
||||
_capacity = _size;
|
||||
}
|
||||
}
|
||||
|
||||
private void Swap(ref T a, ref T b)
|
||||
{
|
||||
T temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
public enum Comparator
|
||||
{
|
||||
less = -1,
|
||||
equal = 0,
|
||||
greater = 1
|
||||
}
|
||||
}
|
||||
}
|
129
Convention/Runtime/Plugins/Windows/WindowsKit.cs
Normal file
129
Convention/Runtime/Plugins/Windows/WindowsKit.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Convention
|
||||
{
|
||||
public static class WindowsKit
|
||||
{
|
||||
public static string current_initialDir = "";
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public class OpenFileName
|
||||
{
|
||||
public int structSize = 0;
|
||||
public IntPtr dlgOwner = IntPtr.Zero;
|
||||
public IntPtr instance = IntPtr.Zero;
|
||||
public string filter = null;
|
||||
public string customFilter = null;
|
||||
public int maxCustFilter = 0;
|
||||
public int filterIndex = 0;
|
||||
public string file = null;
|
||||
public int maxFile = 0;
|
||||
public string fileTitle = null;
|
||||
public int maxFileTitle = 0;
|
||||
public string initialDir = null;
|
||||
public string title = null;
|
||||
public int flags = 0;
|
||||
public short fileOffset = 0;
|
||||
public short fileExtension = 0;
|
||||
public string defExt = null;
|
||||
public IntPtr custData = IntPtr.Zero;
|
||||
public IntPtr hook = IntPtr.Zero;
|
||||
public string templateName = null;
|
||||
public IntPtr reservedPtr = IntPtr.Zero;
|
||||
public int reservedInt = 0;
|
||||
public int flagsEx = 0;
|
||||
}
|
||||
|
||||
[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
|
||||
|
||||
[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
|
||||
public static extern bool GetSaveFileName([In, Out] OpenFileName ofn);
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr SHBrowseForFolder(ref BROWSEINFO lpbi);
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern bool SHGetPathFromIDList(IntPtr pidl, IntPtr pszPath);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public struct BROWSEINFO
|
||||
{
|
||||
public IntPtr hwndOwner;
|
||||
public IntPtr pidlRoot;
|
||||
public string pszDisplayName;
|
||||
public string lpszTitle;
|
||||
public uint ulFlags;
|
||||
public IntPtr lpfn;
|
||||
public IntPtr lParam;
|
||||
public int iImage;
|
||||
}
|
||||
|
||||
public static string SelectFolder(string description = "请选择文件夹")
|
||||
{
|
||||
BROWSEINFO bi = new BROWSEINFO();
|
||||
bi.lpszTitle = description;
|
||||
bi.ulFlags = 0x00000040; // BIF_NEWDIALOGSTYLE
|
||||
bi.hwndOwner = IntPtr.Zero;
|
||||
|
||||
IntPtr pidl = SHBrowseForFolder(ref bi);
|
||||
if (pidl != IntPtr.Zero)
|
||||
{
|
||||
IntPtr pathPtr = Marshal.AllocHGlobal(260);
|
||||
if (SHGetPathFromIDList(pidl, pathPtr))
|
||||
{
|
||||
string path = Marshal.PtrToStringAuto(pathPtr);
|
||||
Marshal.FreeHGlobal(pathPtr);
|
||||
current_initialDir = path;
|
||||
return path;
|
||||
}
|
||||
Marshal.FreeHGlobal(pathPtr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string[] SelectMultipleFiles(string filter = "所有文件|*.*", string title = "选择文件")
|
||||
{
|
||||
OpenFileName ofn = new OpenFileName();
|
||||
ofn.structSize = Marshal.SizeOf(ofn);
|
||||
ofn.filter = filter.Replace("|", "\0") + "\0";
|
||||
ofn.file = new string(new char[256]);
|
||||
ofn.maxFile = ofn.file.Length;
|
||||
ofn.fileTitle = new string(new char[64]);
|
||||
ofn.maxFileTitle = ofn.fileTitle.Length;
|
||||
ofn.initialDir = current_initialDir;
|
||||
ofn.title = title;
|
||||
ofn.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000008 | 0x00000200; // OFN_ALLOWMULTISELECT
|
||||
|
||||
if (GetOpenFileName(ofn))
|
||||
{
|
||||
current_initialDir = Path.GetDirectoryName(ofn.file);
|
||||
return ofn.file.Split('\0');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string SaveFile(string filter = "所有文件|*.*", string title = "保存文件")
|
||||
{
|
||||
OpenFileName ofn = new OpenFileName();
|
||||
ofn.structSize = Marshal.SizeOf(ofn);
|
||||
ofn.filter = filter.Replace("|", "\0") + "\0";
|
||||
ofn.file = new string(new char[256]);
|
||||
ofn.maxFile = ofn.file.Length;
|
||||
ofn.fileTitle = new string(new char[64]);
|
||||
ofn.maxFileTitle = ofn.fileTitle.Length;
|
||||
ofn.initialDir = current_initialDir;
|
||||
ofn.title = title;
|
||||
ofn.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000008 | 0x00000002; // OFN_OVERWRITEPROMPT
|
||||
|
||||
if (GetSaveFileName(ofn))
|
||||
{
|
||||
current_initialDir = Path.GetDirectoryName(ofn.file);
|
||||
return ofn.file;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
734
Convention/Runtime/Web.cs
Normal file
734
Convention/Runtime/Web.cs
Normal file
@@ -0,0 +1,734 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Convention
|
||||
{
|
||||
[Serializable]
|
||||
public class ToolURL : LeftValueReference<string>
|
||||
#if UNITY_EDITOR
|
||||
, ISerializationCallbackReceiver
|
||||
#endif
|
||||
{
|
||||
[System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
|
||||
public class URLAttribute : Attribute
|
||||
{
|
||||
public string[] urlTypes;
|
||||
public URLAttribute(params string[] types)
|
||||
{
|
||||
urlTypes = types;
|
||||
}
|
||||
public URLAttribute(bool IsAnyURL)
|
||||
{
|
||||
if (IsAnyURL)
|
||||
urlTypes = new string[] { "*" };
|
||||
else
|
||||
urlTypes = new string[] { };
|
||||
}
|
||||
}
|
||||
|
||||
public static string[] ImageURLTypes = new string[] { "jpg", "jpeg", "png", "gif", "bmp", "webp" };
|
||||
public static string[] AudioURLTypes = new string[] { "mp3", "wav", "ogg", "aac", "m4a" };
|
||||
public static string[] VideoURLTypes = new string[] { "mp4", "webm", "mov", "avi", "mkv" };
|
||||
public static string[] DocumentURLTypes = new string[] { "pdf", "doc", "docx", "txt", "rtf" };
|
||||
public static string[] JsonURLTypes = new string[] { "json" };
|
||||
|
||||
[Content, SerializeField] private string url { get => ref_value; set => ref_value = value; }
|
||||
[Ignore][HideInInspector] public UnityWebRequest WebRequest { get; protected set; }
|
||||
[Content] public object data;
|
||||
|
||||
public ToolURL([In] string url) : base(url) { }
|
||||
|
||||
~ToolURL()
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
public override string SymbolName()
|
||||
{
|
||||
return
|
||||
$"url<" +
|
||||
$"{(IsValid ? "v" : "-")}" +
|
||||
$">";
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.url;
|
||||
}
|
||||
|
||||
public delegate void GetCallback([In] UnityWebRequest request);
|
||||
public bool Get([In] GetCallback callback)
|
||||
{
|
||||
if (!IsValid)
|
||||
return false;
|
||||
|
||||
WebRequest = UnityWebRequest.Get(this.url);
|
||||
WebRequest.SendWebRequest();
|
||||
|
||||
while (!WebRequest.isDone) ;
|
||||
|
||||
callback(WebRequest);
|
||||
return WebRequest.result == UnityWebRequest.Result.Success;
|
||||
}
|
||||
|
||||
public delegate void GetAsyncCallback([In, Opt] UnityWebRequest request);
|
||||
public IEnumerator GetAsync([In] GetAsyncCallback callback)
|
||||
{
|
||||
if (!IsValid)
|
||||
{
|
||||
callback(null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
WebRequest = UnityWebRequest.Get(this.url);
|
||||
WebRequest.SendWebRequest();
|
||||
|
||||
while (!WebRequest.isDone)
|
||||
yield return null;
|
||||
|
||||
callback(WebRequest);
|
||||
}
|
||||
|
||||
public delegate void PostCallback([In] UnityWebRequest request);
|
||||
public delegate UnityWebRequest PostIniter([In]UnityWebRequest request);
|
||||
public bool Post([In] PostCallback callback, [In]WWWForm form)
|
||||
{
|
||||
if (!IsValid)
|
||||
return false;
|
||||
|
||||
WebRequest = UnityWebRequest.Post(this.url, form);
|
||||
WebRequest.SendWebRequest();
|
||||
|
||||
while (!WebRequest.isDone) ;
|
||||
|
||||
callback(WebRequest);
|
||||
return WebRequest.result == UnityWebRequest.Result.Success;
|
||||
}
|
||||
public bool Post([In]PostCallback callback, [In]PostIniter initer, [In]WWWForm form)
|
||||
{
|
||||
if (!IsValid)
|
||||
return false;
|
||||
|
||||
WebRequest = initer(UnityWebRequest.Post(this.url, form));
|
||||
WebRequest.SendWebRequest();
|
||||
|
||||
while (!WebRequest.isDone) ;
|
||||
|
||||
callback(WebRequest);
|
||||
return WebRequest.result == UnityWebRequest.Result.Success;
|
||||
}
|
||||
|
||||
public delegate void PostAsyncCallback([In, Opt] UnityWebRequest request);
|
||||
public IEnumerator PostAsync([In] PostAsyncCallback callback, [In] WWWForm form)
|
||||
{
|
||||
if (!IsValid)
|
||||
{
|
||||
callback(null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
WebRequest = UnityWebRequest.Post(this.url, form);
|
||||
WebRequest.SendWebRequest();
|
||||
|
||||
while (!WebRequest.isDone)
|
||||
yield return null;
|
||||
|
||||
callback(WebRequest);
|
||||
}
|
||||
|
||||
#region URL Properties
|
||||
public string FullURL => this.url;
|
||||
public static implicit operator string(ToolURL data) => data.FullURL;
|
||||
public string GetFullURL()
|
||||
{
|
||||
return this.url;
|
||||
}
|
||||
|
||||
public string GetFilename()
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.url))
|
||||
return "";
|
||||
|
||||
Uri uri = new Uri(this.url);
|
||||
string path = uri.AbsolutePath;
|
||||
return Path.GetFileName(path);
|
||||
}
|
||||
|
||||
public string GetExtension()
|
||||
{
|
||||
string filename = GetFilename();
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
return "";
|
||||
|
||||
return Path.GetExtension(filename);
|
||||
}
|
||||
|
||||
public bool ExtensionIs(params string[] extensions)
|
||||
{
|
||||
string el = GetExtension().ToLower();
|
||||
string eln = el.Length > 1 ? el[1..] : null;
|
||||
foreach (string extension in extensions)
|
||||
if (el == extension || eln == extension)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Validation
|
||||
public bool IsValid => ValidateURL();
|
||||
public bool ValidateURL()
|
||||
{
|
||||
if (string.IsNullOrEmpty(this.url))
|
||||
return false;
|
||||
|
||||
return Uri.TryCreate(this.url, UriKind.Absolute, out Uri uriResult)
|
||||
&& (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
|
||||
}
|
||||
public static implicit operator bool(ToolURL url) => url.IsValid;
|
||||
#endregion
|
||||
|
||||
public ToolURL Refresh()
|
||||
{
|
||||
this.Close();
|
||||
return this;
|
||||
}
|
||||
|
||||
public static object LoadObjectFromBinary([In] byte[] data)
|
||||
{
|
||||
using MemoryStream fs = new(data, false);
|
||||
return new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter().Deserialize(fs);
|
||||
}
|
||||
|
||||
public ToolURL Data2Object()
|
||||
{
|
||||
this.data = LoadObjectFromBinary((byte[])this.data);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ToolURL Data2Bytes()
|
||||
{
|
||||
using MemoryStream ms = new();
|
||||
new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter().Serialize(ms, this.data);
|
||||
var outdata = ms.GetBuffer();
|
||||
this.data = outdata;
|
||||
return this;
|
||||
}
|
||||
|
||||
public bool IsDataByteArray()
|
||||
{
|
||||
return this.data != null && this.data.GetType() == typeof(byte[]);
|
||||
}
|
||||
|
||||
#region Load
|
||||
public object Load()
|
||||
{
|
||||
if (IsText)
|
||||
return this.LoadAsText();
|
||||
else if (IsJson)
|
||||
return LoadAsJson();
|
||||
else if (IsImage)
|
||||
return LoadAsImage();
|
||||
else if (IsAudio)
|
||||
return LoadAsAudio();
|
||||
else if (IsDocument)
|
||||
return LoadAsDocument();
|
||||
else
|
||||
return LoadAsText();
|
||||
}
|
||||
|
||||
public static T LoadFromText<T>([In] string requestText)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(requestText);
|
||||
}
|
||||
[return: ReturnMayNull]
|
||||
public static T LoadFromRequest<T>([In] UnityWebRequest request)
|
||||
{
|
||||
while (!request.isDone) ;
|
||||
|
||||
return request.result == UnityWebRequest.Result.Success
|
||||
? LoadFromText<T>(request.downloadHandler.text)
|
||||
: default;
|
||||
}
|
||||
[return: ReturnNotNull]
|
||||
public static T LoadFromRequestNotNull<T>([In] UnityWebRequest request) where T : class, new()
|
||||
{
|
||||
while (!request.isDone) ;
|
||||
|
||||
return request.result == UnityWebRequest.Result.Success
|
||||
? LoadFromText<T>(request.downloadHandler.text)
|
||||
: new();
|
||||
}
|
||||
[return: ReturnMayNull]
|
||||
public static IEnumerator LoadFromRequestAsync<T>([In] UnityWebRequest request,[In]Action<T> callback)
|
||||
{
|
||||
while (!request.isDone)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
callback(request.result == UnityWebRequest.Result.Success
|
||||
? LoadFromText<T>(request.downloadHandler.text)
|
||||
: default);
|
||||
}
|
||||
[return: ReturnNotNull]
|
||||
public static IEnumerator LoadFromRequestNotNullAsync<T>([In] UnityWebRequest request, [In] Action<T> callback) where T : class, new()
|
||||
{
|
||||
while (!request.isDone)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
callback(request.result == UnityWebRequest.Result.Success
|
||||
? LoadFromText<T>(request.downloadHandler.text)
|
||||
: new());
|
||||
}
|
||||
|
||||
public object LoadAsJson()
|
||||
{
|
||||
return LoadAsJsonWithType<object>();
|
||||
}
|
||||
|
||||
public T LoadAsJsonWithType<T>()
|
||||
{
|
||||
string jsonText = LoadAsText();
|
||||
try
|
||||
{
|
||||
T result = JsonConvert.DeserializeObject<T>(jsonText);
|
||||
this.data = result;
|
||||
return result;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Debug.Log(jsonText);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public T LoadAsJsonWithType<T>(T whenThrow)
|
||||
{
|
||||
string jsonText = LoadAsText();
|
||||
try
|
||||
{
|
||||
T result = JsonConvert.DeserializeObject<T>(jsonText);
|
||||
this.data = result;
|
||||
return result;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Debug.Log(jsonText);
|
||||
return whenThrow;
|
||||
}
|
||||
}
|
||||
|
||||
public string LoadAsText()
|
||||
{
|
||||
if (!IsValid)
|
||||
return null;
|
||||
|
||||
WebRequest = UnityWebRequest.Get(this.url);
|
||||
WebRequest.SendWebRequest();
|
||||
|
||||
while (!WebRequest.isDone)
|
||||
{
|
||||
// 等待请求完成
|
||||
}
|
||||
|
||||
if (WebRequest.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
this.data = WebRequest.downloadHandler.text;
|
||||
return (string)this.data;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerator LoadAsTextAsync([In] Action<string> callback)
|
||||
{
|
||||
if (!IsValid)
|
||||
{
|
||||
callback(null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
WebRequest = UnityWebRequest.Get(this.url);
|
||||
yield return WebRequest.SendWebRequest();
|
||||
|
||||
if (WebRequest.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
this.data = WebRequest.downloadHandler.text;
|
||||
callback((string)this.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] LoadAsBinary()
|
||||
{
|
||||
if (!IsValid)
|
||||
return null;
|
||||
|
||||
WebRequest = UnityWebRequest.Get(this.url);
|
||||
WebRequest.SendWebRequest();
|
||||
|
||||
while (!WebRequest.isDone)
|
||||
{
|
||||
// 等待请求完成
|
||||
}
|
||||
|
||||
if (WebRequest.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
this.data = WebRequest.downloadHandler.data;
|
||||
return (byte[])this.data;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerator LoadAsBinaryAsync([In] Action<byte[]> callback)
|
||||
{
|
||||
if (!IsValid)
|
||||
{
|
||||
callback(null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
WebRequest = UnityWebRequest.Get(this.url);
|
||||
yield return WebRequest.SendWebRequest();
|
||||
|
||||
if (WebRequest.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
this.data = WebRequest.downloadHandler.data;
|
||||
callback((byte[])this.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
|
||||
public Texture2D LoadAsImage()
|
||||
{
|
||||
if (!IsValid)
|
||||
return null;
|
||||
|
||||
WebRequest = UnityWebRequestTexture.GetTexture(this.url);
|
||||
WebRequest.SendWebRequest();
|
||||
|
||||
while (!WebRequest.isDone)
|
||||
{
|
||||
// 等待请求完成
|
||||
}
|
||||
|
||||
if (WebRequest.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
this.data = DownloadHandlerTexture.GetContent(WebRequest);
|
||||
return (Texture2D)this.data;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerator LoadAsImageAsync([In] Action<Texture2D> callback)
|
||||
{
|
||||
if (!IsValid)
|
||||
{
|
||||
callback(null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
WebRequest = UnityWebRequestTexture.GetTexture(this.url);
|
||||
yield return WebRequest.SendWebRequest();
|
||||
|
||||
if (WebRequest.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
this.data = DownloadHandlerTexture.GetContent(WebRequest);
|
||||
callback((Texture2D)this.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
|
||||
public AudioClip LoadAsAudio()
|
||||
{
|
||||
if (!IsValid)
|
||||
return null;
|
||||
|
||||
WebRequest = UnityWebRequestMultimedia.GetAudioClip(this.url, GetAudioType());
|
||||
WebRequest.SendWebRequest();
|
||||
|
||||
while (!WebRequest.isDone)
|
||||
{
|
||||
// 等待请求完成
|
||||
}
|
||||
|
||||
if (WebRequest.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
this.data = DownloadHandlerAudioClip.GetContent(WebRequest);
|
||||
return (AudioClip)this.data;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerator LoadAsAudioAsync([In] Action<AudioClip> callback)
|
||||
{
|
||||
if (!IsValid)
|
||||
{
|
||||
callback(null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
WebRequest = UnityWebRequestMultimedia.GetAudioClip(this.url, GetAudioType());
|
||||
yield return WebRequest.SendWebRequest();
|
||||
|
||||
if (WebRequest.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
this.data = DownloadHandlerAudioClip.GetContent(WebRequest);
|
||||
callback((AudioClip)this.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] LoadAsDocument()
|
||||
{
|
||||
return LoadAsBinary();
|
||||
}
|
||||
|
||||
public IEnumerator LoadAsDocumentAsync([In] Action<byte[]> callback)
|
||||
{
|
||||
yield return LoadAsBinaryAsync(callback);
|
||||
}
|
||||
|
||||
public object LoadAsUnknown()
|
||||
{
|
||||
this.data = this.LoadAsBinary();
|
||||
return this;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Save
|
||||
public void Save([In][Opt] string localPath = null)
|
||||
{
|
||||
if (IsText)
|
||||
SaveAsText(localPath);
|
||||
else if (IsJson)
|
||||
SaveAsJson(localPath);
|
||||
else if (IsImage)
|
||||
SaveAsImage(localPath);
|
||||
else if (IsAudio)
|
||||
SaveAsAudio(localPath);
|
||||
else if (IsVideo)
|
||||
SaveAsVideo(localPath);
|
||||
else if (IsDocument)
|
||||
SaveAsDocument(localPath);
|
||||
else
|
||||
SaveAsBinary(localPath);
|
||||
}
|
||||
|
||||
public void SaveAsJson([In][Opt] string localPath = null)
|
||||
{
|
||||
if (localPath == null)
|
||||
{
|
||||
localPath = Path.Combine(Application.temporaryCachePath, GetFilename());
|
||||
}
|
||||
|
||||
string jsonText = JsonConvert.SerializeObject(this.data);
|
||||
File.WriteAllText(localPath, jsonText);
|
||||
}
|
||||
|
||||
public void SaveAsText([In][Opt] string localPath = null)
|
||||
{
|
||||
if (localPath == null)
|
||||
{
|
||||
localPath = Path.Combine(Application.temporaryCachePath, GetFilename());
|
||||
}
|
||||
|
||||
File.WriteAllText(localPath, (string)this.data);
|
||||
}
|
||||
|
||||
public void SaveAsBinary([In][Opt] string localPath = null)
|
||||
{
|
||||
if (localPath == null)
|
||||
{
|
||||
localPath = Path.Combine(Application.temporaryCachePath, GetFilename());
|
||||
}
|
||||
|
||||
File.WriteAllBytes(localPath, (byte[])this.data);
|
||||
}
|
||||
|
||||
public void SaveAsImage([In][Opt] string localPath = null)
|
||||
{
|
||||
if (localPath == null)
|
||||
{
|
||||
localPath = Path.Combine(Application.temporaryCachePath, GetFilename());
|
||||
}
|
||||
|
||||
Texture2D texture = (Texture2D)this.data;
|
||||
byte[] bytes = texture.EncodeToPNG();
|
||||
File.WriteAllBytes(localPath, bytes);
|
||||
}
|
||||
|
||||
public void SaveAsAudio([In][Opt] string localPath = null)
|
||||
{
|
||||
// 注意:Unity不直接支持将AudioClip保存为文件
|
||||
// 这里只是一个示例,实际应用中可能需要其他方法
|
||||
Debug.LogWarning("Direct saving of AudioClip to file is not supported in Unity");
|
||||
}
|
||||
|
||||
public void SaveAsVideo([In][Opt] string localPath = null)
|
||||
{
|
||||
// 注意:Unity不直接支持将VideoClip保存为文件
|
||||
// 这里只是一个示例,实际应用中可能需要其他方法
|
||||
Debug.LogWarning("Direct saving of VideoClip to file is not supported in Unity");
|
||||
}
|
||||
|
||||
public void SaveAsDocument([In][Opt] string localPath = null)
|
||||
{
|
||||
SaveAsBinary(localPath);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public static AudioType GetAudioType(string url)
|
||||
{
|
||||
return Path.GetExtension(url) switch
|
||||
{
|
||||
"ogg" => AudioType.OGGVORBIS,
|
||||
"mp2" => AudioType.MPEG,
|
||||
"mp3" => AudioType.MPEG,
|
||||
"mod" => AudioType.MOD,
|
||||
"wav" => AudioType.WAV,
|
||||
"aif" => AudioType.IT,
|
||||
_ => AudioType.UNKNOWN
|
||||
};
|
||||
}
|
||||
|
||||
public AudioType GetAudioType()
|
||||
{
|
||||
return GetAudioType(this.url);
|
||||
}
|
||||
|
||||
#region URL Types
|
||||
public bool IsText => ExtensionIs("txt", "html", "htm", "css", "js", "xml", "csv");
|
||||
public bool IsJson => ExtensionIs(JsonURLTypes);
|
||||
public bool IsImage => ExtensionIs(ImageURLTypes);
|
||||
public bool IsAudio => ExtensionIs(AudioURLTypes);
|
||||
public bool IsVideo => ExtensionIs(VideoURLTypes);
|
||||
public bool IsDocument => ExtensionIs(DocumentURLTypes);
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
[return: ReturnNotNull, ReturnNotSelf]
|
||||
public static ToolURL operator |([In] ToolURL left, [In] string rightPath)
|
||||
{
|
||||
string baseUrl = left.GetFullURL();
|
||||
if (baseUrl.EndsWith("/"))
|
||||
{
|
||||
return new ToolURL(baseUrl + rightPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ToolURL(baseUrl + "/" + rightPath);
|
||||
}
|
||||
}
|
||||
|
||||
public ToolURL Open([In] string url)
|
||||
{
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ToolURL Close()
|
||||
{
|
||||
if (WebRequest != null)
|
||||
{
|
||||
WebRequest.Dispose();
|
||||
WebRequest = null;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ToolURL Download([In][Opt] string localPath = null)
|
||||
{
|
||||
if (!IsValid)
|
||||
return this;
|
||||
|
||||
if (localPath == null)
|
||||
{
|
||||
localPath = Path.Combine(Application.temporaryCachePath, GetFilename());
|
||||
}
|
||||
|
||||
WebRequest = UnityWebRequest.Get(this.url);
|
||||
WebRequest.SendWebRequest();
|
||||
|
||||
while (!WebRequest.isDone)
|
||||
{
|
||||
// 等待请求完成
|
||||
}
|
||||
|
||||
if (WebRequest.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
File.WriteAllBytes(localPath, WebRequest.downloadHandler.data);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public IEnumerator DownloadAsync([In] Action<bool> callback, [In][Opt] string localPath = null)
|
||||
{
|
||||
if (!IsValid)
|
||||
{
|
||||
callback(false);
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (localPath == null)
|
||||
{
|
||||
localPath = Path.Combine(Application.temporaryCachePath, GetFilename());
|
||||
}
|
||||
|
||||
WebRequest = UnityWebRequest.Get(this.url);
|
||||
yield return WebRequest.SendWebRequest();
|
||||
|
||||
if (WebRequest.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
File.WriteAllBytes(localPath, WebRequest.downloadHandler.data);
|
||||
callback(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[SerializeField, ToolURL.URL] private string m_URL;
|
||||
public void OnBeforeSerialize()
|
||||
{
|
||||
m_URL = this.FullURL;
|
||||
}
|
||||
|
||||
public void OnAfterDeserialize()
|
||||
{
|
||||
if (m_URL != this.FullURL)
|
||||
{
|
||||
this.url = m_URL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user