using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Threading; #if UNITY_WINDOW using AnotherFileBrowser.Windows; #endif #if UNITY_5_3_OR_NEWER using UnityEngine; #endif using Cysharp.Threading.Tasks; namespace BITKit.IO { public interface IApplicationFile { string Extension { get; set; } string Current { get; } event Func<(string, byte[])> DataHandle; event Action OnPathChanged; void Save(); void SaveAs(string path=null); void Load(string file=null); void Reload(); void AddListener(string key, Action action); void RemoveListener(string key, Action action); } #if UNITY_WINDOW [Serializable] public sealed class ApplicationFile:IApplicationFile { private const string DefaultPath = nameof(ApplicationFile)+"."+nameof(DefaultPath); #if UNITY_5_3_OR_NEWER [UnityEngine.RuntimeInitializeOnLoadMethod] private static void Reload() { Current = null; DataHandle = null; _genericEvent.Clear(); _OpenFileCancellationTokenSource = new(); } #endif public static IStorageFile Current { get => _current; set { OnPathChanged?.Invoke(_current,value); _current = value; } } private static IStorageFile _current; public static event Func<(string, byte[])> DataHandle; public static event Action OnPathChanged; private static readonly GenericEvent _genericEvent = new(); private static CancellationTokenSource _OpenFileCancellationTokenSource = new(); private static string Extension { get; set; } = "zip"; private static BrowserProperties _browserProperties { get { var bp = new BrowserProperties(); #if UNITY_5_3_OR_NEWER if (PlayerPrefs.HasKey(DefaultPath)) { bp.initialDir = PlayerPrefs.GetString(DefaultPath); } #endif if (string.IsNullOrEmpty(Extension) is false) { bp.filter = $"{Extension} files (*.{Extension})|*.{Extension}"; } return bp; } } public static void Save() { if (Current is null) { var bp = _browserProperties; new Thread(() => { new FileBrowser().SaveFileBrowser(bp, nameof(ApplicationFile), $".{Extension}", async path => { await BITApp.SwitchToMainThread(); Current = new FileProvider(path); Save(); }); }).Start(); BIT4Log.Log($"无已加载的数据,等待选择保存地址"); return; } if (DataHandle is null) { BIT4Log.Log("无任何可保存的数据"); } List assets = new(); foreach (var func in DataHandle.CastAsFunc()) { (string name,byte[] bytes) value = func.Invoke(); var asset = new BITAsset(value.name,value.bytes); assets.Add(asset); } BITAssets.Build(Current.GetPath(),assets.ToArray()); BIT4Log.Log($"已保存为:{Current.GetPath()}"); } public static async void SaveAs(string path) { if (path is null) { var bp = _browserProperties; new Thread(() => { new FileBrowser().SaveFileBrowser(bp, nameof(ApplicationFile), $".{Extension}", async path => { await BITApp.SwitchToMainThread(); Current = new FileProvider(path); SaveAs(path); }); }).Start(); return; } Current = new FileProvider(path); Save(); } public void AddListener(string key, Action action) { _genericEvent.AddListener(key,action); } public void RemoveListener(string key, Action action) { _genericEvent.RemoveListener(key,action); } public static void ReloadFile() { Load(Current); } public static void Load(IStorageFile file=null) { if (file is null) { _OpenFileCancellationTokenSource.Cancel(); _OpenFileCancellationTokenSource = new(); BIT4Log.Log("正在选择文件,跳过该次载入"); var bp = _browserProperties; new Thread(() => { new FileBrowser().OpenFileBrowser(bp, Filepath); return; async void Filepath(string path) { await BITApp.SwitchToMainThread(); Current = new FileProvider(path); Load(Current); } }).Start(); return; } Current = file; var path = file.GetPath(); var header = BITAssets.ReadHeader(path); foreach (var name in header.Files) { var asset = BITAssets.ReadAsset(path, name); _genericEvent.Invoke(asset.Name,asset.Buffer); } BIT4Log.Log($"已加载{header.Files.Count}个数据"); } string IApplicationFile.Extension { get => Extension; set => Extension = value; } IStorageFile IApplicationFile.Current => Current; event Func<(string, byte[])> IApplicationFile.DataHandle { add => DataHandle += value; remove => DataHandle -= value; } event Action IApplicationFile.OnPathChanged { add => OnPathChanged += value; remove=>OnPathChanged -= value; } void IApplicationFile.Save() => Save(); void IApplicationFile.SaveAs(string path) => SaveAs(path); void IApplicationFile.Load(IStorageFile file) => Load(file); void IApplicationFile.Reload()=>ReloadFile(); } #endif }