feat: add outgoing messages to client

This commit is contained in:
k0t9i 2023-02-09 22:45:08 +04:00
parent abcf3b20c0
commit ad5d7a5159
25 changed files with 739 additions and 74 deletions

View File

@ -78,6 +78,7 @@ namespace Client
) )
.AddSingleton(typeof(EntityHandlerFactoryInterface), typeof(EntityHandlerFactory)) .AddSingleton(typeof(EntityHandlerFactoryInterface), typeof(EntityHandlerFactory))
.AddSingleton(typeof(MessageParserInterface), typeof(JsonMessageParser)) .AddSingleton(typeof(MessageParserInterface), typeof(JsonMessageParser))
.AddSingleton(typeof(OutgoingMessageBuilderInterface), typeof(JsonOutgoingMessageBuilder))
.AddSingleton( .AddSingleton(
typeof(TransportInterface), typeof(TransportInterface),
x => new NamedPipeTransport( x => new NamedPipeTransport(
@ -103,6 +104,7 @@ namespace Client
.AddSingleton<ChatMessageHandler>() .AddSingleton<ChatMessageHandler>()
.AddSingleton<SkillHandler>() .AddSingleton<SkillHandler>()
.AddSingleton<ItemHander>() .AddSingleton<ItemHander>()
.AddSingleton<WorldHandler>()
.AddSingleton<MainViewModel>(); .AddSingleton<MainViewModel>();
} }

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace Client.Application.Commands
{
public class RelayCommand : ICommand
{
private Action<object?> execute;
private Func<object?, bool>? canExecute;
public event EventHandler? CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object?> execute, Func<object?, bool>? canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object? parameter)
{
return canExecute == null || canExecute(parameter);
}
public void Execute(object? parameter)
{
execute(parameter);
}
}
}

View File

@ -3,7 +3,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Client.Application.Components"
xmlns:services="clr-namespace:Client.Application.Services" xmlns:services="clr-namespace:Client.Application.Services"
xmlns:components="clr-namespace:Client.Application.Components" xmlns:components="clr-namespace:Client.Application.Components"
mc:Ignorable="d" mc:Ignorable="d"
@ -11,7 +10,10 @@
services:SizeObserver.ObservedWidth="{Binding ViewportWidth, Mode=OneWayToSource}" services:SizeObserver.ObservedWidth="{Binding ViewportWidth, Mode=OneWayToSource}"
services:SizeObserver.ObservedHeight="{Binding ViewportHeight, Mode=OneWayToSource}" services:SizeObserver.ObservedHeight="{Binding ViewportHeight, Mode=OneWayToSource}"
> >
<Grid> <Grid Background="Transparent">
<Grid.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding MouseLeftClickCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Grid}}" />
</Grid.InputBindings>
<ItemsControl ItemsSource="{Binding Path=Blocks}"> <ItemsControl ItemsSource="{Binding Path=Blocks}">
<ItemsControl.Resources> <ItemsControl.Resources>
<services:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> <services:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
@ -55,21 +57,46 @@
<TranslateTransform X="{Binding Position.X,Mode=OneWay}" Y="{Binding Position.Y,Mode=OneWay}"/> <TranslateTransform X="{Binding Position.X,Mode=OneWay}" Y="{Binding Position.Y,Mode=OneWay}"/>
</Path.RenderTransform> </Path.RenderTransform>
</Path> </Path>
<Path x:Name="CreatureBody" StrokeThickness="2"> </Grid>
<Path.Data> <DataTemplate.Triggers>
<EllipseGeometry <DataTrigger Binding="{Binding IsAggressive,Mode=OneWay}" Value="True">
RadiusX="{Binding Radius,Mode=OneWay}" <Setter TargetName="CreatureAggroRadius" Property="Visibility" Value="Visible" />
RadiusY="{Binding Radius,Mode=OneWay}" /> </DataTrigger>
</Path.Data> </DataTemplate.Triggers>
<Path.RenderTransform> </DataTemplate>
<TranslateTransform X="{Binding Position.X,Mode=OneWay}" Y="{Binding Position.Y,Mode=OneWay}"/> </ItemsControl.ItemTemplate>
</Path.RenderTransform> </ItemsControl>
</Path> <ItemsControl ItemsSource="{Binding Path=Creatures}">
<Line x:Name="CreatureDirection" X1="0" Y1="0" X2="{Binding Direction.X,Mode=OneWay}" Y2="{Binding Direction.Y,Mode=OneWay}" StrokeThickness="2"> <ItemsControl.ItemsPanel>
<Line.RenderTransform> <ItemsPanelTemplate>
<TranslateTransform X="{Binding Position.X,Mode=OneWay}" Y="{Binding Position.Y,Mode=OneWay}"/> <Canvas ClipToBounds="True" />
</Line.RenderTransform> </ItemsPanelTemplate>
</Line> </ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid x:Name="CreatureMain">
<Grid.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding MouseLeftClickCommand}" />
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding MouseLeftDoubleClickCommand}" />
<MouseBinding Gesture="RightClick" Command="{Binding MouseRightClickCommand}" />
</Grid.InputBindings>
<Path x:Name="CreatureBody" StrokeThickness="2" Fill="Transparent">
<Path.Data>
<EllipseGeometry
RadiusX="{Binding Radius,Mode=OneWay}"
RadiusY="{Binding Radius,Mode=OneWay}" />
</Path.Data>
<Path.RenderTransform>
<TranslateTransform X="{Binding Position.X,Mode=OneWay}" Y="{Binding Position.Y,Mode=OneWay}"/>
</Path.RenderTransform>
</Path>
<Line x:Name="CreatureDirection" X1="0" Y1="0" X2="{Binding Direction.X,Mode=OneWay}" Y2="{Binding Direction.Y,Mode=OneWay}" StrokeThickness="2">
<Line.RenderTransform>
<TranslateTransform X="{Binding Position.X,Mode=OneWay}" Y="{Binding Position.Y,Mode=OneWay}"/>
</Line.RenderTransform>
</Line>
</Grid>
<Grid x:Name="CreatureName" Visibility="Hidden" VerticalAlignment="Top" HorizontalAlignment="Left"> <Grid x:Name="CreatureName" Visibility="Hidden" VerticalAlignment="Top" HorizontalAlignment="Left">
<Grid.RenderTransform> <Grid.RenderTransform>
<TransformGroup> <TransformGroup>
@ -125,9 +152,9 @@
<DataTrigger Binding="{Binding IsTarget,Mode=OneWay}" Value="True"> <DataTrigger Binding="{Binding IsTarget,Mode=OneWay}" Value="True">
<Setter TargetName="CreatureName" Property="Visibility" Value="Visible" /> <Setter TargetName="CreatureName" Property="Visibility" Value="Visible" />
</DataTrigger> </DataTrigger>
<DataTrigger Binding="{Binding IsAggressive,Mode=OneWay}" Value="True"> <Trigger SourceName="CreatureMain" Property="IsMouseOver" Value="True">
<Setter TargetName="CreatureAggroRadius" Property="Visibility" Value="Visible" /> <Setter TargetName="CreatureName" Property="Visibility" Value="Visible"></Setter>
</DataTrigger> </Trigger>
</DataTemplate.Triggers> </DataTemplate.Triggers>
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
@ -141,17 +168,52 @@
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate> <DataTemplate>
<Grid> <Grid>
<Path StrokeThickness="2" Stroke="Gold"> <Grid x:Name="DropMain">
<Path.Data> <Grid.InputBindings>
<EllipseGeometry <MouseBinding Gesture="LeftClick" Command="{Binding MouseLeftClickCommand}" />
RadiusX="{Binding Radius,Mode=OneWay}" <MouseBinding Gesture="RightClick" Command="{Binding MouseRightClickCommand}" />
RadiusY="{Binding Radius,Mode=OneWay}" /> </Grid.InputBindings>
</Path.Data> <Path StrokeThickness="2" Stroke="Gold" Fill="Transparent">
<Path.RenderTransform> <Path.Data>
<TranslateTransform X="{Binding Position.X,Mode=OneWay}" Y="{Binding Position.Y,Mode=OneWay}"/> <EllipseGeometry
</Path.RenderTransform> RadiusX="{Binding Radius,Mode=OneWay}"
</Path> RadiusY="{Binding Radius,Mode=OneWay}" />
</Path.Data>
<Path.RenderTransform>
<TranslateTransform X="{Binding Position.X,Mode=OneWay}" Y="{Binding Position.Y,Mode=OneWay}"/>
</Path.RenderTransform>
</Path>
</Grid>
<Grid x:Name="DropName" Visibility="Hidden" VerticalAlignment="Top" HorizontalAlignment="Left">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="-2" ScaleY="-1" />
<TranslateTransform
X="{Binding Path=ActualWidth,RelativeSource={RelativeSource AncestorType=Grid}}"
Y="{Binding Path=ActualHeight,RelativeSource={RelativeSource AncestorType=Grid}}"
/>
<ScaleTransform ScaleX="-0.5" ScaleY="-1" />
<ScaleTransform ScaleY="-0.5" />
<TranslateTransform Y="{Binding Radius}" />
<ScaleTransform ScaleY="-2" />
<TranslateTransform X="{Binding Position.X,Mode=OneWay}" Y="{Binding Position.Y,Mode=OneWay}"/>
</TransformGroup>
</Grid.RenderTransform>
<TextBlock Text="{Binding Name,Mode=OneWay}" Foreground="Black" FontSize="11">
<TextBlock.Effect>
<BlurEffect
Radius="2"
KernelType="Box"/>
</TextBlock.Effect>
</TextBlock>
<TextBlock Text="{Binding Name,Mode=OneWay}" Foreground="White" FontSize="11"/>
</Grid>
</Grid> </Grid>
<DataTemplate.Triggers>
<Trigger SourceName="DropMain" Property="IsMouseOver" Value="True">
<Setter TargetName="DropName" Property="Visibility" Value="Visible"></Setter>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
</ItemsControl> </ItemsControl>

