Instance是用Asset克隆出来的
ResourceEntity描述的是在内存种的信息,窗体是通过ResourceEntity的Target来克隆出来的,两者的对应关系存在InstanceReourceDic中,每克隆出一个实体,就存在一个Id
资源实体的依赖关系,通过Assetinfo.json解析出来的是AssetEntity,就是下面的信息,只是存的信息
/// <summary>
/// Asset实体
/// </summary>
public class AssetEntity
{
/// <summary>
/// 资源分类
/// </summary>
public AssetCategory Category;
/// <summary>
/// 资源名称
/// </summary>
public string AssetName;
/// <summary>
/// 资源完整名称(路径)
/// </summary>
public string AssetFullName;
/// <summary>
/// 所属资源包(这个资源在哪一个Assetbundle里)
/// </summary>
public string AssetBundleName;
/// <summary>
/// 依赖资源
/// </summary>
public List<AssetDependsEntity> DependsAssetList;
}
ResourceEntity,是从bundle中load出来的对象,存的具体的内容,比如资源被引用了多少次,上次使用的时间,关联的目标
/// <summary>
/// 资源实体(AssetBundle和Asset)
/// </summary>
public class ResourceEntity
{
/// <summary>
/// 资源名称
/// </summary>
public string ResourceName;
/// <summary>
/// 资源分类(用于Asset)
/// </summary>
public AssetCategory Category;
/// <summary>
/// 是否AssetBundle
/// </summary>
public bool IsAssetBundle;
/// <summary>
/// 关联目标
/// </summary>
public object Target;
/// <summary>
/// 上次使用时间
/// </summary>
private float m_LastUseTime;
/// <summary>
/// 引用计数
/// </summary>
public int ReferenceCount { get; private set; }
/// <summary>
/// 依赖的资源实体链表
/// </summary>
public LinkedList<ResourceEntity> DependsResourceList { get; private set; }
public ResourceEntity()
{
DependsResourceList = new LinkedList<ResourceEntity>();
}
/// <summary>
/// 对象取池
/// </summary>
public void Spawn()
{
//取池的时候设置一下最后使用时间
m_LastUseTime = Time.time;
if (!IsAssetBundle)
{
//如果不是assetbundle,引用计数加1
ReferenceCount++;
}
else
{
//如果是锁定的资源包 不释放
if (GameEntry.Pool.CheckAssetBundleIsLock(ResourceName))
{
ReferenceCount = 1;
}
}
}
/// <summary>
/// 对象回池
/// </summary>
public void Unspawn()
{
m_LastUseTime = Time.time;
ReferenceCount--;
if (ReferenceCount < 0)
{
ReferenceCount = 0;
}
}
/// <summary>
/// 对象是否可以释放
/// </summary>
/// <returns></returns>
public bool GetCanRelease()
{
//引用计数为0,并且超出时间间隔
if (ReferenceCount == 0 && Time.time - m_LastUseTime > GameEntry.Pool.ReleaseResourceInterval)
{
return true;
}
return false;
}
/// <summary>
/// 释放资源
/// </summary>
public void Release()
{
ResourceName = null;
ReferenceCount = 0;
if (IsAssetBundle)
{
//如果是assetbundle,Target关联的是Assetbundle,要执行bundle.Unload方法
AssetBundle bundle = Target as AssetBundle;
GameEntry.Log(LogCategory.Resource, "卸载了资源包", bundle.name);
bundle.Unload(false);
}
Target = null;
//把依赖的资源实体链表清空
DependsResourceList.Clear();
//同时把这个类对象也回池
GameEntry.Pool.EnqueueClassObject(this);//当前资源实体回池
}
}
加载的时候,把依赖资源加入到链表中,依赖资源数目+1,
加载某个依赖资源完毕后,把依赖的资源实体放入临时链表,目的是加载依赖的时候,把依赖上的依赖也顺便返回。
把克隆出来的资源,加入到实例资源池中
/// <summary>
/// 打开UI窗口
/// </summary>
/// <param name="uiFormId">窗口Id</param>
internal void OpenUIForm(int uiFormId, object userData, BaseAction<UIFormBase> onOpen)
{
//不能重复打开同一个UI窗口
if (IsExists(uiFormId)) return;
//1,读表
Sys_UIFormEntity entity = GameEntry.DataTable.DataTableManager.Sys_UIFormDBModel.GetDic(uiFormId);
if (entity == null)
{
List<Sys_UIFormEntity> lst = GameEntry.DataTable.DataTableManager.Sys_UIFormDBModel.GetList();
Debug.LogError(uiFormId + "对应的UI窗口不存在");
for (int i = 0; i < lst.Count; i++)
{
Debug.LogError(lst[i].AssetPath_Chinese + "==" + lst[i].Id);
}
return;
}
UIFormBase formBase = GameEntry.UI.Dequeue(uiFormId);
if (formBase == null)
{
//TODO:异步加载UI需要时间 此处需要处理过滤加载中的UI
string assetPath = string.Empty;
switch (GameEntry.Localization.CurrLanguage)
{
case YouYouLanguage.Chinese:
assetPath = entity.AssetPath_Chinese;
break;
case YouYouLanguage.English:
assetPath = entity.AssetPath_English;
break;
}
//加载UI资源并克隆
LoadUIAsset(assetPath, (GameObject uiObj) =>
{
uiObj.SetParent(GameEntry.UI.GetUIGroup(entity.UIGroupId).Group);
formBase = uiObj.GetComponent<UIFormBase>();
formBase.Init(uiFormId, entity.UIGroupId, entity.DisableUILayer == 1, entity.IsLock == 1, userData);
m_OpenUIFormList.AddLast(formBase);
if (onOpen != null) onOpen(formBase);
});
}
else
{
formBase.gameObject.SetActive(true);
formBase.Open(userData);
m_OpenUIFormList.AddLast(formBase);
if (onOpen != null) onOpen(formBase);
}
}
/// <summary>
/// 加载UI资源并克隆
/// </summary>
/// <param name="assetPath"></param>
/// <param name="onComplete"></param>
private void LoadUIAsset(string assetPath, BaseAction<GameObject> onComplete)
{
GameEntry.Resource.ResourceLoaderManager.LoadMainAsset(AssetCategory.UIPrefab, string.Format("UI/UIPrefab/{0}.prefab", assetPath), (ResourceEntity resourcesEntity) =>
{
GameObject uiObj = Object.Instantiate((Object)resourcesEntity.Target) as GameObject;
//把克隆出来的资源 加入实体资源池
GameEntry.Pool.RegisterInstanceResource(uiObj.GetInstanceID(), resourcesEntity);
if (onComplete != null) onComplete(uiObj);
});
}
PoolComPonent定义的实力资源字典
实例资源字典,注册,释放,释放的时候先释放依赖,
#region 实例管理和分类资源池释放
/// <summary>
/// 实例字典(克隆出来的)
/// </summary>
private Dictionary<int, ResourceEntity> m_InstanceResourceDic;
/// <summary>
/// 注册到实例字典
/// </summary>
/// <param name="instanceId"></param>
/// <param name="resourcesEntity"></param>
internal void RegisterInstanceResource(int instanceId, ResourceEntity resourcesEntity)
{
GameEntry.Log(LogCategory.Resource, "注册到实例字典instanceId = {0}", instanceId);
m_InstanceResourceDic[instanceId] = resourcesEntity;
}
/// <summary>
/// 释放实例
/// </summary>
/// <param name="instanceId">实例Id</param>
internal void ReleaseInstanceResource(int instanceId)
{
GameEntry.Log(LogCategory.Resource, "释放实例instanceId = {0}", instanceId);
ResourceEntity resourceEntity = null;
if (m_InstanceResourceDic.TryGetValue(instanceId, out resourceEntity))
{
#if ASSETBUNDLE
UnapawnResourceEntity(resourceEntity);
#else
resourceEntity.Target = null;
GameEntry.Pool.EnqueueClassObject(resourceEntity);
#endif
m_InstanceResourceDic.Remove(instanceId);
}
}
/// <summary>
/// 资源实体回池
/// </summary>
/// <param name="entity"></param>
private void UnapawnResourceEntity(ResourceEntity entity)
{
//依赖资源实体 递归回池
var curr = entity.DependsResourceList.First;
while (curr != null)
{
UnapawnResourceEntity(curr.Value);
curr = curr.Next;
}
//自身资源实体 回池
GameEntry.Pool.PoolManager.AssetPool[entity.Category].Unspawn(entity.ResourceName);
}
#endregion
释放调用的地方
关闭界面之后, 先释放UI实例回池,释放类对象池,释放Assetbundle池,然后释放Asset池,时间调过,不是正常释放顺序。