CombatManager, Monster AI, monster death
This commit is contained in:
parent
4e82ccb871
commit
d733766909
13 changed files with 636 additions and 207 deletions
14
GameServer/Controllers/Attributes/CombatRequestAttribute.cs
Normal file
14
GameServer/Controllers/Attributes/CombatRequestAttribute.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using Protocol;
|
||||||
|
|
||||||
|
namespace GameServer.Controllers.Attributes;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
|
internal class CombatRequestAttribute : Attribute
|
||||||
|
{
|
||||||
|
public CombatRequestData.MessageOneofCase MessageCase { get; }
|
||||||
|
|
||||||
|
public CombatRequestAttribute(CombatRequestData.MessageOneofCase messageCase)
|
||||||
|
{
|
||||||
|
MessageCase = messageCase;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,14 +16,16 @@ internal class ChatSpawnCommandHandler
|
||||||
private readonly EntityFactory _entityFactory;
|
private readonly EntityFactory _entityFactory;
|
||||||
private readonly PlayerSession _session;
|
private readonly PlayerSession _session;
|
||||||
private readonly ConfigManager _configManager;
|
private readonly ConfigManager _configManager;
|
||||||
|
private readonly CreatureController _creatureController;
|
||||||
|
|
||||||
public ChatSpawnCommandHandler(ModelManager modelManager, EntitySystem entitySystem, EntityFactory entityFactory, PlayerSession session, ConfigManager configManager)
|
public ChatSpawnCommandHandler(ModelManager modelManager, EntitySystem entitySystem, EntityFactory entityFactory, PlayerSession session, ConfigManager configManager, CreatureController creatureController)
|
||||||
{
|
{
|
||||||
_helperRoom = modelManager.Chat.GetChatRoom(1338);
|
_helperRoom = modelManager.Chat.GetChatRoom(1338);
|
||||||
_entitySystem = entitySystem;
|
_entitySystem = entitySystem;
|
||||||
_entityFactory = entityFactory;
|
_entityFactory = entityFactory;
|
||||||
_session = session;
|
_session = session;
|
||||||
_configManager = configManager;
|
_configManager = configManager;
|
||||||
|
_creatureController = creatureController;
|
||||||
}
|
}
|
||||||
|
|
||||||
[ChatCommand("monster")]
|
[ChatCommand("monster")]
|
||||||
|
@ -57,6 +59,8 @@ internal class ChatSpawnCommandHandler
|
||||||
EntityPbs = { monster.Pb }
|
EntityPbs = { monster.Pb }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await _creatureController.UpdateAiHate();
|
||||||
|
|
||||||
_helperRoom.AddMessage(1338, 0, $"Successfully spawned monster with id {levelEntityId} at ({x}, {y}, {z})");
|
_helperRoom.AddMessage(1338, 0, $"Successfully spawned monster with id {levelEntityId} at ({x}, {y}, {z})");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
306
GameServer/Controllers/Combat/CombatManager.cs
Normal file
306
GameServer/Controllers/Combat/CombatManager.cs
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using GameServer.Controllers.Attributes;
|
||||||
|
using GameServer.Network;
|
||||||
|
using GameServer.Systems.Entity;
|
||||||
|
using GameServer.Systems.Entity.Component;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Protocol;
|
||||||
|
|
||||||
|
namespace GameServer.Controllers.Combat;
|
||||||
|
internal class CombatManager
|
||||||
|
{
|
||||||
|
private delegate Task<CombatResponseData> CombatRequestHandler(CombatManager combatManager, CombatRequestContext context);
|
||||||
|
private static readonly ImmutableDictionary<CombatRequestData.MessageOneofCase, CombatRequestHandler> s_requestHandlers;
|
||||||
|
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly EntitySystem _entitySystem;
|
||||||
|
private readonly PlayerSession _session;
|
||||||
|
private readonly CreatureController _creatureController;
|
||||||
|
|
||||||
|
static CombatManager()
|
||||||
|
{
|
||||||
|
s_requestHandlers = MapRequestHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CombatManager(ILogger<CombatManager> logger, EntitySystem entitySystem, PlayerSession session, CreatureController creatureController)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_entitySystem = entitySystem;
|
||||||
|
_session = session;
|
||||||
|
_creatureController = creatureController;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CombatRequest(CombatRequestData.MessageOneofCase.DamageExecuteRequest)]
|
||||||
|
public async Task<CombatResponseData> OnDamageExecuteRequest(CombatRequestContext context)
|
||||||
|
{
|
||||||
|
DamageExecuteRequest request = context.Request.DamageExecuteRequest;
|
||||||
|
|
||||||
|
EntityBase? entity = _entitySystem.Get<EntityBase>(request.TargetEntityId);
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
return new CombatResponseData
|
||||||
|
{
|
||||||
|
RequestId = context.Request.RequestId,
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
DamageExecuteResponse = new()
|
||||||
|
{
|
||||||
|
ErrorCode = (int)ErrorCode.ErrThrowDamageReqEntityIsAlreadyDead
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityAttributeComponent attr = entity.ComponentSystem.Get<EntityAttributeComponent>();
|
||||||
|
attr.SetAttribute(EAttributeType.Life, (int)request.DamageId); // Pakchunk patch! (cur hp instead of damageid)
|
||||||
|
|
||||||
|
if (request.DamageId <= 0 && entity.Type != EEntityType.Player) // Player death not implemented
|
||||||
|
{
|
||||||
|
_entitySystem.Destroy(entity);
|
||||||
|
await _session.Push(MessageId.EntityRemoveNotify, new EntityRemoveNotify
|
||||||
|
{
|
||||||
|
IsRemove = true,
|
||||||
|
RemoveInfos =
|
||||||
|
{
|
||||||
|
new EntityRemoveInfo
|
||||||
|
{
|
||||||
|
EntityId = entity.Id,
|
||||||
|
Type = (int)ERemoveEntityType.RemoveTypeNormal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CombatResponseData
|
||||||
|
{
|
||||||
|
RequestId = context.Request.RequestId,
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
DamageExecuteResponse = new()
|
||||||
|
{
|
||||||
|
AttackerEntityId = request.AttackerEntityId,
|
||||||
|
TargetEntityId = request.TargetEntityId,
|
||||||
|
ShieldCoverDamage = 0,
|
||||||
|
Damage = (int)request.DamageId,
|
||||||
|
PartId = request.PartId
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[CombatRequest(CombatRequestData.MessageOneofCase.HitRequest)]
|
||||||
|
public CombatResponseData OnHitRequest(CombatRequestContext context)
|
||||||
|
{
|
||||||
|
return new CombatResponseData
|
||||||
|
{
|
||||||
|
RequestId = context.Request.RequestId,
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
HitResponse = new()
|
||||||
|
{
|
||||||
|
HitInfo = context.Request.HitRequest.HitInfo
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[CombatRequest(CombatRequestData.MessageOneofCase.LogicStateInitRequest)]
|
||||||
|
public CombatResponseData OnLogicStateInitRequest(CombatRequestContext context)
|
||||||
|
{
|
||||||
|
CombatResponseData rsp = new()
|
||||||
|
{
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
RequestId = context.Request.RequestId,
|
||||||
|
LogicStateInitResponse = new()
|
||||||
|
};
|
||||||
|
|
||||||
|
EntityBase? entity = _entitySystem.Get<EntityBase>(context.Request.CombatCommon.EntityId);
|
||||||
|
if (entity == null) return rsp;
|
||||||
|
|
||||||
|
EntityLogicStateComponent logicStateComponent = entity.ComponentSystem.Get<EntityLogicStateComponent>();
|
||||||
|
logicStateComponent.States = [.. context.Request.LogicStateInitRequest.InitData.States];
|
||||||
|
|
||||||
|
context.Notifies.Add(new CombatNotifyData
|
||||||
|
{
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
LogicStateInitNotify = new()
|
||||||
|
{
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
EntityId = entity.Id,
|
||||||
|
InitData = logicStateComponent.Pb.LogicStateComponentPb
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CombatRequest(CombatRequestData.MessageOneofCase.SwitchLogicStateRequest)]
|
||||||
|
public CombatResponseData OnSwitchLogicStateRequest(CombatRequestContext context)
|
||||||
|
{
|
||||||
|
CombatResponseData rsp = new()
|
||||||
|
{
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
RequestId = context.Request.RequestId,
|
||||||
|
SwitchLogicStateResponse = new()
|
||||||
|
};
|
||||||
|
|
||||||
|
EntityBase? entity = _entitySystem.Get<EntityBase>(context.Request.CombatCommon.EntityId);
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
rsp.SwitchLogicStateResponse.ErrorCode = (int)ErrorCode.ErrActionEntityNoExist;
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityLogicStateComponent logicStateComponent = entity.ComponentSystem.Get<EntityLogicStateComponent>();
|
||||||
|
logicStateComponent.States = [.. context.Request.SwitchLogicStateRequest.States];
|
||||||
|
|
||||||
|
context.Notifies.Add(new CombatNotifyData
|
||||||
|
{
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
SwitchLogicStateNotify = new()
|
||||||
|
{
|
||||||
|
States = { logicStateComponent.States }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CombatRequest(CombatRequestData.MessageOneofCase.BattleStateChangeRequest)]
|
||||||
|
public CombatResponseData OnBattleStateChangeRequest(CombatRequestContext context)
|
||||||
|
{
|
||||||
|
return new CombatResponseData
|
||||||
|
{
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
RequestId = context.Request.RequestId,
|
||||||
|
BattleStateChangeResponse = new()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[CombatRequest(CombatRequestData.MessageOneofCase.ChangeStateConfirmRequest)]
|
||||||
|
public CombatResponseData OnChangeStateConfirmRequest(CombatRequestContext context)
|
||||||
|
{
|
||||||
|
CombatResponseData rsp = new()
|
||||||
|
{
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
RequestId = context.Request.RequestId,
|
||||||
|
ChangeStateConfirmResponse = new()
|
||||||
|
{
|
||||||
|
Error = new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EntityBase? entity = _entitySystem.Get<EntityBase>(context.Request.CombatCommon.EntityId);
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
rsp.ChangeStateConfirmResponse.Error.ErrorCode = (int)ErrorCode.ErrEntityIsNotAlive;
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangeStateConfirmRequest request = context.Request.ChangeStateConfirmRequest;
|
||||||
|
if (entity.ComponentSystem.TryGet(out EntityFsmComponent? fsmComponent))
|
||||||
|
{
|
||||||
|
DFsm? dfsm = fsmComponent.Fsms.FirstOrDefault(fsm => fsm.FsmId == request.FsmId);
|
||||||
|
dfsm ??= new()
|
||||||
|
{
|
||||||
|
FsmId = request.FsmId,
|
||||||
|
Status = 1,
|
||||||
|
Flag = (int)EFsmStateFlag.Confirmed
|
||||||
|
};
|
||||||
|
|
||||||
|
dfsm.CurrentState = request.State;
|
||||||
|
context.Notifies.Add(new CombatNotifyData
|
||||||
|
{
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
ChangeStateConfirmNotify = new ChangeStateConfirmNotify
|
||||||
|
{
|
||||||
|
State = request.State,
|
||||||
|
FsmId = request.FsmId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
rsp.ChangeStateConfirmResponse.State = context.Request.ChangeStateConfirmRequest.State;
|
||||||
|
rsp.ChangeStateConfirmResponse.FsmId = context.Request.ChangeStateConfirmRequest.FsmId;
|
||||||
|
|
||||||
|
return rsp;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CombatRequest(CombatRequestData.MessageOneofCase.FsmConditionPassRequest)]
|
||||||
|
public CombatResponseData OnFsmConditionPassRequest(CombatRequestContext context)
|
||||||
|
{
|
||||||
|
return new CombatResponseData
|
||||||
|
{
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
RequestId = context.Request.RequestId,
|
||||||
|
FsmConditionPassResponse = new()
|
||||||
|
{
|
||||||
|
FsmId = context.Request.FsmConditionPassRequest.FsmId,
|
||||||
|
Error = new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[CombatRequest(CombatRequestData.MessageOneofCase.AiInformationRequest)]
|
||||||
|
public CombatResponseData OnAiInformationRequest(CombatRequestContext context)
|
||||||
|
{
|
||||||
|
// Currently like this, TODO!
|
||||||
|
context.Notifies.Add(new CombatNotifyData
|
||||||
|
{
|
||||||
|
CombatCommon = new CombatCommon
|
||||||
|
{
|
||||||
|
EntityId = context.Request.CombatCommon.EntityId, // id of monster
|
||||||
|
},
|
||||||
|
AiHateNotify = new AiHateNotify
|
||||||
|
{
|
||||||
|
HateList =
|
||||||
|
{
|
||||||
|
new AiHateEntity
|
||||||
|
{
|
||||||
|
EntityId = _creatureController.GetPlayerEntity()!.Id, // id of hated entity (the player)
|
||||||
|
HatredValue = 99999
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return new CombatResponseData
|
||||||
|
{
|
||||||
|
CombatCommon = context.Request.CombatCommon,
|
||||||
|
RequestId = context.Request.RequestId,
|
||||||
|
AiInformationResponse = new() // ?? contains nothing
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<CombatResponseData?> HandleRequest(CombatRequestContext context)
|
||||||
|
{
|
||||||
|
if (s_requestHandlers.TryGetValue(context.Request.MessageCase, out CombatRequestHandler? handler))
|
||||||
|
return handler(this, context)!;
|
||||||
|
|
||||||
|
_logger.LogWarning("Combat request not handled: {type}", context.Request.MessageCase);
|
||||||
|
return Task.FromResult<CombatResponseData?>(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ImmutableDictionary<CombatRequestData.MessageOneofCase, CombatRequestHandler> MapRequestHandlers()
|
||||||
|
{
|
||||||
|
var builder = ImmutableDictionary.CreateBuilder<CombatRequestData.MessageOneofCase, CombatRequestHandler>();
|
||||||
|
|
||||||
|
MethodInfo taskFromResultMethod = typeof(Task).GetMethod(nameof(Task.FromResult))!.MakeGenericMethod(typeof(CombatResponseData));
|
||||||
|
|
||||||
|
foreach (MethodInfo method in typeof(CombatManager).GetMethods())
|
||||||
|
{
|
||||||
|
CombatRequestAttribute? attribute = method.GetCustomAttribute<CombatRequestAttribute>();
|
||||||
|
if (attribute == null) continue;
|
||||||
|
|
||||||
|
ParameterExpression combatManagerParam = Expression.Parameter(typeof(CombatManager));
|
||||||
|
ParameterExpression contextParam = Expression.Parameter(typeof(CombatRequestContext));
|
||||||
|
|
||||||
|
Expression call = Expression.Call(combatManagerParam, method, contextParam);
|
||||||
|
if (method.ReturnType == typeof(CombatResponseData))
|
||||||
|
call = Expression.Call(taskFromResultMethod, call);
|
||||||
|
|
||||||
|
Expression<CombatRequestHandler> lambda = Expression.Lambda<CombatRequestHandler>(call, combatManagerParam, contextParam);
|
||||||
|
builder.Add(attribute.MessageCase, lambda.Compile());
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToImmutable();
|
||||||
|
}
|
||||||
|
}
|
14
GameServer/Controllers/Combat/CombatRequestContext.cs
Normal file
14
GameServer/Controllers/Combat/CombatRequestContext.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using Protocol;
|
||||||
|
|
||||||
|
namespace GameServer.Controllers.Combat;
|
||||||
|
internal class CombatRequestContext
|
||||||
|
{
|
||||||
|
public CombatRequestData Request { get; }
|
||||||
|
public List<CombatNotifyData> Notifies { get; }
|
||||||
|
|
||||||
|
public CombatRequestContext(CombatRequestData request)
|
||||||
|
{
|
||||||
|
Request = request;
|
||||||
|
Notifies = [];
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using GameServer.Controllers.Attributes;
|
using GameServer.Controllers.Attributes;
|
||||||
|
using GameServer.Controllers.Combat;
|
||||||
using GameServer.Network;
|
using GameServer.Network;
|
||||||
using GameServer.Network.Messages;
|
using GameServer.Network.Messages;
|
||||||
using Protocol;
|
using Protocol;
|
||||||
|
@ -12,5 +13,33 @@ internal class CombatMessageController : Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
[NetEvent(MessageId.CombatSendPackRequest)] // TODO: CombatSendPackRequest is important
|
[NetEvent(MessageId.CombatSendPackRequest)] // TODO: CombatSendPackRequest is important
|
||||||
public ResponseMessage OnCombatSendPackRequest() => Response(MessageId.CombatSendPackResponse, new CombatSendPackResponse());
|
public async Task<ResponseMessage> OnCombatSendPackRequest(CombatSendPackRequest request, CombatManager combatManager)
|
||||||
|
{
|
||||||
|
CombatReceivePackNotify combatPackNotify = new();
|
||||||
|
|
||||||
|
foreach (CombatSendData sendData in request.Data)
|
||||||
|
{
|
||||||
|
if (sendData.Request != null)
|
||||||
|
{
|
||||||
|
CombatRequestContext context = new(sendData.Request);
|
||||||
|
CombatResponseData? responseData = await combatManager.HandleRequest(context);
|
||||||
|
|
||||||
|
combatPackNotify.Data.AddRange(context.Notifies.Select(notify => new CombatReceiveData
|
||||||
|
{
|
||||||
|
CombatNotifyData = notify
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (responseData != null)
|
||||||
|
{
|
||||||
|
combatPackNotify.Data.Add(new CombatReceiveData
|
||||||
|
{
|
||||||
|
CombatResponseData = responseData
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Session.Push(MessageId.CombatReceivePackNotify, combatPackNotify);
|
||||||
|
return Response(MessageId.CombatSendPackResponse, new CombatSendPackResponse());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,9 +67,10 @@ internal class CreatureController : Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
[NetEvent(MessageId.SceneLoadingFinishRequest)]
|
[NetEvent(MessageId.SceneLoadingFinishRequest)]
|
||||||
public ResponseMessage OnSceneLoadingFinishRequest()
|
public async Task<ResponseMessage> OnSceneLoadingFinishRequest()
|
||||||
{
|
{
|
||||||
_modelManager.Creature.OnWorldDone();
|
_modelManager.Creature.OnWorldDone();
|
||||||
|
await UpdateAiHate();
|
||||||
|
|
||||||
return Response(MessageId.SceneLoadingFinishResponse, new SceneLoadingFinishResponse());
|
return Response(MessageId.SceneLoadingFinishResponse, new SceneLoadingFinishResponse());
|
||||||
}
|
}
|
||||||
|
@ -79,10 +80,7 @@ internal class CreatureController : Controller
|
||||||
{
|
{
|
||||||
// Remove old entities
|
// Remove old entities
|
||||||
|
|
||||||
IEnumerable<PlayerEntity> oldEntities = _entitySystem.EnumerateEntities()
|
IEnumerable<PlayerEntity> oldEntities = GetPlayerEntities().ToArray();
|
||||||
.Where(e => e is PlayerEntity entity && entity.PlayerId == _modelManager.Player.Id)
|
|
||||||
.Cast<PlayerEntity>().ToArray();
|
|
||||||
|
|
||||||
foreach (PlayerEntity oldEntity in oldEntities)
|
foreach (PlayerEntity oldEntity in oldEntities)
|
||||||
{
|
{
|
||||||
_entitySystem.Destroy(oldEntity);
|
_entitySystem.Destroy(oldEntity);
|
||||||
|
@ -105,10 +103,7 @@ internal class CreatureController : Controller
|
||||||
|
|
||||||
CreateTeamPlayerEntities();
|
CreateTeamPlayerEntities();
|
||||||
|
|
||||||
IEnumerable<PlayerEntity> newEntities = _entitySystem.EnumerateEntities()
|
IEnumerable<PlayerEntity> newEntities = GetPlayerEntities();
|
||||||
.Where(e => e is PlayerEntity entity && entity.PlayerId == _modelManager.Player.Id)
|
|
||||||
.Cast<PlayerEntity>();
|
|
||||||
|
|
||||||
await Session.Push(MessageId.EntityAddNotify, new EntityAddNotify
|
await Session.Push(MessageId.EntityAddNotify, new EntityAddNotify
|
||||||
{
|
{
|
||||||
IsAdd = true,
|
IsAdd = true,
|
||||||
|
@ -124,6 +119,8 @@ internal class CreatureController : Controller
|
||||||
PlayerId = _modelManager.Player.Id,
|
PlayerId = _modelManager.Player.Id,
|
||||||
FightRoleInfos = { GetFightRoleInfos() }
|
FightRoleInfos = { GetFightRoleInfos() }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await UpdateAiHate();
|
||||||
}
|
}
|
||||||
|
|
||||||
[GameEvent(GameEventType.VisionSkillChanged)]
|
[GameEvent(GameEventType.VisionSkillChanged)]
|
||||||
|
@ -165,13 +162,43 @@ internal class CreatureController : Controller
|
||||||
|
|
||||||
prevEntity.IsCurrentRole = false;
|
prevEntity.IsCurrentRole = false;
|
||||||
|
|
||||||
PlayerEntity? newEntity = _entitySystem.EnumerateEntities().FirstOrDefault(e => e is PlayerEntity playerEntity && playerEntity.ConfigId == roleId) as PlayerEntity;
|
if (_entitySystem.EnumerateEntities().FirstOrDefault(e => e is PlayerEntity playerEntity && playerEntity.ConfigId == roleId) is not PlayerEntity newEntity) return;
|
||||||
if (newEntity == null) return;
|
|
||||||
|
|
||||||
_modelManager.Creature.PlayerEntityId = newEntity.Id;
|
_modelManager.Creature.PlayerEntityId = newEntity.Id;
|
||||||
newEntity.IsCurrentRole = true;
|
newEntity.IsCurrentRole = true;
|
||||||
|
|
||||||
await OnVisionSkillChanged();
|
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()
|
private SceneInformation CreateSceneInfo() => new()
|
||||||
|
@ -200,11 +227,7 @@ internal class CreatureController : Controller
|
||||||
|
|
||||||
private IEnumerable<FightRoleInformation> GetFightRoleInfos()
|
private IEnumerable<FightRoleInformation> GetFightRoleInfos()
|
||||||
{
|
{
|
||||||
IEnumerable<PlayerEntity> playerEntities = _entitySystem.EnumerateEntities()
|
return GetPlayerEntities().Select(playerEntity => new FightRoleInformation
|
||||||
.Where(e => e is PlayerEntity entity && entity.PlayerId == _modelManager.Player.Id)
|
|
||||||
.Cast<PlayerEntity>();
|
|
||||||
|
|
||||||
return playerEntities.Select(playerEntity => new FightRoleInformation
|
|
||||||
{
|
{
|
||||||
EntityId = playerEntity.Id,
|
EntityId = playerEntity.Id,
|
||||||
CurHp = playerEntity.Health,
|
CurHp = playerEntity.Health,
|
||||||
|
|
|
@ -35,8 +35,9 @@ internal class RoleController : Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
[NetEvent(MessageId.SwitchRoleRequest)]
|
[NetEvent(MessageId.SwitchRoleRequest)]
|
||||||
public ResponseMessage OnSwitchRoleRequest(SwitchRoleRequest request)
|
public async Task<ResponseMessage> OnSwitchRoleRequest(SwitchRoleRequest request, CreatureController creatureController)
|
||||||
{
|
{
|
||||||
|
await creatureController.SwitchPlayerEntity(request.RoleId);
|
||||||
return Response(MessageId.SwitchRoleResponse, new SwitchRoleResponse
|
return Response(MessageId.SwitchRoleResponse, new SwitchRoleResponse
|
||||||
{
|
{
|
||||||
RoleId = request.RoleId
|
RoleId = request.RoleId
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using Core.Config;
|
using Core.Config;
|
||||||
using Core.Extensions;
|
using Core.Extensions;
|
||||||
using GameServer.Controllers.ChatCommands;
|
using GameServer.Controllers.ChatCommands;
|
||||||
|
using GameServer.Controllers.Combat;
|
||||||
using GameServer.Controllers.Factory;
|
using GameServer.Controllers.Factory;
|
||||||
using GameServer.Controllers.Manager;
|
using GameServer.Controllers.Manager;
|
||||||
using GameServer.Extensions;
|
using GameServer.Extensions;
|
||||||
|
@ -39,7 +40,8 @@ internal static class Program
|
||||||
.AddScoped<RpcManager>().AddScoped<IRpcEndPoint, RpcSessionEndPoint>()
|
.AddScoped<RpcManager>().AddScoped<IRpcEndPoint, RpcSessionEndPoint>()
|
||||||
.AddSingleton<SessionManager>()
|
.AddSingleton<SessionManager>()
|
||||||
.AddScoped<EventSystem>().AddScoped<EntitySystem>().AddScoped<EntityFactory>()
|
.AddScoped<EventSystem>().AddScoped<EntitySystem>().AddScoped<EntityFactory>()
|
||||||
.AddScoped<ModelManager>().AddScoped<ControllerManager>().AddScoped<ChatCommandManager>()
|
.AddScoped<ModelManager>().AddScoped<ControllerManager>()
|
||||||
|
.AddScoped<CombatManager>().AddScoped<ChatCommandManager>()
|
||||||
.AddHostedService<WWGameServer>();
|
.AddHostedService<WWGameServer>();
|
||||||
|
|
||||||
IHost host = builder.Build();
|
IHost host = builder.Build();
|
||||||
|
|
|
@ -37,6 +37,7 @@ internal class EntityAttributeComponent : EntityComponentBase
|
||||||
}
|
}
|
||||||
|
|
||||||
attribute.CurrentValue = currentValue;
|
attribute.CurrentValue = currentValue;
|
||||||
|
attribute.BaseValue = currentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetAttribute(EAttributeType type)
|
public int GetAttribute(EAttributeType type)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Protocol;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Protocol;
|
||||||
|
|
||||||
namespace GameServer.Systems.Entity.Component;
|
namespace GameServer.Systems.Entity.Component;
|
||||||
internal class EntityComponentSystem
|
internal class EntityComponentSystem
|
||||||
|
@ -25,7 +26,7 @@ internal class EntityComponentSystem
|
||||||
return (_components.Single(component => component is TEntityComponent) as TEntityComponent)!;
|
return (_components.Single(component => component is TEntityComponent) as TEntityComponent)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGet<TEntityComponent>(out TEntityComponent? component) where TEntityComponent : EntityComponentBase
|
public bool TryGet<TEntityComponent>([NotNullWhen(true)] out TEntityComponent? component) where TEntityComponent : EntityComponentBase
|
||||||
{
|
{
|
||||||
return (component = _components.SingleOrDefault(component => component is TEntityComponent) as TEntityComponent) != null;
|
return (component = _components.SingleOrDefault(component => component is TEntityComponent) as TEntityComponent) != null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
using Protocol;
|
||||||
|
|
||||||
|
namespace GameServer.Systems.Entity.Component;
|
||||||
|
internal class EntityLogicStateComponent : EntityComponentBase
|
||||||
|
{
|
||||||
|
public List<int> States { get; set; }
|
||||||
|
|
||||||
|
public EntityLogicStateComponent()
|
||||||
|
{
|
||||||
|
States = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override EntityComponentType Type => EntityComponentType.LogicState;
|
||||||
|
|
||||||
|
public override EntityComponentPb Pb => new()
|
||||||
|
{
|
||||||
|
LogicStateComponentPb = new()
|
||||||
|
{
|
||||||
|
States = { States }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -28,6 +28,8 @@ internal abstract class EntityBase
|
||||||
public virtual void OnCreate()
|
public virtual void OnCreate()
|
||||||
{
|
{
|
||||||
State = EntityState.Born;
|
State = EntityState.Born;
|
||||||
|
|
||||||
|
_ = ComponentSystem.Create<EntityLogicStateComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Activate()
|
public virtual void Activate()
|
||||||
|
|
|
@ -1604,6 +1604,7 @@ message CombatMaxCaseMessageResponse { // MessageId: 11987
|
||||||
|
|
||||||
message CombatNotifyData {
|
message CombatNotifyData {
|
||||||
CombatCommon combat_common = 1;
|
CombatCommon combat_common = 1;
|
||||||
|
oneof message {
|
||||||
CreateBulletNotify create_bullet_notify = 2;
|
CreateBulletNotify create_bullet_notify = 2;
|
||||||
DestroyBulletNotify destroy_bullet_notify = 3;
|
DestroyBulletNotify destroy_bullet_notify = 3;
|
||||||
DamageExecuteNotify damage_execute_notify = 4;
|
DamageExecuteNotify damage_execute_notify = 4;
|
||||||
|
@ -1662,9 +1663,11 @@ message CombatNotifyData {
|
||||||
RemoveBuffByIdS2cRequestNotify remove_buff_by_id_s2c_request_notify = 59;
|
RemoveBuffByIdS2cRequestNotify remove_buff_by_id_s2c_request_notify = 59;
|
||||||
FormationBuffRemoveByIdS2cRequestNotify formation_buff_remove_by_id_s2c_request_notify = 60;
|
FormationBuffRemoveByIdS2cRequestNotify formation_buff_remove_by_id_s2c_request_notify = 60;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
message CombatPushData {
|
message CombatPushData {
|
||||||
CombatCommon combat_common = 1;
|
CombatCommon combat_common = 1;
|
||||||
|
oneof message {
|
||||||
FormationBuffApplyS2cResponsePush formation_buff_apply_s2c_response_push = 2;
|
FormationBuffApplyS2cResponsePush formation_buff_apply_s2c_response_push = 2;
|
||||||
FormationBuffRemoveS2cResponsePush formation_buff_remove_s2c_response_push = 3;
|
FormationBuffRemoveS2cResponsePush formation_buff_remove_s2c_response_push = 3;
|
||||||
ApplyBuffS2cResponsePush apply_buff_s2c_response_push = 4;
|
ApplyBuffS2cResponsePush apply_buff_s2c_response_push = 4;
|
||||||
|
@ -1672,11 +1675,14 @@ message CombatPushData {
|
||||||
RemoveBuffByIdS2cResponsePush remove_buff_by_id_s2c_response_push = 6;
|
RemoveBuffByIdS2cResponsePush remove_buff_by_id_s2c_response_push = 6;
|
||||||
FormationBuffRemoveByIdS2cResponsePush formation_buff_remove_by_id_s2c_response_push = 7;
|
FormationBuffRemoveByIdS2cResponsePush formation_buff_remove_by_id_s2c_response_push = 7;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
message CombatReceiveData {
|
message CombatReceiveData {
|
||||||
|
oneof message {
|
||||||
CombatNotifyData combat_notify_data = 2;
|
CombatNotifyData combat_notify_data = 2;
|
||||||
CombatResponseData combat_response_data = 3;
|
CombatResponseData combat_response_data = 3;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
message CombatReceivePackNotify { // MessageId: 1332
|
message CombatReceivePackNotify { // MessageId: 1332
|
||||||
repeated CombatReceiveData data = 1;
|
repeated CombatReceiveData data = 1;
|
||||||
|
@ -1685,6 +1691,7 @@ message CombatReceivePackNotify { // MessageId: 1332
|
||||||
message CombatRequestData {
|
message CombatRequestData {
|
||||||
CombatCommon combat_common = 1;
|
CombatCommon combat_common = 1;
|
||||||
int32 request_id = 2;
|
int32 request_id = 2;
|
||||||
|
oneof message {
|
||||||
CreateBulletRequest create_bullet_request = 3;
|
CreateBulletRequest create_bullet_request = 3;
|
||||||
DestroyBulletRequest destroy_bullet_request = 4;
|
DestroyBulletRequest destroy_bullet_request = 4;
|
||||||
DamageExecuteRequest damage_execute_request = 5;
|
DamageExecuteRequest damage_execute_request = 5;
|
||||||
|
@ -1745,12 +1752,14 @@ message CombatRequestData {
|
||||||
DrownEndTeleportRequest drown_end_teleport_request = 60;
|
DrownEndTeleportRequest drown_end_teleport_request = 60;
|
||||||
MonsterDrownRequest monster_drown_request = 61;
|
MonsterDrownRequest monster_drown_request = 61;
|
||||||
CombatMaxCaseMessageRequest combat_max_case_message_request = 62;
|
CombatMaxCaseMessageRequest combat_max_case_message_request = 62;
|
||||||
|
}
|
||||||
CombatContext context = 100;
|
CombatContext context = 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CombatResponseData {
|
message CombatResponseData {
|
||||||
CombatCommon combat_common = 1;
|
CombatCommon combat_common = 1;
|
||||||
int32 request_id = 2;
|
int32 request_id = 2;
|
||||||
|
oneof message {
|
||||||
CreateBulletResponse create_bullet_response = 3;
|
CreateBulletResponse create_bullet_response = 3;
|
||||||
DestroyBulletResponse destroy_bullet_response = 4;
|
DestroyBulletResponse destroy_bullet_response = 4;
|
||||||
DamageExecuteResponse damage_execute_response = 5;
|
DamageExecuteResponse damage_execute_response = 5;
|
||||||
|
@ -1811,6 +1820,7 @@ message CombatResponseData {
|
||||||
DrownEndTeleportResponse drown_end_teleport_response = 60;
|
DrownEndTeleportResponse drown_end_teleport_response = 60;
|
||||||
MonsterDrownResponse monster_drown_response = 61;
|
MonsterDrownResponse monster_drown_response = 61;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
message CombatSendData {
|
message CombatSendData {
|
||||||
CombatPushData push = 2;
|
CombatPushData push = 2;
|
||||||
|
|
Loading…
Reference in a new issue