View File

@ -8,7 +8,8 @@
mc:Ignorable="d" mc:Ignorable="d"
IsEnabled="{Binding Path=IsButtonActive,ElementName=root,Mode=OneWay}" IsEnabled="{Binding Path=IsButtonActive,ElementName=root,Mode=OneWay}"
ToolTipService.ShowOnDisabled="True" ToolTipService.ShowOnDisabled="True"
x:Name="root"> x:Name="root"
Command="{Binding MouseLeftClickCommand}">
<Button.Resources> <Button.Resources>
<services:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/> <services:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<services:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/> <services:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>

View File

@ -1,11 +1,14 @@
using Client.Domain.Common; using Client.Application.Commands;
using Client.Domain.Common;
using Client.Domain.Entities; using Client.Domain.Entities;
using Client.Domain.Service;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input;
namespace Client.Application.ViewModels namespace Client.Application.ViewModels
{ {
@ -21,14 +24,36 @@ namespace Client.Application.ViewModels
public float DeltaZ => creature.DeltaZ(hero); public float DeltaZ => creature.DeltaZ(hero);
public CreatureListViewModel(CreatureInterface creature, Hero hero) public ICommand MouseLeftClickCommand { get; }
public ICommand MouseLeftDoubleClickCommand { get; }
public ICommand MouseRightClickCommand { get; }
private void OnMouseLeftClick(object? obj)
{
worldHandler.RequestAcquireTarget(Id);
}
private void OnMouseLeftDoubleClick(object? obj)
{
worldHandler.RequestAttackOrFollow(Id);
}
private void OnMouseRightClick(object? obj)
{
worldHandler.RequestMoveToEntity(Id);
}
public CreatureListViewModel(CreatureInterface creature, Hero hero, WorldHandler worldHandler)
{ {
creature.PropertyChanged += Creature_PropertyChanged; creature.PropertyChanged += Creature_PropertyChanged;
creature.Transform.Position.PropertyChanged += Position_PropertyChanged; creature.Transform.Position.PropertyChanged += Position_PropertyChanged;
hero.Transform.Position.PropertyChanged += HeroPosition_PropertyChanged; hero.Transform.Position.PropertyChanged += HeroPosition_PropertyChanged;
MouseLeftClickCommand = new RelayCommand(OnMouseLeftClick);
MouseLeftDoubleClickCommand = new RelayCommand(OnMouseLeftDoubleClick);
MouseRightClickCommand = new RelayCommand(OnMouseRightClick);
this.creature = creature; this.creature = creature;
this.hero = hero; this.hero = hero;
this.worldHandler = worldHandler;
} }
private void HeroPosition_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) private void HeroPosition_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
@ -57,5 +82,6 @@ namespace Client.Application.ViewModels
private readonly CreatureInterface creature; private readonly CreatureInterface creature;
private readonly Hero hero; private readonly Hero hero;
private readonly WorldHandler worldHandler;
} }
} }

