using System.Collections.Generic;
using GameFramework.DataTable;
using GeometryTD.CustomEvent;
using GeometryTD.DataTable;
using GeometryTD.Definition;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace GeometryTD.CustomComponent
{
///
/// 鎴樻枟鑺傜偣缁勪欢
///
public class CombatNodeComponent : GameFrameworkComponent
{
// Level.Id => Level
private readonly Dictionary _levelsById = new();
// LevelId => LevelPhases
private readonly Dictionary> _phasesByLevelId = new();
// LevelPhase.Id => LevelSpawnEntries
private readonly Dictionary> _spawnEntriesByPhaseId = new();
private readonly Dictionary> _selectedSpawnEntriesByPhaseId = new();
private readonly List _levelIdBuffer = new();
private readonly CombatScheduler _combatScheduler = new CombatScheduler();
private bool _runtimeInitialized;
public LevelThemeType CurrentThemeType { get; private set; }
public DRLevel CurrentLevel { get; private set; }
public void OnInit(LevelThemeType themeType)
{
ShutdownBattleRuntime();
CurrentThemeType = themeType;
CurrentLevel = null;
_levelsById.Clear();
_phasesByLevelId.Clear();
_spawnEntriesByPhaseId.Clear();
_selectedSpawnEntriesByPhaseId.Clear();
_levelIdBuffer.Clear();
IDataTable dtLevel = GameEntry.DataTable.GetDataTable();
IDataTable dtLevelPhase = GameEntry.DataTable.GetDataTable();
IDataTable dtSpawnEntry = GameEntry.DataTable.GetDataTable();
if (dtLevel == null || dtLevelPhase == null || dtSpawnEntry == null)
{
Log.Warning("CombatNodeComponent init failed. Missing data table(s).");
return;
}
DRLevel[] levels = dtLevel.GetAllDataRows();
for (int i = 0; i < levels.Length; i++)
{
DRLevel level = levels[i];
if (level.LevelThemeType != themeType)
{
continue;
}
_levelsById[level.Id] = level;
_phasesByLevelId[level.Id] = new List();
_levelIdBuffer.Add(level.Id);
}
DRLevelPhase[] levelPhases = dtLevelPhase.GetAllDataRows();
foreach (var phase in levelPhases)
{
int levelId = phase.Id / 1000;
if (!_levelsById.ContainsKey(levelId))
{
continue;
}
if (!_phasesByLevelId.TryGetValue(levelId, out List phases))
{
phases = new List();
_phasesByLevelId[levelId] = phases;
}
phases.Add(phase);
_spawnEntriesByPhaseId[phase.Id] = new List();
}
DRLevelSpawnEntry[] spawnEntries = dtSpawnEntry.GetAllDataRows();
foreach (var spawnEntry in spawnEntries)
{
int phaseId = spawnEntry.Id / 1000;
int levelId = phaseId / 1000;
if (!_levelsById.ContainsKey(levelId))
{
continue;
}
if (!_spawnEntriesByPhaseId.TryGetValue(phaseId, out List entries))
{
entries = new List();
_spawnEntriesByPhaseId[phaseId] = entries;
}
entries.Add(spawnEntry);
}
foreach (List phaseList in _phasesByLevelId.Values)
{
phaseList.Sort((left, right) => left.Id.CompareTo(right.Id));
}
foreach (List phaseSpawnEntries in _spawnEntriesByPhaseId.Values)
{
phaseSpawnEntries.Sort((left, right) =>
{
int timeCompare = left.StartTime.CompareTo(right.StartTime);
if (timeCompare != 0)
{
return timeCompare;
}
return left.Id.CompareTo(right.Id);
});
}
Log.Info(
"CombatNodeComponent initialized. Theme={0}, Levels={1}, Phases={2}, Entries={3}.",
themeType,
_levelsById.Count,
CountPhases(),
CountEntries());
EnsureBattleRuntimeInitialized();
}
public void StartCombat()
{
if (!EnsureBattleRuntimeInitialized())
{
Log.Warning("CombatNodeComponent start failed. Missing scheduler runtime.");
return;
}
if (!TrySelectRandomLevel(out DRLevel selectedLevel))
{
Log.Warning("CombatNodeComponent has no level cache. Call OnInit(levelThemeType) first.");
return;
}
if (!_phasesByLevelId.TryGetValue(selectedLevel.Id, out List phaseList) ||
phaseList == null ||
phaseList.Count <= 0)
{
Log.Warning("CombatNodeComponent start failed. Level '{0}' has no phase data.", selectedLevel.Id);
return;
}
_selectedSpawnEntriesByPhaseId.Clear();
foreach (var phase in phaseList)
{
if (_spawnEntriesByPhaseId.TryGetValue(phase.Id, out List entries) &&
entries != null)
{
_selectedSpawnEntriesByPhaseId[phase.Id] = entries;
}
else
{
_selectedSpawnEntriesByPhaseId[phase.Id] = new List();
}
}
CurrentLevel = selectedLevel;
_combatScheduler.Start(selectedLevel, phaseList, _selectedSpawnEntriesByPhaseId);
GameEntry.Event.Fire(this, NodeEnterEventArgs.Create());
}
public void EndCombat()
{
GameEntry.Event.Fire(this, NodeCompleteEventArgs.Create());
}
public void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
if (!_runtimeInitialized)
{
return;
}
_combatScheduler.OnUpdate(elapseSeconds, realElapseSeconds);
}
public void OnShutdown()
{
CurrentLevel = null;
ShutdownBattleRuntime();
}
private void OnDestroy()
{
OnShutdown();
}
private bool EnsureBattleRuntimeInitialized()
{
if (_runtimeInitialized)
{
return true;
}
_combatScheduler.OnInit();
_runtimeInitialized = true;
return true;
}
private void ShutdownBattleRuntime()
{
if (!_runtimeInitialized)
{
return;
}
_combatScheduler.OnDestroy();
_runtimeInitialized = false;
}
private bool TrySelectRandomLevel(out DRLevel level)
{
level = null;
if (_levelIdBuffer.Count <= 0)
{
return false;
}
int selectedIndex = Random.Range(0, _levelIdBuffer.Count);
int selectedLevelId = _levelIdBuffer[selectedIndex];
return _levelsById.TryGetValue(selectedLevelId, out level);
}
private int CountPhases()
{
int count = 0;
foreach (List phases in _phasesByLevelId.Values)
{
count += phases.Count;
}
return count;
}
private int CountEntries()
{
int count = 0;
foreach (List list in _spawnEntriesByPhaseId.Values)
{
count += list.Count;
}
return count;
}
}
}