WutheringWaves/GameServer/Controllers/CreatureController.cs

334 lines
12 KiB
C#
Raw Normal View History

2024-02-12 06:26:32 +00:00
using Core.Config;
using GameServer.Controllers.Attributes;
2024-02-21 21:14:56 +00:00
using GameServer.Extensions.Logic;
2024-02-10 16:04:03 +00:00
using GameServer.Models;
using GameServer.Network;
using GameServer.Settings;
2024-02-10 16:04:03 +00:00
using GameServer.Systems.Entity;
using GameServer.Systems.Entity.Component;
using GameServer.Systems.Event;
using GameServer.Systems.Notify;
using Microsoft.Extensions.Options;
2024-02-10 16:04:03 +00:00
using Protocol;
namespace GameServer.Controllers;
internal class CreatureController : Controller
{
private const float DynamicSpawnRadius = 5000;
private const float DynamicSpawnPositionDelta = 2500;
2024-02-10 16:04:03 +00:00
private readonly EntitySystem _entitySystem;
private readonly EntityFactory _entityFactory;
private readonly ModelManager _modelManager;
2024-02-12 00:23:27 +00:00
private readonly ConfigManager _configManager;
private readonly IGameActionListener _listener;
2024-02-10 16:04:03 +00:00
private readonly GameplayFeatureSettings _gameplayFeatures;
private readonly Vector _lastDynamicSpawnPos;
public CreatureController(PlayerSession session, EntitySystem entitySystem, EntityFactory entityFactory, ModelManager modelManager, ConfigManager configManager, IOptions<GameplayFeatureSettings> gameplayFeatures, IGameActionListener listener) : base(session)
2024-02-10 16:04:03 +00:00
{
_entitySystem = entitySystem;
_entityFactory = entityFactory;
_modelManager = modelManager;
2024-02-12 00:23:27 +00:00
_configManager = configManager;
_listener = listener;
_gameplayFeatures = gameplayFeatures.Value;
_lastDynamicSpawnPos = new();
2024-02-10 16:04:03 +00:00
}
public async Task JoinScene(int instanceId)
{
_modelManager.Creature.SetSceneLoadingData(instanceId);
CreateTeamPlayerEntities();
2024-02-14 21:22:21 +00:00
CreateWorldEntities();
2024-02-10 16:04:03 +00:00
await _listener.OnJoinedScene(CreateSceneInfo(), TransitionType.Empty);
2024-02-10 16:04:03 +00:00
}
[NetEvent(MessageId.EntityActiveRequest)]
public async Task<RpcResult> OnEntityActiveRequest(EntityActiveRequest request)
2024-02-10 16:04:03 +00:00
{
EntityActiveResponse response;
EntityBase? entity = _entitySystem.Get<EntityBase>(request.EntityId);
if (entity != null)
{
_entitySystem.Activate(entity);
response = new EntityActiveResponse
{
ErrorCode = (int)ErrorCode.Success,
IsVisible = entity.IsVisible
2024-02-10 16:04:03 +00:00
};
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<RpcResult> OnSceneLoadingFinishRequest()
2024-02-10 16:04:03 +00:00
{
_modelManager.Creature.OnWorldDone();
await UpdateAiHate();
2024-02-10 16:04:03 +00:00
return Response(MessageId.SceneLoadingFinishResponse, new SceneLoadingFinishResponse());
}
[GameEvent(GameEventType.FormationUpdated)]
public async Task OnFormationUpdated()
{
_entitySystem.Destroy(GetPlayerEntities().ToArray());
CreateTeamPlayerEntities();
_modelManager.Creature.PlayerEntityId = GetPlayerEntities().First().Id;
await _listener.OnPlayerFightRoleInfoUpdated(_modelManager.Player.Id, GetFightRoleInfos());
await UpdateAiHate();
}
[GameEvent(GameEventType.PlayerPositionChanged)]
public void OnPlayerPositionChanged()
{
_modelManager.Player.Position.MergeFrom(GetPlayerEntity()!.Pos);
if (_lastDynamicSpawnPos.GetDistance(_modelManager.Player.Position) >= DynamicSpawnPositionDelta)
{
_lastDynamicSpawnPos.MergeFrom(_modelManager.Player.Position);
ClearInactiveEntities();
SpawnDynamicEntities();
}
}
2024-02-10 16:04:03 +00:00
[GameEvent(GameEventType.VisionSkillChanged)]
public async Task OnVisionSkillChanged()
{
PlayerEntity? playerEntity = GetPlayerEntity();
2024-02-10 16:04:03 +00:00
if (playerEntity == null) return;
EntityVisionSkillComponent visionSkillComponent = playerEntity.ComponentSystem.Get<EntityVisionSkillComponent>();
VisionSkillChangeNotify skillChangeNotify = new() { EntityId = playerEntity.Id };
skillChangeNotify.VisionSkillInfos.AddRange(visionSkillComponent.Skills);
await Session.Push(MessageId.VisionSkillChangeNotify, skillChangeNotify);
}
public PlayerEntity? GetPlayerEntity()
2024-02-10 16:04:03 +00:00
{
return _entitySystem.Get<PlayerEntity>(_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;
}
2024-02-14 21:22:21 +00:00
public IEnumerable<PlayerEntity> GetPlayerEntities()
{
return _entitySystem.EnumerateEntities()
.Where(e => e is PlayerEntity entity && entity.PlayerId == _modelManager.Player.Id)
.Cast<PlayerEntity>();
}
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;
newEntity.Pos.MergeFrom(prevEntity.Pos);
newEntity.Rot.MergeFrom(prevEntity.Rot);
await UpdateAiHate();
}
public async Task UpdateAiHate()
{
IEnumerable<EntityBase> 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!
})
}
}
}
})
}
});
2024-02-10 16:04:03 +00:00
}
2024-02-12 01:03:50 +00:00
private SceneInformation CreateSceneInfo() => new()
2024-02-10 16:04:03 +00:00
{
2024-02-12 01:03:50 +00:00
InstanceId = _modelManager.Creature.InstanceId,
OwnerId = _modelManager.Creature.OwnerId,
CurContextId = _modelManager.Player.Id,
TimeInfo = new(),
AoiData = new PlayerSceneAoiData
2024-02-10 16:04:03 +00:00
{
2024-02-12 01:03:50 +00:00
Entities = { _entitySystem.Pb }
},
PlayerInfos =
{
new ScenePlayerInformation
2024-02-10 16:04:03 +00:00
{
2024-02-12 01:03:50 +00:00
PlayerId = _modelManager.Player.Id,
Level = 1,
IsOffline = false,
2024-02-15 18:33:05 +00:00
Location = _modelManager.Player.Position,
2024-02-12 01:03:50 +00:00
PlayerName = _modelManager.Player.Name,
FightRoleInfos = { GetFightRoleInfos() }
2024-02-10 16:04:03 +00:00
}
}
2024-02-12 01:03:50 +00:00
};
private IEnumerable<FightRoleInformation> GetFightRoleInfos()
{
return GetPlayerEntities().Select(playerEntity => new FightRoleInformation
2024-02-12 01:03:50 +00:00
{
EntityId = playerEntity.Id,
CurHp = playerEntity.Health,
MaxHp = playerEntity.HealthMax,
IsControl = playerEntity.Id == _modelManager.Creature.PlayerEntityId,
RoleId = playerEntity.ConfigId,
RoleLevel = 1,
});
2024-02-10 16:04:03 +00:00
}
private void CreateTeamPlayerEntities()
2024-02-10 16:04:03 +00:00
{
PlayerEntity[] playerEntities = new PlayerEntity[_modelManager.Formation.RoleIds.Length];
for (int i = 0; i < _modelManager.Formation.RoleIds.Length; i++)
2024-02-10 16:04:03 +00:00
{
2024-02-21 21:14:56 +00:00
int roleId = _modelManager.Formation.RoleIds[i];
PlayerEntity entity = _entityFactory.CreatePlayer(roleId, _modelManager.Player.Id);
2024-02-15 18:33:05 +00:00
entity.Pos = _modelManager.Player.Position.Clone();
entity.IsCurrentRole = i == 0;
2024-02-21 21:14:56 +00:00
entity.ComponentSystem.Get<EntityAttributeComponent>().SetAll(_modelManager.Roles.GetRoleById(roleId)!.GetAttributeList());
2024-02-17 20:09:49 +00:00
CreateConcomitants(entity);
2024-02-21 22:00:48 +00:00
entity.WeaponId = _modelManager.Inventory.GetEquippedWeapon(roleId)?.Id ?? 0;
2024-02-12 00:23:27 +00:00
if (i == 0) _modelManager.Creature.PlayerEntityId = entity.Id;
if (_gameplayFeatures.UnlimitedEnergy)
{
EntityAttributeComponent attr = entity.ComponentSystem.Get<EntityAttributeComponent>();
attr.SetAttribute(EAttributeType.EnergyMax, 0);
attr.SetAttribute(EAttributeType.SpecialEnergy1Max, 0);
attr.SetAttribute(EAttributeType.SpecialEnergy2Max, 0);
attr.SetAttribute(EAttributeType.SpecialEnergy3Max, 0);
attr.SetAttribute(EAttributeType.SpecialEnergy4Max, 0);
}
playerEntities[i] = entity;
}
_entitySystem.Add(playerEntities);
2024-02-14 21:22:21 +00:00
}
2024-02-17 20:09:49 +00:00
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);
2024-02-24 12:23:00 +00:00
EntityConcomitantsComponent concomitants = entity.ComponentSystem.Create<EntityConcomitantsComponent>();
2024-02-17 20:09:49 +00:00
concomitants.CustomEntityIds.Clear();
2024-02-24 12:23:00 +00:00
concomitants.VisionEntityId = concomitant.Id;
2024-02-17 20:09:49 +00:00
concomitants.CustomEntityIds.Add(concomitant.Id);
EntitySummonerComponent summoner = concomitant.ComponentSystem.Create<EntitySummonerComponent>();
summoner.SummonerId = entity.Id;
summoner.SummonConfigId = summonConfigId;
summoner.SummonType = ESummonType.ConcomitantCustom;
summoner.PlayerId = _modelManager.Player.Id;
2024-02-24 12:23:00 +00:00
2024-02-17 20:09:49 +00:00
concomitant.InitProps(_configManager.GetConfig<BasePropertyConfig>(roleId)!);
_entitySystem.Add([concomitant]);
2024-02-17 20:09:49 +00:00
}
}
2024-02-14 21:22:21 +00:00
private void CreateWorldEntities()
{
_lastDynamicSpawnPos.MergeFrom(_modelManager.Player.Position.Clone());
SpawnDynamicEntities();
}
private void ClearInactiveEntities()
{
_entitySystem.Destroy(_entitySystem.EnumerateEntities()
.Where(e => e is MonsterEntity && e.DynamicId != 0 &&
e.Pos.GetDistance(_modelManager.Player.Position) > DynamicSpawnRadius).ToArray());
}
private void SpawnDynamicEntities()
2024-02-14 21:22:21 +00:00
{
2024-02-15 18:33:05 +00:00
Vector playerPos = _modelManager.Player.Position;
// Currently only monsters
IEnumerable<LevelEntityConfig> entitiesToSpawn = _configManager.Enumerate<LevelEntityConfig>()
.Where(config => config.MapId == 8 && Math.Abs(config.Transform[0].X / 100 - playerPos.X) < DynamicSpawnRadius && Math.Abs(config.Transform[0].Y / 100 - playerPos.Y) < DynamicSpawnRadius &&
config.BlueprintType.StartsWith("Monster"));
List<MonsterEntity> spawnMonsters = [];
foreach (LevelEntityConfig levelEntity in entitiesToSpawn)
{
if (_entitySystem.HasDynamicEntity(levelEntity.EntityId)) continue;
MonsterEntity monster = _entityFactory.CreateMonster(levelEntity.EntityId);
monster.Pos = new()
{
X = levelEntity.Transform[0].X / 100,
Y = levelEntity.Transform[0].Y / 100,
Z = levelEntity.Transform[0].Z / 100
};
monster.InitProps(_configManager.GetConfig<BasePropertyConfig>(600000100)!);
spawnMonsters.Add(monster);
}
_entitySystem.Add(spawnMonsters);
2024-02-10 16:04:03 +00:00
}
}