View File

@ -1,12 +1,17 @@
using Client.Domain.Common; using Client.Domain.Common;
using Client.Domain.Entities; using Client.Domain.Entities;
using Client.Domain.Enums; using Client.Domain.Enums;
using Client.Domain.Service;
using Client.Domain.ValueObjects; using Client.Domain.ValueObjects;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows;
using Client.Application.Commands;
using System.Net.Http;
namespace Client.Application.ViewModels namespace Client.Application.ViewModels
{ {
@ -56,20 +61,41 @@ namespace Client.Application.ViewModels
} }
public CreatureTypeEnum Type => creature.Type; public CreatureTypeEnum Type => creature.Type;
public bool IsTarget => Id == hero.TargetId; public bool IsTarget => Id == hero.TargetId;
public bool IsAggressive => creature.AggroRadius > 0; public bool IsAggressive => creature.AggroRadius > 0 && !creature.VitalStats.IsDead && creature.IsHostile;
public float AggroRadius => creature.AggroRadius / scale; public float AggroRadius => creature.AggroRadius / scale;
public ICommand MouseLeftClickCommand { get; }
public ICommand MouseLeftDoubleClickCommand { get; }
public ICommand MouseRightClickCommand { get; }
private void OnMouseLeftClick(object? obj)
{
worldHandler.RequestAcquireTarget(Id);
}
public CreatureMapViewModel(CreatureInterface creature, Hero hero) private void OnMouseLeftDoubleClick(object? obj)
{
worldHandler.RequestAttackOrFollow(Id);
}
private void OnMouseRightClick(object? obj)
{
worldHandler.RequestMoveToEntity(Id);
}
public CreatureMapViewModel(CreatureInterface creature, Hero hero, WorldHandler worldHandler)
{ {
this.creature = creature; this.creature = creature;
this.hero = hero; this.hero = hero;
this.worldHandler = worldHandler;
creature.PropertyChanged += Creature_PropertyChanged; creature.PropertyChanged += Creature_PropertyChanged;
creature.Transform.PropertyChanged += Transform_PropertyChanged; creature.Transform.PropertyChanged += Transform_PropertyChanged;
creature.Transform.Position.PropertyChanged += Position_PropertyChanged; creature.Transform.Position.PropertyChanged += Position_PropertyChanged;
creature.VitalStats.PropertyChanged += VitalStats_PropertyChanged; creature.VitalStats.PropertyChanged += VitalStats_PropertyChanged;
hero.Transform.Position.PropertyChanged += HeroPosition_PropertyChanged; hero.Transform.Position.PropertyChanged += HeroPosition_PropertyChanged;
hero.PropertyChanged += Hero_PropertyChanged; hero.PropertyChanged += Hero_PropertyChanged;
MouseLeftClickCommand = new RelayCommand(OnMouseLeftClick);
MouseLeftDoubleClickCommand = new RelayCommand(OnMouseLeftDoubleClick);
MouseRightClickCommand = new RelayCommand(OnMouseRightClick);
} }
private void VitalStats_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) private void VitalStats_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
@ -78,6 +104,10 @@ namespace Client.Application.ViewModels
{ {
OnPropertyChanged("VitalStats"); OnPropertyChanged("VitalStats");
} }
if (e.PropertyName == "IsDead")
{
OnPropertyChanged("IsAggressive");
}
} }
private void Hero_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) private void Hero_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
@ -118,6 +148,7 @@ namespace Client.Application.ViewModels
private readonly CreatureInterface creature; private readonly CreatureInterface creature;
private readonly Hero hero; private readonly Hero hero;
private readonly WorldHandler worldHandler;
private float scale = 1; private float scale = 1;
private static readonly float MAX_RADIUS = 10; private static readonly float MAX_RADIUS = 10;
private static readonly float MIN_RADIUS = 4; private static readonly float MIN_RADIUS = 4;

