NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Gameplay/Camp/CampSceneManager.cs

337 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<DataCampShowConfig> 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<GameObject> _showPoints = new();
private List<CharacterDataInfo> _allCharacterInfos = new();
private Dictionary<int, CampShowConfigGroup> _allCampShowConfigGroups = new();
private List<CampShowConfigGroup> _remindCampShowConfigGroups = new();
private List<CharacterDataInfo> _remindCharacters = new();
private List<CampShowPointResult> _campShowPointResults = new();
private Dictionary<CharacterDataInfo, GameObject> _models = new();
private Dictionary<int, TimelineAsset> _timeLines = new();
private TimelineAsset _mainTimeline;
//asset相关
private HashSet<string> _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<CharacterDataInfo>(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<CampShowPointResult> _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>();
groupTrack.name = timelineAsset.name;
foreach (var trackAsset in timelineAsset.GetRootTracks())
{
trackAsset.SetGroup(groupTrack);
//trackAsset.outputs
//_director.SetGenericBinding();
}
}
}
private async UniTask<GameObject> GetModel(CharacterDataInfo characterDataInfo)
{
if (!_models.TryGetValue(characterDataInfo, out var model))
{
string prefabPath = characterDataInfo.PrefabPath;
model = await AssetManager.Instance.LoadAssetAsync<GameObject>(prefabPath);
if (model == null)
{
DebugUtil.LogError($"找不到模型, path:{prefabPath}");
}
else
{
_assetToUnload.Add(prefabPath);
}
_models.Add(characterDataInfo, model);
}
return model;
}
private async UniTask<TimelineAsset> GetTimeLineAsset(int timelineID)
{
if (!_timeLines.TryGetValue(timelineID, out var timelineAsset))
{
string timelinePath = string.Format(TIMELINE_ASSET_PATH_PREFIX, timelineID);
timelineAsset = await AssetManager.Instance.LoadAssetAsync<TimelineAsset>(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;
}
}