305 lines
10 KiB
C#
305 lines
10 KiB
C#
using Core.Config;
|
|
using GameServer.Controllers.Attributes;
|
|
using GameServer.Extensions.Logic;
|
|
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<RpcResult> OnEntityActiveRequest(EntityActiveRequest request)
|
|
{
|
|
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
|
|
};
|
|
|
|
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()
|
|
{
|
|
_modelManager.Creature.OnWorldDone();
|
|
await UpdateAiHate();
|
|
|
|
return Response(MessageId.SceneLoadingFinishResponse, new SceneLoadingFinishResponse());
|
|
}
|
|
|
|
[GameEvent(GameEventType.FormationUpdated)]
|
|
public async Task OnFormationUpdated()
|
|
{
|
|
// Remove old entities
|
|
|
|
IEnumerable<PlayerEntity> 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<PlayerEntity> 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<EntityVisionSkillComponent>();
|
|
|
|
VisionSkillChangeNotify skillChangeNotify = new() { EntityId = playerEntity.Id };
|
|
skillChangeNotify.VisionSkillInfos.AddRange(visionSkillComponent.Skills);
|
|
|
|
await Session.Push(MessageId.VisionSkillChangeNotify, skillChangeNotify);
|
|
}
|
|
|
|
public PlayerEntity? GetPlayerEntity()
|
|
{
|
|
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;
|
|
}
|
|
|
|
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;
|
|
|
|
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!
|
|
})
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
});
|
|
}
|
|
|
|
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<FightRoleInformation> 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++)
|
|
{
|
|
int roleId = _modelManager.Formation.RoleIds[i];
|
|
|
|
PlayerEntity entity = _entityFactory.CreatePlayer(roleId, _modelManager.Player.Id);
|
|
entity.Pos = _modelManager.Player.Position.Clone();
|
|
entity.IsCurrentRole = i == 0;
|
|
|
|
_entitySystem.Create(entity);
|
|
entity.ComponentSystem.Get<EntityAttributeComponent>().SetAll(_modelManager.Roles.GetRoleById(roleId)!.GetAttributeList());
|
|
|
|
CreateConcomitants(entity);
|
|
entity.WeaponId = _modelManager.Inventory.GetEquippedWeapon(roleId)?.Id ?? 0;
|
|
|
|
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<EntityConcomitantsComponent>();
|
|
concomitants.CustomEntityIds.Clear();
|
|
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;
|
|
concomitant.InitProps(_configManager.GetConfig<BasePropertyConfig>(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<BasePropertyConfig>(600000100)!);
|
|
}
|
|
}
|