View File

@ -1,10 +1,13 @@
using Client.Domain.Common; using Client.Application.Commands;
using Client.Domain.Common;
using Client.Domain.Entities; using Client.Domain.Entities;
using Client.Domain.Service;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Input;
namespace Client.Application.ViewModels namespace Client.Application.ViewModels
{ {
@ -46,14 +49,14 @@ namespace Client.Application.ViewModels
{ {
get get
{ {
return drop.Transform.Position.HorizontalDistance(hero.Transform.Position) / 100; return drop.Transform.Position.HorizontalDistance(hero.Transform.Position);
} }
} }
public float DeltaZ public float DeltaZ
{ {
get get
{ {
return (drop.Transform.Position.Z - hero.Transform.Position.Z) / 100; return (drop.Transform.Position.Z - hero.Transform.Position.Z);
} }
} }
@ -65,14 +68,27 @@ namespace Client.Application.ViewModels
} }
} }
public DropListViewModel(Drop drop, Hero hero) public ICommand MouseLeftClickCommand { get; }
public ICommand MouseRightClickCommand { get; }
private void OnMouseLeftClick(object? obj)
{
worldHandler.RequestPickUp(Id);
}
private void OnMouseRightClick(object? obj)
{
worldHandler.RequestMoveToEntity(Id);
}
public DropListViewModel(Drop drop, Hero hero, WorldHandler worldHandler)
{ {
this.drop = drop; this.drop = drop;
this.hero = hero; this.hero = hero;
this.worldHandler = worldHandler;
drop.PropertyChanged += Drop_PropertyChanged; drop.PropertyChanged += Drop_PropertyChanged;
drop.Transform.Position.PropertyChanged += DropPosition_PropertyChanged; drop.Transform.Position.PropertyChanged += DropPosition_PropertyChanged;
hero.Transform.Position.PropertyChanged += HeroPosition_PropertyChanged; hero.Transform.Position.PropertyChanged += HeroPosition_PropertyChanged;
MouseLeftClickCommand = new RelayCommand(OnMouseLeftClick);
MouseRightClickCommand = new RelayCommand(OnMouseRightClick);
} }
private void HeroPosition_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) private void HeroPosition_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
@ -109,5 +125,6 @@ namespace Client.Application.ViewModels
private readonly Drop drop; private readonly Drop drop;
private readonly Hero hero; private readonly Hero hero;
private readonly WorldHandler worldHandler;
} }
} }

View File

