feat: add outgoing messages to client
This commit is contained in:
@@ -12,12 +12,12 @@ namespace Client.Domain.Common
|
||||
{
|
||||
public static float Distance(this CreatureInterface creature, CreatureInterface other)
|
||||
{
|
||||
return creature.Transform.Position.HorizontalDistance(other.Transform.Position) / 100;
|
||||
return creature.Transform.Position.HorizontalDistance(other.Transform.Position);
|
||||
}
|
||||
|
||||
public static float DeltaZ(this CreatureInterface creature, CreatureInterface other)
|
||||
{
|
||||
return (creature.Transform.Position.Z - other.Transform.Position.Z) / 100;
|
||||
return (creature.Transform.Position.Z - other.Transform.Position.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
28
Client/Domain/DTO/OutgoingMessage.cs
Normal file
28
Client/Domain/DTO/OutgoingMessage.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Client.Domain.Enums;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Client.Domain.DTO
|
||||
{
|
||||
public class OutgoingMessage<T>
|
||||
{
|
||||
public readonly OutgoingMessageTypeEnum Type;
|
||||
public readonly T? Content;
|
||||
|
||||
public OutgoingMessage(OutgoingMessageTypeEnum type, T? content = default)
|
||||
{
|
||||
Type = type;
|
||||
Content = content;
|
||||
}
|
||||
}
|
||||
|
||||
public class EmptyOutgoingMessage : OutgoingMessage<uint>
|
||||
{
|
||||
public EmptyOutgoingMessage(OutgoingMessageTypeEnum type) : base(type)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -18,6 +18,6 @@ namespace Client.Domain.Entities
|
||||
string BriefInfo { get; }
|
||||
CreatureTypeEnum Type { get; }
|
||||
uint AggroRadius { get; set; }
|
||||
|
||||
bool IsHostile { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -62,6 +62,7 @@ namespace Client.Domain.Entities
|
||||
}
|
||||
}
|
||||
public uint AggroRadius { get; set; } = 0;
|
||||
public bool IsHostile { get; set; } = false;
|
||||
|
||||
public Hero(uint id, Transform transform, FullName fullName, VitalStats vitalStats, Phenotype phenotype, ExperienceInfo experienceInfo, PermanentStats permanentStats, VariableStats variableStats, Reputation reputation, InventoryInfo inventoryInfo, uint targetId, bool isStanding)
|
||||
{
|
||||
|
@@ -74,7 +74,7 @@ namespace Client.Domain.Entities
|
||||
{
|
||||
string result = FullName.Nickname;
|
||||
|
||||
if (IsDead())
|
||||
if (VitalStats.IsDead)
|
||||
{
|
||||
result += " (dead)";
|
||||
}
|
||||
@@ -124,17 +124,12 @@ namespace Client.Domain.Entities
|
||||
|
||||
private void VitalStats_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == "Hp" || e.PropertyName == "MaxHp")
|
||||
if (e.PropertyName == "IsDead")
|
||||
{
|
||||
OnPropertyChanged("Name");
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDead()
|
||||
{
|
||||
return VitalStats.MaxHp > 0 && VitalStats.Hp <= 0;
|
||||
}
|
||||
|
||||
private uint level;
|
||||
private uint aggroRadius;
|
||||
private VitalStats vitalStats;
|
||||
|
@@ -62,6 +62,7 @@ namespace Client.Domain.Entities
|
||||
public VitalStats VitalStats { get => vitalStats; set => vitalStats = value; }
|
||||
public CreatureTypeEnum Type { get => CreatureTypeEnum.Player; }
|
||||
public uint AggroRadius { get; set; } = 0;
|
||||
public bool IsHostile { get; set; } = false;
|
||||
|
||||
public Player(uint id, Transform transform, FullName fullName, Phenotype phenotype)
|
||||
{
|
||||
|
22
Client/Domain/Enums/OutgoingMessageTypeEnum.cs
Normal file
22
Client/Domain/Enums/OutgoingMessageTypeEnum.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Client.Domain.Enums
|
||||
{
|
||||
public enum OutgoingMessageTypeEnum
|
||||
{
|
||||
Invalidate,
|
||||
Move,
|
||||
AcquireTarget,
|
||||
Attack,
|
||||
Pickup,
|
||||
UseSkill,
|
||||
UseItem,
|
||||
ToggleSoulshot,
|
||||
Sit,
|
||||
Stand
|
||||
}
|
||||
}
|
14
Client/Domain/Parsers/OutgoingMessageBuilderInterface.cs
Normal file
14
Client/Domain/Parsers/OutgoingMessageBuilderInterface.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Client.Domain.DTO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Client.Domain.Parsers
|
||||
{
|
||||
public interface OutgoingMessageBuilderInterface
|
||||
{
|
||||
string Build<T>(OutgoingMessage<T> message);
|
||||
}
|
||||
}
|
289
Client/Domain/Service/WorldHandler.cs
Normal file
289
Client/Domain/Service/WorldHandler.cs
Normal file
@@ -0,0 +1,289 @@
|
||||
using Client.Domain.Entities;
|
||||
using Client.Domain.Events;
|
||||
using Client.Domain.Parsers;
|
||||
using Client.Domain.ValueObjects;
|
||||
using Client.Domain.DTO;
|
||||
using Client.Domain.Enums;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
using Client.Domain.Transports;
|
||||
|
||||
namespace Client.Domain.Service
|
||||
{
|
||||
public class WorldHandler :
|
||||
EventHandlerInterface<HeroCreatedEvent>,
|
||||
EventHandlerInterface<HeroDeletedEvent>,
|
||||
EventHandlerInterface<CreatureCreatedEvent>,
|
||||
EventHandlerInterface<CreatureDeletedEvent>,
|
||||
EventHandlerInterface<DropCreatedEvent>,
|
||||
EventHandlerInterface<DropDeletedEvent>,
|
||||
EventHandlerInterface<SkillCreatedEvent>,
|
||||
EventHandlerInterface<SkillDeletedEvent>,
|
||||
EventHandlerInterface<ItemCreatedEvent>,
|
||||
EventHandlerInterface<ItemDeletedEvent>
|
||||
{
|
||||
public void RequestMoveToLocation(Vector3 location)
|
||||
{
|
||||
if (hero == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(OutgoingMessageTypeEnum.Move, location);
|
||||
}
|
||||
|
||||
public void RequestMoveToEntity(uint id)
|
||||
{
|
||||
if (hero == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!creatures.ContainsKey(id) && !drops.ContainsKey(id))
|
||||
{
|
||||
Debug.WriteLine("RequestMoveToEntity: entity " + id + " not found");
|
||||
return;
|
||||
}
|
||||
|
||||
var position = creatures.ContainsKey(id) ? creatures[id].Transform.Position : drops[id].Transform.Position;
|
||||
|
||||
RequestMoveToLocation(position);
|
||||
}
|
||||
|
||||
public void RequestAcquireTarget(uint id)
|
||||
{
|
||||
if (hero == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (hero.TargetId == id)
|
||||
{
|
||||
Debug.WriteLine("RequestAcquireTarget: creature " + id + " is already target");
|
||||
return;
|
||||
}
|
||||
if (!creatures.ContainsKey(id) && hero.Id != id)
|
||||
{
|
||||
Debug.WriteLine("RequestAcquireTarget: creature " + id + " not found");
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(OutgoingMessageTypeEnum.AcquireTarget, id);
|
||||
}
|
||||
|
||||
public void RequestAttackOrFollow(uint id)
|
||||
{
|
||||
if (hero == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!creatures.ContainsKey(id))
|
||||
{
|
||||
Debug.WriteLine("RequestAttackOrFollow: creature " + id + " not found");
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(OutgoingMessageTypeEnum.Attack, id);
|
||||
}
|
||||
|
||||
public void RequestPickUp(uint id)
|
||||
{
|
||||
if (hero == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!drops.ContainsKey(id))
|
||||
{
|
||||
Debug.WriteLine("RequestPickUp: drop " + id + " not found");
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(OutgoingMessageTypeEnum.Pickup, id);
|
||||
}
|
||||
|
||||
public void RequestUseSkill(uint id, bool isForced, bool isShiftPressed)
|
||||
{
|
||||
if (hero == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!skills.TryGetValue(id, out Skill? skill))
|
||||
{
|
||||
Debug.WriteLine("RequestUseSkill: skill " + id + " not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!skill.IsActive)
|
||||
{
|
||||
Debug.WriteLine("RequestUseSkill: skill " + id + " is passive");
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(OutgoingMessageTypeEnum.UseSkill, id);
|
||||
}
|
||||
|
||||
public void RequestUseItem(uint id)
|
||||
{
|
||||
if (hero == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!items.ContainsKey(id))
|
||||
{
|
||||
Debug.WriteLine("RequestUseItem: item " + id + " not found");
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(OutgoingMessageTypeEnum.UseItem, id);
|
||||
}
|
||||
|
||||
public void RequestToggleAutouseSoulshot(uint id)
|
||||
{
|
||||
if (hero == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!items.ContainsKey(id))
|
||||
{
|
||||
Debug.WriteLine("RequestToggleAutouseSoulshot: item " + id + " not found");
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(OutgoingMessageTypeEnum.ToggleSoulshot, id);
|
||||
}
|
||||
|
||||
public void RequestSit()
|
||||
{
|
||||
if (hero == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hero.IsStanding)
|
||||
{
|
||||
Debug.WriteLine("RequestSit: hero is already sitting");
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(OutgoingMessageTypeEnum.Sit);
|
||||
}
|
||||
|
||||
public void RequestStand()
|
||||
{
|
||||
if (hero == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (hero.IsStanding)
|
||||
{
|
||||
Debug.WriteLine("RequestStand: hero is already standing");
|
||||
return;
|
||||
}
|
||||
|
||||
SendMessage(OutgoingMessageTypeEnum.Stand);
|
||||
}
|
||||
|
||||
private void SendMessage<T>(OutgoingMessageTypeEnum type, T? content = default)
|
||||
{
|
||||
var message = outgoingMessageBuilder.Build(
|
||||
new OutgoingMessage<T>(type, content)
|
||||
);
|
||||
transport.SendAsync(message);
|
||||
Debug.WriteLine(message);
|
||||
}
|
||||
|
||||
private void SendMessage(OutgoingMessageTypeEnum type)
|
||||
{
|
||||
SendMessage<uint>(type);
|
||||
}
|
||||
|
||||
#region Handle Entity
|
||||
public void Handle(HeroCreatedEvent @event)
|
||||
{
|
||||
hero = @event.Hero;
|
||||
}
|
||||
|
||||
public void Handle(HeroDeletedEvent @event)
|
||||
{
|
||||
hero = null;
|
||||
}
|
||||
|
||||
public void Handle(CreatureCreatedEvent @event)
|
||||
{
|
||||
if (!creatures.ContainsKey(@event.Creature.Id))
|
||||
{
|
||||
creatures.TryAdd(@event.Creature.Id, @event.Creature);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(CreatureDeletedEvent @event)
|
||||
{
|
||||
creatures.Remove(@event.Id, out CreatureInterface? value);
|
||||
}
|
||||
|
||||
public void Handle(DropCreatedEvent @event)
|
||||
{
|
||||
if (!drops.ContainsKey(@event.Drop.Id))
|
||||
{
|
||||
drops.TryAdd(@event.Drop.Id, @event.Drop);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(DropDeletedEvent @event)
|
||||
{
|
||||
drops.Remove(@event.Id, out Drop? value);
|
||||
}
|
||||
|
||||
public void Handle(SkillCreatedEvent @event)
|
||||
{
|
||||
if (!skills.ContainsKey(@event.Skill.Id))
|
||||
{
|
||||
skills.TryAdd(@event.Skill.Id, @event.Skill);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(SkillDeletedEvent @event)
|
||||
{
|
||||
skills.Remove(@event.Id, out Skill? value);
|
||||
}
|
||||
|
||||
public void Handle(ItemCreatedEvent @event)
|
||||
{
|
||||
if (!items.ContainsKey(@event.Item.Id))
|
||||
{
|
||||
items.TryAdd(@event.Item.Id, @event.Item);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(ItemDeletedEvent @event)
|
||||
{
|
||||
items.Remove(@event.Id, out BaseItem? value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public WorldHandler(OutgoingMessageBuilderInterface outgoingMessageBuilder, TransportInterface transport)
|
||||
{
|
||||
this.outgoingMessageBuilder = outgoingMessageBuilder;
|
||||
this.transport = transport;
|
||||
}
|
||||
|
||||
private Hero? hero;
|
||||
private ConcurrentDictionary<uint, CreatureInterface> creatures = new ConcurrentDictionary<uint, CreatureInterface>();
|
||||
private ConcurrentDictionary<uint, Drop> drops = new ConcurrentDictionary<uint, Drop>();
|
||||
private ConcurrentDictionary<uint, Skill> skills = new ConcurrentDictionary<uint, Skill>();
|
||||
private ConcurrentDictionary<uint, BaseItem> items = new ConcurrentDictionary<uint, BaseItem>();
|
||||
private readonly OutgoingMessageBuilderInterface outgoingMessageBuilder;
|
||||
private readonly TransportInterface transport;
|
||||
}
|
||||
}
|
@@ -12,12 +12,12 @@ namespace Client.Domain.ValueObjects
|
||||
private uint cp;
|
||||
private uint maxCp;
|
||||
|
||||
public uint Hp { get => hp; set { if (value != hp) { hp = value; OnPropertyChanged("Hp"); OnPropertyChanged("MaxHp"); } } }
|
||||
public uint MaxHp { get => Math.Max(hp, maxHp); set { if (value != maxHp) { maxHp = value; OnPropertyChanged("MaxHp"); } } }
|
||||
public uint Mp { get => mp; set { if (value != mp) { mp = value; OnPropertyChanged("Mp"); } } }
|
||||
public uint MaxMp { get => maxMp; set { if (value != maxMp) { maxMp = value; OnPropertyChanged("MaxMp"); } } }
|
||||
public uint Cp { get => cp; set { if (value != cp) { cp = value; OnPropertyChanged("Cp"); } } }
|
||||
public uint MaxCp { get => maxCp; set { if (value != maxCp) { maxCp = value; OnPropertyChanged("MaxCp"); } } }
|
||||
public uint Hp { get => hp; set { if (value != hp) { hp = value; OnPropertyChanged(); OnPropertyChanged("MaxHp"); OnPropertyChanged("IsDead"); } } }
|
||||
public uint MaxHp { get => Math.Max(hp, maxHp); set { if (value != maxHp) { maxHp = value; OnPropertyChanged(); OnPropertyChanged("IsDead"); } } }
|
||||
public uint Mp { get => mp; set { if (value != mp) { mp = value; OnPropertyChanged(); } } }
|
||||
public uint MaxMp { get => maxMp; set { if (value != maxMp) { maxMp = value; OnPropertyChanged(); } } }
|
||||
public uint Cp { get => cp; set { if (value != cp) { cp = value; OnPropertyChanged(); } } }
|
||||
public uint MaxCp { get => maxCp; set { if (value != maxCp) { maxCp = value; OnPropertyChanged(); } } }
|
||||
|
||||
public double HpPercent
|
||||
{
|
||||
@@ -41,6 +41,8 @@ namespace Client.Domain.ValueObjects
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDead => MaxHp > 0 && hp == 0;
|
||||
|
||||
public VitalStats(uint hp, uint maxHp, uint mp, uint maxMp, uint cp, uint maxCp)
|
||||
{
|
||||
this.hp = hp;
|
||||
|
Reference in New Issue
Block a user