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

450 lines
13 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
{
2024-01-12 18:37:15 +08:00
public int groupID;
2024-01-10 18:30:01 +08:00
public List<DataCampShowConfig> cfgs = new();
2024-01-11 18:32:08 +08:00
public bool hasToBeFull => cfgs.Any(cfg => cfg.HasCharacter);
}
public class CampShowPointResult
{
2024-01-12 18:37:15 +08:00
public int groupID;
2024-01-11 18:32:08 +08:00
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
2024-01-12 18:37:15 +08:00
//抽取流程的记录
[Serializable]
public class ExtractRecord
{
[Serializable]
public class SinglePointRecord
{
[LabelText("演出点ID")]
public int showPoint;
public int timelineID;
public uint characterID;
}
[LabelText("组ID")]
public int groupID;
[LabelText("是否抛弃")]
public bool isDispose;
[LabelText("抛弃原因")]
[ShowIf("isDispose")]
public EDisposeReason disposeReason;
[LabelText("角色记录")]
public List<SinglePointRecord> records = new();
}
//被弃用的原因
public enum EDisposeReason
{
None,
[LabelText("演出点重复")]
ShowPointRepeat,
[LabelText("组内人数不满")]
CharacterCountNotFull,
[LabelText("固定角色不存在")]
FixedCharacterNotExist,
}
2024-01-10 14:56:43 +08:00
public class CampSceneManager : MonoBehaviour
{
private enum ECurrState
{
None = 0,
LoadingCampObjects,
LoadingCharacters,
Present,
}
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
2024-01-12 18:37:15 +08:00
[ReadOnly]
[LabelText("抽取记录")]
[SerializeField]
[ShowIf("@_extractRecords.Count > 0")]
private List<ExtractRecord> _extractRecords = 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();
2024-01-12 18:37:15 +08:00
private TimelineAsset _mainTimeline;
public IEnumerable<GameObject> ShowPoints => _showPoints;
//asset相关
2024-01-11 18:32:08 +08:00
private Dictionary<CharacterDataInfo, GameObject> _models = new();
private Dictionary<int, TimelineAsset> _timeLines = new();
private HashSet<string> _assetToUnload = new();
2024-01-12 18:37:15 +08:00
public int CharacterMaxCount => Mathf.Min(_allCharacterInfos.Count, _characterMaxCount, _showPoints.Count);
2024-01-11 18:32:08 +08:00
private ECurrState _currState = ECurrState.None;
2024-01-11 18:32:08 +08:00
private void Awake()
{
2024-01-12 18:37:15 +08:00
if (!CommonUtils.IsInGame())
2024-01-12 14:59:34 +08:00
return;
_currState = ECurrState.None;
2024-01-11 18:32:08 +08:00
_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
{
await RefreshCampObjects();
2024-01-11 18:32:08 +08:00
await RefreshCampShow();
_currState = ECurrState.Present;
2024-01-10 18:30:01 +08:00
}
private async UniTask RefreshCampObjects()
2024-01-10 18:30:01 +08:00
{
_currState = ECurrState.LoadingCampObjects;
return;
2024-01-10 18:30:01 +08:00
}
2024-01-11 18:32:08 +08:00
private async UniTask RefreshCampShow()
2024-01-10 18:30:01 +08:00
{
_currState = ECurrState.LoadingCharacters;
2024-01-10 18:30:01 +08:00
RefreshCampShowData();
2024-01-12 18:37:15 +08:00
CampShowExtract();
await ExecuteCampShowResult();
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-12 18:37:15 +08:00
group.groupID = groupID;
2024-01-10 18:30:01 +08:00
}
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();
2024-01-12 18:37:15 +08:00
_extractRecords.Clear();
2024-01-11 18:32:08 +08:00
_remindCampShowConfigGroups = new(_allCampShowConfigGroups.Values);
_remindCharacters = new(_allCharacterInfos);
}
//抽取
2024-01-12 18:37:15 +08:00
private void CampShowExtract()
2024-01-11 18:32:08 +08:00
{
List<CampShowPointResult> _tempResultList = new();
while (_campShowPointResults.Count < CharacterMaxCount)
{
var randomGroup = CommonUtils.GetRandomItem(_remindCampShowConfigGroups, true);
if (randomGroup == null)
{
//如果所有组都抽完了,则直接返回
return;
}
2024-01-12 18:37:15 +08:00
ExtractRecord record = new()
{
groupID = randomGroup.groupID
};
_extractRecords.Add(record);
2024-01-11 18:32:08 +08:00
//如果组里的演出点和当前已经使用的演出点重复,则跳过该组
if (IsShowPointExist(randomGroup))
2024-01-12 18:37:15 +08:00
{
record.isDispose = true;
record.disposeReason = EDisposeReason.ShowPointRepeat;
2024-01-11 18:32:08 +08:00
continue;
2024-01-12 18:37:15 +08:00
}
2024-01-11 18:32:08 +08:00
//如果组里有限定演员,但演员已使用,则跳过该组
if (!CanUseCharacter(randomGroup))
2024-01-12 18:37:15 +08:00
{
record.isDispose = true;
record.disposeReason = EDisposeReason.FixedCharacterNotExist;
2024-01-11 18:32:08 +08:00
continue;
2024-01-12 18:37:15 +08:00
}
2024-01-11 18:32:08 +08:00
//临时存放抽取的结果
_tempResultList.Clear();
foreach (var cfg in randomGroup.cfgs)
{
//如果当前没有剩余的演员,则直接跳出抽取
if (_remindCharacters.Count == 0)
break;
2024-01-12 18:37:15 +08:00
ExtractRecord.SinglePointRecord singlePointRecord = new();
record.records.Add(singlePointRecord);
2024-01-11 18:32:08 +08:00
//抽取timeline
var timelineID = CommonUtils.GetRandomItem(cfg.TimelineIDs);
2024-01-12 18:37:15 +08:00
singlePointRecord.timelineID = timelineID;
2024-01-11 18:32:08 +08:00
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()
{
2024-01-12 18:37:15 +08:00
groupID = randomGroup.groupID,
2024-01-11 18:32:08 +08:00
showPoint = cfg.PointID,
timelineID = timelineID,
characterDataInfo = characterDataInfo
};
2024-01-12 18:37:15 +08:00
singlePointRecord.showPoint = cfg.PointID;
singlePointRecord.characterID = characterDataInfo.ID;
2024-01-11 18:32:08 +08:00
_tempResultList.Add(result);
}
if (randomGroup.hasToBeFull && _tempResultList.Count < randomGroup.cfgs.Count)
{
//如果该组必须满员但没满员
//取出来的CharacterDataInfo归还
foreach (var result in _tempResultList)
{
_remindCharacters.Add(result.characterDataInfo);
}
2024-01-12 18:37:15 +08:00
record.isDispose = true;
record.disposeReason = EDisposeReason.CharacterCountNotFull;
2024-01-11 18:32:08 +08:00
}
else
{
//添加到最后的result列表中
_campShowPointResults.AddRange(_tempResultList);
}
}
}
//执行抽取结果
2024-01-12 18:37:15 +08:00
private async UniTask ExecuteCampShowResult()
2024-01-11 18:32:08 +08:00
{
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;
}
2024-01-12 19:27:56 +08:00
2024-01-11 18:32:08 +08:00
model.transform.position = showPointTransform.transform.position;
var timelineAsset = await GetTimeLineAsset(result.timelineID);
if (timelineAsset == null)
{
continue;
}
var director = model.GetComponent<PlayableDirector>();
if (director == null)
{
continue;
}
director.playableAsset = timelineAsset;
director.extrapolationMode = DirectorWrapMode.Loop;
foreach (var playableBinding in timelineAsset.outputs)
2024-01-11 18:32:08 +08:00
{
director.SetGenericBinding(playableBinding.sourceObject, model.GetComponentInChildren<Animator>());
2024-01-11 18:32:08 +08:00
}
director.Play();
2024-01-11 18:32:08 +08:00
}
}
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}");
return null;
2024-01-11 18:32:08 +08:00
}
2024-01-12 19:27:56 +08:00
model = Instantiate(model, _characterRoot);
model.AddComponent<PlayableDirector>();
model.SetLayerEx(LayerMask.NameToLayer("UIView"));
_assetToUnload.Add(prefabPath);
2024-01-11 18:32:08 +08:00
_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()
{
switch (_currState)
{
case ECurrState.None:
return 0;
case ECurrState.LoadingCampObjects:
2024-01-12 15:35:41 +08:00
return 0.5f;
case ECurrState.LoadingCharacters:
2024-01-12 15:35:41 +08:00
return 0.5f + (float)_campShowPointResults.Count / CharacterMaxCount * 0.5f;
case ECurrState.Present:
2024-01-12 15:35:41 +08:00
return 1;
default:
return 0;
}
2024-01-10 18:30:01 +08:00
}
2024-01-10 14:56:43 +08:00
}