@ -8,13 +8,16 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.ComponentModel; using System.ComponentModel;
using Client.Domain.Service;
using System.Windows.Input;
using Client.Application.Commands;
namespace Client.Application.ViewModels namespace Client.Application.ViewModels
{ {
public class DropMapViewModel : ObservableObject public class DropMapViewModel : ObservableObject
{ {
public uint Id => drop.Id; public uint Id => drop.Id;
public string Name => drop.Name; public string Name => drop.Name + " (" + drop.Amount + ")";
public Vector3 Position => new Vector3( public Vector3 Position => new Vector3(
(drop.Transform.Position.X - hero.Transform.Position.X) / scale + (VieportSize.X / 2), (drop.Transform.Position.X - hero.Transform.Position.X) / scale + (VieportSize.X / 2),
(drop.Transform.Position.Y - hero.Transform.Position.Y) / scale + (VieportSize.Y / 2), (drop.Transform.Position.Y - hero.Transform.Position.Y) / scale + (VieportSize.Y / 2),
@ -47,13 +50,27 @@ namespace Client.Application.ViewModels
} }
} }
public DropMapViewModel(Drop drop, Hero hero) public ICommand MouseLeftClickCommand { get; }
public ICommand MouseRightClickCommand { get; }
private void OnMouseLeftClick(object? obj)
{
worldHandler.RequestPickUp(Id);
}
private void OnMouseRightClick(object? obj)
{
worldHandler.RequestMoveToEntity(Id);
}
public DropMapViewModel(Drop drop, Hero hero, WorldHandler worldHandler)
{ {
this.drop = drop; this.drop = drop;
this.hero = hero; this.hero = hero;
this.worldHandler = worldHandler;
drop.PropertyChanged += Creature_PropertyChanged; drop.PropertyChanged += Creature_PropertyChanged;
drop.Transform.Position.PropertyChanged += Position_PropertyChanged; drop.Transform.Position.PropertyChanged += Position_PropertyChanged;
hero.Transform.Position.PropertyChanged += HeroPosition_PropertyChanged; hero.Transform.Position.PropertyChanged += HeroPosition_PropertyChanged;
MouseLeftClickCommand = new RelayCommand(OnMouseLeftClick);
MouseRightClickCommand = new RelayCommand(OnMouseRightClick);
} }
private void HeroPosition_PropertyChanged(object? sender, PropertyChangedEventArgs e) private void HeroPosition_PropertyChanged(object? sender, PropertyChangedEventArgs e)
@ -68,7 +85,7 @@ namespace Client.Application.ViewModels
private void Creature_PropertyChanged(object? sender, PropertyChangedEventArgs e) private void Creature_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{ {
if (e.PropertyName == "Name") if (e.PropertyName == "Name" || e.PropertyName == "Amount")
{ {
OnPropertyChanged("Name"); OnPropertyChanged("Name");
} }
@ -76,6 +93,7 @@ namespace Client.Application.ViewModels
private readonly Drop drop; private readonly Drop drop;
private readonly Hero hero; private readonly Hero hero;
private readonly WorldHandler worldHandler;
private float scale = 1; private float scale = 1;
private static readonly float MAX_RADIUS = 8; private static readonly float MAX_RADIUS = 8;
private static readonly float MIN_RADIUS = 2; private static readonly float MIN_RADIUS = 2;

View File

@ -1,6 +1,8 @@
using Client.Domain.Common; using Client.Application.Components;
using Client.Domain.Common;
using Client.Domain.Entities; using Client.Domain.Entities;
using Client.Domain.Events; using Client.Domain.Events;
using Client.Domain.Service;
using Client.Domain.ValueObjects; using Client.Domain.ValueObjects;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -57,7 +59,7 @@ namespace Client.Application.ViewModels
{ {
if (hero != null) if (hero != null)
{ {
Creatures.Add(new CreatureListViewModel(@event.Creature, hero)); Creatures.Add(new CreatureListViewModel(@event.Creature, hero, worldHandler));
AddCreature(@event.Creature); AddCreature(@event.Creature);
} }
} }
@ -72,8 +74,8 @@ namespace Client.Application.ViewModels
{ {
if (hero != null) if (hero != null)
{ {
Drops.Add(new DropListViewModel(@event.Drop, hero)); Drops.Add(new DropListViewModel(@event.Drop, hero, worldHandler));
Map.Drops.Add(new DropMapViewModel(@event.Drop, hero)); Map.Drops.Add(new DropMapViewModel(@event.Drop, hero, worldHandler));
} }
} }
@ -94,11 +96,11 @@ namespace Client.Application.ViewModels
{ {
if (@event.Skill.IsActive) if (@event.Skill.IsActive)
{ {
ActiveSkills.Add(new SkillListViewModel(@event.Skill)); ActiveSkills.Add(new SkillListViewModel(worldHandler, @event.Skill));
} }
else else
{ {
PassiveSkills.Add(new SkillListViewModel(@event.Skill)); PassiveSkills.Add(new SkillListViewModel(worldHandler, @event.Skill));
} }
} }
} }
@ -126,7 +128,7 @@ namespace Client.Application.ViewModels
{ {
if (hero != null) if (hero != null)
{ {
Map.Creatures.Add(new CreatureMapViewModel(creature, hero)); Map.Creatures.Add(new CreatureMapViewModel(creature, hero, worldHandler));
} }
} }
@ -135,6 +137,12 @@ namespace Client.Application.ViewModels
Map.Creatures.RemoveAll(x => x.Id == id); Map.Creatures.RemoveAll(x => x.Id == id);
} }
public MainViewModel(WorldHandler worldHandler)
{
this.worldHandler = worldHandler;
Map = new MapViewModel(worldHandler);
}
public ObservableCollection<ChatMessageViewModel> ChatMessages { get; } = new ObservableCollection<ChatMessageViewModel>(); public ObservableCollection<ChatMessageViewModel> ChatMessages { get; } = new ObservableCollection<ChatMessageViewModel>();
public ObservableCollection<CreatureListViewModel> Creatures { get; } = new ObservableCollection<CreatureListViewModel>(); public ObservableCollection<CreatureListViewModel> Creatures { get; } = new ObservableCollection<CreatureListViewModel>();
public ObservableCollection<DropListViewModel> Drops { get; } = new ObservableCollection<DropListViewModel>(); public ObservableCollection<DropListViewModel> Drops { get; } = new ObservableCollection<DropListViewModel>();
@ -142,7 +150,8 @@ namespace Client.Application.ViewModels
public ObservableCollection<SkillListViewModel> PassiveSkills { get; } = new ObservableCollection<SkillListViewModel>(); public ObservableCollection<SkillListViewModel> PassiveSkills { get; } = new ObservableCollection<SkillListViewModel>();
public ObservableCollection<BaseItem> Items { get; } = new ObservableCollection<BaseItem>(); public ObservableCollection<BaseItem> Items { get; } = new ObservableCollection<BaseItem>();
public HeroSummaryInfoViewModel? Hero { get; private set; } public HeroSummaryInfoViewModel? Hero { get; private set; }
public MapViewModel Map { get; private set; } = new MapViewModel(); public MapViewModel Map { get; private set; }
public Hero? hero; public Hero? hero;
private readonly WorldHandler worldHandler;
} }
} }

