Last active
April 4, 2019 03:47
-
-
Save ifshuaishuai/74b616c5f282a2efb9decea44d3b6d2b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using RSG; | |
using UnityEngine; | |
using UnityEngine.Assertions; | |
using System.IO; | |
using System.Runtime.InteropServices; | |
using Object = UnityEngine.Object; | |
using System.Text; | |
public class NetworkTextureManager | |
{ | |
public const int DEFAULT_LIST_SIZE = 32; | |
private static NetworkTextureManager _instance; | |
public static NetworkTextureManager Instance | |
{ | |
get | |
{ | |
if(_instance == null) | |
{ | |
_instance = new NetworkTextureManager(); | |
} | |
return _instance; | |
} | |
} | |
private NetworkTextureManager() | |
{ } | |
abstract class WWWResource | |
{ | |
public Object asset; | |
public abstract void GenerateAsset(WWW www); | |
public abstract void Destroy(); | |
} | |
class WWWTexture : WWWResource | |
{ | |
public override void GenerateAsset(WWW www) | |
{ | |
Assert.IsNotNull(www); | |
Assert.IsTrue(string.IsNullOrEmpty(www.error)); | |
asset = www.texture; | |
} | |
public override void Destroy() | |
{ | |
if (asset) | |
{ | |
Object.Destroy(asset); | |
} | |
} | |
} | |
class WWWWrapper | |
{ | |
class RefData | |
{ | |
public object owner; | |
public List<int> internalRefList = new List<int>(1); | |
} | |
public string path; | |
public WWWResource asset; | |
public bool loadDone; | |
public List<Action> loadDoneAction; | |
private List<RefData> _referenceList = new List<RefData>(DEFAULT_LIST_SIZE); | |
public override string ToString() | |
{ | |
var sb = new StringBuilder(); | |
for(int i=0, length=_referenceList.Count ; i<length; ++i) | |
{ | |
sb.Append(string.Format("\nowner: {0}, refCount: {1}", _referenceList[i].owner, _referenceList[i].internalRefList.Count)); | |
} | |
return string.Format("path: {0} loadDone: {1}, RefList: {2}", path, loadDone, sb.ToString()); | |
} | |
private RefData FindRefData(object owner) | |
{ | |
for (int i = 0, length = _referenceList.Count; i < length; ++i) | |
{ | |
RefData refData = _referenceList[i]; | |
if (refData.owner.Equals(owner)) | |
{ | |
return refData; | |
} | |
} | |
return null; | |
} | |
public void DestroyAllReference() | |
{ | |
_referenceList.Clear(); | |
} | |
public void DestroyReference(object owner) | |
{ | |
RefData refData = FindRefData(owner); | |
Assert.IsNotNull(refData); | |
Assert.IsTrue(refData.internalRefList.Count > 0); | |
refData.internalRefList.RemoveAt(0); // remove first internal id | |
if (refData.internalRefList.Count == 0) | |
{ | |
bool removed = _referenceList.Remove(refData); | |
Assert.IsTrue(removed, string.Format("remove {0} is not exist", owner)); | |
} | |
} | |
public void AddReference(object owner, int id) | |
{ | |
RefData refData = FindRefData(owner); | |
if (refData == null) | |
{ | |
refData = new RefData { owner = owner }; | |
refData.internalRefList.Add(id); | |
_referenceList.Add(refData); | |
} | |
else | |
{ | |
Assert.IsNotNull(refData.internalRefList); | |
Assert.IsFalse(refData.internalRefList.Contains(id)); | |
refData.internalRefList.Add(id); | |
} | |
} | |
public bool IsAllDestroyed() | |
{ | |
return _referenceList.Count == 0; | |
} | |
public bool IsContainTarget(object owner, int id) | |
{ | |
RefData refData = FindRefData(owner); | |
return refData != null && refData.internalRefList.Contains(id); | |
} | |
public int GetReferenceCount() | |
{ | |
int refCount = 0; | |
for (int i = 0, length = _referenceList.Count; i < length; ++i) | |
{ | |
refCount += _referenceList[i].internalRefList.Count; | |
} | |
return refCount; | |
} | |
} | |
private Dictionary<string, WWWWrapper> _wwwWrappers = new Dictionary<string, WWWWrapper>(); | |
public int GetWWWWrappersCount(string path) | |
{ | |
WWWWrapper wrapper; | |
if (_wwwWrappers.TryGetValue(path, out wrapper)) | |
{ | |
return wrapper.GetReferenceCount(); | |
} | |
else | |
{ | |
return 0; | |
} | |
} | |
public void DestroyWWW(string path, object owner) | |
{ | |
WWWWrapper wrapper; | |
if (_wwwWrappers.TryGetValue(path, out wrapper)) | |
{ | |
wrapper.DestroyReference(owner); | |
if (wrapper.IsAllDestroyed()) | |
{ | |
DestroyAllWWW(path); | |
} | |
} | |
else | |
{ | |
throw new Exception(string.Format("DestroyWWW path: {0} owner: {1}", path, owner)); | |
} | |
} | |
private void DestroyAllWWW(string path) | |
{ | |
WWWWrapper wrapper = null; | |
if (_wwwWrappers.TryGetValue(path, out wrapper)) | |
{ | |
if (wrapper.loadDone) | |
{ | |
wrapper.asset.Destroy(); | |
_wwwWrappers.Remove(path); | |
} | |
else | |
{ | |
wrapper.DestroyAllReference(); | |
} | |
} | |
else | |
{ | |
throw new Exception("WWW not found"); | |
} | |
} | |
public IPromise<Texture> GetWWWTexture(string path, object owner) | |
{ | |
WWWWrapper wwwWrapper = null; | |
int id = GetNextIDWWW(); | |
if (_wwwWrappers.TryGetValue(path, out wwwWrapper)) | |
{ | |
wwwWrapper.AddReference(owner, id); | |
if (wwwWrapper.loadDone) | |
{ | |
return RetriveWWW(wwwWrapper, path, owner, id); | |
} | |
else | |
{ | |
return DelayRetriveWWW(wwwWrapper, path, owner, id); | |
} | |
} | |
else | |
{ | |
return BrandNewLoadWWW(path, owner, id); | |
} | |
} | |
private IPromise<Texture> RetriveWWW(WWWWrapper wwwWrapper, string path, object owner, int id) | |
{ | |
var promise = new Promise<Texture>(); | |
var asset = wwwWrapper.asset.asset; | |
if (asset) | |
{ | |
if (IsTargetDestroyed(wwwWrapper, owner, id)) | |
{ | |
promise.Reject(new TargetDestroyedException(null, owner)); | |
} | |
else | |
{ | |
Texture result = asset as Texture; | |
if (result) | |
{ | |
promise.Resolve(result); | |
} | |
else | |
{ | |
promise.Reject(new WWWAssetException(path)); | |
} | |
} | |
} | |
else | |
{ | |
promise.Reject(new UnknownException("WWW Asset dead: " + path)); | |
} | |
return promise; | |
} | |
private void AddLoadDoneAction<T>(Promise<T> promise, WWWWrapper wwwWrapper, string path, object owner, int id) where T : Object | |
{ | |
Action loadDoneAction = new Action(() => | |
{ | |
T asset = wwwWrapper.asset.asset as T; | |
if (wwwWrapper.IsAllDestroyed()) | |
{ | |
promise.Reject(new LoadDoneAndDestroyAllException()); | |
} | |
else if (IsTargetDestroyed(wwwWrapper, owner, id)) | |
{ | |
promise.Reject(new TargetDestroyedException(null, owner)); | |
} | |
else if (!wwwWrapper.IsContainTarget(owner, id)) | |
{ | |
promise.Reject(new LoadDoneAndDestroyMainException()); | |
} | |
else | |
{ | |
T result = asset; | |
if (result) | |
{ | |
promise.Resolve(result); | |
} | |
else | |
{ | |
promise.Reject(new WWWAssetException(path)); | |
} | |
} | |
}); | |
wwwWrapper.loadDoneAction.Add(loadDoneAction); | |
} | |
private IPromise<Texture> DelayRetriveWWW(WWWWrapper wwwWrapper, string path, object owner, int id) | |
{ | |
var promise = new Promise<Texture>(); | |
AddLoadDoneAction(promise, wwwWrapper, path, owner, id); | |
return promise; | |
} | |
private IPromise<Texture> BrandNewLoadWWW(string path, object owner, int id) | |
{ | |
var promise = new Promise<Texture>(); | |
var wwwWrapper = new WWWWrapper() | |
{ | |
path = path, | |
asset = new WWWTexture(), | |
loadDone = false, | |
loadDoneAction = new List<Action>(DEFAULT_LIST_SIZE), | |
}; | |
wwwWrapper.AddReference(owner, id); | |
AddLoadDoneAction(promise, wwwWrapper, path, owner, id); | |
_wwwWrappers.Add(path, wwwWrapper); | |
CoroutineStarter.Instance.StartCoroutine(GetWWWInternal(path)); | |
return promise; | |
} | |
private IEnumerator GetWWWInternal(string path) | |
{ | |
var www = new WWW(path); | |
while (!www.isDone) | |
{ | |
yield return null; | |
} | |
if (string.IsNullOrEmpty(www.error)) | |
{ | |
var wrapper = _wwwWrappers[path]; | |
Assert.IsNotNull(wrapper); | |
if (wrapper.IsAllDestroyed()) | |
{ | |
www.Dispose(); | |
} | |
else | |
{ | |
wrapper.asset.GenerateAsset(www); | |
www.Dispose(); | |
} | |
wrapper.loadDone = true; | |
if (wrapper.loadDoneAction != null) | |
{ | |
for (int i = 0, length = wrapper.loadDoneAction.Count; i < length; ++i) | |
{ | |
wrapper.loadDoneAction[i](); | |
} | |
wrapper.loadDoneAction = null; | |
} | |
if (wrapper.IsAllDestroyed()) | |
{ | |
wrapper.asset.Destroy(); | |
_wwwWrappers.Remove(path); | |
} | |
} | |
else | |
{ | |
www.Dispose(); | |
} | |
} | |
private static bool IsTargetDestroyed(WWWWrapper wrapper, object owner, int id) | |
{ | |
return !wrapper.IsContainTarget(owner, id); | |
} | |
private static int _idWWW = 0; | |
private static int GetNextIDWWW() | |
{ | |
_idWWW = _idWWW + 1; | |
return _idWWW; | |
} | |
public void DumpStatus() | |
{ | |
foreach(var item in _wwwWrappers) | |
{ | |
Debug.LogWarning(item.Value.ToString()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment