Handle movement, no cooldowns for skills (reset immediately)
This commit is contained in:
parent
a762ec8241
commit
42cca1e786
13 changed files with 179 additions and 21 deletions
|
@ -7,6 +7,7 @@ using NahidaImpact.Gameserver.Network;
|
|||
using NahidaImpact.Protocol;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace NahidaImpact.Gameserver.Controllers.Dispatching;
|
||||
internal class NetCommandDispatcher(IServiceProvider serviceProvider, ILogger<NetCommandDispatcher> logger)
|
||||
|
@ -29,7 +30,7 @@ internal class NetCommandDispatcher(IServiceProvider serviceProvider, ILogger<Ne
|
|||
return await handler(_serviceProvider, packet);
|
||||
}
|
||||
|
||||
_logger.LogWarning("No handler defined for command of type {cmdType}", packet.CmdType);
|
||||
Debug.WriteLine("No handler defined for command of type {0}", packet.CmdType);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
using NahidaImpact.Gameserver.Controllers.Attributes;
|
||||
using Google.Protobuf;
|
||||
using NahidaImpact.Gameserver.Controllers.Attributes;
|
||||
using NahidaImpact.Gameserver.Controllers.Result;
|
||||
using NahidaImpact.Gameserver.Game;
|
||||
using NahidaImpact.Gameserver.Game.Scene;
|
||||
using NahidaImpact.Gameserver.Helpers;
|
||||
using NahidaImpact.Gameserver.Network.Session;
|
||||
using NahidaImpact.Protocol;
|
||||
|
||||
namespace NahidaImpact.Gameserver.Controllers;
|
||||
|
@ -9,6 +12,42 @@ namespace NahidaImpact.Gameserver.Controllers;
|
|||
[NetController]
|
||||
internal class SceneController : ControllerBase
|
||||
{
|
||||
[NetCommand(CmdType.EvtDoSkillSuccNotify)]
|
||||
public async ValueTask<IResult> OnEvtDoSkillSuccNotify(SceneManager sceneManager)
|
||||
{
|
||||
EvtDoSkillSuccNotify notify = Packet!.DecodeBody<EvtDoSkillSuccNotify>();
|
||||
await sceneManager.ResetAllCoolDownsForAvatar(notify.CasterId);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[NetCommand(CmdType.CombatInvocationsNotify)]
|
||||
public async ValueTask<IResult> OnCombatInvocationsNotify(ClientActionManager clientActionManager)
|
||||
{
|
||||
CombatInvocationsNotify notify = Packet!.DecodeBody<CombatInvocationsNotify>();
|
||||
foreach (CombatInvokeEntry invocation in notify.InvokeList)
|
||||
{
|
||||
IMessage? message = invocation.DecodeCombatInvocation();
|
||||
if (message != null)
|
||||
await clientActionManager.InvokeAsync(invocation.ArgumentType, message);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[NetCommand(CmdType.UnionCmdNotify)]
|
||||
public async ValueTask<IResult> OnUnionCmdNotify(NetSession session)
|
||||
{
|
||||
UnionCmdNotify notify = Packet!.DecodeBody<UnionCmdNotify>();
|
||||
|
||||
foreach (UnionCmd cmd in notify.CmdList)
|
||||
{
|
||||
await session.HandlePacket(cmd.ToNetPacket());
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[NetCommand(CmdType.GetScenePointReq)]
|
||||
public ValueTask<IResult> OnGetScenePointReq(SceneManager sceneManager, Player player)
|
||||
{
|
||||
|
|
|
@ -13,6 +13,18 @@ internal class EntityManager(IEntityEventListener listener)
|
|||
await _listener.OnEntitySpawned(entity, visionType);
|
||||
}
|
||||
|
||||
public async ValueTask ChangeAvatarFightPropAsync(uint entityId, uint key, float value)
|
||||
{
|
||||
if (GetEntityById(entityId) is AvatarEntity entity)
|
||||
{
|
||||
entity.SetFightProp(key, value);
|
||||
await _listener.OnAvatarFightPropChanged(entity, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public SceneEntity? GetEntityById(uint id) =>
|
||||
_entities.Find(entity => entity.EntityId == id);
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_entities.Clear();
|
||||
|
|
|
@ -4,4 +4,5 @@ namespace NahidaImpact.Gameserver.Game.Entity.Listener;
|
|||
internal interface IEntityEventListener
|
||||
{
|
||||
ValueTask OnEntitySpawned(SceneEntity entity, VisionType visionType);
|
||||
ValueTask OnAvatarFightPropChanged(AvatarEntity entity, uint key, float value);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,18 @@ internal abstract class SceneEntity
|
|||
MotionInfo.Rot.Z = z;
|
||||
}
|
||||
|
||||
public void SetFightProp(uint key, float value)
|
||||
{
|
||||
FightPropPair? pair = FightProperties.Find(p => p.PropType == key);
|
||||
if (pair == null)
|
||||
{
|
||||
pair = new() { PropType = key };
|
||||
FightProperties.Add(pair);
|
||||
}
|
||||
|
||||
pair.PropValue = value;
|
||||
}
|
||||
|
||||
public virtual SceneEntityInfo AsInfo()
|
||||
{
|
||||
SceneEntityInfo info = new()
|
||||
|
|
|
@ -15,6 +15,8 @@ internal class Player(ExcelTableCollection excelTables)
|
|||
public List<GameAvatarTeam> AvatarTeams { get; set; } = [];
|
||||
public uint CurTeamIndex { get; set; }
|
||||
|
||||
public uint CurAvatarEntityId { get; set; }
|
||||
|
||||
private readonly ExcelTableCollection _excelTables = excelTables;
|
||||
|
||||
public void InitDefaultPlayer()
|
||||
|
|
20
NahidaImpact.Gameserver/Game/Scene/ClientActionManager.cs
Normal file
20
NahidaImpact.Gameserver/Game/Scene/ClientActionManager.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using Google.Protobuf;
|
||||
|
||||
namespace NahidaImpact.Gameserver.Game.Scene;
|
||||
internal class ClientActionManager(SceneManager sceneManager)
|
||||
{
|
||||
public async ValueTask InvokeAsync(CombatTypeArgument combatTypeArgument, IMessage data)
|
||||
{
|
||||
switch (combatTypeArgument)
|
||||
{
|
||||
case CombatTypeArgument.EntityMove:
|
||||
await PerformEntityMovement((EntityMoveInfo)data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask PerformEntityMovement(EntityMoveInfo info)
|
||||
{
|
||||
await sceneManager.MotionChanged(info.EntityId, info.MotionInfo);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System.Numerics;
|
||||
using NahidaImpact.Common.Constants;
|
||||
using NahidaImpact.Common.Data.Binout;
|
||||
using NahidaImpact.Gameserver.Controllers;
|
||||
using NahidaImpact.Gameserver.Game.Avatar;
|
||||
|
@ -60,13 +61,35 @@ internal class SceneManager(NetSession session, Player player, EntityManager ent
|
|||
_enterState = SceneEnterState.Complete;
|
||||
}
|
||||
|
||||
public async ValueTask ResetAllCoolDownsForAvatar(uint entityId)
|
||||
{
|
||||
await _entityManager.ChangeAvatarFightPropAsync(entityId, FightProp.FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO, 1);
|
||||
await _entityManager.ChangeAvatarFightPropAsync(entityId, FightProp.FIGHT_PROP_SKILL_CD_MINUS_RATIO, 1);
|
||||
}
|
||||
|
||||
public ValueTask MotionChanged(uint entityId, MotionInfo motion)
|
||||
{
|
||||
SceneEntity? entity = _entityManager.GetEntityById(entityId);
|
||||
if (entity == null) return ValueTask.CompletedTask;
|
||||
|
||||
entity.MotionInfo = motion;
|
||||
// need to notify peers, but it's single player anyway (for now)
|
||||
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
public async ValueTask ReplaceCurrentAvatarAsync(ulong replaceToGuid)
|
||||
{
|
||||
// TODO: add logic checks.
|
||||
|
||||
SceneEntity previousEntity = _entityManager.GetEntityById(_player.CurAvatarEntityId)!;
|
||||
|
||||
AvatarEntity avatar = _teamAvatars.Find(a => a.GameAvatar.Guid == replaceToGuid)
|
||||
?? throw new ArgumentException($"ReplaceCurrentAvatar: avatar with guid {replaceToGuid} not in team!");
|
||||
|
||||
avatar.MotionInfo = previousEntity.MotionInfo; // maybe make a better way to do this?
|
||||
|
||||
_player.CurAvatarEntityId = avatar.EntityId;
|
||||
await _entityManager.SpawnEntityAsync(avatar, VisionType.Replace);
|
||||
}
|
||||
|
||||
|
@ -74,22 +97,28 @@ internal class SceneManager(NetSession session, Player player, EntityManager ent
|
|||
{
|
||||
_teamAvatars.Clear();
|
||||
|
||||
SceneEntity previousEntity = _entityManager.GetEntityById(_player.CurAvatarEntityId)!;
|
||||
Vector pos = previousEntity.MotionInfo.Pos;
|
||||
|
||||
foreach (ulong guid in guidList)
|
||||
{
|
||||
GameAvatar gameAvatar = _player.Avatars.Find(avatar => avatar.Guid == guid)!;
|
||||
|
||||
AvatarEntity avatarEntity = _entityFactory.CreateAvatar(gameAvatar, _player.Uid);
|
||||
avatarEntity.SetPosition(2336.789f, 249.98896f, -751.3081f);
|
||||
avatarEntity.SetPosition(pos.X, pos.Y, pos.Z);
|
||||
|
||||
_teamAvatars.Add(avatarEntity);
|
||||
}
|
||||
|
||||
await SendSceneTeamUpdate();
|
||||
|
||||
_player.CurAvatarEntityId = _teamAvatars[0].EntityId;
|
||||
await _entityManager.SpawnEntityAsync(_teamAvatars[0], VisionType.Born);
|
||||
}
|
||||
|
||||
private async ValueTask OnEnterDone()
|
||||
{
|
||||
_player.CurAvatarEntityId = _teamAvatars[0].EntityId;
|
||||
await _entityManager.SpawnEntityAsync(_teamAvatars[0], VisionType.Born);
|
||||
}
|
||||
|
||||
|
|
25
NahidaImpact.Gameserver/Helpers/UnionCmdHelper.cs
Normal file
25
NahidaImpact.Gameserver/Helpers/UnionCmdHelper.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using Google.Protobuf;
|
||||
using NahidaImpact.Gameserver.Network;
|
||||
using NahidaImpact.Protocol;
|
||||
|
||||
namespace NahidaImpact.Gameserver.Helpers;
|
||||
internal static class UnionCmdHelper
|
||||
{
|
||||
public static IMessage? DecodeCombatInvocation(this CombatInvokeEntry invocation)
|
||||
{
|
||||
return invocation.ArgumentType switch
|
||||
{
|
||||
CombatTypeArgument.EntityMove => EntityMoveInfo.Parser.ParseFrom(invocation.CombatData),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
public static NetPacket ToNetPacket(this UnionCmd cmd)
|
||||
{
|
||||
return new NetPacket()
|
||||
{
|
||||
CmdType = (CmdType)cmd.MessageId,
|
||||
Body = cmd.Body.Memory
|
||||
};
|
||||
}
|
||||
}
|
|
@ -9,8 +9,8 @@ internal class NetPacket
|
|||
private const ushort TailMagic = 0x89AB;
|
||||
|
||||
public CmdType CmdType { get; set; }
|
||||
public Memory<byte> Head { get; set; }
|
||||
public Memory<byte> Body { get; set; }
|
||||
public ReadOnlyMemory<byte> Head { get; set; }
|
||||
public ReadOnlyMemory<byte> Body { get; set; }
|
||||
|
||||
public TBody DecodeBody<TBody>() where TBody : IMessage<TBody>, new()
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ using NahidaImpact.Gameserver.Controllers.Result;
|
|||
using NahidaImpact.Protocol;
|
||||
using Google.Protobuf;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace NahidaImpact.Gameserver.Network.Session;
|
||||
internal abstract class NetSession(ILogger<NetSession> logger, NetSessionManager sessionManager, NetCommandDispatcher commandDispatcher) : IDisposable
|
||||
|
@ -41,6 +42,25 @@ internal abstract class NetSession(ILogger<NetSession> logger, NetSessionManager
|
|||
});
|
||||
}
|
||||
|
||||
public async ValueTask HandlePacket(NetPacket packet)
|
||||
{
|
||||
IResult? result = await _commandDispatcher.InvokeHandler(packet);
|
||||
if (result != null)
|
||||
{
|
||||
while (result.NextPacket(out NetPacket? serverPacket))
|
||||
{
|
||||
await SendAsync(serverPacket);
|
||||
|
||||
if (serverPacket.CmdType == CmdType.GetPlayerTokenRsp)
|
||||
{
|
||||
InitializeEncryption(1337); // hardcoded MT seed with patch
|
||||
}
|
||||
}
|
||||
|
||||
Debug.WriteLine("Successfully handled command of type {0}", packet.CmdType);
|
||||
}
|
||||
}
|
||||
|
||||
protected async ValueTask<int> ConsumePacketsAsync(Memory<byte> buffer)
|
||||
{
|
||||
if (buffer.Length < 12)
|
||||
|
@ -55,21 +75,7 @@ internal abstract class NetSession(ILogger<NetSession> logger, NetSessionManager
|
|||
if (packet == null)
|
||||
return consumed;
|
||||
|
||||
IResult? result = await _commandDispatcher.InvokeHandler(packet);
|
||||
if (result != null)
|
||||
{
|
||||
while (result.NextPacket(out NetPacket? serverPacket))
|
||||
{
|
||||
await SendAsync(serverPacket);
|
||||
|
||||
if (serverPacket.CmdType == CmdType.GetPlayerTokenRsp)
|
||||
{
|
||||
InitializeEncryption(1337); // hardcoded MT seed with patch
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("Successfully handled command of type {cmdType}", packet.CmdType);
|
||||
}
|
||||
if (packet != null) await HandlePacket(packet);
|
||||
} while (buffer.Length - consumed >= 12);
|
||||
|
||||
return consumed;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using NahidaImpact.Gameserver.Game.Entity;
|
||||
using NahidaImpact.Common.Constants;
|
||||
using NahidaImpact.Gameserver.Game.Entity;
|
||||
using NahidaImpact.Gameserver.Game.Entity.Listener;
|
||||
using NahidaImpact.Protocol;
|
||||
|
||||
|
@ -7,6 +8,15 @@ internal class SessionEntityEventListener(NetSession session) : IEntityEventList
|
|||
{
|
||||
private readonly NetSession _session = session;
|
||||
|
||||
public async ValueTask OnAvatarFightPropChanged(AvatarEntity entity, uint key, float value)
|
||||
{
|
||||
await _session.NotifyAsync(CmdType.AvatarFightPropUpdateNotify, new AvatarFightPropUpdateNotify
|
||||
{
|
||||
AvatarGuid = entity.GameAvatar.Guid,
|
||||
FightPropMap = {{key, value}}
|
||||
});
|
||||
}
|
||||
|
||||
public async ValueTask OnEntitySpawned(SceneEntity entity, VisionType visionType)
|
||||
{
|
||||
await _session.NotifyAsync(CmdType.SceneEntityAppearNotify, new SceneEntityAppearNotify
|
||||
|
|
|
@ -39,6 +39,7 @@ builder.Services.AddScoped<Player>();
|
|||
builder.Services.AddScoped<SceneManager>();
|
||||
builder.Services.AddScoped<EntityManager>();
|
||||
builder.Services.AddScoped<EntityFactory>();
|
||||
builder.Services.AddScoped<ClientActionManager>();
|
||||
|
||||
// Logic Listeners
|
||||
builder.Services.AddScoped<IEntityEventListener, SessionEntityEventListener>();
|
||||
|
|
Loading…
Reference in a new issue