View File

@ -11,6 +11,9 @@ using System.Threading.Tasks;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media.Animation; using System.Windows.Media.Animation;
using System.Collections.Specialized; using System.Collections.Specialized;
using Client.Application.Commands;
using System.Reflection.Metadata;
using System.Windows;
namespace Client.Application.ViewModels namespace Client.Application.ViewModels
{ {
@ -125,10 +128,33 @@ namespace Client.Application.ViewModels
} }
} }
public MapViewModel() public ICommand MouseLeftClickCommand { get; }
private void OnLeftMouseClick(object? obj)
{
if (obj == null)
{
return;
}
if (hero == null)
{
return;
}
Point mousePos = Mouse.GetPosition((IInputElement)obj);
var location = new Vector3(
(float)(mousePos.X - ViewportWidth / 2) * scale + hero.Transform.Position.X,
(float)(mousePos.Y - ViewportHeight / 2) * scale + hero.Transform.Position.Y,
hero.Transform.Position.Z
);
worldHandler.RequestMoveToLocation(location);
}
public MapViewModel(WorldHandler worldHandler)
{ {
Creatures.CollectionChanged += Creatures_CollectionChanged; Creatures.CollectionChanged += Creatures_CollectionChanged;
Drops.CollectionChanged += Drops_CollectionChanged; Drops.CollectionChanged += Drops_CollectionChanged;
this.worldHandler = worldHandler;
MouseLeftClickCommand = new RelayCommand(OnLeftMouseClick);
} }
private void Drops_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) private void Drops_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
@ -167,5 +193,6 @@ namespace Client.Application.ViewModels
private float scale = 8; private float scale = 8;
private double viewportWidth = 0; private double viewportWidth = 0;
private double viewportHeight = 0; private double viewportHeight = 0;
private readonly WorldHandler worldHandler;
} }
} }

View File

@ -1,10 +1,13 @@
using Client.Domain.Common; using Client.Domain.Common;
using Client.Domain.Entities; using Client.Domain.Entities;
using Client.Domain.Service;
using System.Windows.Input;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Client.Application.Commands;
namespace Client.Application.ViewModels namespace Client.Application.ViewModels
{ {
@ -21,11 +24,19 @@ namespace Client.Application.ViewModels
public uint? Cost => skill.Cost == 0 ? null : skill.Cost; public uint? Cost => skill.Cost == 0 ? null : skill.Cost;
public int? Range => skill.Range <= 0 ? null : skill.Range; public int? Range => skill.Range <= 0 ? null : skill.Range;
public SkillListViewModel(Skill skill) public ICommand MouseLeftClickCommand { get; }
private void OnLeftMouseClick(object? obj)
{ {
worldHandler.RequestUseSkill(Id, false, false);
}
public SkillListViewModel(WorldHandler worldHandler, Skill skill)
{
this.worldHandler = worldHandler;
this.skill = skill; this.skill = skill;
skill.PropertyChanged += Skill_PropertyChanged; skill.PropertyChanged += Skill_PropertyChanged;
MouseLeftClickCommand = new RelayCommand(OnLeftMouseClick);
} }
private void Skill_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) private void Skill_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
@ -61,6 +72,7 @@ namespace Client.Application.ViewModels
} }
} }
private readonly WorldHandler worldHandler;
private readonly Skill skill; private readonly Skill skill;
} }
} }

View File

