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

337 lines
10 KiB
C#
Raw Normal View History

2024-01-10 18:30:01 +08:00
using System;
2024-01-10 14:56:43 +08:00
using System.Collections;
using System.Collections.Generic;
2024-01-11 18:32:08 +08:00
using System.Linq;
2024-01-10 18:30:01 +08:00
using cfg.CampCfg;
2024-01-11 18:32:08 +08:00
using Cysharp.Threading.Tasks;
2024-01-10 18:30:01 +08:00
using Framework;
2024-01-11 18:32:08 +08:00
using Gameplay;
using PhxhSDK;
2024-01-10 14:56:43 +08:00
using Sirenix.OdinInspector;
using UnityEngine;
2024-01-11 18:32:08 +08:00
using UnityEngine.Playables;
2024-01-10 18:30:01 +08:00
using UnityEngine.Serialization;
2024-01-11 18:32:08 +08:00
using UnityEngine.Timeline;
using Object = UnityEngine.Object;
2024-01-10 18:30:01 +08:00
public class CampShowConfigGroup
{
public List<DataCampShowConfig> cfgs = new();
2024-01-11 18:32:08 +08:00
public bool hasToBeFull => cfgs.Any(cfg => cfg.HasCharacter);
}
public class CampShowPointResult
{
public int showPoint;
public int timelineID;
public CharacterDataInfo characterDataInfo;
2024-01-10 18:30:01 +08:00
}
2024-01-10 14:56:43 +08:00
public class CampSceneManager : MonoBehaviour
{
2024-01-11 18:32:08 +08:00
private const string TIMELINE_ASSET_PATH_PREFIX = "Assets/Art/Camp/Timeline/camp_timeline_{0}.playable";
2024-01-10 18:30:01 +08:00
2024-01-10 19:01:07 +08:00
[LabelText("抽取角色数")]
[SerializeField]
private int _characterMaxCount = 20;
2024-01-10 18:30:01 +08:00
2024-01-11 18:32:08 +08:00
[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();
2024-01-10 18:30:01 +08:00
private List<CharacterDataInfo> _allCharacterInfos = new();
private Dictionary<int, CampShowConfigGroup> _allCampShowConfigGroups = new();
2024-01-11 18:32:08 +08:00
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()
2024-01-10 18:30:01 +08:00
{
RefreshCampObjects();
2024-01-11 18:32:08 +08:00
await RefreshCampShow();
2024-01-10 18:30:01 +08:00
}
private void RefreshCampObjects()
{
}
2024-01-11 18:32:08 +08:00
private async UniTask RefreshCampShow()
2024-01-10 18:30:01 +08:00
{
RefreshCampShowData();
2024-01-11 18:32:08 +08:00
await ExecuteCampShow();
2024-01-10 18:30:01 +08:00
}
2024-01-11 18:32:08 +08:00
private void LoadData()
2024-01-10 18:30:01 +08:00
{
_allCharacterInfos = new List<CharacterDataInfo>(CharacterDataInfoManager.Instance.DataList);
var campShowConfigList = TableManager.Instance.Tables.CampShowConfig.DataList;
_allCampShowConfigGroups.Clear();
2024-01-11 18:32:08 +08:00
2024-01-10 18:30:01 +08:00
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);
}
2024-01-11 18:32:08 +08:00
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);
2024-01-10 18:30:01 +08:00
}
2024-01-10 19:01:07 +08:00
2024-01-10 18:30:01 +08:00
public float GetRefreshProcess()
{
return 100;
}
2024-01-10 14:56:43 +08:00
}