2026-04-22 09:52:55 +08:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using UnityEngine ;
using FairyGUI.Utils ;
// #if UNITY_EDITOR
using UnityEditor ;
2026-04-22 11:13:16 +08:00
using LoveLegend ;
2026-04-22 09:52:55 +08:00
// #endif
namespace FairyGUI
{
/// <summary>
/// A UI Package contains a description file and some texture, sound assets.
/// </summary>
public class UIPackage
{
/// <summary>
/// Unload UIAssetBundle by FairyGUI system.
/// if use AssetBundlesManager set value to false
/// then unload UIAssetBundle by AssetBundlesManager
/// </summary>
public static bool unloadBundleByFGUI = true ;
/// <summary>
/// The event is triggered when all reference to this package item dropped.
/// </summary>
public static event Action < PackageItem > onReleaseResource ;
/// <summary>
/// Package id. It is generated by the Editor.
/// </summary>
public string id { get ; private set ; }
/// <summary>
/// Package name.
/// </summary>
public string name { get ; private set ; }
/// <summary>
/// Use this callback to provide resources to the package.
/// </summary>
/// <param name="name">Resource name without extension.</param>
/// <param name="extension">Resource extension. e.g. '.png' '.wav'</param>
/// <param name="type">Resource type. e.g. 'Texture' 'AudioClip'</param>
/// <param name="destroyMethod">How to destroy this resource.</param>
/// <returns></returns>
public delegate object LoadResource ( string name , string extension , System . Type type ,
out DestroyMethod destroyMethod );
/// <summary>
/// A async load resource callback. After loaded, you should call item.owner.SetItemAsset.
/// </summary>
/// <param name="name">Resource name without extension.</param>
/// <param name="extension">Resource extension. e.g. '.png' '.wav'</param>
/// <param name="type">Resource type. e.g. 'Texture' 'AudioClip'</param>
/// <param name="item">Resource item object.</param>
/// <returns></returns>
public delegate void LoadResourceAsync ( string name , string extension , System . Type type , PackageItem item );
/// <summary>
///
/// </summary>
/// <param name="result"></param>
public delegate void CreateObjectCallback ( GObject result );
List < PackageItem > _items ;
Dictionary < string , PackageItem > _itemsById ;
Dictionary < string , PackageItem > _itemsByName ;
Dictionary < string , string >[] _dependencies ;
string _assetPath ;
string [] _branches ;
internal int _branchIndex ;
AssetBundle _resBundle ;
string _customId ;
bool _fromBundle ;
LoadResource _loadFunc ;
LoadResourceAsync _loadAsyncFunc ;
class AtlasSprite
{
public PackageItem atlas ;
public Rect rect = new Rect ();
public Vector2 offset = new Vector2 ();
public Vector2 originalSize = new Vector2 ();
public bool rotated ;
}
Dictionary < string , AtlasSprite > _sprites ;
static Dictionary < string , UIPackage > _packageInstById = new Dictionary < string , UIPackage >();
static Dictionary < string , UIPackage > _packageInstByName = new Dictionary < string , UIPackage >();
static List < UIPackage > _packageList = new List < UIPackage >();
static string _branch ;
static Dictionary < string , string > _vars = new Dictionary < string , string >();
internal static int _constructing ;
public const string URL_PREFIX = "ui://" ;
#if UNITY_EDITOR
static LoadResource _loadFromAssetsPath =
( string name , string extension , System . Type type , out DestroyMethod destroyMethod ) =>
{
destroyMethod = DestroyMethod . Unload ;
return AssetDatabase . LoadAssetAtPath ( name + extension , type );
};
#endif
static LoadResource _loadFromResourcesPath =
( string name , string extension , System . Type type , out DestroyMethod destroyMethod ) =>
{
destroyMethod = DestroyMethod . Unload ;
// LoadKit.Instance.LoadAsset();
return Resources . Load ( name , type );
};
public UIPackage ()
{
_items = new List < PackageItem >();
_itemsById = new Dictionary < string , PackageItem >();
_itemsByName = new Dictionary < string , PackageItem >();
_sprites = new Dictionary < string , AtlasSprite >();
_branchIndex = - 1 ;
}
/// <summary>
///
/// </summary>
public static string branch
{
get { return _branch ; }
set
{
_branch = value ;
bool empty = string . IsNullOrEmpty ( _branch );
var iter = _packageInstById . GetEnumerator ();
while ( iter . MoveNext ())
{
UIPackage pkg = iter . Current . Value ;
if ( empty )
pkg . _branchIndex = - 1 ;
else if ( pkg . _branches != null )
pkg . _branchIndex = Array . IndexOf ( pkg . _branches , value );
}
iter . Dispose ();
}
}
/// <summary>
///
/// </summary>
public static string GetVar ( string key )
{
string value ;
if ( _vars . TryGetValue ( key , out value ))
return value ;
else
return null ;
}
/// <summary>
///
/// </summary>
public static void SetVar ( string key , string value )
{
if ( value == null )
_vars . Remove ( key );
else
_vars [ key ] = value ;
}
/// <summary>
/// Return a UIPackage with a certain id.
/// </summary>
/// <param name="id">ID of the package.</param>
/// <returns>UIPackage</returns>
public static UIPackage GetById ( string id )
{
UIPackage pkg ;
if ( _packageInstById . TryGetValue ( id , out pkg ))
return pkg ;
else
return null ;
}
/// <summary>
/// Return a UIPackage with a certain name.
/// </summary>
/// <param name="name">Name of the package.</param>
/// <returns>UIPackage</returns>
public static UIPackage GetByName ( string name )
{
UIPackage pkg ;
if ( _packageInstByName . TryGetValue ( name , out pkg ))
return pkg ;
else
return null ;
}
/// <summary>
/// Add a UI package from assetbundle.
/// </summary>
/// <param name="bundle">A assetbundle.</param>
/// <returns>UIPackage</returns>
public static UIPackage AddPackage ( AssetBundle bundle )
{
return AddPackage ( bundle , bundle , null );
}
/// <summary>
/// Add a UI package from two assetbundles. desc and res can be same.
/// </summary>
/// <param name="desc">A assetbunble contains description file.</param>
/// <param name="res">A assetbundle contains resources.</param>
/// <returns>UIPackage</returns>
public static UIPackage AddPackage ( AssetBundle desc , AssetBundle res )
{
return AddPackage ( desc , res , null );
}
/// <summary>
/// Add a UI package from two assetbundles with a optional main asset name.
/// </summary>
/// <param name="desc">A assetbunble contains description file.</param>
/// <param name="res">A assetbundle contains resources.</param>
/// <param name="mainAssetName">Main asset name. e.g. Basics_fui</param>
/// <returns>UIPackage</returns>
public static UIPackage AddPackage ( AssetBundle desc , AssetBundle res , string mainAssetName )
{
byte [] source = null ;
if (! string . IsNullOrEmpty ( mainAssetName ))
{
TextAsset ta = desc . LoadAsset < TextAsset >( mainAssetName );
if ( ta != null )
source = ta . bytes ;
}
else
{
string [] names = desc . GetAllAssetNames ();
string searchPattern = "_fui" ;
foreach ( string n in names )
{
if ( n . IndexOf ( searchPattern ) != - 1 )
{
TextAsset ta = desc . LoadAsset < TextAsset >( n );
if ( ta != null )
{
source = ta . bytes ;
mainAssetName = Path . GetFileNameWithoutExtension ( n );
break ;
}
}
}
}
if ( source == null )
throw new Exception ( "FairyGUI: no package found in this bundle." );
if ( unloadBundleByFGUI && desc != res )
desc . Unload ( true );
ByteBuffer buffer = new ByteBuffer ( source );
UIPackage pkg = new UIPackage ();
pkg . _resBundle = res ;
pkg . _fromBundle = true ;
int pos = mainAssetName . IndexOf ( "_fui" );
if ( pos != - 1 )
mainAssetName = mainAssetName . Substring ( 0 , pos );
if (! pkg . LoadPackage ( buffer , mainAssetName ))
return null ;
_packageInstById [ pkg . id ] = pkg ;
_packageInstByName [ pkg . name ] = pkg ;
_packageList . Add ( pkg );
return pkg ;
}
/*public static UIPackage AddPackage(byte[] source, string assetName, LoadResource loadFunc)
{
ByteBuffer buffer = new ByteBuffer(source);
UIPackage pkg = new UIPackage();
if (!pkg.LoadPackage(buffer, assetName))
return null;
_packageInstById[pkg.id] = pkg;
_packageInstByName[pkg.name] = pkg;
_packageList.Add(pkg);
pkg._loadFunc = loadFunc;
return pkg;
}*/
/// <summary>
/// Add a UI package from a path relative to Unity Resources path.
/// </summary>
/// <param name="descFilePath">Path relative to Unity Resources path.</param>
/// <returns>UIPackage</returns>
public static UIPackage AddPackage ( string descFilePath )
{
if ( descFilePath . StartsWith ( "Assets/" ))
{
#if UNITY_EDITOR
return AddPackage ( descFilePath , _loadFromAssetsPath );
#else
Debug . LogWarning ( "FairyGUI: failed to load package in '" + descFilePath + "'" );
return null ;
#endif
}
else
return AddPackage ( descFilePath , _loadFromResourcesPath );
}
/// <summary>
/// 使用自定义的加载方式载入一个包。
/// </summary>
/// <param name="assetPath">包资源路径。</param>
/// <param name="loadFunc">载入函数</param>
/// <returns></returns>
public static UIPackage AddPackage ( string assetPath , LoadResource loadFunc )
{
if ( _packageInstById . ContainsKey ( assetPath ))
return _packageInstById [ assetPath ];
DestroyMethod dm ;
TextAsset asset = ( TextAsset ) loadFunc ( assetPath + "_fui" , ".bytes" , typeof ( TextAsset ), out dm );
if ( asset == null )
{
if ( Application . isPlaying )
{
// throw new Exception("FairyGUI: Cannot load ui package in '" + assetPath + "'");
}
else
Debug . LogWarning ( "FairyGUI: Cannot load ui package in '" + assetPath + "'" );
}
ByteBuffer buffer = new ByteBuffer ( asset . bytes );
UIPackage pkg = new UIPackage ();
pkg . _loadFunc = loadFunc ;
pkg . _assetPath = assetPath ;
if (! pkg . LoadPackage ( buffer , assetPath ))
return null ;
_packageInstById [ pkg . id ] = pkg ;
_packageInstByName [ pkg . name ] = pkg ;
_packageInstById [ assetPath ] = pkg ;
_packageList . Add ( pkg );
return pkg ;
}
/// <summary>
/// Load Package by custom load method.
/// </summary>
/// <param name="descData">Description file data</param>
/// <param name="assetNamePrefix">Prefix of the resource file name. The file name would be in format of 'assetNamePrefix_resFileName'. It can be empty.</param>
/// <param name="loadFunc">Load method</param>
/// <returns></returns>
public static UIPackage AddPackage ( byte [] descData , string assetNamePrefix , LoadResource loadFunc )
{
ByteBuffer buffer = new ByteBuffer ( descData );
UIPackage pkg = new UIPackage ();
pkg . _loadFunc = loadFunc ;
if (! pkg . LoadPackage ( buffer , assetNamePrefix ))
return null ;
_packageInstById [ pkg . id ] = pkg ;
_packageInstByName [ pkg . name ] = pkg ;
_packageList . Add ( pkg );
return pkg ;
}
/// <summary>
/// Load Package async by custom load method.
/// </summary>
/// <param name="descData">Description file data</param>
/// <param name="assetNamePrefix">refix of the resource file name. The file name would be in format of 'assetNamePrefix_resFileName'. It can be empty.</param>
/// <param name="loadFunc">Load method</param>
/// <returns></returns>
public static UIPackage AddPackage ( byte [] descData , string assetNamePrefix , LoadResourceAsync loadFunc )
{
ByteBuffer buffer = new ByteBuffer ( descData );
UIPackage pkg = new UIPackage ();
pkg . _loadAsyncFunc = loadFunc ;
if (! pkg . LoadPackage ( buffer , assetNamePrefix ))
return null ;
_packageInstById [ pkg . id ] = pkg ;
_packageInstByName [ pkg . name ] = pkg ;
_packageList . Add ( pkg );
return pkg ;
}
/// <summary>
/// Remove a package. All resources in this package will be disposed.
/// </summary>
/// <param name="packageIdOrName"></param>
public static void RemovePackage ( string packageIdOrName )
{
UIPackage pkg = null ;
if (! _packageInstById . TryGetValue ( packageIdOrName , out pkg ))
{
if (! _packageInstByName . TryGetValue ( packageIdOrName , out pkg ))
throw new Exception ( "FairyGUI: '" + packageIdOrName + "' is not a valid package id or name." );
}
pkg . Dispose ();
_packageInstById . Remove ( pkg . id );
if ( pkg . _customId != null )
_packageInstById . Remove ( pkg . _customId );
if ( pkg . _assetPath != null )
_packageInstById . Remove ( pkg . _assetPath );
_packageInstByName . Remove ( pkg . name );
_packageList . Remove ( pkg );
}
/// <summary>
///
/// </summary>
public static void RemoveAllPackages ()
{
if ( _packageInstById . Count > 0 )
{
UIPackage [] pkgs = _packageList . ToArray ();
foreach ( UIPackage pkg in pkgs )
{
pkg . Dispose ();
}
}
_packageList . Clear ();
_packageInstById . Clear ();
_packageInstByName . Clear ();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static List < UIPackage > GetPackages ()
{
return _packageList ;
}
/// <summary>
/// Create a UI object.
/// </summary>
/// <param name="pkgName">Package name.</param>
/// <param name="resName">Resource name.</param>
/// <returns>A UI object.</returns>
public static GObject CreateObject ( string pkgName , string resName )
{
UIPackage pkg = GetByName ( pkgName );
if ( pkg != null )
return pkg . CreateObject ( resName );
else
return null ;
}
/// <summary>
/// Create a UI object.
/// </summary>
/// <param name="pkgName">Package name.</param>
/// <param name="resName">Resource name.</param>
/// <param name="userClass">Custom implementation of this object.</param>
/// <returns>A UI object.</returns>
public static GObject CreateObject ( string pkgName , string resName , System . Type userClass )
{
UIPackage pkg = GetByName ( pkgName );
if ( pkg != null )
return pkg . CreateObject ( resName , userClass );
else
return null ;
}
/// <summary>
/// Create a UI object.
/// </summary>
/// <param name="url">Resource url.</param>
/// <returns>A UI object.</returns>
public static GObject CreateObjectFromURL ( string url )
{
PackageItem pi = GetItemByURL ( url );
if ( pi != null )
return pi . owner . CreateObject ( pi , null );
else
return null ;
}
/// <summary>
/// Create a UI object.
/// </summary>
/// <param name="url">Resource url.</param>
/// <param name="userClass">Custom implementation of this object.</param>
/// <returns>A UI object.</returns>
public static GObject CreateObjectFromURL ( string url , System . Type userClass )
{
PackageItem pi = GetItemByURL ( url );
if ( pi != null )
return pi . owner . CreateObject ( pi , userClass );
else
return null ;
}
public static void CreateObjectAsync ( string pkgName , string resName , CreateObjectCallback callback )
{
UIPackage pkg = GetByName ( pkgName );
if ( pkg != null )
pkg . CreateObjectAsync ( resName , callback );
else
Debug . LogError ( "FairyGUI: package not found - " + pkgName );
}
public static void CreateObjectFromURL ( string url , CreateObjectCallback callback )
{
PackageItem pi = GetItemByURL ( url );
if ( pi != null )
AsyncCreationHelper . CreateObject ( pi , callback );
else
Debug . LogError ( "FairyGUI: resource not found - " + url );
}
/// <summary>
/// Get a asset with a certain name.
/// </summary>
/// <param name="pkgName">Package name.</param>
/// <param name="resName">Resource name.</param>
/// <returns>If resource is atlas, returns NTexture; If resource is sound, returns AudioClip.</returns>
public static object GetItemAsset ( string pkgName , string resName )
{
UIPackage pkg = GetByName ( pkgName );
if ( pkg != null )
return pkg . GetItemAsset ( resName );
else
return null ;
}
/// <summary>
/// Get a asset with a certain name.
/// </summary>
/// <param name="url">Resource url.</param>
/// <returns>If resource is atlas, returns NTexture; If resource is sound, returns AudioClip.</returns>
public static object GetItemAssetByURL ( string url )
{
PackageItem item = GetItemByURL ( url );
if ( item == null )
return null ;
return item . owner . GetItemAsset ( item );
}
/// <summary>
/// Get url of an item in package.
/// </summary>
/// <param name="pkgName">Package name.</param>
/// <param name="resName">Resource name.</param>
/// <returns>Url.</returns>
public static string GetItemURL ( string pkgName , string resName )
{
UIPackage pkg = GetByName ( pkgName );
if ( pkg == null )
return null ;
PackageItem pi ;
if (! pkg . _itemsByName . TryGetValue ( resName , out pi ))
return null ;
return URL_PREFIX + pkg . id + pi . id ;
}
public static PackageItem GetItemByURL ( string url )
{
if ( url == null )
return null ;
int pos1 = url . IndexOf ( "//" );
if ( pos1 == - 1 )
return null ;
int pos2 = url . IndexOf ( '/' , pos1 + 2 );
if ( pos2 == - 1 )
{
if ( url . Length > 13 )
{
string pkgId = url . Substring ( 5 , 8 );
UIPackage pkg = GetById ( pkgId );
if ( pkg != null )
{
string srcId = url . Substring ( 13 );
return pkg . GetItem ( srcId );
}
}
}
else
{
string pkgName = url . Substring ( pos1 + 2 , pos2 - pos1 - 2 );
UIPackage pkg = GetByName ( pkgName );
if ( pkg != null )
{
string srcName = url . Substring ( pos2 + 1 );
return pkg . GetItemByName ( srcName );
}
}
return null ;
}
/// <summary>
/// 将'ui://包名/组件名'转换为以内部id表达的url格式。如果传入的url本身就是内部id格式,则直接返回。
/// 同时这个方法还带格式检测,如果传入不正确的url,会返回null。
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public static string NormalizeURL ( string url )
{
if ( url == null )
return null ;
int pos1 = url . IndexOf ( "//" );
if ( pos1 == - 1 )
return null ;
int pos2 = url . IndexOf ( '/' , pos1 + 2 );
if ( pos2 == - 1 )
return url ;
else
{
string pkgName = url . Substring ( pos1 + 2 , pos2 - pos1 - 2 );
string srcName = url . Substring ( pos2 + 1 );
return GetItemURL ( pkgName , srcName );
}
}
/// <summary>
/// Set strings source.
/// </summary>
/// <param name="source"></param>
public static void SetStringsSource ( XML source )
{
TranslationHelper . LoadFromXML ( source );
}
/// <summary>
///
/// </summary>
public string assetPath
{
get { return _assetPath ; }
}
/// <summary>
/// Set a custom id for package, then you can use it in GetById.
/// </summary>
public string customId
{
get { return _customId ; }
set
{
if ( _customId != null )
_packageInstById . Remove ( _customId );
_customId = value ;
if ( _customId != null )
_packageInstById [ _customId ] = this ;
}
}
/// <summary>
///
/// </summary>
public AssetBundle resBundle
{
get { return _resBundle ; }
}
/// <summary>
/// 获得本包依赖的包的id列表
/// </summary>
public Dictionary < string , string >[] dependencies
{
get { return _dependencies ; }
}
bool LoadPackage ( ByteBuffer buffer , string assetNamePrefix )
{
if ( buffer . ReadUint () != 0x46475549 )
{
if ( Application . isPlaying )
throw new Exception ( "FairyGUI: old package format found in '" + assetNamePrefix + "'" );
else
{
Debug . LogWarning ( "FairyGUI: old package format found in '" + assetNamePrefix + "'" );
return false ;
}
}
buffer . version = buffer . ReadInt ();
bool ver2 = buffer . version >= 2 ;
buffer . ReadBool (); //compressed
id = buffer . ReadString ();
name = buffer . ReadString ();
UIPackage existingPkg ;
if ( _packageInstById . TryGetValue ( id , out existingPkg ))
{
if ( name != existingPkg . name )
Debug . LogWarning ( "FairyGUI: Package conflicts, '" + name + "' and '" + existingPkg . name + "'" );
#if UNITY_EDITOR
//maybe multiple pkgs in different folder, pefer the one in resources
if ( Application . isEditor )
{
if ( existingPkg . _loadFunc == _loadFromAssetsPath ) //old one is outside resources path
existingPkg . Dispose (); //replace the existing
else if ( existingPkg . _loadFunc == _loadFromResourcesPath && _loadFunc == _loadFromResourcesPath
&& _assetPath . Length <
existingPkg . _assetPath
. Length ) //both in resources path, pefer short path
existingPkg . Dispose (); //replace the existing
else //keep the existing
return false ;
}
#endif
}
buffer . Skip ( 20 );
int indexTablePos = buffer . position ;
int cnt ;
buffer . Seek ( indexTablePos , 4 );
cnt = buffer . ReadInt ();
string [] stringTable = new string [ cnt ];
for ( int i = 0 ; i < cnt ; i ++)
stringTable [ i ] = buffer . ReadString ();
buffer . stringTable = stringTable ;
if ( buffer . Seek ( indexTablePos , 5 ))
{
cnt = buffer . ReadInt ();
for ( int i = 0 ; i < cnt ; i ++)
{
int index = buffer . ReadUshort ();
int len = buffer . ReadInt ();
stringTable [ index ] = buffer . ReadString ( len );
}
}
buffer . Seek ( indexTablePos , 0 );
cnt = buffer . ReadShort ();
_dependencies = new Dictionary < string , string >[ cnt ];
for ( int i = 0 ; i < cnt ; i ++)
{
Dictionary < string , string > kv = new Dictionary < string , string >();
kv . Add ( "id" , buffer . ReadS ());
kv . Add ( "name" , buffer . ReadS ());
_dependencies [ i ] = kv ;
}
bool branchIncluded = false ;
if ( ver2 )
{
cnt = buffer . ReadShort ();
if ( cnt > 0 )
{
_branches = buffer . ReadSArray ( cnt );
if (! string . IsNullOrEmpty ( _branch ))
_branchIndex = Array . IndexOf ( _branches , _branch );
}
branchIncluded = cnt > 0 ;
}
buffer . Seek ( indexTablePos , 1 );
PackageItem pi ;
string assetPath ;
if ( assetNamePrefix . Length > 0 )
{
assetPath = Path . GetDirectoryName ( assetNamePrefix );
if ( assetPath . Length > 0 )
assetPath += "/" ;
assetNamePrefix = assetNamePrefix + "_" ;
}
else
assetPath = string . Empty ;
cnt = buffer . ReadShort ();
for ( int i = 0 ; i < cnt ; i ++)
{
int nextPos = buffer . ReadInt ();
nextPos += buffer . position ;
pi = new PackageItem ();
pi . owner = this ;
pi . type = ( PackageItemType ) buffer . ReadByte ();
pi . id = buffer . ReadS ();
pi . name = buffer . ReadS ();
buffer . ReadS (); //path
pi . file = buffer . ReadS ();
pi . exported = buffer . ReadBool ();
pi . width = buffer . ReadInt ();
pi . height = buffer . ReadInt ();
switch ( pi . type )
{
case PackageItemType . Image :
{
pi . objectType = ObjectType . Image ;
int scaleOption = buffer . ReadByte ();
if ( scaleOption == 1 )
{
Rect rect = new Rect ();
rect . x = buffer . ReadInt ();
rect . y = buffer . ReadInt ();
rect . width = buffer . ReadInt ();
rect . height = buffer . ReadInt ();
pi . scale9Grid = rect ;
pi . tileGridIndice = buffer . ReadInt ();
}
else if ( scaleOption == 2 )
pi . scaleByTile = true ;
buffer . ReadBool (); //smoothing
break ;
}
case PackageItemType . MovieClip :
{
buffer . ReadBool (); //smoothing
pi . objectType = ObjectType . MovieClip ;
pi . rawData = buffer . ReadBuffer ();
break ;
}
case PackageItemType . Font :
{
pi . rawData = buffer . ReadBuffer ();
break ;
}
case PackageItemType . Component :
{
int extension = buffer . ReadByte ();
if ( extension > 0 )
pi . objectType = ( ObjectType ) extension ;
else
pi . objectType = ObjectType . Component ;
pi . rawData = buffer . ReadBuffer ();
UIObjectFactory . ResolvePackageItemExtension ( pi );
break ;
}
case PackageItemType . Atlas :
case PackageItemType . Sound :
case PackageItemType . Misc :
{
pi . file = assetNamePrefix + pi . file ;
break ;
}
case PackageItemType . Spine :
case PackageItemType . DragoneBones :
{
pi . file = assetPath + pi . file ;
pi . skeletonAnchor . x = buffer . ReadFloat ();
pi . skeletonAnchor . y = buffer . ReadFloat ();
break ;
}
}
if ( ver2 )
{
string str = buffer . ReadS (); //branch
if ( str != null )
pi . name = str + "/" + pi . name ;
int branchCnt = buffer . ReadByte ();
if ( branchCnt > 0 )
{
if ( branchIncluded )
pi . branches = buffer . ReadSArray ( branchCnt );
else
_itemsById [ buffer . ReadS ()] = pi ;
}
int highResCnt = buffer . ReadByte ();
if ( highResCnt > 0 )
pi . highResolution = buffer . ReadSArray ( highResCnt );
}
_items . Add ( pi );
_itemsById [ pi . id ] = pi ;
if ( pi . name != null )
_itemsByName [ pi . name ] = pi ;
buffer . position = nextPos ;
}
buffer . Seek ( indexTablePos , 2 );
cnt = buffer . ReadShort ();
for ( int i = 0 ; i < cnt ; i ++)
{
int nextPos = buffer . ReadUshort ();
nextPos += buffer . position ;
string itemId = buffer . ReadS ();
pi = _itemsById [ buffer . ReadS ()];
AtlasSprite sprite = new AtlasSprite ();
sprite . atlas = pi ;
sprite . rect . x = buffer . ReadInt ();
sprite . rect . y = buffer . ReadInt ();
sprite . rect . width = buffer . ReadInt ();
sprite . rect . height = buffer . ReadInt ();
sprite . rotated = buffer . ReadBool ();
if ( ver2 && buffer . ReadBool ())
{
sprite . offset . x = buffer . ReadInt ();
sprite . offset . y = buffer . ReadInt ();
sprite . originalSize . x = buffer . ReadInt ();
sprite . originalSize . y = buffer . ReadInt ();
}
else if ( sprite . rotated )
{
sprite . originalSize . x = sprite . rect . height ;
sprite . originalSize . y = sprite . rect . width ;
}
else
{
sprite . originalSize . x = sprite . rect . width ;
sprite . originalSize . y = sprite . rect . height ;
}
_sprites [ itemId ] = sprite ;
buffer . position = nextPos ;
}
if ( buffer . Seek ( indexTablePos , 3 ))
{
cnt = buffer . ReadShort ();
for ( int i = 0 ; i < cnt ; i ++)
{
int nextPos = buffer . ReadInt ();
nextPos += buffer . position ;
if ( _itemsById . TryGetValue ( buffer . ReadS (), out pi ))
{
if ( pi . type == PackageItemType . Image )
{
pi . pixelHitTestData = new PixelHitTestData ();
pi . pixelHitTestData . Load ( buffer );
}
}
buffer . position = nextPos ;
}
}
if (! Application . isPlaying )
_items . Sort ( ComparePackageItem );
return true ;
}
static int ComparePackageItem ( PackageItem p1 , PackageItem p2 )
{
if ( p1 . name != null && p2 . name != null )
return p1 . name . CompareTo ( p2 . name );
else
return 0 ;
}
/// <summary>
///
/// </summary>
public void LoadAllAssets ()
{
int cnt = _items . Count ;
for ( int i = 0 ; i < cnt ; i ++)
GetItemAsset ( _items [ i ]);
}
/// <summary>
///
/// </summary>
public void UnloadAssets ()
{
int cnt = _items . Count ;
for ( int i = 0 ; i < cnt ; i ++)
{
PackageItem pi = _items [ i ];
if ( pi . type == PackageItemType . Atlas )
{
if ( pi . texture != null )
pi . texture . Unload ();
}
else if ( pi . type == PackageItemType . Sound )
{
if ( pi . audioClip != null )
pi . audioClip . Unload ();
}
}
if ( unloadBundleByFGUI &&
_resBundle != null )
{
_resBundle . Unload ( true );
_resBundle = null ;
}
}
/// <summary>
///
/// </summary>
public void ReloadAssets ()
{
if ( _fromBundle )
throw new Exception ( "FairyGUI: new bundle must be passed to this function" );
ReloadAssets ( null );
}
/// <summary>
///
/// </summary>
public void ReloadAssets ( AssetBundle resBundle )
{
_resBundle = resBundle ;
_fromBundle = _resBundle != null ;
int cnt = _items . Count ;
for ( int i = 0 ; i < cnt ; i ++)
{
PackageItem pi = _items [ i ];
if ( pi . type == PackageItemType . Atlas )
{
if ( pi . texture != null && pi . texture . nativeTexture == null )
LoadAtlas ( pi );
}
else if ( pi . type == PackageItemType . Sound )
{
if ( pi . audioClip != null && pi . audioClip . nativeClip == null )
LoadSound ( pi );
}
}
}
void Dispose ()
{
int cnt = _items . Count ;
for ( int i = 0 ; i < cnt ; i ++)
{
PackageItem pi = _items [ i ];
if ( pi . type == PackageItemType . Atlas )
{
if ( pi . texture != null )
{
pi . texture . Dispose ();
pi . texture = null ;
}
}
else if ( pi . type == PackageItemType . Sound )
{
if ( pi . audioClip != null )
{
pi . audioClip . Unload ();
pi . audioClip = null ;
}
}
}
_items . Clear ();
if ( unloadBundleByFGUI &&
_resBundle != null )
{
_resBundle . Unload ( true );
_resBundle = null ;
}
}
/// <summary>
///
/// </summary>
/// <param name="resName"></param>
/// <returns></returns>
public GObject CreateObject ( string resName )
{
PackageItem pi ;
if (! _itemsByName . TryGetValue ( resName , out pi ))
{
Debug . LogError ( "FairyGUI: resource not found - " + resName + " in " + this . name );
return null ;
}
return CreateObject ( pi , null );
}
/// <summary>
///
/// </summary>
/// <param name="resName"></param>
/// <param name="userClass"></param>
/// <returns></returns>
public GObject CreateObject ( string resName , System . Type userClass )
{
PackageItem pi ;
if (! _itemsByName . TryGetValue ( resName , out pi ))
{
Debug . LogError ( "FairyGUI: resource not found - " + resName + " in " + this . name );
return null ;
}
return CreateObject ( pi , userClass );
}
public void CreateObjectAsync ( string resName , CreateObjectCallback callback )
{
PackageItem pi ;
if (! _itemsByName . TryGetValue ( resName , out pi ))
{
Debug . LogError ( "FairyGUI: resource not found - " + resName + " in " + this . name );
return ;
}
AsyncCreationHelper . CreateObject ( pi , callback );
}
GObject CreateObject ( PackageItem item , System . Type userClass )
{
Stats . LatestObjectCreation = 0 ;
Stats . LatestGraphicsCreation = 0 ;
GetItemAsset ( item );
GObject g = UIObjectFactory . NewObject ( item , userClass );
if ( g == null )
return null ;
_constructing ++;
g . ConstructFromResource ();
_constructing --;
return g ;
}
/// <summary>
///
/// </summary>
/// <param name="resName"></param>
/// <returns></returns>
public object GetItemAsset ( string resName )
{
PackageItem pi ;
if (! _itemsByName . TryGetValue ( resName , out pi ))
{
Debug . LogError ( "FairyGUI: Resource not found - " + resName + " in " + this . name );
return null ;
}
return GetItemAsset ( pi );
}
public List < PackageItem > GetItems ()
{
return _items ;
}
public PackageItem GetItem ( string itemId )
{
PackageItem pi ;
if ( _itemsById . TryGetValue ( itemId , out pi ))
return pi ;
else
return null ;
}
public PackageItem GetItemByName ( string itemName )
{
PackageItem pi ;
if ( _itemsByName . TryGetValue ( itemName , out pi ))
return pi ;
else
return null ;
}
public object GetItemAsset ( PackageItem item )
{
switch ( item . type )
{
case PackageItemType . Image :
if ( item . texture == null )
LoadImage ( item );
return item . texture ;
case PackageItemType . Atlas :
if ( item . texture == null )
LoadAtlas ( item );
return item . texture ;
case PackageItemType . Sound :
if ( item . audioClip == null )
LoadSound ( item );
return item . audioClip ;
case PackageItemType . Font :
if ( item . bitmapFont == null )
LoadFont ( item );
return item . bitmapFont ;
case PackageItemType . MovieClip :
if ( item . frames == null )
LoadMovieClip ( item );
return item . frames ;
case PackageItemType . Component :
return item . rawData ;
case PackageItemType . Misc :
return LoadBinary ( item );
case PackageItemType . Spine :
if ( item . skeletonAsset == null )
LoadSpine ( item );
return item . skeletonAsset ;
case PackageItemType . DragoneBones :
if ( item . skeletonAsset == null )
LoadDragonBones ( item );
return item . skeletonAsset ;
default :
return null ;
}
}
/// <summary>
///
/// </summary>
/// <param name="item"></param>
/// <param name="asset"></param>
/// <param name="destroyMethod"></param>
public void SetItemAsset ( PackageItem item , object asset , DestroyMethod destroyMethod )
{
switch ( item . type )
{
case PackageItemType . Atlas :
if ( item . texture == null )
item . texture = new NTexture ( null , new Rect ( 0 , 0 , item . width , item . height ));
item . texture . Reload (( Texture ) asset , null );
item . texture . destroyMethod = destroyMethod ;
break ;
case PackageItemType . Sound :
if ( item . audioClip == null )
item . audioClip = new NAudioClip ( null );
item . audioClip . Reload (( AudioClip ) asset );
item . audioClip . destroyMethod = destroyMethod ;
break ;
case PackageItemType . Spine :
#if FAIRYGUI_SPINE
item . skeletonAsset = ( Spine . Unity . SkeletonDataAsset ) asset ;
#endif
break ;
case PackageItemType . DragoneBones :
#if FAIRYGUI_DRAGONBONES
item . skeletonAsset = ( DragonBones . UnityDragonBonesData ) asset ;
#endif
break ;
}
}
void LoadAtlas ( PackageItem item )
{
string ext = Path . GetExtension ( item . file );
string fileName = item . file . Substring ( 0 , item . file . Length - ext . Length );
if ( _loadAsyncFunc != null )
{
_loadAsyncFunc ( fileName , ext , typeof ( Texture ), item );
if ( item . texture == null )
item . texture = new NTexture ( null , new Rect ( 0 , 0 , item . width , item . height ));
item . texture . destroyMethod = DestroyMethod . None ;
}
else
{
Texture tex = null ;
Texture alphaTex = null ;
DestroyMethod dm ;
if ( _fromBundle )
{
if ( _resBundle != null )
tex = _resBundle . LoadAsset < Texture >( fileName );
else
Debug . LogWarning ( "FairyGUI: bundle already unloaded." );
dm = DestroyMethod . None ;
}
else
{
tex = ( Texture ) _loadFunc ( fileName , ext , typeof ( Texture ), out dm );
}
if ( tex == null )
Debug . LogWarning ( "FairyGUI: texture '" + item . file + "' not found in " + this . name );
else if (!( tex is Texture2D ))
{
Debug . LogWarning ( "FairyGUI: settings for '" + item . file +
"' is wrong! Correct values are: (Texture Type=Default, Texture Shape=2D)" );
tex = null ;
}
else
{
if ((( Texture2D ) tex ). mipmapCount > 1 )
Debug . LogWarning ( "FairyGUI: settings for '" + item . file +
"' is wrong! Correct values are: (Generate Mip Maps=unchecked)" );
}
if ( tex != null )
{
alphaTex = AssetDataBaseKit . GetAssetstatic < Texture2D >( "" , fileName );
}
// if (tex != null)
// {
// fileName = fileName + "!a";
// if (_fromBundle)
// {
// if (_resBundle != null)
// alphaTex = _resBundle.LoadAsset<Texture2D>(fileName);
// }
// else
// alphaTex = (Texture2D)_loadFunc(fileName, ext, typeof(Texture2D), out dm);
// }
if ( tex == null )
{
tex = NTexture . CreateEmptyTexture ();
dm = DestroyMethod . Destroy ;
}
if ( item . texture == null )
{
item . texture = new NTexture ( tex , alphaTex , ( float ) tex . width / item . width ,
( float ) tex . height / item . height );
item . texture . onRelease += ( NTexture t ) =>
{
if ( onReleaseResource != null )
onReleaseResource ( item );
};
}
else
item . texture . Reload ( tex , alphaTex );
item . texture . destroyMethod = dm ;
}
}
void LoadImage ( PackageItem item )
{
AtlasSprite sprite ;
if ( _sprites . TryGetValue ( item . id , out sprite ))
{
NTexture atlas = ( NTexture ) GetItemAsset ( sprite . atlas );
if ( atlas . width == sprite . rect . width && atlas . height == sprite . rect . height )
item . texture = atlas ;
else
item . texture = new NTexture ( atlas , sprite . rect , sprite . rotated , sprite . originalSize , sprite . offset );
}
else
item . texture = NTexture . Empty ;
}
void LoadSound ( PackageItem item )
{
string ext = Path . GetExtension ( item . file );
string fileName = item . file . Substring ( 0 , item . file . Length - ext . Length );
if ( _loadAsyncFunc != null )
{
_loadAsyncFunc ( fileName , ext , typeof ( AudioClip ), item );
if ( item . audioClip == null )
item . audioClip = new NAudioClip ( null );
item . audioClip . destroyMethod = DestroyMethod . None ;
}
else
{
AudioClip audioClip = null ;
DestroyMethod dm ;
if ( _fromBundle )
{
if ( _resBundle != null )
audioClip = _resBundle . LoadAsset < AudioClip >( fileName );
dm = DestroyMethod . None ;
}
else
{
audioClip = ( AudioClip ) _loadFunc ( fileName , ext , typeof ( AudioClip ), out dm );
}
if ( item . audioClip == null )
item . audioClip = new NAudioClip ( audioClip );
else
item . audioClip . Reload ( audioClip );
item . audioClip . destroyMethod = dm ;
}
}
byte [] LoadBinary ( PackageItem item )
{
string ext = Path . GetExtension ( item . file );
string fileName = item . file . Substring ( 0 , item . file . Length - ext . Length );
TextAsset ta ;
if ( _resBundle != null )
{
ta = _resBundle . LoadAsset < TextAsset >( fileName );
if ( ta != null )
return ta . bytes ;
else
return null ;
}
else
{
DestroyMethod dm ;
object ret = _loadFunc ( fileName , ext , typeof ( TextAsset ), out dm );
if ( ret == null )
return null ;
if ( ret is byte [])
return ( byte []) ret ;
else
return (( TextAsset ) ret ). bytes ;
}
}
void LoadMovieClip ( PackageItem item )
{
ByteBuffer buffer = item . rawData ;
buffer . Seek ( 0 , 0 );
item . interval = buffer . ReadInt () / 1000f ;
item . swing = buffer . ReadBool ();
item . repeatDelay = buffer . ReadInt () / 1000f ;
buffer . Seek ( 0 , 1 );
int frameCount = buffer . ReadShort ();
item . frames = new MovieClip . Frame [ frameCount ];
string spriteId ;
MovieClip . Frame frame ;
AtlasSprite sprite ;
Rect frameRect = new Rect ();
for ( int i = 0 ; i < frameCount ; i ++)
{
int nextPos = buffer . ReadUshort ();
nextPos += buffer . position ;
frame = new MovieClip . Frame ();
frameRect . x = buffer . ReadInt ();
frameRect . y = buffer . ReadInt ();
frameRect . width = buffer . ReadInt ();
frameRect . height = buffer . ReadInt ();
frame . addDelay = buffer . ReadInt () / 1000f ;
spriteId = buffer . ReadS ();
if ( spriteId != null && _sprites . TryGetValue ( spriteId , out sprite ))
{
frame . texture = new NTexture (( NTexture ) GetItemAsset ( sprite . atlas ), sprite . rect , sprite . rotated ,
new Vector2 ( item . width , item . height ), frameRect . position );
}
item . frames [ i ] = frame ;
buffer . position = nextPos ;
}
}
void LoadFont ( PackageItem item )
{
BitmapFont font = new BitmapFont ();
font . name = URL_PREFIX + this . id + item . id ;
item . bitmapFont = font ;
ByteBuffer buffer = item . rawData ;
buffer . Seek ( 0 , 0 );
bool ttf = buffer . ReadBool ();
font . canTint = buffer . ReadBool ();
font . resizable = buffer . ReadBool ();
font . hasChannel = buffer . ReadBool ();
int fontSize = buffer . ReadInt ();
int xadvance = buffer . ReadInt ();
int lineHeight = buffer . ReadInt ();
float texScaleX = 1 ;
float texScaleY = 1 ;
int bgX ;
int bgY ;
int bgWidth ;
int bgHeight ;
NTexture mainTexture = null ;
AtlasSprite mainSprite = null ;
if ( ttf && _sprites . TryGetValue ( item . id , out mainSprite ))
{
mainTexture = ( NTexture ) GetItemAsset ( mainSprite . atlas );
texScaleX = mainTexture . root . uvRect . width / mainTexture . width ;
texScaleY = mainTexture . root . uvRect . height / mainTexture . height ;
}
buffer . Seek ( 0 , 1 );
BitmapFont . BMGlyph bg ;
int cnt = buffer . ReadInt ();
for ( int i = 0 ; i < cnt ; i ++)
{
int nextPos = buffer . ReadUshort ();
nextPos += buffer . position ;
bg = new BitmapFont . BMGlyph ();
char ch = buffer . ReadChar ();
font . AddChar ( ch , bg );
string img = buffer . ReadS ();
int bx = buffer . ReadInt ();
int by = buffer . ReadInt ();
bgX = buffer . ReadInt ();
bgY = buffer . ReadInt ();
bgWidth = buffer . ReadInt ();
bgHeight = buffer . ReadInt ();
bg . advance = buffer . ReadInt ();
bg . channel = buffer . ReadByte ();
//The texture channel where the character image is found (1 = blue, 2 = green, 4 = red, 8 = alpha, 15-all).
if ( bg . channel == 1 )
bg . channel = 2 ;
else if ( bg . channel == 2 )
bg . channel = 1 ;
else if ( bg . channel == 4 )
bg . channel = 0 ;
else if ( bg . channel == 8 )
bg . channel = 3 ;
if ( ttf )
{
if ( mainSprite . rotated )
{
bg . uv [ 0 ] = new Vector2 (( float )( by + bgHeight + mainSprite . rect . x ) * texScaleX ,
1 - ( float )( mainSprite . rect . yMax - bx ) * texScaleY );
bg . uv [ 1 ] = new Vector2 ( bg . uv [ 0 ]. x - ( float ) bgHeight * texScaleX , bg . uv [ 0 ]. y );
bg . uv [ 2 ] = new Vector2 ( bg . uv [ 1 ]. x , bg . uv [ 0 ]. y + ( float ) bgWidth * texScaleY );
bg . uv [ 3 ] = new Vector2 ( bg . uv [ 0 ]. x , bg . uv [ 2 ]. y );
}
else
{
bg . uv [ 0 ] = new Vector2 (( float )( bx + mainSprite . rect . x ) * texScaleX ,
1 - ( float )( by + bgHeight + mainSprite . rect . y ) * texScaleY );
bg . uv [ 1 ] = new Vector2 ( bg . uv [ 0 ]. x , bg . uv [ 0 ]. y + ( float ) bgHeight * texScaleY );
bg . uv [ 2 ] = new Vector2 ( bg . uv [ 0 ]. x + ( float ) bgWidth * texScaleX , bg . uv [ 1 ]. y );
bg . uv [ 3 ] = new Vector2 ( bg . uv [ 2 ]. x , bg . uv [ 0 ]. y );
}
bg . lineHeight = lineHeight ;
bg . x = bgX ;
bg . y = bgY ;
bg . width = bgWidth ;
bg . height = bgHeight ;
}
else
{
PackageItem charImg ;
if ( _itemsById . TryGetValue ( img , out charImg ))
{
charImg = charImg . getBranch ();
bgWidth = charImg . width ;
bgHeight = charImg . height ;
charImg = charImg . getHighResolution ();
GetItemAsset ( charImg );
charImg . texture . GetUV ( bg . uv );
texScaleX = ( float ) bgWidth / charImg . width ;
texScaleY = ( float ) bgHeight / charImg . height ;
bg . x = bgX + charImg . texture . offset . x * texScaleX ;
bg . y = bgY + charImg . texture . offset . y * texScaleY ;
bg . width = charImg . texture . width * texScaleX ;
bg . height = charImg . texture . height * texScaleY ;
if ( mainTexture == null )
mainTexture = charImg . texture . root ;
}
if ( fontSize == 0 )
fontSize = bgHeight ;
if ( bg . advance == 0 )
{
if ( xadvance == 0 )
bg . advance = bgX + bgWidth ;
else
bg . advance = xadvance ;
}
bg . lineHeight = bgY < 0 ? bgHeight : ( bgY + bgHeight );
if ( bg . lineHeight < fontSize )
bg . lineHeight = fontSize ;
}
buffer . position = nextPos ;
}
font . size = fontSize ;
font . mainTexture = mainTexture ;
if (! font . hasChannel )
font . shader = ShaderConfig . imageShader ;
}
void LoadSpine ( PackageItem item )
{
#if FAIRYGUI_SPINE
string ext = Path . GetExtension ( item . file );
string fileName = item . file . Substring ( 0 , item . file . Length - ext . Length );
int index = fileName . LastIndexOf ( ".skel" );
if ( index > 0 )
fileName = fileName . Substring ( 0 , index );
Spine . Unity . SkeletonDataAsset asset ;
if ( _resBundle != null )
asset = _resBundle . LoadAsset < Spine . Unity . SkeletonDataAsset >( fileName + "_SkeletonData" );
else
{
DestroyMethod dm ;
asset =
( Spine . Unity . SkeletonDataAsset ) _loadFunc ( fileName + "_SkeletonData" , ".asset" , typeof ( Spine . Unity . SkeletonDataAsset ), out dm );
}
if ( asset == null )
Debug . LogWarning ( "FairyGUI: Failed to load " + fileName );
item . skeletonAsset = asset ;
#else
Debug . LogWarning ( "To enable Spine support, add script define symbol: FAIRYGUI_SPINE" );
#endif
}
void LoadDragonBones ( PackageItem item )
{
#if FAIRYGUI_DRAGONBONES
string ext = Path . GetExtension ( item . file );
string fileName = item . file . Substring ( 0 , item . file . Length - ext . Length );
int index = fileName . LastIndexOf ( "_ske" );
if ( index > 0 )
fileName = fileName . Substring ( 0 , index );
index = fileName . LastIndexOf ( ".dbbin" );
if ( index > 0 )
fileName = fileName . Substring ( 0 , index );
DragonBones . UnityDragonBonesData asset ;
if ( _resBundle != null )
asset = _resBundle . LoadAsset < DragonBones . UnityDragonBonesData >( fileName + "_Data" );
else
{
DestroyMethod dm ;
asset =
( DragonBones . UnityDragonBonesData ) _loadFunc ( fileName + "_Data" , ".asset" , typeof ( DragonBones . UnityDragonBonesData ), out dm );
}
if ( asset != null )
{
foreach ( var atlas in asset . textureAtlas )
{
if ( atlas . material == null )
{
atlas . material = new Material ( ShaderConfig . GetShader ( ShaderConfig . imageShader ));
atlas . material . mainTexture = atlas . texture ;
}
}
item . skeletonAsset = DragonBones . UnityFactory . factory . LoadData ( asset );
}
else
Debug . LogWarning ( "FairyGUI: Failed to load " + fileName );
#else
Debug . LogWarning ( "To enable DragonBones support, add script define symbol: FAIRYGUI_DRAGONBONES" );
#endif
}
}
}