@ -53,10 +53,15 @@
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<StackPanel Margin="5"> <StackPanel Margin="5">
<StackPanel.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding MouseLeftClickCommand}" />
<MouseBinding Gesture="LeftDoubleClick" Command="{Binding MouseLeftDoubleClickCommand}" />
<MouseBinding Gesture="RightClick" Command="{Binding MouseRightClickCommand}" />
</StackPanel.InputBindings>
<TextBlock FontSize="16" Text="{Binding Path=Name,Mode=OneWay}" /> <TextBlock FontSize="16" Text="{Binding Path=Name,Mode=OneWay}" />
<TextBlock FontSize="11"> <TextBlock FontSize="11">
<TextBlock.Text> <TextBlock.Text>
<MultiBinding StringFormat="{}{0}; distance: {1:F2}m; delta z: {2:F2}m"> <MultiBinding StringFormat="{}{0}; distance: {1:F0}; delta z: {2:F0}">
<Binding Path="BriefInfo" Mode="OneWay"/> <Binding Path="BriefInfo" Mode="OneWay"/>
<Binding Path="Distance" Mode="OneWay"/> <Binding Path="Distance" Mode="OneWay"/>
<Binding Path="DeltaZ" Mode="OneWay"/> <Binding Path="DeltaZ" Mode="OneWay"/>
@ -71,6 +76,10 @@
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<DockPanel> <DockPanel>
<DockPanel.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding MouseLeftClickCommand}" />
<MouseBinding Gesture="RightClick" Command="{Binding MouseRightClickCommand}" />
</DockPanel.InputBindings>
<Image DockPanel.Dock="Left" Source="{Binding Path=IconName, FallbackValue=./Assets/icons/_fallback.png, Mode=OneWay}" Height="32" Width="32" /> <Image DockPanel.Dock="Left" Source="{Binding Path=IconName, FallbackValue=./Assets/icons/_fallback.png, Mode=OneWay}" Height="32" Width="32" />
<StackPanel Margin="5"> <StackPanel Margin="5">
<TextBlock FontSize="16"> <TextBlock FontSize="16">
@ -83,7 +92,7 @@
</TextBlock> </TextBlock>
<TextBlock FontSize="11"> <TextBlock FontSize="11">
<TextBlock.Text> <TextBlock.Text>
<MultiBinding StringFormat="{}Count {0}; distance: {1:F2}m; delta z: {2:F2}m"> <MultiBinding StringFormat="{}Count {0}; distance: {1:F0}; delta z: {2:F0}">
<Binding Path="Amount" Mode="OneWay"/> <Binding Path="Amount" Mode="OneWay"/>
<Binding Path="Distance" Mode="OneWay"/> <Binding Path="Distance" Mode="OneWay"/>
<Binding Path="DeltaZ" Mode="OneWay"/> <Binding Path="DeltaZ" Mode="OneWay"/>
@ -146,7 +155,8 @@
</Button.Resources> </Button.Resources>
<Button.Content> <Button.Content>
<Grid> <Grid>
<Image Source="{Binding Path=ImageSource}" Height="32" Width="32" /> <!--Image Source="{Binding Path=ImageSource}" Height="32" Width="32" /-->
<TextBlock Text="{Binding Name,Mode=OneWay}" />
</Grid> </Grid>
</Button.Content> </Button.Content>
<Button.ToolTip > <Button.ToolTip >
@ -270,8 +280,8 @@
</MultiBinding> </MultiBinding>
</TextBlock.Text> </TextBlock.Text>
</TextBlock> </TextBlock>
<TextBlock Padding="0 0 0 3" Text="{Binding Distance,Mode=OneWay,StringFormat='{}{0:F2}m'}"></TextBlock> <TextBlock Padding="0 0 0 3" Text="{Binding Distance,Mode=OneWay,StringFormat='{}{0:F0}'}"></TextBlock>
<TextBlock Padding="0 0 0 3" Text="{Binding DeltaZ,Mode=OneWay,StringFormat='{}{0:F2}m'}"></TextBlock> <TextBlock Padding="0 0 0 3" Text="{Binding DeltaZ,Mode=OneWay,StringFormat='{}{0:F0}'}"></TextBlock>
</StackPanel> </StackPanel>
</DockPanel> </DockPanel>
</Grid> </Grid>

View File

@ -78,6 +78,18 @@ namespace Client
eventBus.Subscrbe((EventHandlerInterface<ItemCreatedEvent>)viewModel); eventBus.Subscrbe((EventHandlerInterface<ItemCreatedEvent>)viewModel);
eventBus.Subscrbe((EventHandlerInterface<ItemDeletedEvent>)viewModel); eventBus.Subscrbe((EventHandlerInterface<ItemDeletedEvent>)viewModel);
var worldHandler = serviceProvider.GetRequiredService<WorldHandler>();
eventBus.Subscrbe((EventHandlerInterface<HeroCreatedEvent>)worldHandler);
eventBus.Subscrbe((EventHandlerInterface<HeroDeletedEvent>)worldHandler);
eventBus.Subscrbe((EventHandlerInterface<CreatureCreatedEvent>)worldHandler);
eventBus.Subscrbe((EventHandlerInterface<CreatureDeletedEvent>)worldHandler);
eventBus.Subscrbe((EventHandlerInterface<DropCreatedEvent>)worldHandler);
eventBus.Subscrbe((EventHandlerInterface<DropDeletedEvent>)worldHandler);
eventBus.Subscrbe((EventHandlerInterface<SkillCreatedEvent>)worldHandler);
eventBus.Subscrbe((EventHandlerInterface<SkillDeletedEvent>)worldHandler);
eventBus.Subscrbe((EventHandlerInterface<ItemCreatedEvent>)worldHandler);
eventBus.Subscrbe((EventHandlerInterface<ItemDeletedEvent>)worldHandler);
eventBus.Subscrbe((EventHandlerInterface<TargetChangedEvent>)serviceProvider.GetRequiredService<HeroHandler>()); eventBus.Subscrbe((EventHandlerInterface<TargetChangedEvent>)serviceProvider.GetRequiredService<HeroHandler>());
eventBus.Subscrbe((EventHandlerInterface<TargetChangedEvent>)serviceProvider.GetRequiredService<NpcHandler>()); eventBus.Subscrbe((EventHandlerInterface<TargetChangedEvent>)serviceProvider.GetRequiredService<NpcHandler>());
eventBus.Subscrbe((EventHandlerInterface<TargetChangedEvent>)serviceProvider.GetRequiredService<PlayerHandler>()); eventBus.Subscrbe((EventHandlerInterface<TargetChangedEvent>)serviceProvider.GetRequiredService<PlayerHandler>());

