using System; using System.Collections.Generic; using UnityEngine; using XGame.Framework.Asset; using XGame.Framework.Asyncs; using XGame.Framework.Interfaces; namespace XGame.Framework.Map { public class MapModule : IMapModule, IUpdate, ILateUpdate, IMapContextSetter, IDisposable { private MapContext _context; private Transform _mapRoot; private IAssetModule _assetModule; /// /// 加载中的 /// private Dictionary _loadingMap; /// /// 已打开的 /// private Dictionary _openedMap; /// /// 已关闭的 /// private Dictionary _closedMap; /// /// pdate 和 LateUpdate用 /// private List _updates; public MapModule(IAssetModule assetModule, Transform root) { _assetModule = assetModule; _mapRoot = root; _loadingMap = new Dictionary(); _openedMap = new Dictionary(); _closedMap = new Dictionary(); _updates = new List(); } #region 接口实现 public MapContext Context { get => _context; set => _context = value; } IAsync IMapModule.RunAsync(MapKey mapKey, object intent) { string key = mapKey; if (_loadingMap.ContainsKey(key)) { return _loadingMap[key]; } var asyncGroup = new AsyncGroup(); if (_openedMap.ContainsKey(key)) { Log.Warn($"重复打开地图:{key}"); } else if (_closedMap.TryGetValue(key, out var closedView)) { //已关闭的地图 asyncGroup.On(_ => { _closedMap.Remove(key); closedView.Behaviour.transform.SetAsLastSibling(); closedView.Enable(intent); _openedMap.Add(key, closedView); }); } else { _loadingMap.Add(key, asyncGroup); var loadAsync = _assetModule.LoadAsync(key); loadAsync.Join(asyncGroup); loadAsync.On(_ => { _loadingMap.Remove(key); var behaviour = loadAsync.Result; if (behaviour == null) { Log.Error($"地图加载结果为空. MapKey:{key}"); return; } var view = Activator.CreateInstance(mapKey.MapViewType) as IMapView; (view as IMapContextSetter).Context = _context.Clone(); view.Behaviour = behaviour; behaviour.transform.SetParent(_mapRoot, false); view.Enable(intent); _openedMap.Add(key, view); }); } asyncGroup.End(); return asyncGroup; } void IMapModule.Close(MapKey mapKey, bool isDestroy) { if (mapKey == null) return; var key = mapKey.Key; if (_loadingMap.TryGetValue(key, out var async)) { _loadingMap.Remove(key); async.RemoveAll(); return; } if (_openedMap.TryGetValue(key, out var mapView)) { _openedMap.Remove(key); mapView.Disable(); if (isDestroy) { DestroyView(mapView); } else { _closedMap.Add(key, mapView); } return; } if (isDestroy && _closedMap.TryGetValue(key, out mapView)) { _closedMap.Remove(key); DestroyView(mapView); } } IAsync IMapModule.Preload(MapKey mapKey) { var loadAsync = _assetModule.PreloadAsync(mapKey); return loadAsync; } 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(); GameObject.Destroy(_mapRoot.gameObject); (_assetModule as IDisposable)?.Dispose(); _assetModule = null; _context = null; } #endregion private void DestroyView(IMapView view) { var behaviour = view.Behaviour; (view as IDisposable).Dispose(); _assetModule.Recycle(behaviour.gameObject, true); } } }