using System; using System.Collections.Generic; using System.IO; using UnityEngine; using FairyGUI.Utils; #if UNITY_EDITOR using UnityEditor; #endif namespace FairyGUI { /// /// A UI Package contains a description file and some texture, sound assets. /// public class UIPackage { /// /// Unload UIAssetBundle by FairyGUI system. /// if use AssetBundlesManager set value to false /// then unload UIAssetBundle by AssetBundlesManager /// public static bool unloadBundleByFGUI = true; /// /// The event is triggered when all reference to this package item dropped. /// public static event Action onReleaseResource; /// /// Package id. It is generated by the Editor. /// public string id { get; private set; } /// /// Package name. /// public string name { get; private set; } /// /// Use this callback to provide resources to the package. /// /// Resource name without extension. /// Resource extension. e.g. '.png' '.wav' /// Resource type. e.g. 'Texture' 'AudioClip' /// How to destroy this resource. /// public delegate object LoadResource(string name, string extension, System.Type type, out DestroyMethod destroyMethod); /// /// A async load resource callback. After loaded, you should call item.owner.SetItemAsset. /// /// Resource name without extension. /// Resource extension. e.g. '.png' '.wav' /// Resource type. e.g. 'Texture' 'AudioClip' /// Resource item object. /// public delegate void LoadResourceAsync(string name, string extension, System.Type type, PackageItem item); /// /// /// /// public delegate void CreateObjectCallback(GObject result); List _items; Dictionary _itemsById; Dictionary _itemsByName; Dictionary[] _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 _sprites; static Dictionary _packageInstById = new Dictionary(); static Dictionary _packageInstByName = new Dictionary(); static List _packageList = new List(); static string _branch; static Dictionary _vars = new Dictionary(); 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; return Resources.Load(name, type); }; public UIPackage() { _items = new List(); _itemsById = new Dictionary(); _itemsByName = new Dictionary(); _sprites = new Dictionary(); _branchIndex = -1; } /// /// /// 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(); } } /// /// /// public static string GetVar(string key) { string value; if (_vars.TryGetValue(key, out value)) return value; else return null; } /// /// /// public static void SetVar(string key, string value) { if (value == null) _vars.Remove(key); else _vars[key] = value; } /// /// Return a UIPackage with a certain id. /// /// ID of the package. /// UIPackage public static UIPackage GetById(string id) { UIPackage pkg; if (_packageInstById.TryGetValue(id, out pkg)) return pkg; else return null; } /// /// Return a UIPackage with a certain name. /// /// Name of the package. /// UIPackage public static UIPackage GetByName(string name) { UIPackage pkg; if (_packageInstByName.TryGetValue(name, out pkg)) return pkg; else return null; } /// /// Add a UI package from assetbundle. /// /// A assetbundle. /// UIPackage public static UIPackage AddPackage(AssetBundle bundle) { return AddPackage(bundle, bundle, null); } /// /// Add a UI package from two assetbundles. desc and res can be same. /// /// A assetbunble contains description file. /// A assetbundle contains resources. /// UIPackage public static UIPackage AddPackage(AssetBundle desc, AssetBundle res) { return AddPackage(desc, res, null); } /// /// Add a UI package from two assetbundles with a optional main asset name. /// /// A assetbunble contains description file. /// A assetbundle contains resources. /// Main asset name. e.g. Basics_fui /// UIPackage public static UIPackage AddPackage(AssetBundle desc, AssetBundle res, string mainAssetName) { byte[] source = null; if (!string.IsNullOrEmpty(mainAssetName)) { TextAsset ta = desc.LoadAsset(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(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; } /// /// Add a UI package from a path relative to Unity Resources path. /// /// Path relative to Unity Resources path. /// UIPackage 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); } /// /// 使用自定义的加载方式载入一个包。 /// /// 包资源路径。 /// 载入函数 /// 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; } /// /// Load Package by custom load method. /// /// Description file data /// Prefix of the resource file name. The file name would be in format of 'assetNamePrefix_resFileName'. It can be empty. /// Load method /// 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; } /// /// Load Package async by custom load method. /// /// Description file data /// refix of the resource file name. The file name would be in format of 'assetNamePrefix_resFileName'. It can be empty. /// Load method /// 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; } /// /// Remove a package. All resources in this package will be disposed. /// /// 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); } /// /// /// 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(); } /// /// /// /// public static List GetPackages() { return _packageList; } /// /// Create a UI object. /// /// Package name. /// Resource name. /// A UI object. public static GObject CreateObject(string pkgName, string resName) { UIPackage pkg = GetByName(pkgName); if (pkg != null) return pkg.CreateObject(resName); else return null; } /// /// Create a UI object. /// /// Package name. /// Resource name. /// Custom implementation of this object. /// A UI object. 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; } /// /// Create a UI object. /// /// Resource url. /// A UI object. public static GObject CreateObjectFromURL(string url) { PackageItem pi = GetItemByURL(url); if (pi != null) return pi.owner.CreateObject(pi, null); else return null; } /// /// Create a UI object. /// /// Resource url. /// Custom implementation of this object. /// A UI object. 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); } /// /// Get a asset with a certain name. /// /// Package name. /// Resource name. /// If resource is atlas, returns NTexture; If resource is sound, returns AudioClip. public static object GetItemAsset(string pkgName, string resName) { UIPackage pkg = GetByName(pkgName); if (pkg != null) return pkg.GetItemAsset(resName); else return null; } /// /// Get a asset with a certain name. /// /// Resource url. /// If resource is atlas, returns NTexture; If resource is sound, returns AudioClip. public static object GetItemAssetByURL(string url) { PackageItem item = GetItemByURL(url); if (item == null) return null; return item.owner.GetItemAsset(item); } /// /// Get url of an item in package. /// /// Package name. /// Resource name. /// Url. 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; } /// /// 将'ui://包名/组件名'转换为以内部id表达的url格式。如果传入的url本身就是内部id格式,则直接返回。 /// 同时这个方法还带格式检测,如果传入不正确的url,会返回null。 /// /// /// 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); } } /// /// Set strings source. /// /// public static void SetStringsSource(XML source) { TranslationHelper.LoadFromXML(source); } /// /// /// public string assetPath { get { return _assetPath; } } /// /// Set a custom id for package, then you can use it in GetById. /// public string customId { get { return _customId; } set { if (_customId != null) _packageInstById.Remove(_customId); _customId = value; if (_customId != null) _packageInstById[_customId] = this; } } /// /// /// public AssetBundle resBundle { get { return _resBundle; } } /// /// 获得本包依赖的包的id列表 /// public Dictionary[] 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[cnt]; for (int i = 0; i < cnt; i++) { Dictionary kv = new Dictionary(); 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; } /// /// /// public void LoadAllAssets() { int cnt = _items.Count; for (int i = 0; i < cnt; i++) GetItemAsset(_items[i]); } /// /// /// 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; } } /// /// /// public void ReloadAssets() { if (_fromBundle) throw new Exception("FairyGUI: new bundle must be passed to this function"); ReloadAssets(null); } /// /// /// 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; } } /// /// /// /// /// 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); } /// /// /// /// /// /// 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; } /// /// /// /// /// 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 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; } } /// /// /// /// /// /// 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(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) { fileName = fileName + "!a"; if (_fromBundle) { if (_resBundle != null) alphaTex = _resBundle.LoadAsset(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(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(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(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(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 } } }