249 lines
8.4 KiB
C#
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
|