123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- using FairyGUI;
- using Spine.Unity;
- using System;
- using System.Collections.Generic;
- using UnityEngine;
- using XGame.Framework.Asset;
- using XGame.Framework.Asyncs;
- using XGame.Framework.Interfaces;
- using XGame.Framework.UI;
- namespace XGame.Framework.FGUI
- {
- internal partial class FguiModule : IUIModule, IUpdate, ILateUpdate, IUIContextSetter, IDisposable, IUIAssetModuleCreator, IPackageHandle
- {
- /// <summary>
- /// bitmapFont的shader名字
- /// </summary>
- private const string bitmap_font_shader = "XGame/Text Shader";
- private UIContext _context;
- private IUITree _uitree;
- private IAssetModule _assetModule;
- /// <summary>
- /// 加载中的
- /// </summary>
- private Dictionary<string, IAsync> _loadingMap;
- /// <summary>
- /// 已打开的UI
- /// </summary>
- private Dictionary<string, IUIView> _openedMap;
- /// <summary>
- /// 已关闭的UI
- /// </summary>
- private Dictionary<string, IUIView> _closedMap;
- /// <summary>
- /// Update 和 LateUpdate用
- /// </summary>
- private List<IUIView> _updates;
- /// <summary>
- /// 已加载的字体
- /// </summary>
- private HashSet<string> _fontNames;
- public FguiModule(IAssetModule assetModule, IUITree uitree)
- {
- _assetModule = assetModule;
- _uitree = uitree;
- _loadingMap = new Dictionary<string, IAsync>();
- _openedMap = new Dictionary<string, IUIView>();
- _closedMap = new Dictionary<string, IUIView>();
- _updates = new List<IUIView>();
- _fontNames = new HashSet<string>();
- //Gtween的默认曲线
- GTweener.defaultEaseType = EaseType.Linear;
- #region 只对PackageItem有效
- NTexture.CustomDestroyMethod += RecycleTexture;
- NAudioClip.CustomDestroyMethod += RecycleAudio;
- #if FAIRYGUI_SPINE
- GLoader3D.CustomLoadSpine += OnLoadSpine;
- GLoader3D.CustomSpineDestroyMethod += RecycleSpine;
- #endif
- #endregion
- UIObjectFactory.SetLoaderExtension(CreatCustomLoader);
- }
- public UIContext Context { get => _context; set => _context = value; }
- #region 接口实现
- Camera IUIModule.Camera => _uitree.Camera;
- Canvas IUIModule.GetCanvas(UILayer layer)
- {
- return _uitree.GetCanvas(layer);
- }
- IAsync IUIModule.OpenAsync(UIKey uikey, object intent)
- {
- string key = uikey;
- if (_loadingMap.ContainsKey(key))
- {
- return _loadingMap[key];
- }
- var asyncGroup = new AsyncGroup();
- if (_openedMap.ContainsKey(key))
- {
- Log.Warn($"重复开启UI:{key}");
- }
- else if (_closedMap.TryGetValue(key, out var closedView))
- { // 已关闭的UI
- asyncGroup.On(_ =>
- {
- _closedMap.Remove(key);
- _uitree.SetAsLastSibling(closedView.Panel);
- closedView.Enable(intent);
- _openedMap.Add(key, closedView);
- FrameworkEvent.Instance.Notify(EventDefine.UI_OPENED, uikey);
- });
- }
- else
- {
- _loadingMap.Add(key, asyncGroup);
- var objLoadAsync = new GObjectFromPackageAsync(uikey.PackageName, uikey.PanelName);
- objLoadAsync.Join(asyncGroup);
- objLoadAsync.On(_ =>
- {
- _loadingMap.Remove(key);
- var panelObj = objLoadAsync.Result as GComponent;
- if (panelObj == null)
- {
- Log.Error($"UI加载结果为空. UIKey:{uikey}");
- return;
- }
- var panel = new FguiPanel(panelObj, GetLayer(uikey.UIViewType));
- var view = Activator.CreateInstance(uikey.UIViewType) as IUIView;
- var context = _context.Clone();
- (context as IUIViewAdapter).Key = uikey;
- (view as UIView).Init(context, panel);
- _uitree.AddPanel(panel);
- view.Enable(intent);
- _openedMap.Add(key, view);
- FrameworkEvent.Instance.Notify(EventDefine.UI_OPENED, uikey);
- });
- var pkgLoadAsync = LoadPackageAsync(uikey);
- if (pkgLoadAsync != null)
- {
- pkgLoadAsync.Join(asyncGroup);
- pkgLoadAsync.On(_ =>
- {
- objLoadAsync.Start();
- });
- }
- else
- {
- objLoadAsync.Start();
- }
- }
- asyncGroup.End();
- return asyncGroup;
- }
- void IUIModule.Close(UIKey uikey, bool isDestroy)
- {
- var key = uikey.Key;
- if (_loadingMap.TryGetValue(key, out var async))
- {
- _loadingMap.Remove(key);
- async.RemoveAll();
- return;
- }
- if (_openedMap.TryGetValue(key, out var uiView))
- {
- _openedMap.Remove(key);
- uiView.Disable();
- _uitree.RemovePanel(uiView.Panel);
- if (isDestroy)
- {
- DestroyView(uiView);
- }
- else
- {
- _closedMap.Add(key, uiView);
- }
- FrameworkEvent.Instance.Notify(EventDefine.UI_CLOSED, uikey);
- return;
- }
- if (isDestroy && _closedMap.TryGetValue(key, out uiView))
- {
- _closedMap.Remove(key);
- DestroyView(uiView);
- }
- }
- IAsync IUIModule.Preload(UIKey uikey)
- {
- var loadAsync = LoadPackageAsync(uikey);
- return loadAsync;
- }
- bool IUIModule.IsOpened(UIKey uikey)
- {
- return _openedMap.ContainsKey(uikey);
- }
- void IUpdate.Update(int millisecond)
- {
- if (_openedMap.Count == 0)
- return;
- _updates.Clear();
- _updates.AddRange(_openedMap.Values);
- for (var i = 0; i < _updates.Count;)
- {
- var view = _updates[i];
- view.Update(millisecond);
- if (view.Active)
- {
- i++;
- }
- else
- {
- _updates.RemoveAt(i);
- }
- }
- }
- void ILateUpdate.LateUpdate(int millisecond)
- {
- if (_updates.Count == 0)
- return;
- foreach (var uiview in _updates)
- {
- uiview.LateUpdate(millisecond);
- }
- _updates.Clear();
- }
- void IDisposable.Dispose()
- {
- _updates.Clear();
- foreach (var async in _loadingMap.Values)
- {
- async.RemoveAll();
- }
- _loadingMap.Clear();
- foreach (var uiview in _closedMap.Values)
- {
- DestroyView(uiview);
- }
- _closedMap.Clear();
- foreach (var uiview in _openedMap.Values)
- {
- DestroyView(uiview);
- }
- _openedMap.Clear();
- foreach (var fontName in _fontNames)
- {
- var font = FontManager.UnregisterFont(fontName);
- if (font is DynamicFont dynFont)
- {
- _assetModule.Recycle(dynFont.nativeFont);
- }
- font?.Dispose();
- }
- _fontNames.Clear();
- #region 清理FGUI緩存
- StageEngine.beingQuit = true;
- UIPackage.RemoveAllPackages();
- Stage.inst.Dispose();
- NTexture.CustomDestroyMethod -= RecycleTexture;
- NAudioClip.CustomDestroyMethod -= RecycleAudio;
- #if FAIRYGUI_SPINE
- GLoader3D.CustomLoadSpine -= OnLoadSpine;
- GLoader3D.CustomSpineDestroyMethod -= RecycleSpine;
- #endif
- UIObjectFactory.Clear();
- ClearGloaderAssets();
- #endregion
- (_uitree as IDisposable)?.Dispose();
- (_assetModule as IDisposable)?.Dispose();
- _assetModule = null;
- _context = null;
- }
- #endregion
- #region IPackageHandle 接口实现
- public IGObjectLoadAsync LoadGobjectAsync(UIKey uikey)
- {
- var objLoadAsync = new GObjectFromPackageAsync(uikey.PackageName, uikey.PanelName);
- var pkgLoadAsync = LoadPackageAsync(uikey);
- if (pkgLoadAsync != null)
- {
- pkgLoadAsync.On(_ =>
- {
- objLoadAsync.Start();
- });
- }
- else
- {
- objLoadAsync.Start();
- }
- return objLoadAsync;
- }
- /// <summary>
- /// 加载UIPackage
- /// </summary>
- /// <param name="uikey"></param>
- /// <returns></returns>
- public IAsync LoadPackageAsync(UIKey uikey)
- {
- if (UIPackage.GetByName(uikey.PackageName) == null)
- {
- var pkgAddressable = FguiUtils.ToDescFileName(uikey.PackageName);
- if (_loadingMap.ContainsKey(pkgAddressable))
- {
- return _loadingMap[pkgAddressable];
- }
- var pkgLoadAsync = _assetModule.LoadAsync<TextAsset>(pkgAddressable);
- _loadingMap.Add(pkgAddressable, pkgLoadAsync);
- pkgLoadAsync.On(_ =>
- {
- _loadingMap.Remove(pkgAddressable);
- var pkgAsset = pkgLoadAsync.Result;
- var descData = pkgAsset?.bytes;
- _assetModule.Recycle(pkgAsset);
- if (descData == null || descData.Length == 0)
- {
- Log.Error($"UIPackage 加载失败. UIKey:{uikey}");
- return;
- }
- if (UIPackage.GetByName(uikey.PackageName) == null)
- {
- UIPackage.AddPackage(descData, string.Empty, LoadPackageItemAsync);
- //var pkg = UIPackage.GetByName(uikey.PackageName);
- //if (pkg != null && pkg.dependencies != null)
- //{
- // Log.Debug($"{uikey.PackageName} dependencies:{pkg.dependencies.Length}");
- // foreach (var dependency in pkg.dependencies)
- // {
- // foreach(var item in dependency)
- // {
- // Log.Debug($"dependency key:{item.Key} value:{item.Value}");
- // }
- // }
- //}
- }
- });
- return pkgLoadAsync;
- }
- else
- {
- Log.Info($"UIPackage已加载. UIKey:{uikey}");
- return null;
- }
- }
- public IAsync LoadFontAsync(string fontName)
- {
- if (_fontNames.Contains(fontName))
- {
- return null;
- }
- if (_loadingMap.TryGetValue(fontName, out var loading))
- {
- return loading;
- }
- var async = _assetModule.LoadAsync<Font>(fontName);
- _loadingMap.Add(fontName, async);
- async.On(_ =>
- {
- _loadingMap.Remove(fontName);
- var result = async.Result;
- if (result == null)
- return;
- _fontNames.Add(fontName);
- var fguiFont = new DynamicFont()
- {
- name = fontName,
- nativeFont = result
- };
- if (result.material != null && result.material.shader.name == bitmap_font_shader)
- { // bitmapfont字体使用自带的shader
- fguiFont.shader = bitmap_font_shader;
- }
- FontManager.RegisterFont(fguiFont);
- });
- return async;
- }
- #endregion
- IUIAssetModule IUIAssetModuleCreator.Create(UIContext context)
- {
- return new FguiAssetModule(context, this);
- }
- #region 内部函数
- /// <summary>
- /// 异步加载PackageItem
- /// UIPackage的Texture、AudioClip等资源
- /// </summary>
- /// <param name="name"></param>
- /// <param name="extension"></param>
- /// <param name="type"></param>
- /// <param name="item"></param>
- private void LoadPackageItemAsync(string name, string extension, System.Type type, PackageItem item)
- {
- Log.Info($"LoadPackageItemAsync name:{name} extension:{extension} type:{type} itemName:{item.name}");
- var addressable = $"{item.owner.name}_{name}";
- var loadAsync = _assetModule.LoadAsync<UnityEngine.Object>(addressable);
- loadAsync.On(_ =>
- {
- var asset = loadAsync.Result;
- item.owner.SetItemAsset(item, Convert(asset, type), DestroyMethod.Custom);
- });
- }
- private object Convert(UnityEngine.Object value, Type type)
- {
- if (value == null)
- return default;
- if (type.IsInstanceOfType(value))
- {
- return value;
- }
- if (type.IsClass)
- {
- if (type.IsSubclassOf(typeof(Component)))
- {
- var go = value as GameObject;
- if (go != null)
- {
- return go.GetComponent(type);
- }
- var component = value as Component;
- if (component != null)
- {
- return component.gameObject.GetComponent(type);
- }
- }
- else if (type == typeof(Sprite) && value is Texture2D texture)
- {
- object sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
- return sprite;
- }
- }
- Log.Error($"UIModuleFGUI object conver type Error. source type:{value.GetType()} name:{value} target:{type}");
- return value;
- }
- private void DestroyView(IUIView view)
- {
- var uiPanel = (view.Panel as FguiPanel).Panel;
- (view as IDisposable).Dispose();
- uiPanel.Dispose();
- }
- /// <summary>
- /// 只对LoadPackageItemAsync加载的资源有效
- /// </summary>
- /// <param name="texture"></param>
- private void RecycleTexture(Texture texture)
- {
- Log.Info($"RecycleTexture Texture:{texture.name}");
- _assetModule.Recycle(texture);
- }
- /// <summary>
- /// 只对LoadPackageItemAsync加载的资源有效
- /// </summary>
- /// <param name="audioClip"></param>
- private void RecycleAudio(AudioClip audioClip)
- {
- Log.Info($"RecycleAudio AudioClip:{audioClip.name}");
- _assetModule?.Recycle(audioClip);
- }
- private GLoader CreatCustomLoader()
- {
- return new CustomLoader(this);
- }
- private void OnLoadSpine(string addressable, Action<SkeletonDataAsset> action)
- {
- var loadAsync = _assetModule.LoadAsync<SkeletonDataAsset>(addressable);
- loadAsync.On(_ =>
- {
- var data = loadAsync.Result;
- if (data == null)
- {
- return;
- }
- action(data);
- });
- }
- private void RecycleSpine(SkeletonDataAsset asset)
- {
- _assetModule.Recycle(asset);
- }
- private UILayer GetLayer(Type uiviewType)
- {
- var layer = UILayer.Normal;
- var property = uiviewType.GetProperty("Layer", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.IgnoreCase);
- if (property != null)
- {
- layer = (UILayer)property.GetValue(null);
- }
- return layer;
- }
- #endregion
- }
- }
|