using RPG.GameCore.Excel; using RPG.GameCore.Level; using RPG.GameCore.Level.Floor; using RPG.GameCore.Level.Group; using RPG.GameCore.Level.Objects; using RPG.Network.Proto; using RPG.Services.Gameserver.Game.Entity; using RPG.Services.Gameserver.Game.Entity.Factory; using RPG.Services.Gameserver.Game.Team; using RPG.Services.Gameserver.Game.Util; using MazeInfo = RPG.Network.Proto.Maze; namespace RPG.Services.Gameserver.Game.Maze; internal class MazeManager { private readonly EntityFactory _entityFactory; private readonly ExcelTables _excelTables; private readonly LevelTables _levelTables; private MapEntryRow? _mapEntry; private LevelFloorInfo? _floor; private PlayerTeam? _playerTeam; private uint _uid; public EntityManager EntityManager { get; } public MazeManager(EntityManager entityManager, EntityFactory entityFactory, ExcelTables excelTables, LevelTables levelTables) { EntityManager = entityManager; _entityFactory = entityFactory; _excelTables = excelTables; _levelTables = levelTables; } public void ResetAvatarPosition() { foreach (TeamMember? member in _playerTeam!.Members) { if (member == null) continue; AvatarEntity? entity = EntityManager.GetAvatar(_uid, member.AvatarId); if (entity != null) { entity.SetMotion(CreateInitialAvatarMotion()); EntityManager.NotifyMove(entity); } } } public void RemoveEntities(IEnumerable entities) { EntityManager.RemoveEntities(entities); } public void SetPlayerUid(uint uid) { _uid = uid; } public void EnterMaze(uint entryId, PlayerTeam team) { BeforeEnter(); _playerTeam = team; _mapEntry = _excelTables.GetExcelRow(ExcelType.MapEntry, entryId) ?? throw new ArgumentException("EnterMaze: specified entryId doesn't exist!", nameof(entryId)); _floor = _levelTables.GetFloorInfo(_mapEntry.FloorID); AddTeamMemberEntities(); InitLevelGroups(); } public MazeInfo Maze { get { if (_mapEntry == null) throw new InvalidOperationException("GetMaze: maze not loaded!"); return new() { MapEntryId = _mapEntry.ID, Id = _mapEntry.PlaneID, Floor = new() { FloorId = _mapEntry.FloorID, Scene = SceneInfo } }; } } public SceneInfo SceneInfo { get { if (_mapEntry == null || _playerTeam == null) throw new InvalidOperationException("GetSceneInfo: scene not loaded!"); AvatarEntity? leaderEntity = EntityManager.GetAvatar(_uid, _playerTeam.Leader.AvatarId); SceneInfo info = new() { EntryId = _mapEntry.ID, PlaneId = _mapEntry.PlaneID, FloorId = _mapEntry.FloorID, LeaderEntityId = leaderEntity?.Id ?? 0, }; info.EntityList.AddRange(EntityManager.EntityInfoList); return info; } } private void InitLevelGroups() { foreach (LevelGroupInstanceInfo groupInstanceInfo in _floor!.GroupList) { LevelGroupInfo? levelGroup = _levelTables.GetGroupInfo(groupInstanceInfo.GroupGUID); if (levelGroup == null) continue; foreach (LevelMonsterInfo levelMonster in levelGroup.MonsterList) { if (!levelMonster.CreateOnInitial) continue; NpcMonsterEntity monsterEntity = _entityFactory.CreateNpcMonsterEntity(levelMonster, groupInstanceInfo.ID); monsterEntity.SetMotion(MazeUtil.CreateDefaultMotion(levelMonster)); EntityManager.AddEntity(monsterEntity); } foreach (LevelPropInfo levelProp in levelGroup.PropList) { if (!levelProp.CreateOnInitial) continue; PropEntity propEntity = _entityFactory.CreatePropEntity(levelProp, groupInstanceInfo.ID); propEntity.SetMotion(MazeUtil.CreateDefaultMotion(levelProp)); EntityManager.AddEntity(propEntity); } foreach (LevelNPCInfo levelNPC in levelGroup.NPCList) { if (!levelNPC.CreateOnInitial) continue; NpcEntity npcEntity = _entityFactory.CreateNpcEntity(levelNPC, groupInstanceInfo.ID); npcEntity.SetMotion(MazeUtil.CreateDefaultMotion(levelNPC)); EntityManager.AddEntity(npcEntity); } } } private void AddTeamMemberEntities() { foreach (TeamMember? member in _playerTeam!.Members) { if (member == null) continue; AvatarEntity entity = _entityFactory.CreateAvatarEntity(member.AvatarId, member.AvatarType, _uid); entity.SetMotion(CreateInitialAvatarMotion()); EntityManager.AddEntity(entity); } } private MotionInfo CreateInitialAvatarMotion() { LevelGroupInfo startGroup = _levelTables.GetGroupInfo(_floor!.StartGroup.GroupGUID)!; LevelAnchorInfo startAnchor = startGroup.AnchorList.First(anchor => anchor.ID == _floor.StartAnchorID); return MazeUtil.CreateDefaultMotion(startAnchor); } private void BeforeEnter() { _entityFactory.Reset(); EntityManager.Clear(); } }