using System; using System.Collections; using System.Collections.Generic; using System.Linq; using cfg.CampCfg; using Cysharp.Threading.Tasks; using Framework; using Gameplay; using PhxhSDK; using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.Playables; using UnityEngine.Serialization; using UnityEngine.Timeline; using Object = UnityEngine.Object; public class CampShowConfigGroup { public List cfgs = new(); public bool hasToBeFull => cfgs.Any(cfg => cfg.HasCharacter); } public class CampShowPointResult { public int showPoint; public int timelineID; public CharacterDataInfo characterDataInfo; } public class CampSceneManager : MonoBehaviour { private const string TIMELINE_ASSET_PATH_PREFIX = "Assets/Art/Camp/Timeline/camp_timeline_{0}.playable"; [LabelText("抽取角色数")] [SerializeField] private int _characterMaxCount = 20; [LabelText("timeline导演")] [HideInInspector] [SerializeField] private PlayableDirector _director; [LabelText("角色根节点")] [HideInInspector] [SerializeField] private Transform _characterRoot; [LabelText("营地物品根节点")] [HideInInspector] [SerializeField] private Transform _campObjectsRoot; [LabelText("演出点")] [FormerlySerializedAs("interactionPoints")] [ListDrawerSettings(ShowIndexLabels = true, AlwaysAddDefaultValue = true)] [SerializeField] private List _showPoints = new(); private List _allCharacterInfos = new(); private Dictionary _allCampShowConfigGroups = new(); private List _remindCampShowConfigGroups = new(); private List _remindCharacters = new(); private List _campShowPointResults = new(); private Dictionary _models = new(); private Dictionary _timeLines = new(); private TimelineAsset _mainTimeline; //asset相关 private HashSet _assetToUnload = new(); private int CharacterMaxCount => Mathf.Min(_allCharacterInfos.Count, _characterMaxCount); private void Awake() { _mainTimeline = _director.playableAsset as TimelineAsset; LoadData(); } private void OnDestroy() { foreach (var path in _assetToUnload) { AssetManager.Instance.Unload(path); } } public async UniTask Refresh() { RefreshCampObjects(); await RefreshCampShow(); } private void RefreshCampObjects() { } private async UniTask RefreshCampShow() { RefreshCampShowData(); await ExecuteCampShow(); } private void LoadData() { _allCharacterInfos = new List(CharacterDataInfoManager.Instance.DataList); var campShowConfigList = TableManager.Instance.Tables.CampShowConfig.DataList; _allCampShowConfigGroups.Clear(); foreach (var campShowConfig in campShowConfigList) { var groupID = campShowConfig.GroupID; if (!_allCampShowConfigGroups.TryGetValue(groupID, out var group)) { group = new(); _allCampShowConfigGroups.Add(groupID, group); } group.cfgs.Add(campShowConfig); } foreach (var group in _allCampShowConfigGroups.Values) { //有指定ID的先选 group.cfgs.Sort((a, b) => b.CharacterID.CompareTo(a.CharacterID)); } } private void RefreshCampShowData() { _remindCampShowConfigGroups.Clear(); _remindCharacters.Clear(); _campShowPointResults.Clear(); _remindCampShowConfigGroups = new(_allCampShowConfigGroups.Values); _remindCharacters = new(_allCharacterInfos); } private async UniTask ExecuteCampShow() { Extract(); await ExecuteResult(); } //抽取 private void Extract() { List _tempResultList = new(); while (_campShowPointResults.Count < CharacterMaxCount) { var randomGroup = CommonUtils.GetRandomItem(_remindCampShowConfigGroups, true); if (randomGroup == null) { //如果所有组都抽完了,则直接返回 return; } //如果组里的演出点和当前已经使用的演出点重复,则跳过该组 if (IsShowPointExist(randomGroup)) continue; //如果组里有限定演员,但演员已使用,则跳过该组 if (!CanUseCharacter(randomGroup)) continue; //临时存放抽取的结果 _tempResultList.Clear(); foreach (var cfg in randomGroup.cfgs) { //如果当前没有剩余的演员,则直接跳出抽取 if (_remindCharacters.Count == 0) break; //抽取timeline var timelineID = CommonUtils.GetRandomItem(cfg.TimelineIDs); if (timelineID == 0) //说明不站人 continue; CharacterDataInfo characterDataInfo = null; if (cfg.CharacterID > 0) { //抽取指定演员 var index = _remindCharacters.FindIndex(characterInfo => characterInfo.ID == cfg.CharacterID); characterDataInfo = _remindCharacters[index]; _remindCharacters.RemoveAt(index); } else { //随机抽取演员 characterDataInfo = CommonUtils.GetRandomItem(_remindCharacters, true); } CampShowPointResult result = new() { showPoint = cfg.PointID, timelineID = timelineID, characterDataInfo = characterDataInfo }; _tempResultList.Add(result); } if (randomGroup.hasToBeFull && _tempResultList.Count < randomGroup.cfgs.Count) { //如果该组必须满员但没满员 //取出来的CharacterDataInfo归还 foreach (var result in _tempResultList) { _remindCharacters.Add(result.characterDataInfo); } } else { //添加到最后的result列表中 _campShowPointResults.AddRange(_tempResultList); } } } //执行抽取结果 private async UniTask ExecuteResult() { if (_campShowPointResults.Count == 0) return; foreach (var result in _campShowPointResults) { var showPointID = result.showPoint; if (showPointID < 0 || showPointID >= _showPoints.Count || _showPoints[showPointID] == null) { DebugUtil.LogError($"找不到演出点!演出点ID:{showPointID}"); continue; } var showPointTransform = _showPoints[showPointID]; var model = await GetModel(result.characterDataInfo); if (model == null) { continue; } model = Instantiate(model, _characterRoot); model.transform.position = showPointTransform.transform.position; model.transform.rotation = showPointTransform.transform.rotation; var timelineAsset = await GetTimeLineAsset(result.timelineID); if (timelineAsset == null) { continue; } var groupTrack = _mainTimeline.CreateTrack(); groupTrack.name = timelineAsset.name; foreach (var trackAsset in timelineAsset.GetRootTracks()) { trackAsset.SetGroup(groupTrack); //trackAsset.outputs //_director.SetGenericBinding(); } } } private async UniTask GetModel(CharacterDataInfo characterDataInfo) { if (!_models.TryGetValue(characterDataInfo, out var model)) { string prefabPath = characterDataInfo.PrefabPath; model = await AssetManager.Instance.LoadAssetAsync(prefabPath); if (model == null) { DebugUtil.LogError($"找不到模型, path:{prefabPath}"); } else { _assetToUnload.Add(prefabPath); } _models.Add(characterDataInfo, model); } return model; } private async UniTask GetTimeLineAsset(int timelineID) { if (!_timeLines.TryGetValue(timelineID, out var timelineAsset)) { string timelinePath = string.Format(TIMELINE_ASSET_PATH_PREFIX, timelineID); timelineAsset = await AssetManager.Instance.LoadAssetAsync(timelinePath); if (timelineAsset == null) { DebugUtil.LogError($"找不到TimelineAsset, timelineID:{timelineID} path:{timelinePath}"); } else { _assetToUnload.Add(timelinePath); } _timeLines.Add(timelineID, timelineAsset); } return timelineAsset; } private bool IsShowPointExist(CampShowConfigGroup group) { return group.cfgs.Any(cfg => IsShowPointExist(cfg.PointID)); } private bool IsShowPointExist(int showPointID) { return _campShowPointResults.Any(result => result.showPoint == showPointID); } private bool CanUseCharacter(CampShowConfigGroup group) { return !group.cfgs.Any(cfg => cfg.CharacterID > 0 && !CanUseCharacter(cfg.CharacterID)); } private bool CanUseCharacter(int characterID) { return _remindCharacters.Any(characterInfo => characterInfo.ID == characterID); } public float GetRefreshProcess() { return 100; } }