using Core.Config; using GameServer.Controllers.Attributes; using GameServer.Models; using GameServer.Network; using GameServer.Network.Messages; using GameServer.Systems.Entity; using GameServer.Systems.Entity.Component; using GameServer.Systems.Event; using Protocol; namespace GameServer.Controllers; internal class CreatureController : Controller { private readonly EntitySystem _entitySystem; private readonly EntityFactory _entityFactory; private readonly ModelManager _modelManager; private readonly ConfigManager _configManager; public CreatureController(PlayerSession session, EntitySystem entitySystem, EntityFactory entityFactory, ModelManager modelManager, ConfigManager configManager) : base(session) { _entitySystem = entitySystem; _entityFactory = entityFactory; _modelManager = modelManager; _configManager = configManager; } public async Task JoinScene(int instanceId) { _modelManager.Creature.SetSceneLoadingData(instanceId); CreateTeamPlayerEntities(); CreateWorldEntities(); await Session.Push(MessageId.JoinSceneNotify, new JoinSceneNotify { MaxEntityId = 10000000, TransitionOption = new TransitionOptionPb { TransitionType = (int)TransitionType.Empty }, SceneInfo = CreateSceneInfo() }); } [NetEvent(MessageId.EntityActiveRequest)] public async Task OnEntityActiveRequest(EntityActiveRequest request) { EntityActiveResponse response; EntityBase? entity = _entitySystem.Get(request.EntityId); if (entity != null) { _entitySystem.Activate(entity); response = new EntityActiveResponse { ErrorCode = (int)ErrorCode.Success }; response.ComponentPbs.AddRange(entity.ComponentSystem.Pb); } else { response = new EntityActiveResponse { ErrorCode = (int)ErrorCode.ErrActionEntityNoExist }; } await OnVisionSkillChanged(); return Response(MessageId.EntityActiveResponse, response); } [NetEvent(MessageId.SceneLoadingFinishRequest)] public async Task OnSceneLoadingFinishRequest() { _modelManager.Creature.OnWorldDone(); await UpdateAiHate(); return Response(MessageId.SceneLoadingFinishResponse, new SceneLoadingFinishResponse()); } [GameEvent(GameEventType.FormationUpdated)] public async Task OnFormationUpdated() { // Remove old entities IEnumerable oldEntities = GetPlayerEntities().ToArray(); foreach (PlayerEntity oldEntity in oldEntities) { _entitySystem.Destroy(oldEntity); } await Session.Push(MessageId.EntityRemoveNotify, new EntityRemoveNotify { IsRemove = true, RemoveInfos = { oldEntities.Select(entity => new EntityRemoveInfo { EntityId = entity.Id, Type = (int)entity.Type }) } }); // Spawn new entities CreateTeamPlayerEntities(); IEnumerable newEntities = GetPlayerEntities(); await Session.Push(MessageId.EntityAddNotify, new EntityAddNotify { IsAdd = true, EntityPbs = { newEntities.Select(entity => entity.Pb) } }); _modelManager.Creature.PlayerEntityId = newEntities.First().Id; await Session.Push(MessageId.UpdatePlayerAllFightRoleNotify, new UpdatePlayerAllFightRoleNotify { PlayerId = _modelManager.Player.Id, FightRoleInfos = { GetFightRoleInfos() } }); await UpdateAiHate(); } [GameEvent(GameEventType.VisionSkillChanged)] public async Task OnVisionSkillChanged() { PlayerEntity? playerEntity = GetPlayerEntity(); if (playerEntity == null) return; EntityVisionSkillComponent visionSkillComponent = playerEntity.ComponentSystem.Get(); VisionSkillChangeNotify skillChangeNotify = new() { EntityId = playerEntity.Id }; skillChangeNotify.VisionSkillInfos.AddRange(visionSkillComponent.Skills); await Session.Push(MessageId.VisionSkillChangeNotify, skillChangeNotify); } public PlayerEntity? GetPlayerEntity() { return _entitySystem.Get(_modelManager.Creature.PlayerEntityId); } public PlayerEntity? GetPlayerEntityByRoleId(int roleId) { return _entitySystem.EnumerateEntities() .FirstOrDefault(e => e is PlayerEntity playerEntity && playerEntity.ConfigId == roleId && playerEntity.PlayerId == _modelManager.Player.Id) as PlayerEntity; } public IEnumerable GetPlayerEntities() { return _entitySystem.EnumerateEntities() .Where(e => e is PlayerEntity entity && entity.PlayerId == _modelManager.Player.Id) .Cast(); } public async Task SwitchPlayerEntity(int roleId) { PlayerEntity? prevEntity = GetPlayerEntity(); if (prevEntity == null) return; prevEntity.IsCurrentRole = false; if (_entitySystem.EnumerateEntities().FirstOrDefault(e => e is PlayerEntity playerEntity && playerEntity.ConfigId == roleId) is not PlayerEntity newEntity) return; _modelManager.Creature.PlayerEntityId = newEntity.Id; newEntity.IsCurrentRole = true; await UpdateAiHate(); } public async Task UpdateAiHate() { IEnumerable monsters = _entitySystem.EnumerateEntities().Where(e => e is MonsterEntity); if (!monsters.Any()) return; await Session.Push(MessageId.CombatReceivePackNotify, new CombatReceivePackNotify { Data = { monsters.Select(monster => new CombatReceiveData { CombatNotifyData = new() { CombatCommon = new() { EntityId = monster.Id }, AiHateNotify = new() { HateList = { GetPlayerEntities().Select(player => new AiHateEntity { EntityId = player.Id, HatredValue = 99999 // currently this, TODO! }) } } } }) } }); } private SceneInformation CreateSceneInfo() => new() { InstanceId = _modelManager.Creature.InstanceId, OwnerId = _modelManager.Creature.OwnerId, CurContextId = _modelManager.Player.Id, TimeInfo = new(), AoiData = new PlayerSceneAoiData { Entities = { _entitySystem.Pb } }, PlayerInfos = { new ScenePlayerInformation { PlayerId = _modelManager.Player.Id, Level = 1, IsOffline = false, Location = _modelManager.Player.Position, PlayerName = _modelManager.Player.Name, FightRoleInfos = { GetFightRoleInfos() } } } }; private IEnumerable GetFightRoleInfos() { return GetPlayerEntities().Select(playerEntity => new FightRoleInformation { EntityId = playerEntity.Id, CurHp = playerEntity.Health, MaxHp = playerEntity.HealthMax, IsControl = playerEntity.Id == _modelManager.Creature.PlayerEntityId, RoleId = playerEntity.ConfigId, RoleLevel = 1, }); } private void CreateTeamPlayerEntities() { for (int i = 0; i < _modelManager.Formation.RoleIds.Length; i++) { PlayerEntity entity = _entityFactory.CreatePlayer(_modelManager.Formation.RoleIds[i], _modelManager.Player.Id); entity.Pos = _modelManager.Player.Position.Clone(); entity.IsCurrentRole = i == 0; _entitySystem.Create(entity); entity.InitProps(_configManager.GetConfig(entity.ConfigId)!); CreateConcomitants(entity); // Give weapon to entity RoleInfoConfig roleConfig = _configManager.GetConfig(entity.ConfigId)!; WeaponConfig weaponConfig = _configManager.GetConfig(roleConfig.InitWeaponItemId)!; entity.WeaponId = weaponConfig.ItemId; if (i == 0) _modelManager.Creature.PlayerEntityId = entity.Id; } } private void CreateConcomitants(PlayerEntity entity) { (int roleId, int summonConfigId) = entity.ConfigId switch { 1302 => (5002, 10070301), _ => (-1, -1) }; if (roleId != -1) { PlayerEntity concomitant = _entityFactory.CreatePlayer(roleId, 0); _entitySystem.Create(concomitant); EntityConcomitantsComponent concomitants = entity.ComponentSystem.Get(); concomitants.CustomEntityIds.Clear(); concomitants.CustomEntityIds.Add(concomitant.Id); EntitySummonerComponent summoner = concomitant.ComponentSystem.Create(); summoner.SummonerId = entity.Id; summoner.SummonConfigId = summonConfigId; summoner.SummonType = ESummonType.ConcomitantCustom; summoner.PlayerId = _modelManager.Player.Id; concomitant.InitProps(_configManager.GetConfig(roleId)!); } } private void CreateWorldEntities() { Vector playerPos = _modelManager.Player.Position; // Test monster MonsterEntity monster = _entityFactory.CreateMonster(106003002); // Turtle. monster.Pos = new() { X = playerPos.X + 250, Y = playerPos.Y + 250, Z = playerPos.Z }; _entitySystem.Create(monster); monster.InitProps(_configManager.GetConfig(600000100)!); } }