JD2022-TU1/main/phone_apps/JDCompanionApp/Assets/Scripts/ResourceLoading/Manager.cs

249 lines
8.4 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Network;
using UnityEngine;
namespace ResourceLoading
{
public delegate void OnResourceLoaded(Resource loadedResource);
public class Manager : MonoBehaviour
{
#region members
public GameObject _resourceLoadWorkerPrefab;
private static Manager _instance = null;
private Cache _resourceCache = new Cache();
private Loader _resourceLoader = new Loader();
private List<PendingOpData> _pendingOps = new List<PendingOpData>();
private const int _loadWokersCount = 4;
private List<GameObject> _loadWorkers = new List<GameObject>();
#endregion
#region public interface
public static Manager Get() { return _instance; }
public Resource NewResource(string uri, Resource.EType type, bool permanent = false)
{
Resource res = null;
if (_resourceCache.FindResource(uri, out res))
{
if (res.Type != type)
{
Debug.LogError("Resource type mismatch: requested " +
uri + " with type " + type + " but in cache it exists with type " + res.Type);
res = null;
}
else
{
res.incRefCount();
}
}
else
{
res = new Resource(uri, type);
_resourceCache.AddResource(uri, res, permanent);
}
return res;
}
public void ReleaseResource(Resource resource)
{
resource.decRefCount();
if (resource.RefCount == 0 && !resource.HasPendingOps)
{
resource.HasPendingOps = true;
_pendingOps.Add(new PendingOpData { _resource = resource, _onLoadedCbChain = null });
}
}
public void LoadResource(Resource resource, OnResourceLoaded onLoadedCb)
{
resource.incLoadCount();
if (!resource.HasPendingOps)
{
resource.HasPendingOps = true;
_pendingOps.Add(new PendingOpData { _resource = resource, _onLoadedCbChain = onLoadedCb });
}
else
{
var pendingOpsForRes = _pendingOps.Where(item => item._resource == resource).ToList();
foreach (var item in pendingOpsForRes) { item._onLoadedCbChain += onLoadedCb; }
}
}
public void UnloadResource(Resource resource, OnResourceLoaded onLoadedCb)
{
resource.decLoadCount();
if (!resource.HasPendingOps)
{
resource.HasPendingOps = true;
_pendingOps.Add(new PendingOpData { _resource = resource, _onLoadedCbChain = null });
}
else
{
var pendingOpsForRes = _pendingOps.Where(item => item._resource == resource).ToList();
foreach (var item in pendingOpsForRes) { item._onLoadedCbChain -= onLoadedCb; }
}
}
public ConsoleServer ResourceServer
{
get { return _resourceLoader.ResourceServer; }
set { _resourceLoader.ResourceServer = value; }
}
public void Awake()
{
if (_instance == null)
{
_instance = this;
// clean resource cache
string resourceCachePath = Application.temporaryCachePath;
if (System.IO.Directory.Exists(resourceCachePath))
{
CleanCacheFolder(resourceCachePath);
}
// instantiate load workers
for (int i = 0; i < _loadWokersCount; ++i)
{
GameObject gao = Instantiate(_resourceLoadWorkerPrefab);
gao.transform.SetParent(gameObject.transform);
_loadWorkers.Add(gao);
LoadWorker worker = gao.GetComponent<LoadWorker>();
_resourceLoader.AddWorker(worker);
}
}
else
{
Debug.LogError("JDCompanionApp.Resources.Manager created twice!");
}
}
private static bool CleanCacheFolder(string path)
{
try
{
foreach (var subFolder in Directory.GetDirectories(path))
{
if (CleanCacheFolder(subFolder))
Directory.Delete(subFolder);
}
foreach (var file in Directory.GetFiles(path))
{
FileInfo fileInfo = new FileInfo(file);
if ((DateTime.Now - fileInfo.LastAccessTime).Days / 30 > 3) // if file is unused for more than 3 months
File.Delete(file);
}
return (Directory.GetFiles(path).Length == 0) && (Directory.GetDirectories(path).Length == 0);
}
catch (Exception e)
{
Debug.Log("Skipping folder " + path + " (" + e.Message + ")");
return false;
}
}
// Update is called once per frame
public void Update()
{
_resourceLoader.Update();
ProcessPendingOps();
}
#endregion
#region implementation
private void ProcessPendingOps()
{
foreach (var item in _pendingOps)
{
Resource resource = item._resource;
switch (resource.State)
{
case Resource.EState.Idle:
// resource needs load?
if (resource.LoadCount > 0 && resource.UnityResource == null)
{
_resourceLoader.LoadResource(resource);
}
// resource needs unload?
else if (resource.LoadCount == 0 && resource.UnityResource != null)
{
_resourceLoader.UnloadResource(resource);
}
// resource is loaded?
else if (resource.LoadCount > 0 && resource.UnityResource != null)
{
if (item._onLoadedCbChain != null)
item._onLoadedCbChain(resource);
// will remove from pending
resource.HasPendingOps = false;
item._resource = null;
}
// resource needs destruction?
else if (resource.RefCount == 0)
{
// will remove from pending
resource.HasPendingOps = false;
item._resource = null;
_resourceCache.RemoveResource(resource.URI);
}
else
{
// nothing else to do, remove from pending
resource.HasPendingOps = false;
item._resource = null;
}
break;
case Resource.EState.Error:
if (resource.LoadCount > 0)
{
if (item._onLoadedCbChain != null)
item._onLoadedCbChain(resource);
// will remove from pending
resource.HasPendingOps = false;
item._resource = null;
}
// resource needs unload?
else if (resource.LoadCount == 0)
{
_resourceLoader.UnloadResource(resource);
}
break;
}
}
// remove all items which have been completely processed (item._resource == null)
_pendingOps.RemoveAll(item => item._resource == null);
}
private class PendingOpData
{
public Resource _resource;
public OnResourceLoaded _onLoadedCbChain;
}
#endregion
}
} // namespace JDCompanionApp.Resources