fix: 1、更换命名空间和文件夹名字

This commit is contained in:
2026-06-02 11:11:47 +08:00
parent dfead2c461
commit 2a53f34659
4305 changed files with 582 additions and 603 deletions
@@ -0,0 +1,24 @@
using ZooMatch;
using UnityEngine;
public sealed class AnimationCurveData : ScriptableObject
{
private static AnimationCurveData instance;
public static AnimationCurveData Instance
{
get
{
if (instance == null)
{
instance = LoadKit.Instance.LoadAsset<AnimationCurveData>("Data.ScriptableObjectData",
"AnimationCurveData");
}
return instance;
}
}
public AnimationCurve LuckySpinAniCurve;
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b0a921ff368c47588249df420aa52091
timeCreated: 1704964086
@@ -0,0 +1,32 @@
using System;
using System.Text;
namespace FutureCore
{
public static class Base64EncodeUtil
{
public static string Base64Encode(string source)
{
return Base64Encode(Encoding.UTF8, source);
}
public static string Base64Decode(string result)
{
return Base64Decode(Encoding.UTF8, result);
}
public static string Base64Encode(Encoding encoding, string source)
{
byte[] bytes = encoding.GetBytes(source);
string encode = Convert.ToBase64String(bytes);
return encode;
}
public static string Base64Decode(Encoding encoding, string result)
{
byte[] bytes = Convert.FromBase64String(result);
string decode = encoding.GetString(bytes);
return decode;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7cb6f0cfcd844347bfe34d48a1f77555
timeCreated: 1693215248
+32
View File
@@ -0,0 +1,32 @@
using System;
using DG.Tweening;
using FairyGUI;
using ZooMatch;
public static class CommonExpand
{
public static GTweener FadeIn(this GObject obj, float duration = 0.3f, float delay = 0)
{
return CommonHelper.FadeIn(obj, duration, delay);
}
public static GTweener FadeOut(this GObject obj, float duration = 0.3f, float delay = 0)
{
return CommonHelper.FadeOut(obj, duration, delay);
}
public static void SetClick(this GObject button, Action action, bool isNetworkCheck = false,
bool isQuickClickCheck = true)
{
CommonHelper.InitGButton(button, action, isNetworkCheck, isQuickClickCheck);
}
public static void SafeKill(this Tween tween)
{
if (tween != null && tween.IsActive())
{
tween.Kill();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 774c7c1119b44f86819883ab6e9240ec
timeCreated: 1681803724
+207
View File
@@ -0,0 +1,207 @@
using System;
using System.Collections.Generic;
using DG.Tweening;
using FairyGUI;
using UnityEngine.UI;
namespace ZooMatch
{
public enum CountDownType
{
Second,
Minute,
Hour,
Day
}
public class CountDownKit
{
private int countDownTime;
private int leftTime = 0;
private GTextField textGComponent;
private GProgressBar barGComponent;
private Text textComponent;
private CountDownType countDownType = CountDownType.Second;
private Dictionary<int, Action> onTriggerEventDict = new Dictionary<int, Action>();
private Tween timer;
private Action onCompletedEvent;
private long endTime;
private bool isDependenceServerTime = true;
public CountDownKit SetTime(int second)
{
countDownTime = second;
leftTime = countDownTime;
return this;
}
public CountDownKit SetCountDownType(CountDownType countDownType)
{
this.countDownType = countDownType;
return this;
}
public CountDownKit SetText(GTextField gText)
{
textComponent = null;
textGComponent = gText;
return this;
}
public CountDownKit SetBar(GProgressBar gProgressBar)
{
barGComponent = null;
barGComponent = gProgressBar;
return this;
}
public int interval = 1;
public void Start()
{
endTime = (int)(DateTimeManager.Instance.GetServerCurrTimestamp() / 1000) + leftTime;
UpdateView();
timer = DOVirtual.DelayedCall(interval, () =>
{
leftTime -= interval;
if (isDependenceServerTime)
{
var current = DateTimeManager.Instance.GetServerCurrTimestamp() / 1000;
if (endTime <= current)
{
leftTime = 0;
}
}
UpdateView();
if (leftTime <= 0)
{
Stop();
OnCompleted();
}
else
{
OnTrigger();
}
}, true).SetLoops(-1);
}
private void UpdateView()
{
UpdateText();
UpdateBar();
}
public void Pause()
{
if (timer != null)
{
timer.Pause();
}
}
public void Resume()
{
if (timer != null)
{
timer.Play();
}
}
public void Stop()
{
if (timer != null && timer.IsActive())
{
timer?.Kill();
}
}
public void OnDestroy()
{
Stop();
leftTime = 0;
textGComponent = null;
textComponent = null;
onTriggerEventDict = null;
onCompletedEvent = null;
}
public void ConsumeTime(int consumeTime)
{
leftTime -= consumeTime;
UpdateView();
if (leftTime <= 0)
{
Stop();
OnCompleted();
}
else
{
OnTrigger();
}
}
private void OnTrigger()
{
if (onTriggerEventDict.ContainsKey(leftTime))
{
onTriggerEventDict[leftTime]?.Invoke();
}
}
public void ClearTriggerEvent()
{
onTriggerEventDict.Clear();
}
public CountDownKit SetCompletedEvent(Action onCompleted)
{
onCompletedEvent = onCompleted;
return this;
}
private void OnCompleted()
{
onCompletedEvent?.Invoke();
}
private void UpdateText()
{
if (textGComponent != null)
{
textGComponent.text = CommonHelper.TimeFormat(leftTime, countDownType);
}
if (textComponent != null)
{
textComponent.text = CommonHelper.TimeFormat(leftTime, countDownType);
}
}
private void UpdateBar()
{
if (barGComponent != null)
{
if (barGComponent.max == 0)
{
barGComponent.max = countDownTime;
}
barGComponent.TweenValue(leftTime, 1);
}
}
public int GetLeftTime()
{
return leftTime;
}
public CountDownKit SetServerTimeDependence(bool _isDependenceServerTime)
{
isDependenceServerTime = _isDependenceServerTime;
return this;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 34ed4a143324499ab1864f3c64019e16
timeCreated: 1681804392
+145
View File
@@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;
public class FXPool<T> : IDisposable where T : Enum
{
private Dictionary<T, List<Object>> PoolDic;
private Dictionary<T, Transform> PollPar;
private List<T> temp;
private Transform objectPoolPar;
public Func<T, Object> NewObjFunc;
public Action<T, Object> RecObjFunc;
public Action<T, Object> GetObjFunc;
public FXPool(Transform _objectPoolPar = null)
{
objectPoolPar = _objectPoolPar;
if (objectPoolPar == null)
{
objectPoolPar = new GameObject("ObjectPool").transform;
objectPoolPar.localPosition = Vector3.zero;
objectPoolPar.localEulerAngles = Vector3.zero;
}
PoolDic = new Dictionary<T, List<Object>>();
PollPar = new Dictionary<T, Transform>();
temp = new List<T>();
}
public Obj GetObject<Obj>(T key) where Obj : Object
{
Obj obj = null;
if (!PoolDic.ContainsKey(key))
{
AddKey(key);
}
if (PoolDic[key].Count > 0)
{
obj = PoolDic[key][0] as Obj;
PoolDic[key].RemoveAt(0);
}
else
{
obj = LoadObject<Obj>(key);
}
GetObjFunc?.Invoke(key, obj);
return obj;
}
private void AddKey(T key)
{
PoolDic.Add(key, new List<Object>());
Transform par = new GameObject(key.ToString()).transform;
par.SetParent(objectPoolPar);
par.localScale = Vector3.one;
par.localPosition = Vector3.zero;
par.localEulerAngles = Vector3.zero;
PollPar.Add(key, par.transform);
}
private Obj LoadObject<Obj>(T key) where Obj : UnityEngine.Object
{
Obj obj = NewObjFunc?.Invoke(key) as Obj;
if (obj != null)
{
GameObject go = obj as GameObject ?? (obj as Component).gameObject;
if (PollPar.TryGetValue(key, out Transform par) && go != null)
{
go.transform.SetParent(par);
}
}
return obj;
}
public void RecObject(T key, Object obj)
{
if (obj == null) return;
if (!PoolDic.ContainsKey(key))
{
PoolDic.Add(key, new List<Object>());
}
GameObject go = obj as GameObject ?? (obj as Component).gameObject;
if (PollPar.TryGetValue(key, out Transform par))
{
go.transform.parent = (par);
}
RecObjFunc?.Invoke(key, obj);
PoolDic[key].Add(obj);
}
public void RemoveKey(T key)
{
if (PoolDic.ContainsKey(key))
{
foreach (Object item in PoolDic[key])
{
if (item != null)
{
GameObject go = item as GameObject;
if (go == null)
{
Component cot = item as Component;
go = cot.gameObject;
}
GameObject.Destroy(go);
}
}
PoolDic[key].Clear();
PoolDic.Remove(key);
}
}
public void RemoveAll()
{
temp.Clear();
foreach (var item in PoolDic)
{
temp.Add(item.Key);
}
foreach (var item in temp)
{
RemoveKey(item);
}
temp.Clear();
}
public void Dispose()
{
RemoveAll();
PoolDic = null;
PollPar = null;
temp = null;
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3de141293f3240ffbdc26570a545e96c
timeCreated: 1681806263
+156
View File
@@ -0,0 +1,156 @@
using System.Collections.Generic;
using UnityEngine;
using FairyGUI;
namespace ZooMatch
{
public class GLoaderPool
{
private static GLoaderPool _instance;
public static GLoaderPool Instance => _instance ??= new GLoaderPool();
private readonly Queue<GLoader> pool = new Queue<GLoader>();
private readonly LinkedList<GLoader> inUseLoaders = new LinkedList<GLoader>(); // 维护活跃顺序(LRU
private int maxCount = 10; // 最大池子数量
private int _width = 0;
private int _height = 0;
private bool _autoDisposeTexture = true; // 是否自动释放贴图
private GLoaderPool() { }
/// <summary>
/// 初始化 Loader 池
/// </summary>
public void Init(GComponent parentObj, int maxPoolCount, int width, int height, bool autoDisposeTexture = true)
{
maxCount = maxPoolCount;
_width = width;
_height = height;
_autoDisposeTexture = autoDisposeTexture;
DisposeAll();
// 预创建 loader
for (int i = 0; i < maxCount; i++)
{
var loader = CreateLoader();
pool.Enqueue(loader);
}
}
private GLoader CreateLoader()
{
var loader = new GLoader
{
fill = FillType.ScaleMatchWidth,
align = AlignType.Center,
verticalAlign = VertAlignType.Top,
visible = false
};
loader.SetSize(_width, _height);
return loader;
}
/// <summary>
/// 从池中获取 Loader
/// </summary>
public GLoader GetLoader()
{
GLoader loader = null;
// 如果池子里有,直接取
if (pool.Count > 0)
{
loader = pool.Dequeue();
}
else if (inUseLoaders.Count >= maxCount)
{
// 如果池满了,回收最久未使用的一个(LRU)
loader = inUseLoaders.First.Value;
inUseLoaders.RemoveFirst();
RecycleLoader(loader);
Debug.Log($"[LRU回收] 回收并复用一个 Loader");
}
else
{
// 未达到上限,新建
loader = CreateLoader();
}
// 标记为使用中,放到链表末尾(最近使用)
inUseLoaders.AddLast(loader);
loader.visible = true;
return loader;
}
/// <summary>
/// 归还 Loader
/// </summary>
public void ReturnLoader(GLoader loader)
{
if (loader == null) return;
if (inUseLoaders.Contains(loader))
{
inUseLoaders.Remove(loader);
RecycleLoader(loader);
pool.Enqueue(loader);
}
else
{
Debug.LogWarning("尝试归还未分配的 GLoader");
}
}
/// <summary>
/// 回收 loader 的资源
/// </summary>
private void RecycleLoader(GLoader loader)
{
if (_autoDisposeTexture && loader.texture != null)
{
loader.texture.Dispose();
}
loader.url = null;
loader.texture = null;
loader.visible = false;
}
/// <summary>
/// 更新 Loader 的使用顺序(需要主动调用,避免 LRU 误判)
/// </summary>
public void TouchLoader(GLoader loader)
{
if (loader == null || !inUseLoaders.Contains(loader)) return;
inUseLoaders.Remove(loader);
inUseLoaders.AddLast(loader); // 移到链表末尾,标记为最新使用
}
public bool IsFromPool(GLoader loader)
{
return inUseLoaders.Contains(loader) || pool.Contains(loader);
}
public int GetPoolCount() => pool.Count;
public int GetInUseCount() => inUseLoaders.Count;
/// <summary>
/// 清理全部
/// </summary>
public void DisposeAll()
{
foreach (var loader in pool)
{
loader?.Dispose();
}
foreach (var loader in inUseLoaders)
{
loader?.Dispose();
}
pool.Clear();
inUseLoaders.Clear();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8c8dd0b885ee4574ad4a1b5222cc5d99
timeCreated: 1756968997
+577
View File
@@ -0,0 +1,577 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using FairyGUI;
using SGModule.Common;
using SGModule.Common.Base;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Video;
namespace ZooMatch
{
public class LiveVideoManager : SingletonMonoBehaviour<LiveVideoManager>
{
public static string videoBaseUrl = "";
// 封面缓存
private readonly Dictionary<string, Texture2D> coverCache = new Dictionary<string, Texture2D>();
// 封面提取队列(避免同时开多个VideoPlayer
private readonly Queue<CoverTask> coverQueue = new();
// 已下载视频缓存
private readonly HashSet<string> downloadedVideos = new();
// 当前正在下载的视频,用于去重
private readonly HashSet<string> downloadingSet = new();
// ==== 队列 ====
// 普通视频队列和优先队列
private readonly Queue<VideoTask> normalQueue = new();
private readonly Queue<VideoTask> priorityQueue = new();
private bool isExtracting;
private Coroutine normalCoroutine;
private Coroutine priorityCoroutine;
private string videoLocalDir => Path.Combine(TextureHelper.getResPath(), "LiveVideos");
private string coverLocalDir => Path.Combine(TextureHelper.getResPath(), "LiveVideoCovers");
protected override void Awake()
{
base.Awake();
InitDirs();
InitCache();
}
private void InitDirs()
{
if (!Directory.Exists(videoLocalDir))
Directory.CreateDirectory(videoLocalDir);
if (!Directory.Exists(coverLocalDir))
Directory.CreateDirectory(coverLocalDir);
}
private void InitCache()
{
var files = Directory.GetFiles(videoLocalDir, "*.mp4");
foreach (var file in files)
{
var fileName = Path.GetFileNameWithoutExtension(file);
downloadedVideos.Add(fileName);
}
}
#region
public void ClearAllCache()
{
foreach (var tex in coverCache.Values)
if (tex != null)
Destroy(tex);
coverCache.Clear();
if (Directory.Exists(coverLocalDir))
{
Directory.Delete(coverLocalDir, true);
Directory.CreateDirectory(coverLocalDir);
}
if (Directory.Exists(videoLocalDir))
{
Directory.Delete(videoLocalDir, true);
Directory.CreateDirectory(videoLocalDir);
downloadedVideos.Clear();
}
}
#endregion
#region
public IEnumerator LoadCover(string fileName, Action<Texture2D> callback)
{
Texture2D tex = null;
var persistentPath = Path.Combine(TextureHelper.getResPath(), "LiveVideoCovers", fileName + ".png");
if (File.Exists(persistentPath))
{
tex = LoadTextureFromFile(persistentPath);
if (tex != null)
{
callback?.Invoke(tex);
yield break;
}
}
var saPath = Path.Combine(Application.streamingAssetsPath, "LiveVideoCovers", fileName + ".jpg");
#if UNITY_ANDROID && !UNITY_EDITOR
using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(saPath))
{
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.Success)
tex = DownloadHandlerTexture.GetContent(www);
else
Debug.LogWarning($"LoadCover StreamingAssets失败: {www.error}, file: {fileName}");
}
#else
if (File.Exists(saPath))
try
{
var data = File.ReadAllBytes(saPath);
tex = new Texture2D(2, 2);
tex.LoadImage(data);
}
catch (Exception e)
{
Debug.LogWarning($"LoadCover StreamingAssets读取失败: {fileName}, error: {e}");
}
#endif
callback?.Invoke(tex);
}
#endregion
public static IEnumerator LoadVideoToPlayer(VideoPlayer player, string fileName, GLoader loader,
Action<VideoPlayer> onComplete, bool play = true)
{
string localPath = null;
var isDone = false;
Instance.GetVideoLocalPath(fileName, path =>
{
localPath = path;
isDone = true;
});
Debug.Log("LoadVideoToPlayer ------1------" + isDone);
while (!isDone)
yield return null;
if (string.IsNullOrEmpty(localPath))
{
onComplete?.Invoke(null);
yield break;
}
if (player.IsDestroyed())
{
onComplete?.Invoke(null);
yield break;
}
player.source = VideoSource.Url;
Debug.Log("LoadVideoToPlayer diaoyongyici: " + fileName);
player.url = Application.platform == RuntimePlatform.Android && !Application.isEditor
? localPath
: "file://" + localPath;
player.isLooping = true;
player.playOnAwake = false;
var rtWidth = (int)loader.width;
var rtHeight = (int)loader.height;
var rt = new RenderTexture(rtWidth, rtHeight, 0);
rt.Create();
player.targetTexture = rt;
if (!loader.isDisposed)
{
Debug.Log("LoadVideoToPlayer loader is isDisposed: ");
loader.texture = new NTexture(rt);
loader.visible = false;
}
player.Prepare();
var timeout = 3f;
var timer = 0f;
while (!player.IsDestroyed() && !player.isPrepared && timer < timeout)
{
yield return null;
timer += Time.deltaTime;
}
if (player.IsDestroyed())
{
onComplete?.Invoke(null);
yield break;
}
if (!player.isPrepared)
{
if (rt != null && !rt.Equals(null)) rt.Release();
onComplete?.Invoke(null);
yield break;
}
if (play)
player.Play();
else
player.Pause();
if (!loader.isDisposed)
loader.visible = true;
onComplete?.Invoke(player);
}
#region + + +
public void GetVideoLocalPath(string fileName, Action<string> callback, bool priority = true, int maxRetry = 3,
bool hardCancel = false)
{
var localPath = Path.Combine(videoLocalDir, fileName + ".mp4");
// 已下载直接回调
if (downloadedVideos.Contains(fileName) && File.Exists(localPath))
{
callback?.Invoke(localPath);
return;
}
// 去重:如果正在下载中,也直接等待回调
if (downloadingSet.Contains(fileName))
{
StartCoroutine(WaitForDownload(fileName, callback));
return;
}
var task = new VideoTask
{
FileName = fileName,
LocalPath = localPath,
Callback = callback,
MaxRetry = maxRetry
};
if (priority)
{
if (hardCancel)
{
// 硬取消:停止当前优先队列协程,清空队列
if (priorityCoroutine != null)
{
StopCoroutine(priorityCoroutine);
priorityCoroutine = null;
}
priorityQueue.Clear();
}
priorityQueue.Enqueue(task);
if (priorityCoroutine == null)
priorityCoroutine = StartCoroutine(ProcessPriorityQueue());
}
else
{
normalQueue.Enqueue(task);
if (normalCoroutine == null)
normalCoroutine = StartCoroutine(ProcessNormalQueue());
}
}
// 等待正在下载的视频完成再回调
private IEnumerator WaitForDownload(string fileName, Action<string> callback)
{
while (downloadingSet.Contains(fileName))
yield return null;
var localPath = Path.Combine(videoLocalDir, fileName + ".mp4");
callback?.Invoke(File.Exists(localPath) ? localPath : null);
}
// 优先队列协程(单任务)
private IEnumerator ProcessPriorityQueue()
{
while (priorityQueue.Count > 0)
{
var task = priorityQueue.Dequeue();
yield return DownloadVideoCoroutine(task);
}
priorityCoroutine = null;
}
// 普通队列协程(单任务)
private IEnumerator ProcessNormalQueue()
{
while (normalQueue.Count > 0)
{
var task = normalQueue.Dequeue();
yield return DownloadVideoCoroutine(task);
}
normalCoroutine = null;
}
// 核心下载协程
private IEnumerator DownloadVideoCoroutine(VideoTask task)
{
// 再次检查本地是否已有,避免重复下载
if (downloadedVideos.Contains(task.FileName) && File.Exists(task.LocalPath))
{
task.Callback?.Invoke(task.LocalPath);
yield break;
}
downloadingSet.Add(task.FileName);
var tmpPath = task.LocalPath + ".downloading";
var url = videoBaseUrl + "LiveAlbums/" + task.FileName + ".mp4";
if (File.Exists(tmpPath)) File.Delete(tmpPath);
Debug.Log($"[DownloadVideo] 开始下载视频 url== {url}");
var attempt = 0;
var success = false;
while (attempt < task.MaxRetry)
{
attempt++;
using (var www = UnityWebRequest.Get(url))
{
www.downloadHandler = new DownloadHandlerFile(tmpPath, true);
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.Success)
{
if (File.Exists(task.LocalPath)) File.Delete(task.LocalPath);
Debug.Log($"[DownloadVideo] 下载成功,开始解密视频 {task.FileName}");
Rescrypt.DecryptFile(tmpPath, task.LocalPath);
Debug.Log($"[DownloadVideo] 解密完成,保存路径:{task.LocalPath}");
downloadedVideos.Add(task.FileName);
success = true;
break;
}
Debug.LogWarning($"视频下载失败(第 {attempt} 次): {task.FileName}, {www.error}");
if (attempt < task.MaxRetry)
yield return new WaitForSeconds(1f);
}
}
if (!success)
{
Debug.LogError($"视频下载失败,超过最大重试次数:{task.FileName}");
if (File.Exists(tmpPath)) File.Delete(tmpPath);
}
downloadingSet.Remove(task.FileName);
task.Callback?.Invoke(success ? task.LocalPath : null);
LiveVideoMemoryManager.RequestCleanup();
}
#endregion
#region
// 你的封面逻辑保持不变
public void GetVideoCover(GLoader loader, string fileName, Action<Texture2D> onComplete)
{
if (coverCache.TryGetValue(fileName, out var cached))
{
onComplete?.Invoke(cached);
return;
}
var coverPath = Path.Combine(coverLocalDir, fileName + ".png");
if (File.Exists(coverPath))
{
var tex = LoadTextureFromFile(coverPath);
coverCache[fileName] = tex;
onComplete?.Invoke(tex);
return;
}
StartCoroutine(LoadCover(fileName, onComplete));
coverQueue.Enqueue(new CoverTask { FileName = fileName, Callback = onComplete });
if (!isExtracting)
ProcessCoverQueue(loader);
}
private void ProcessCoverQueue(GLoader loader)
{
isExtracting = true;
while (coverQueue.Count > 0)
{
var task = coverQueue.Dequeue();
ProcessGetCoverCoroutine(loader, task.FileName, task.Callback);
}
isExtracting = false;
}
private void ProcessGetCoverCoroutine(GLoader loader, string fileName, Action<Texture2D> callback)
{
TextureHelper.SetImgLoader(loader, fileName,
(a) => {
if (a != null && a.nativeTexture != null)
{
coverCache[fileName] = a.nativeTexture as Texture2D;
callback?.Invoke(coverCache[fileName]);
}
else
{
Debug.LogWarning($"[LiveVideoManager] 封面加载失败: {fileName}");
callback?.Invoke(null);
}
}, "LiveAlbums/", FolderNames.VideoCoversName);
}
private IEnumerator ExtractCoverFromVideo(string fileName, string videoPath, Action<Texture2D> callback)
{
var go = new GameObject("LiveVideoCoverExtractor_" + fileName);
var vp = go.AddComponent<VideoPlayer>();
vp.audioOutputMode = VideoAudioOutputMode.None;
vp.source = VideoSource.Url;
vp.url = Application.platform == RuntimePlatform.Android && !Application.isEditor
? videoPath
: "file://" + videoPath;
vp.isLooping = false;
vp.playOnAwake = false;
var rt = new RenderTexture(460,690, 0);
vp.targetTexture = rt;
vp.Prepare();
var timeout = 5f;
var timer = 0f;
while (!vp.isPrepared && timer < timeout)
{
timer += Time.deltaTime;
yield return null;
}
if (!vp.isPrepared)
{
Debug.LogWarning($"LiveVideoManager: Video '{fileName}' prepare timeout.");
Destroy(go);
callback?.Invoke(null);
yield break;
}
vp.Pause();
yield return new WaitForEndOfFrame();
var tex = CaptureFrame(vp);
SaveCover(fileName, tex);
coverCache[fileName] = tex;
callback?.Invoke(tex);
Destroy(go);
}
private Texture2D CaptureFrame(VideoPlayer vp)
{
var rt = vp.targetTexture;
RenderTexture.active = rt;
var tex = new Texture2D(rt.width, rt.height, TextureFormat.RGB24, false);
tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
tex.Apply();
RenderTexture.active = null;
vp.Stop();
vp.targetTexture = null;
return tex;
}
private void SaveCover(string fileName, Texture2D tex)
{
try
{
var pngData = tex.EncodeToPNG();
var path = Path.Combine(coverLocalDir, fileName + ".png");
File.WriteAllBytes(path, pngData);
}
catch (Exception e)
{
Debug.LogWarning($"Save cover PNG failed for '{fileName}': {e}");
}
}
private Texture2D LoadTextureFromFile(string filePath)
{
try
{
var data = File.ReadAllBytes(filePath);
var tex = new Texture2D(2, 2);
tex.LoadImage(data);
return tex;
}
catch
{
return null;
}
}
public bool ExistVideo(string fileName)
{
var path = Path.Combine(videoLocalDir, fileName + ".mp4");
return File.Exists(path);
}
#endregion
}
internal class VideoTask
{
public Action<string> Callback;
public string FileName;
public string LocalPath;
public int MaxRetry;
}
internal class CoverTask
{
public Action<Texture2D> Callback;
public string FileName;
}
internal static class LiveVideoMemoryManager
{
private const int CLEANUP_INTERVAL = 30;
private const int CLEANUP_THRESHOLD = 10;
private static readonly float lastCleanupTime = 0f;
private static int downloadCount;
public static void RequestCleanup()
{
downloadCount++;
if (downloadCount >= CLEANUP_THRESHOLD ||
Time.realtimeSinceStartup - lastCleanupTime > CLEANUP_INTERVAL)
LiveVideoManager.Instance.StartCoroutine(CleanupCoroutine());
}
private static IEnumerator CleanupCoroutine()
{
yield return null;
// Debug.Log("[LiveVideoMemoryManager] 清理内存...");
// yield return Resources.UnloadUnusedAssets();
// GC.Collect();
//
// lastCleanupTime = Time.realtimeSinceStartup;
// downloadCount = 0;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 16644af6755946d5a939ec93ad17f0a0
timeCreated: 1755569216
+72
View File
@@ -0,0 +1,72 @@
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
public class MD5Kit
{
public static string GetFileMD5(string file)
{
try
{
var fs = new FileStream(file, FileMode.Open);
MD5 md5 = new MD5CryptoServiceProvider();
var retVal = md5.ComputeHash(fs);
fs.Close();
var sb = new StringBuilder();
foreach (var str in retVal)
{
sb.Append(str.ToString("X2"));
}
return sb.ToString();
}
catch (Exception ex)
{
throw new Exception("GetFileMD5 fail error: " + ex.Message);
}
}
/// <summary>
/// 获取字符串的MD5值
/// </summary>
public static string GetStringMD5(string str)
{
if (string.IsNullOrEmpty(str))
{
return null;
}
MD5 md5 = new MD5CryptoServiceProvider();
byte[] bytResult = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
string strResult = BitConverter.ToString(bytResult);
strResult = strResult.Replace("-", string.Empty);
return strResult;
}
public static string MD5String1(string text)
{
var buffer = Encoding.Default.GetBytes(text);
var check = new MD5CryptoServiceProvider();
var somme = check.ComputeHash(buffer);
var result = new StringBuilder();
foreach (var a in somme)
{
var value = a.ToString("X");
if (a < 16)
{
result.Append(0);
result.Append(value);
}
else
{
result.Append(value);
}
}
return result.ToString().ToLower();
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a5697bf9fd10d9548977711311a96a00
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,355 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using UnityEngine;
namespace ZooMatch
{
public static class PreDownloadManager
{
#region Live
public static void InitializeLiveData()
{
List<Live> liveConfigList = ConfigSystem.GetLiveConfig();
Debug.Log($"[预下载视频 数据初始化]-0-----{DataMgr.LiveDataDic.Value.Count}");
var newData = new Dictionary<int, LiveData>();
for (var i = 0; i < liveConfigList.Count; i++)
{
var oldData = GetLiveDataByIndex(liveConfigList[i], i);
if (oldData.progress > 0) newData[i] = oldData;
}
Debug.Log($"[预下载视频 数据初始化]--1----- {newData.Count}");
DataMgr.LiveDataDic.Value = newData;
}
public static LiveData GetLiveDataByIndex(Live liveConfig, int i)
{
DataMgr.LiveDataDic.Value.TryGetValue(i, out var oldData);
oldData ??= new LiveData
{
progress = liveConfig.Progress,
AD_num = 0,
Singleprogress = (100 - liveConfig.Progress) / liveConfig.AD
};
if (oldData.progress < liveConfig.Progress) oldData.progress = liveConfig.Progress;
return oldData;
}
// 最大同时下载数量
private const int MaxConcurrentDownloads = 1;
public static void StartDownload()
{
CrazyAsyKit.StartCoroutine(DownloadVideosCoroutine());
}
private static IEnumerator DownloadVideosCoroutine()
{
List<Live> liveConfigList = ConfigSystem.GetLiveConfig();
var liveDic = DataMgr.LiveDataDic.Value;
var downloadNameList = new List<string>();
// 先加入已有进度的视频
foreach (var kvp in liveDic)
{
var index = kvp.Key;
var data = kvp.Value;
if (data.progress > 0 && index < liveConfigList.Count) downloadNameList.Add(liveConfigList[index].Name);
}
Debug.Log($"[init down video]---1---nameList----------{JsonConvert.SerializeObject(downloadNameList)}");
// 添加不在downloadNameList中的项,最多添加6个
var addedCount = 0;
for (var i = 0; i < liveConfigList.Count && addedCount < 6; i++)
if (!downloadNameList.Contains(liveConfigList[i].Name))
{
downloadNameList.Add(liveConfigList[i].Name);
addedCount++;
}
Debug.Log($"[init down video]---2---nameList----------{JsonConvert.SerializeObject(downloadNameList)}");
// 当前正在下载的协程数量
var runningCount = 0;
var currentIndex = 0;
if (downloadNameList.Count > 0)
{
var name = downloadNameList[currentIndex];
var localPath = Path.Combine(TextureHelper.getResPath(), FolderNames.VideoName, name + ".enc");
Debug.Log($"[预下载 视频 路径]-------localPath===={localPath}");
if (!File.Exists(localPath))
{
Debug.Log("[开始预下载 视频 ]---------------");
runningCount++;
CrazyAsyKit.StartCoroutine(DownloadSingleVideoCoroutine(name, () => { runningCount--; }));
}
}
// 等待下一帧再检查
yield return null;
Debug.Log("[init down video]---All downloads finished---");
}
private static IEnumerator DownloadSingleVideoCoroutine(string name, Action onComplete)
{
var isDone = false;
LiveVideoManager.Instance.GetVideoLocalPath(name, tex =>
{
Debug.Log($"[init down video]----------------{name}");
isDone = true;
}, false);
// 等待下载完成
while (!isDone) yield return null;
onComplete?.Invoke();
}
#endregion
#region Picture
public static void StartDownloadSecretPicture()
{
var liveConfigList = ConfigSystem.GetSecretAlbumsConfig();
var liveList = DataMgr.SecretUnlockList.Value;
var downloadNameList = new List<string>();
// 先加入所有可用的图片
for (var i = 0; i < liveList.Count; i++)
if (liveConfigList[i] != null && !downloadNameList.Contains(liveConfigList[i].Name))
downloadNameList.Add(liveConfigList[i].Name);
Debug.Log(
$"[init down picture Secret]---1---nameList----------{JsonConvert.SerializeObject(downloadNameList)}");
// 添加不在downloadNameList中的项,最多添加6个
var addedCount = 0;
for (var i = 0; i < liveConfigList.Count && addedCount < 6; i++)
if (!downloadNameList.Contains(liveConfigList[i].Name))
{
downloadNameList.Add(liveConfigList[i].Name);
addedCount++;
}
Debug.Log(
$"[init down picture Secret]---2---nameList----------{JsonConvert.SerializeObject(downloadNameList)}");
foreach (var name in downloadNameList)
{
var localPath = Path.Combine(TextureHelper.getResPath(), FolderNames.SecretName, name + ".jpg");
Debug.Log($"[预下载 Secret 路径]-------localPath===={localPath}");
if (!File.Exists(localPath))
{
Debug.Log("[开始预下载 Secret ]---------------");
TextureHelper.SetImgLoader(null, name,
s =>
{
Debug.Log($"[init down Secret picture]----------------{name}");
}, "SecretAlbums/", FolderNames.SecretName, false);
}
}
}
public static void StartDownloadAlbumsPicture()
{
int Free_Alubum_0 = PlayerPrefs.GetInt("Free_Alubum_0", -1);
int Free_Alubum_1 = PlayerPrefs.GetInt("Free_Alubum_1", -1);
int AD_Alubum = PlayerPrefs.GetInt("AD_Alubum", -1);
int Spec_Alubum = PlayerPrefs.GetInt("Spec_Alubum", -1);
int Vip_Alubum = PlayerPrefs.GetInt("Vip_Alubum", -1);
if (Free_Alubum_0 >= 0) return;
var FreeImageLibrary_ = ConfigSystem.GetFreeImageConfig();
var ADImageLibrary_ = ConfigSystem.GetADImageConfig();
var SpecialImageLibrary_ = ConfigSystem.GetSpecialImageConfig();
var VIPImageLibrary_ = ConfigSystem.GetVIPImageConfig();
List<int> free_level_list = new List<int>();
List<int> ad_level_list = new List<int>();
List<int> special_level_list = new List<int>();
List<int> vip_level_list = new List<int>();
for (int i = 0; i < DataMgr.LevelUnlockListNew.Value.Count; i++)
{
if (DataMgr.LevelUnlockListNew.Value[i].type == 0) free_level_list.Add(DataMgr.LevelUnlockListNew.Value[i].config_index);
else if (DataMgr.LevelUnlockListNew.Value[i].type == 1) ad_level_list.Add(DataMgr.LevelUnlockListNew.Value[i].config_index);
else if (DataMgr.LevelUnlockListNew.Value[i].type == 2) special_level_list.Add(DataMgr.LevelUnlockListNew.Value[i].config_index);
else if (DataMgr.LevelUnlockListNew.Value[i].type == 3) vip_level_list.Add(DataMgr.LevelUnlockListNew.Value[i].config_index);
}
if (Free_Alubum_0 < 0)
{
HashSet<int> levelIds = new HashSet<int>(free_level_list);
List<FreeImageLibrary> filtered = ConfigSystem.GetFreeImageConfig().Where(x => !levelIds.Contains(x.id)).ToList();
if (filtered.Count > 0)
{
Free_Alubum_0 = filtered[UnityEngine.Random.Range(0, filtered.Count)].id;
}
else
{
Free_Alubum_0 = ConfigSystem.GetFreeImageConfig()[UnityEngine.Random.Range(0, ConfigSystem.GetFreeImageConfig().Count)].id;
}
free_level_list.Add(Free_Alubum_0);
Debug.Log(JsonConvert.SerializeObject(filtered) + ",,,,,,,,,,,,,,,,,,,,");
}
if (Free_Alubum_1 < 0)
{
HashSet<int> levelIds = new HashSet<int>(free_level_list);
List<FreeImageLibrary> filtered = ConfigSystem.GetFreeImageConfig().Where(x => !levelIds.Contains(x.id)).ToList();
if (filtered.Count > 0)
{
Free_Alubum_1 = filtered[UnityEngine.Random.Range(0, filtered.Count)].id;
}
else
{
Free_Alubum_1 = ConfigSystem.GetFreeImageConfig()[UnityEngine.Random.Range(0, ConfigSystem.GetFreeImageConfig().Count)].id;
}
Debug.Log(JsonConvert.SerializeObject(filtered) + ",,,,,,,,,,,,,,,,,,,,");
}
if (AD_Alubum < 0)
{
HashSet<int> levelIds = new HashSet<int>(ad_level_list);
List<ADImageLibrary> filtered = ConfigSystem.GetADImageConfig().Where(x => !levelIds.Contains(x.id)).ToList();
if (filtered.Count > 0)
{
AD_Alubum = filtered[UnityEngine.Random.Range(0, filtered.Count)].id;
}
else
{
AD_Alubum = ConfigSystem.GetADImageConfig()[UnityEngine.Random.Range(0, ConfigSystem.GetADImageConfig().Count)].id;
}
Debug.Log(JsonConvert.SerializeObject(filtered) + ",,,,,,,,,,,,,,,,,,,,");
}
if (Spec_Alubum < 0)
{
HashSet<int> levelIds = new HashSet<int>(special_level_list);
List<SpecialImageLibrary> filtered = ConfigSystem.GetSpecialImageConfig().Where(x => !levelIds.Contains(x.id)).ToList();
if (filtered.Count > 0)
{
Spec_Alubum = filtered[UnityEngine.Random.Range(0, filtered.Count)].id;
}
else
{
Spec_Alubum = ConfigSystem.GetSpecialImageConfig()[UnityEngine.Random.Range(0, ConfigSystem.GetSpecialImageConfig().Count)].id;
}
Debug.Log(JsonConvert.SerializeObject(filtered) + ",,,,,,,,,,,,,,,,,,,,");
}
if (Vip_Alubum < 0)
{
HashSet<int> levelIds = new HashSet<int>(vip_level_list);
List<VIPImageLibrary> filtered = ConfigSystem.GetVIPImageConfig().Where(x => !levelIds.Contains(x.id)).ToList();
if (filtered.Count > 0)
{
Vip_Alubum = filtered[UnityEngine.Random.Range(0, filtered.Count)].id;
}
else
{
Vip_Alubum = ConfigSystem.GetVIPImageConfig()[UnityEngine.Random.Range(0, ConfigSystem.GetVIPImageConfig().Count)].id;
}
Debug.Log(JsonConvert.SerializeObject(filtered) + ",,,,,,,,,,,,,,,,,,,,");
}
PlayerPrefs.SetInt("Free_Alubum_0", Free_Alubum_0);
PlayerPrefs.SetInt("Free_Alubum_1", Free_Alubum_1);
PlayerPrefs.SetInt("AD_Alubum", AD_Alubum);
PlayerPrefs.SetInt("Spec_Alubum", Spec_Alubum);
PlayerPrefs.SetInt("Vip_Alubum", Vip_Alubum);
List<string> downloadNameList = new List<string>
{
FreeImageLibrary_[Free_Alubum_0].Name,
FreeImageLibrary_[Free_Alubum_1].Name,
ADImageLibrary_[AD_Alubum].Name,
SpecialImageLibrary_[Spec_Alubum].Name,
VIPImageLibrary_[Vip_Alubum].Name
};
for (int i = 0; i < GameHelper.GetCommonModel().MultiModal - 1; i++)
{
downloadNameList.Insert(i, ConfigSystem.GetLevelUnlockConfig()[i].Name);
}
Debug.Log(
$"[init down picture Album]---1---nameList----------{JsonConvert.SerializeObject(downloadNameList)}");
// 添加不在downloadNameList中的项,最多添加12个
// var addedCount = 0;
// for (var i = 0; i < liveConfigList.Count && addedCount < 6; i++)
// if (!downloadNameList.Contains(liveConfigList[i].Name))
// {
// downloadNameList.Add(liveConfigList[i].Name);
// addedCount++;
// }
Debug.Log(
$"[init down picture Album]---2---nameList----------{JsonConvert.SerializeObject(downloadNameList)}");
// int centerIndex = GameHelper.GetLevel();
// int totalCount = downloadNameList.Count;
// // 计算起始索引和实际要取的数量
// int rangeStart = Math.Max(0, centerIndex - 5);
// int rangeEnd = Math.Min(totalCount, centerIndex + 5);
// int rangeCount = rangeEnd - rangeStart;
// // 获取范围内元素并反转
// var segment = downloadNameList.GetRange(rangeStart, rangeCount);
// segment.Reverse();
// // 移除原始位置的元素
// downloadNameList.RemoveRange(rangeStart, rangeCount);
// // 插入反转后的元素到最前面
// downloadNameList.InsertRange(0, segment);
Debug.Log(
$"[init down picture Album]---3---nameList----------{JsonConvert.SerializeObject(downloadNameList)}");
foreach (var name in downloadNameList)
{
var localPath = Path.Combine(TextureHelper.getResPath(), FolderNames.AlbumName, name + ".jpg");
Debug.Log($"[预下载 Albums 路径]-------localPath===={localPath}");
if (!File.Exists(localPath))
{
Debug.Log($"[开始预下载 Albums ]--------------name-{name}");
TextureHelper.SetImgLoader(null, name,
s =>
{
Debug.Log($"[init down Album picture]----------------{name}");
}, "LevelAlbums/", FolderNames.AlbumName, false);
}
}
}
#endregion
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4b5fdf790e2e4b9d896042d58c456ffb
timeCreated: 1756814521
@@ -0,0 +1,95 @@
using DG.Tweening;
using FairyGUI;
using UnityEngine;
using UnityEngine.Video;
namespace ZooMatch
{
public static class VideoPlayerHandover
{
private static VideoPlayer currentPlayer;
private static Transform originalParent;
private static GLoader originalLoader;
/// <summary>
/// 接管播放器,切换父物体和绑定loader
/// </summary>
public static void TakeOver(VideoPlayer player, Transform newParent, GLoader newLoader)
{
if (player == null)
{
Debug.LogWarning("[VideoPlayerHandover] TakeOver: player is null");
return;
}
currentPlayer = player;
// 只记录第一次的父物体和loader(方便后面还原)
if (originalParent == null)
originalParent = player.transform.parent;
if (originalLoader == null && newLoader != null)
originalLoader = newLoader;
// 切父物体
player.transform.SetParent(newParent, false);
// 延迟绑定到新loader显示,确保 RenderTexture 已准备好
DOTween.To(() => 0, _ =>
{
if (player.targetTexture != null && IsValidRenderTexture(player.targetTexture))
{
newLoader.texture = new NTexture(player.targetTexture);
newLoader.visible = true;
Debug.Log($"[VideoPlayerHandover] TakeOver: bound to loader {newLoader.name}, texture size: {player.targetTexture.width}x{player.targetTexture.height}");
}
else
{
Debug.LogWarning("[VideoPlayerHandover] TakeOver: targetTexture invalid or not ready");
}
}, 0, 0.05f); // 延迟 0.05s
}
/// <summary>
/// 归还播放器到原父物体和loader
/// </summary>
public static void Return()
{
if (currentPlayer == null)
{
Debug.LogWarning("[VideoPlayerHandover] Return: currentPlayer is null");
return;
}
// 切回原父物体
currentPlayer.transform.SetParent(originalParent, false);
// 绑定回原loader显示
if (originalLoader != null)
{
if (currentPlayer.targetTexture != null && IsValidRenderTexture(currentPlayer.targetTexture))
{
originalLoader.texture = new NTexture(currentPlayer.targetTexture);
originalLoader.visible = true;
Debug.Log($"[VideoPlayerHandover] Return: bound back to original loader {originalLoader.name}, texture size: {currentPlayer.targetTexture.width}x{currentPlayer.targetTexture.height}");
}
else
{
Debug.LogWarning("[VideoPlayerHandover] Return: targetTexture invalid or not ready");
}
}
// 清除引用,下次接管会重新记录
currentPlayer = null;
originalParent = null;
originalLoader = null;
}
/// <summary>
/// RenderTexture 尺寸合法性检查
/// </summary>
private static bool IsValidRenderTexture(RenderTexture rt)
{
return rt != null && rt.width > 0 && rt.height > 0;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 12e1a86fe417443789fb752681b6b947
timeCreated: 1755570462
+109
View File
@@ -0,0 +1,109 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Video;
public class VideoPlayerPool
{
private static VideoPlayerPool _instance;
public static VideoPlayerPool Instance => _instance ??= new VideoPlayerPool();
private readonly Queue<VideoPlayer> pool = new Queue<VideoPlayer>();
private GameObject parent;
private int maxCount = 5;
// 已经分配出去的播放器(方便管理)
private readonly HashSet<VideoPlayer> inUsePlayers = new HashSet<VideoPlayer>();
private VideoPlayerPool()
{
}
public void Init(GameObject parentObj, int maxPoolCount)
{
parent = parentObj;
maxCount = maxPoolCount;
// 先清理旧的
foreach (var player in pool)
{
if (player != null) GameObject.Destroy(player.gameObject);
}
pool.Clear();
inUsePlayers.Clear();
// 创建初始播放器
for (int i = 0; i < maxCount; i++)
{
var go = new GameObject($"VideoPlayer_{i}");
go.transform.SetParent(parent.transform);
var player = go.AddComponent<VideoPlayer>();
player.playOnAwake = false;
player.renderMode = VideoRenderMode.RenderTexture;
pool.Enqueue(player);
}
}
// 获取播放器
public VideoPlayer GetPlayer()
{
Debug.Log($"[VideoPlayerPool] GetPlayer VideoPlayerPool===={pool.Count}");
if (pool.Count == 0)
{
Debug.LogWarning("VideoPlayerPool空了,无法分配更多播放器");
return null;
}
var player = pool.Dequeue();
inUsePlayers.Add(player);
player.gameObject.SetActive(true);
return player;
}
// 归还播放器
public void ReturnPlayer(VideoPlayer player)
{
if (player == null) return;
if (inUsePlayers.Contains(player))
{
player.Stop();
player.clip = null;
if (player.targetTexture != null)
{
player.targetTexture.Release();
GameObject.Destroy(player.targetTexture);
player.targetTexture = null;
}
player.gameObject.SetActive(false);
inUsePlayers.Remove(player);
pool.Enqueue(player);
}
else
{
Debug.LogWarning("尝试归还未被分配的播放器");
}
}
// 释放所有
public void DisposeAll()
{
foreach (var player in pool)
{
if (player != null) GameObject.Destroy(player.gameObject);
}
foreach (var player in inUsePlayers)
{
if (player != null) GameObject.Destroy(player.gameObject);
}
pool.Clear();
inUsePlayers.Clear();
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 865cf6395a2640c29966a4c05bc820cf
timeCreated: 1755569394
@@ -0,0 +1,18 @@
using UnityEngine;
namespace ZooMatch
{
public static class ZooMatchConstant
{
public const string croas = "Assets/ZooMatchAssets/";
public const string setbun = ".assetbundle";
public static readonly string tbund = $"{Application.dataPath}/../AssetBundle/{undles}";
public static readonly string fgklpk = "|";
public const string undles = "AssetBundles";
public const string nifest = ".manifest";
public static readonly string lesest = $"{undles}{nifest}";
public const string zyzootx = "ZooMatchFile.txt";
public const string nifldg = "[ ZooMatch ]";
public const string admsie = "4s2f6ac15sa6ds45";
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 73ce1d7d9d7bd5245878994917b71208
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+205
View File
@@ -0,0 +1,205 @@
using UnityEngine.Events;
namespace ZooMatch
{
using System;
using UnityEngine;
using System.Collections.Generic;
public delegate void onLoaded(AssetBundle param);
public class ZooMatchInfo
{
public string assetBundleName;
public List<string> parentABNameList = new();
public long assetBundleSize;
public AssetBundle assetBundle { get; internal set; }
public ZooMatchState assetBundleState;
public onLoaded ONLoaded;
public long waitUnloadCurrentTime;
public Action<Action<bool>> unloadAction;
public Action<bool> unloadCompletedAction;
public int waitUnloadTime;
public static List<string> StatisticsCacheAssetList = new List<string>();
private static bool isStatisticsCacheAssetList = false;
public int ReferencedCount { get; set; }
public float LastReferencedTimestamp { get; set; }
public ZooMatchInfo(string assetBundleName, UnityAction<AssetBundle> onCompletedLoaded)
{
this.assetBundleName = assetBundleName;
assetBundleState = ZooMatchState.STATE_LOADING;
Referenced(assetBundleName);
LastReferencedTimestamp = Time.realtimeSinceStartup;
if (onCompletedLoaded != null)
{
ONLoaded += a => onCompletedLoaded(a);
}
}
#region
public int GetReferenced()
{
return ReferencedCount;
}
public void Referenced(string parentAbName)
{
parentAbName = parentAbName.ToLower();
if (!parentABNameList.Contains(parentAbName))
{
ReferencedCount++;
parentABNameList.Add(parentAbName);
#if UNITY_EDITOR
#endif
}
}
public void UnReferenced(string parentAbName)
{
if (parentABNameList.Contains(parentAbName))
{
ReferencedCount--;
parentABNameList.Remove(parentAbName);
#if UNITY_EDITOR
#endif
}
}
public void CleanReferenced()
{
ReferencedCount = 0;
}
#endregion
public void callRes(string parentAbName, UnityAction<AssetBundle> action)
{
switch (assetBundleState)
{
case ZooMatchState.STATE_NONE:
break;
case ZooMatchState.STATE_LOADING:
ONLoaded += a => { action(a); };
break;
case ZooMatchState.STATE_LOADED:
Referenced(parentAbName);
action(this.assetBundle);
break;
}
}
public void onLoaded(string parentAbName, AssetBundle assetBundle)
{
Referenced(parentAbName);
this.assetBundle = assetBundle;
this.assetBundleState = ZooMatchState.STATE_LOADED;
ONLoaded(assetBundle);
ONLoaded = null;
OnAddtStatisticsCacheAssetList(assetBundle.name);
}
public void Unload(bool isThorough)
{
CleanReferenced();
if (assetBundle != null)
assetBundle.Unload(isThorough);
assetBundle = null;
}
private void OnAddtStatisticsCacheAssetList(string assetBundleName)
{
if (!isStatisticsCacheAssetList) return;
if (!StatisticsCacheAssetList.Contains(assetBundleName))
{
StatisticsCacheAssetList.Add(assetBundleName);
}
}
public static void OnStartStatisticsCacheAssetList()
{
isStatisticsCacheAssetList = true;
StatisticsCacheAssetList.Clear();
}
public static string[] OnStopStatisticsCacheAssetList()
{
isStatisticsCacheAssetList = false;
string[] tempList = StatisticsCacheAssetList.GetRange(0, StatisticsCacheAssetList.Count).ToArray();
StatisticsCacheAssetList.Clear();
return tempList;
}
public void UpdateWaitUnloadCurrentTime()
{
waitUnloadCurrentTime = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
}
public long GetWaitUpdateTimeTD()
{
var tempTime = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
return tempTime - waitUnloadCurrentTime;
}
public void SetUnloadAction(Action<Action<bool>> action, Action<bool> onCompletedAction)
{
this.unloadAction = action;
this.unloadCompletedAction = onCompletedAction;
}
public void InvokeUnloadAction()
{
unloadAction?.Invoke(unloadCompletedAction);
}
public void SetWaitUnloadTime(int time)
{
waitUnloadTime = time;
}
public int GetWaitUnloadTime()
{
return waitUnloadTime;
}
public void SetAssetBundleSize(long size)
{
if (size > 0)
{
assetBundleSize = size;
}
}
public long GetSize()
{
return assetBundleSize;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7f8e1bf1569620a45ba3a117072e9b57
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+853
View File
@@ -0,0 +1,853 @@
namespace ZooMatch
{
using System;
using System.IO;
using UnityEngine;
using System.Linq;
using System.Text;
using UnityEngine.Events;
using System.Collections;
using System.Collections.Generic;
using Object = UnityEngine.Object;
using System.Security.Cryptography;
public class ZooMatchKit : Singleton<ZooMatchKit>, ILoadAsset
{
private const bool IsMD5Encrypt = false;
private string _assetBundleRootPath = ZooMatchFileKit.GetFilePath();
private static readonly Dictionary<string, ZooMatchInfo> _cacheAssetBundleInfoDict =
new Dictionary<string, ZooMatchInfo>();
private static readonly Dictionary<string, string[]> _cacheDependencyDict = new Dictionary<string, string[]>();
private static readonly List<ZooMatchInfo> _waitUnloadList = new List<ZooMatchInfo>();
private static AssetBundleManifest _manifest;
private static readonly Dictionary<string, string> decryptAssetBundleDict = new Dictionary<string, string>();
private const int UnloadWaitTime = 30;
#region AssetBundle的基础方法
public IEnumerator LoadABFromFileAsync(string assetBundlePath, string bundlePassword,
UnityAction<AssetBundle> onCompleted)
{
yield return LoadDecryptAssetBundle(assetBundlePath, bundlePassword, onCompleted);
}
private IEnumerator LoadDecryptAssetBundle(string assetBundlePath, string bundlePassword,
UnityAction<AssetBundle> onCompleted)
{
string decryptPath;
if (decryptAssetBundleDict.TryGetValue(assetBundlePath, out var outPath) && File.Exists(outPath))
{
decryptPath = outPath;
}
else
{
var cachePath1 = Path.Combine(UnityEngine.Application.persistentDataPath, "Jarvis");
if (!Directory.Exists(cachePath1))
{
Directory.CreateDirectory(cachePath1);
}
var cachePath = Path.Combine(cachePath1, $"decryptedBundle{Guid.NewGuid():N}");
using (Stream stream1 = File.OpenWrite(cachePath))
{
var decryptedData = AESForFileKit.DecryptToBytes(assetBundlePath, bundlePassword, out var dataSize);
yield return stream1.WriteAsync(decryptedData, 0, dataSize);
}
decryptPath = cachePath;
decryptAssetBundleDict.TryAdd(assetBundlePath, decryptPath);
}
var request = AssetBundle.LoadFromFileAsync(decryptPath);
yield return request;
onCompleted?.Invoke(request.assetBundle);
}
private AssetBundle LoadDecryptAssetBundleSync(string assetBundlePath, string bundlePassword)
{
string decryptPath;
if (decryptAssetBundleDict.TryGetValue(assetBundlePath, out var outPath) && File.Exists(outPath))
{
decryptPath = outPath;
}
else
{
var decryptedData = AESForFileKit.DecryptToBytes(assetBundlePath, bundlePassword, out var dataSize);
var cachePath1 = Path.Combine(UnityEngine.Application.persistentDataPath, "Jarvis");
if (!Directory.Exists(cachePath1))
{
Directory.CreateDirectory(cachePath1);
}
var cachePath = Path.Combine(cachePath1, $"decryptedBundle{Guid.NewGuid():N}");
while (File.Exists(cachePath))
{
File.Delete(cachePath);
cachePath = Path.Combine(cachePath1, $"decryptedBundle{Guid.NewGuid():N}");
}
using (Stream stream = File.OpenWrite(cachePath))
{
stream.Write(decryptedData, 0, dataSize);
stream.Close();
}
decryptPath = cachePath;
decryptAssetBundleDict.TryAdd(assetBundlePath, decryptPath);
}
var assetBundle = AssetBundle.LoadFromFile(decryptPath);
return assetBundle;
}
private IEnumerator LoadAssetFromAssetBundle<T>(AssetBundle assetBundle, string assetName,
UnityAction<T> onLoadCompleted) where T : Object
{
T resultAsset = null;
if (typeof(T) == typeof(Sprite))
{
var texture2D = assetBundle.LoadAsset<Texture2D>(assetName);
if (texture2D != null)
{
var sprite = Sprite.Create(texture2D,
new Rect(0, 0, texture2D.width, texture2D.height), new Vector2(0.5f, 0.5f));
resultAsset = sprite as T;
}
else
{
string[] assetNameArray = assetName.Split('.');
if (assetNameArray.Length > 1)
{
var resultAsset1 = assetBundle.LoadAssetWithSubAssets<T>(assetNameArray[0]);
resultAsset = Array.Find(resultAsset1, item => item.name == assetNameArray[1]);
}
else
{
}
}
}
else
{
var assetLoadRequest = assetBundle.LoadAssetAsync<T>(assetName);
yield return assetLoadRequest;
var gameObject = assetLoadRequest.asset;
if (gameObject == null)
{
var subAssetLoadRequest = assetBundle.LoadAssetWithSubAssetsAsync<T>(assetName);
yield return subAssetLoadRequest;
resultAsset = subAssetLoadRequest.asset as T;
}
else
{
resultAsset = gameObject as T;
}
}
onLoadCompleted?.Invoke(resultAsset);
}
private void LoadAssetInternal(string assetBundleName, UnityAction<AssetBundle> onCompleted)
{
var assetBundlePath = GenerateAssetBundlePath(assetBundleName);
GetAssetBundle(assetBundlePath, assetBundleName, onCompleted);
}
public AssetBundle GetAssetBundle(string assetBundlePath, string assetBundleName)
{
assetBundleName = assetBundleName.ToLower();
CrazyAsyKit.StopAction(assetBundleName + "Unload");
UnWaitUnload(assetBundleName);
if (IsCacheAssetBundle(assetBundleName))
{
CacheDependency(assetBundleName, new[] { assetBundleName });
var LoveLegendInfo = GetCacheAssetBundle(assetBundleName);
return LoveLegendInfo?.assetBundle;
}
else
{
var LoveLegendInfo = new ZooMatchInfo(assetBundleName, null);
CacheAssetBundle(assetBundleName, LoveLegendInfo);
var isFileLoadType = File.Exists(assetBundlePath);
if (isFileLoadType)
{
GetAssetBundleDependency(assetBundleName);
var assetBundle =
LoadDecryptAssetBundleSync(assetBundlePath, ZooMatchConstant.admsie);
LoveLegendInfo.assetBundle = assetBundle;
return assetBundle;
}
}
return null;
}
public void GetAssetBundle(string assetBundlePath, string assetBundleName, UnityAction<AssetBundle> onCompleted)
{
assetBundleName = assetBundleName.ToLower();
CrazyAsyKit.StopAction(assetBundleName + "Unload");
UnWaitUnload(assetBundleName);
if (IsCacheAssetBundle(assetBundleName))
{
CacheDependency(assetBundleName, new[] { assetBundleName });
var LoveLegendInfo = GetCacheAssetBundle(assetBundleName);
LoveLegendInfo?.callRes(assetBundleName, onCompleted);
}
else
{
var LoveLegendInfo = new ZooMatchInfo(assetBundleName, onCompleted);
CacheAssetBundle(assetBundleName, LoveLegendInfo);
var isFileLoadType = File.Exists(assetBundlePath);
CrazyAsyKit.StartCoroutine(GetAssetBundleDependency(assetBundleName, delegate
{
if (isFileLoadType)
{
CrazyAsyKit.StartCoroutine(LoadABFromFileAsync(assetBundlePath,
ZooMatchConstant.admsie, bundle =>
{
if (bundle == null)
{
Debug.LogError("加载AssetBundle 失败:" + assetBundleName);
UnCacheAssetBundle(assetBundleName);
}
else
{
ZooMatchInfo abInfo = GetCacheAssetBundle(assetBundleName);
#if UNITY_EDITOR
FileInfo file = new FileInfo(assetBundlePath);
abInfo.SetAssetBundleSize(file.Length);
#endif
abInfo.onLoaded(assetBundleName, bundle);
}
}));
}
else
{
CrazyAsyKit.StartCoroutine(LoadABFromFileAsync(assetBundlePath,
ZooMatchConstant.admsie, delegate (AssetBundle bundle)
{
if (bundle == null)
{
Debug.LogError("加载AssetBundle 失败:" + assetBundleName);
UnCacheAssetBundle(assetBundleName);
}
else
{
var abInfoV = GetCacheAssetBundle(assetBundleName);
var file = new FileInfo(assetBundlePath);
abInfoV.SetAssetBundleSize(file.Length);
abInfoV.onLoaded(assetBundleName, bundle);
}
}));
}
}));
}
}
#region AssetBundle
private IEnumerator GetAssetBundleDependency(string assetBundleName, Action action)
{
assetBundleName = assetBundleName.ToLower();
var allDependencies = new List<string>() { assetBundleName };
allDependencies.AddRange(GetABDependency(assetBundleName));
var index = 0;
CacheDependency(assetBundleName, allDependencies.ToArray());
var allDepends = allDependencies.Where(dependencyAbName => dependencyAbName != assetBundleName).ToList();
foreach (var dependencyAbName in allDepends)
{
yield return LoadDependencyAssetBundle(assetBundleName, dependencyAbName, delegate { index++; });
}
while (index != allDepends.Count)
{
yield return new WaitForEndOfFrame();
}
action?.Invoke();
}
private void GetAssetBundleDependency(string assetBundleName)
{
assetBundleName = assetBundleName.ToLower();
var allDependencies = new List<string>() { assetBundleName };
allDependencies.AddRange(GetABDependency(assetBundleName));
CacheDependency(assetBundleName, allDependencies.ToArray());
var allDepends = allDependencies.Where(dependencyAbName => dependencyAbName != assetBundleName).ToList();
foreach (var dependencyAbName in allDepends)
{
LoadDependencyAssetBundleSync(assetBundleName, dependencyAbName);
}
}
private IEnumerator LoadDependencyAssetBundle(string parentAssetBundleName, string assetBundleName,
UnityAction<AssetBundle> onCompleted)
{
assetBundleName = assetBundleName.ToLower();
var assetBundlePath = GenerateAssetBundlePath(assetBundleName, IsMD5Encrypt);
CrazyAsyKit.StopAction(assetBundleName + "Unload");
UnWaitUnload(assetBundleName);
if (IsCacheAssetBundle(assetBundleName))
{
CacheAssetBundle(assetBundleName, null, true);
var LoveLegendInfo = GetCacheAssetBundle(assetBundleName);
LoveLegendInfo?.callRes(parentAssetBundleName, onCompleted);
}
else
{
var LoveLegendInfo = new ZooMatchInfo(assetBundleName, onCompleted);
CacheAssetBundle(assetBundleName, LoveLegendInfo);
if (File.Exists(assetBundlePath))
{
yield return LoadABFromFileAsync(assetBundlePath, ZooMatchConstant.admsie,
delegate (AssetBundle bundle)
{
if (bundle == null)
{
Debug.LogError("加载AssetBundle 失败:" + assetBundleName);
UnCacheAssetBundle(assetBundleName);
}
else
{
GetCacheAssetBundle(assetBundleName).onLoaded(parentAssetBundleName, bundle);
}
});
}
else
{
CrazyAsyKit.StartCoroutine(LoadABFromFileAsync(assetBundlePath,
ZooMatchConstant.admsie, delegate (AssetBundle bundle)
{
if (bundle == null)
{
Debug.LogError("加载AssetBundle 失败:" + assetBundleName);
UnCacheAssetBundle(assetBundleName);
}
else
{
GetCacheAssetBundle(assetBundleName).onLoaded(parentAssetBundleName, bundle);
}
}));
}
}
}
private AssetBundle LoadDependencyAssetBundleSync(string parentAssetBundleName, string assetBundleName)
{
assetBundleName = assetBundleName.ToLower();
var assetBundlePath = GenerateAssetBundlePath(assetBundleName, IsMD5Encrypt);
CrazyAsyKit.StopAction(assetBundleName + "Unload");
UnWaitUnload(assetBundleName);
if (IsCacheAssetBundle(assetBundleName))
{
CacheAssetBundle(assetBundleName, null, true);
var assetBundleInfos = GetCacheAssetBundle(assetBundleName);
return assetBundleInfos?.assetBundle;
}
var LoveLegendInfo = new ZooMatchInfo(assetBundleName, null);
CacheAssetBundle(assetBundleName, LoveLegendInfo);
if (File.Exists(assetBundlePath))
{
GetAssetBundleDependency(assetBundleName);
var assetBundle =
LoadDecryptAssetBundleSync(assetBundlePath, ZooMatchConstant.admsie);
LoveLegendInfo.assetBundle = assetBundle;
return assetBundle;
}
return null;
}
private string[] GetABDependency(string assetBundleName)
{
assetBundleName = assetBundleName.ToLower();
return GetManifest().GetDirectDependencies(assetBundleName);
}
#region
private bool IsCacheDependency(string assetBundleName)
{
if (_cacheDependencyDict == null || _cacheDependencyDict.Count == 0) return false;
assetBundleName = assetBundleName.ToLower();
var isDependency = _cacheDependencyDict.ContainsKey(assetBundleName);
return isDependency;
}
private bool IsOtherDependency(string assetBundleName)
{
assetBundleName = assetBundleName.ToLower();
var isDependency = false;
if (_cacheDependencyDict == null || _cacheDependencyDict.Count == 0) return false;
foreach (var keyValuePair in _cacheDependencyDict)
{
isDependency = keyValuePair.Value.Contains(assetBundleName);
if (isDependency)
{
break;
}
}
return isDependency;
}
private void CacheDependency(string assetBundleName, string[] assetBundleNameArray)
{
assetBundleName = assetBundleName.ToLower();
if (!IsCacheDependency(assetBundleName))
{
for (int i = 0; i < assetBundleNameArray.Length; i++)
{
assetBundleNameArray[i] = assetBundleNameArray[i].ToLower();
}
_cacheDependencyDict.Add(assetBundleName, assetBundleNameArray);
}
}
private void UnCacheDependency(string assetBundleName)
{
assetBundleName = assetBundleName.ToLower();
if (IsCacheDependency(assetBundleName))
{
_cacheDependencyDict.Remove(assetBundleName);
}
}
private string[] GetCacheDependency(string assetBundleName)
{
assetBundleName = assetBundleName.ToLower();
string[] dependencyList = { };
if (IsCacheDependency(assetBundleName))
{
dependencyList = _cacheDependencyDict[assetBundleName];
}
return dependencyList;
}
#endregion
#endregion
#region AssetBundle文件
private void CacheAssetBundle(string assetBundleName, ZooMatchInfo assetBundleInfoV,
bool isDependency = false)
{
assetBundleName = assetBundleName.ToLower();
if (IsCacheAssetBundle(assetBundleName))
{
if (isDependency)
{
}
else
{
return;
}
}
else
{
_cacheAssetBundleInfoDict.Add(assetBundleName, assetBundleInfoV);
}
}
private void UnCacheAssetBundle(string assetBundleName)
{
if (IsCacheAssetBundle(assetBundleName))
{
_cacheAssetBundleInfoDict.Remove(assetBundleName.ToLower());
}
else
{
}
}
private ZooMatchInfo GetCacheAssetBundle(string assetBundleName)
{
ZooMatchInfo assetBundle = null;
if (IsCacheAssetBundle(assetBundleName))
{
assetBundle = _cacheAssetBundleInfoDict[assetBundleName.ToLower()];
}
else
{
}
return assetBundle;
}
private bool IsCacheAssetBundle(string assetBundleName)
{
assetBundleName = assetBundleName.ToLower();
if (_cacheAssetBundleInfoDict == null)
{
return false;
}
return _cacheAssetBundleInfoDict.ContainsKey(assetBundleName);
}
#endregion
#region AssetBundle相关
#region AssetBundle相关信息管理
private bool WaitUnload(ZooMatchInfo assetBundleInfoV)
{
var isInWait = IsWaitUnload(assetBundleInfoV.assetBundleName);
if (isInWait) return true;
assetBundleInfoV.UpdateWaitUnloadCurrentTime();
_waitUnloadList.Add(assetBundleInfoV);
return false;
}
private bool IsWaitUnloadKey(string assetBundleName)
{
var isWaitUnload = false;
if (_waitUnloadList == null || _waitUnloadList.Count <= 0) return false;
foreach (var bundleInfo in _waitUnloadList)
{
if (bundleInfo == null || !string.IsNullOrEmpty(bundleInfo.assetBundleName)) continue;
if (!bundleInfo.assetBundleName.Equals(assetBundleName)) continue;
isWaitUnload = true;
break;
}
return isWaitUnload;
}
private bool IsWaitUnload(string assetBundleName)
{
var isWaitUnload = false;
if (_waitUnloadList == null || _waitUnloadList.Count == 0) return false;
if (!IsWaitUnloadKey(assetBundleName))
{
foreach (var waitUnloadAssetBundle in _waitUnloadList)
{
if (waitUnloadAssetBundle == null ||
!string.IsNullOrEmpty(waitUnloadAssetBundle.assetBundleName)) continue;
isWaitUnload = GetABDependency(waitUnloadAssetBundle.assetBundleName).Contains(assetBundleName);
if (isWaitUnload)
{
break;
}
}
}
else
{
isWaitUnload = true;
}
return isWaitUnload;
}
private bool UnWaitUnload(string assetBundleName)
{
var isRemove = false;
foreach (var bundleInfo in _waitUnloadList)
{
if (bundleInfo == null) continue;
if (!bundleInfo.assetBundleName.Equals(assetBundleName)) continue;
isRemove = _waitUnloadList.Remove(bundleInfo);
break;
}
return isRemove;
}
#endregion
public void UnloadAssetBundle(string assetBundleName,
bool ignoreDependency = false,
int unloadWaitTime = 0,
Action<bool> onCompleted = null)
{
if (string.IsNullOrEmpty(assetBundleName))
{
onCompleted?.Invoke(false);
return;
}
bool unloadSucceed;
if (IsCacheAssetBundle(assetBundleName))
{
var abInfo = GetCacheAssetBundle(assetBundleName);
if (abInfo == null)
{
onCompleted?.Invoke(false);
return;
}
if (WaitUnload(abInfo) && !ignoreDependency)
{
unloadSucceed = false;
UnCacheDependency(assetBundleName);
onCompleted?.Invoke(unloadSucceed);
}
else
{
CrazyAsyKit.StopAction(assetBundleName + "Unload");
CrazyAsyKit.StartAction(assetBundleName + "Unload", delegate
{
unloadSucceed = IsCacheAssetBundle(assetBundleName) &&
UnloadAssetBundleInternal(assetBundleName, ignoreDependency);
UnWaitUnload(assetBundleName);
#if UNITY_EDITOR
#endif
onCompleted?.Invoke(unloadSucceed);
}, unloadWaitTime);
}
}
else
{
onCompleted?.Invoke(false);
}
}
private bool UnloadAssetBundleInternal(string assetBundleName, bool isIgnoreDependency = false,
bool isThorough = false)
{
var LoveLegendInfo = GetCacheAssetBundle(assetBundleName);
if (LoveLegendInfo == null)
{
return false;
}
var dependencyArray = GetCacheDependency(assetBundleName);
UnCacheDependency(assetBundleName);
if (!isIgnoreDependency)
{
if (IsOtherDependency(assetBundleName))
{
return false;
}
}
UnCacheAssetBundle(assetBundleName);
LoveLegendInfo.Unload(isThorough);
foreach (var dependencyAssetBundleName in dependencyArray)
{
if (dependencyAssetBundleName == assetBundleName)
{
continue;
}
if (!IsOtherDependency(dependencyAssetBundleName))
{
UnloadAssetBundleInternal(dependencyAssetBundleName, false, isThorough);
}
else
{
}
}
return true;
}
#endregion
#endregion
#region
public T GetAsset<T>(string assetBundleName, string assetName) where T : Object
{
var assetBundlePath = GenerateAssetBundlePath(assetBundleName);
var assetBundle = GetAssetBundle(assetBundlePath, assetBundleName);
return assetBundle.LoadAsset<T>(assetName);
}
public void GetAsset<T>(string assetBundleName, string assetName, UnityAction<T> onCompleted) where T : Object
{
LoadAssetInternal(assetBundleName, delegate (AssetBundle bundle)
{
if (bundle == null)
{
Debug.LogError("加载AssetBundle 失败:" + assetBundleName);
}
else
{
CrazyAsyKit.StartCoroutine(LoadAssetFromAssetBundle(bundle, assetName, onCompleted));
}
});
}
public void InitManifest(string assetBundleManifestName, UnityAction<bool> onCompleted)
{
CrazyAsyKit.StopAction(assetBundleManifestName + "Unload");
if (UnWaitUnload(assetBundleManifestName))
{
}
var assetBundles =
AssetBundle.LoadFromFile($"{ZooMatchFileKit.GetFilePath()}{ZooMatchConstant.undles}");
var manifest = assetBundles.LoadAsset<AssetBundleManifest>("assetbundlemanifest");
_manifest = manifest;
onCompleted?.Invoke(manifest != null);
}
#endregion
public void RecycleAssetBundle(string assetBundleName, UnityAction onCompleted = null)
{
if (IsCacheAssetBundle(assetBundleName))
{
var abInfo = GetCacheAssetBundle(assetBundleName);
abInfo.UnReferenced(assetBundleName);
RecycleAssetBundleDependency(assetBundleName, UnloadWaitTime);
if (abInfo.GetReferenced() <= 0)
{
UnloadAssetBundle(assetBundleName, false, UnloadWaitTime);
}
}
onCompleted?.Invoke();
}
private void RecycleAssetBundleDependency(string abName, int waitTime)
{
var otherAbName = GetCacheDependency(abName);
if (otherAbName.Length <= 0) return;
foreach (var dependAbName in otherAbName)
{
if (dependAbName == abName) continue;
var dependAbInfo = GetCacheAssetBundle(dependAbName);
if (dependAbInfo == null) continue;
dependAbInfo.UnReferenced(abName);
if (dependAbInfo.GetReferenced() <= 0)
{
UnloadAssetBundle(dependAbName, false, waitTime);
}
}
}
#region
private string GenerateAssetBundlePath(string assetBundleName, bool isMD5 = false, bool isManifest = false,
bool isAddABSuffix = true)
{
var fileName = assetBundleName.ToLower();
if (isMD5)
{
fileName = MD5String(fileName) + ".data";
}
var filePath = _assetBundleRootPath.Replace("file:///", "") + assetBundleName.ToLower();
if (isAddABSuffix)
{
filePath += ZooMatchConstant.setbun;
}
if (!isManifest)
return filePath;
if (File.Exists(filePath))
{
return filePath;
}
return filePath;
}
private static string MD5String(string str)
{
using var md5 = MD5.Create();
var hash = md5.ComputeHash(Encoding.GetEncoding("utf-8").GetBytes(str));
var tmp = new StringBuilder();
foreach (var i in hash)
{
tmp.Append(i.ToString("x2"));
}
return tmp.ToString();
}
#endregion
public void RecycleAsset(string assetUrl, UnityAction onCompleted)
{
RecycleAssetBundle(assetUrl, onCompleted);
}
private AssetBundleManifest GetManifest()
{
if (_manifest == null)
{
Debug.LogError("AssetBundleManifest is null");
var assetBundles =
AssetBundle.LoadFromFile($"{ZooMatchFileKit.GetFilePath()}{ZooMatchConstant.undles}");
var manifest = assetBundles.LoadAsset<AssetBundleManifest>("assetbundlemanifest");
_manifest = manifest;
}
return _manifest;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0049894e09758c34fb23600e4571504e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+10
View File
@@ -0,0 +1,10 @@
namespace ZooMatch
{
public enum ZooMatchState
{
STATE_NONE,
STATE_LOADING,
STATE_LOADED,
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5e6f867b844a92f4e8799eeb338a9aa2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: