190 lines
6.4 KiB
C#
Raw Permalink Normal View History

2025-06-07 17:43:34 +08:00
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FairyGUI.Utils;
namespace FairyGUI
{
public class AsyncCreationHelper
{
public static void CreateObject(PackageItem item, UIPackage.CreateObjectCallback callback)
{
Timers.inst.StartCoroutine(_CreateObject(item, callback));
}
static IEnumerator _CreateObject(PackageItem item, UIPackage.CreateObjectCallback callback)
{
Stats.LatestObjectCreation = 0;
Stats.LatestGraphicsCreation = 0;
float frameTime = UIConfig.frameTimeForAsyncUIConstruction;
List<DisplayListItem> itemList = new List<DisplayListItem>();
DisplayListItem di = new DisplayListItem(item, ObjectType.Component);
di.childCount = CollectComponentChildren(item, itemList);
itemList.Add(di);
int cnt = itemList.Count;
List<GObject> objectPool = new List<GObject>(cnt);
GObject obj;
float t = Time.realtimeSinceStartup;
bool alreadyNextFrame = false;
for (int i = 0; i < cnt; i++)
{
di = itemList[i];
if (di.packageItem != null)
{
obj = UIObjectFactory.NewObject(di.packageItem);
objectPool.Add(obj);
UIPackage._constructing++;
if (di.packageItem.type == PackageItemType.Component)
{
int poolStart = objectPool.Count - di.childCount - 1;
((GComponent)obj).ConstructFromResource(objectPool, poolStart);
objectPool.RemoveRange(poolStart, di.childCount);
}
else
{
obj.ConstructFromResource();
}
UIPackage._constructing--;
}
else
{
obj = UIObjectFactory.NewObject(di.type);
objectPool.Add(obj);
if (di.type == ObjectType.List && di.listItemCount > 0)
{
int poolStart = objectPool.Count - di.listItemCount - 1;
for (int k = 0; k < di.listItemCount; k++) //把他们都放到pool里这样GList在创建时就不需要创建对象了
((GList)obj).itemPool.ReturnObject(objectPool[k + poolStart]);
objectPool.RemoveRange(poolStart, di.listItemCount);
}
}
if ((i % 5 == 0) && Time.realtimeSinceStartup - t >= frameTime)
{
yield return null;
t = Time.realtimeSinceStartup;
alreadyNextFrame = true;
}
}
if (!alreadyNextFrame) //强制至至少下一帧才调用callback避免调用者逻辑出错
yield return null;
callback(objectPool[0]);
}
/// <summary>
/// 收集创建目标对象所需的所有类型信息
/// </summary>
/// <param name="item"></param>
/// <param name="list"></param>
static int CollectComponentChildren(PackageItem item, List<DisplayListItem> list)
{
ByteBuffer buffer = item.rawData;
buffer.Seek(0, 2);
int dcnt = buffer.ReadShort();
DisplayListItem di;
PackageItem pi;
for (int i = 0; i < dcnt; i++)
{
int dataLen = buffer.ReadShort();
int curPos = buffer.position;
buffer.Seek(curPos, 0);
ObjectType type = (ObjectType)buffer.ReadByte();
string src = buffer.ReadS();
string pkgId = buffer.ReadS();
buffer.position = curPos;
if (src != null)
{
UIPackage pkg;
if (pkgId != null)
pkg = UIPackage.GetById(pkgId);
else
pkg = item.owner;
pi = pkg != null ? pkg.GetItem(src) : null;
di = new DisplayListItem(pi, type);
if (pi != null && pi.type == PackageItemType.Component)
di.childCount = CollectComponentChildren(pi, list);
}
else
{
di = new DisplayListItem(null, type);
if (type == ObjectType.List) //list
di.listItemCount = CollectListChildren(buffer, list);
}
list.Add(di);
buffer.position = curPos + dataLen;
}
return dcnt;
}
static int CollectListChildren(ByteBuffer buffer, List<DisplayListItem> list)
{
buffer.Seek(buffer.position, 8);
string defaultItem = buffer.ReadS();
int listItemCount = 0;
int itemCount = buffer.ReadShort();
for (int i = 0; i < itemCount; i++)
{
int nextPos = buffer.ReadShort();
nextPos += buffer.position;
string url = buffer.ReadS();
if (url == null)
url = defaultItem;
if (!string.IsNullOrEmpty(url))
{
PackageItem pi = UIPackage.GetItemByURL(url);
if (pi != null)
{
DisplayListItem di = new DisplayListItem(pi, pi.objectType);
if (pi.type == PackageItemType.Component)
di.childCount = CollectComponentChildren(pi, list);
list.Add(di);
listItemCount++;
}
}
buffer.position = nextPos;
}
return listItemCount;
}
/// <summary>
///
/// </summary>
class DisplayListItem
{
public PackageItem packageItem;
public ObjectType type;
public int childCount;
public int listItemCount;
public DisplayListItem(PackageItem pi, ObjectType type)
{
this.packageItem = pi;
this.type = type;
}
}
}
}