View File

@ -12,12 +12,12 @@ namespace Client.Domain.Common
{ {
public static float Distance(this CreatureInterface creature, CreatureInterface other) 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) 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);
} }
} }
} }

View 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)
{
}
}
}

View File

@ -18,6 +18,6 @@ namespace Client.Domain.Entities
string BriefInfo { get; } string BriefInfo { get; }
CreatureTypeEnum Type { get; } CreatureTypeEnum Type { get; }
uint AggroRadius { get; set; } uint AggroRadius { get; set; }
bool IsHostile { get; set; }
} }
} }

View File

@ -62,6 +62,7 @@ namespace Client.Domain.Entities
} }
} }
public uint AggroRadius { get; set; } = 0; 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) 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)
{ {

View File

@ -74,7 +74,7 @@ namespace Client.Domain.Entities
{ {
string result = FullName.Nickname; string result = FullName.Nickname;
if (IsDead()) if (VitalStats.IsDead)
{ {
result += " (dead)"; result += " (dead)";
} }
@ -124,17 +124,12 @@ namespace Client.Domain.Entities
private void VitalStats_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) private void VitalStats_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{ {
if (e.PropertyName == "Hp" || e.PropertyName == "MaxHp") if (e.PropertyName == "IsDead")
{ {
OnPropertyChanged("Name"); OnPropertyChanged("Name");
} }
} }
public bool IsDead()
{
return VitalStats.MaxHp > 0 && VitalStats.Hp <= 0;
}
private uint level; private uint level;
private uint aggroRadius; private uint aggroRadius;
private VitalStats vitalStats; private VitalStats vitalStats;

View File

@ -62,6 +62,7 @@ namespace Client.Domain.Entities
public VitalStats VitalStats { get => vitalStats; set => vitalStats = value; } public VitalStats VitalStats { get => vitalStats; set => vitalStats = value; }
public CreatureTypeEnum Type { get => CreatureTypeEnum.Player; } public CreatureTypeEnum Type { get => CreatureTypeEnum.Player; }
public uint AggroRadius { get; set; } = 0; public uint AggroRadius { get; set; } = 0;
public bool IsHostile { get; set; } = false;
public Player(uint id, Transform transform, FullName fullName, Phenotype phenotype) public Player(uint id, Transform transform, FullName fullName, Phenotype phenotype)
{ {

View 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
}
}

View 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);
}
}

View 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;
}
}

View File

@ -12,12 +12,12 @@ namespace Client.Domain.ValueObjects
private uint cp; private uint cp;
private uint maxCp; private uint maxCp;
public uint Hp { get => hp; set { if (value != hp) { hp = value; OnPropertyChanged("Hp"); OnPropertyChanged("MaxHp"); } } } 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("MaxHp"); } } } 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("Mp"); } } } public uint Mp { get => mp; set { if (value != mp) { mp = value; OnPropertyChanged(); } } }
public uint MaxMp { get => maxMp; set { if (value != maxMp) { maxMp = value; OnPropertyChanged("MaxMp"); } } } public uint MaxMp { get => maxMp; set { if (value != maxMp) { maxMp = value; OnPropertyChanged(); } } }
public uint Cp { get => cp; set { if (value != cp) { cp = value; OnPropertyChanged("Cp"); } } } public uint Cp { get => cp; set { if (value != cp) { cp = value; OnPropertyChanged(); } } }
public uint MaxCp { get => maxCp; set { if (value != maxCp) { maxCp = value; OnPropertyChanged("MaxCp"); } } } public uint MaxCp { get => maxCp; set { if (value != maxCp) { maxCp = value; OnPropertyChanged(); } } }
public double HpPercent 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) public VitalStats(uint hp, uint maxHp, uint mp, uint maxMp, uint cp, uint maxCp)
{ {
this.hp = hp; this.hp = hp;

View File

@ -0,0 +1,31 @@
using Client.Domain;
using Client.Domain.Enums;
using Client.Domain.Parsers;
using Client.Domain.DTO;
using Client.Infrastructure.Parsers.Objects;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Client.Infrastructure.Parsers
{
public class JsonOutgoingMessageBuilder : OutgoingMessageBuilderInterface
{
public string Build<T>(OutgoingMessage<T> message)
{
return JsonConvert.SerializeObject(new OutgoingMessage
{
Type = GetStringType(message.Type),
Content = JsonConvert.SerializeObject(message.Content)
});
}
private string GetStringType(OutgoingMessageTypeEnum type)
{
return type.ToString();
}
}
}

View File

@ -0,0 +1,17 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Client.Infrastructure.Parsers.Converters;
namespace Client.Infrastructure.Parsers.Objects
{
internal class OutgoingMessage
{
public string Type { get; set; } = "";
[JsonConverter(typeof(RawConverter))]
public string Content { get; set; } = "";
}
}