From 42d594bbbbcd97b213020603fc283e982d937002 Mon Sep 17 00:00:00 2001 From: k0t9i Date: Sat, 28 Jan 2023 14:54:49 +0400 Subject: [PATCH] feat: create window client app --- Client/App.xaml | 8 ++ Client/App.xaml.cs | 69 +++++++++++ Client/Application.cs | 74 ++++++++++++ Client/AssemblyInfo.cs | 10 ++ Client/Client.csproj | 17 +++ {TestClient => Client}/Directory.Build.Props | 4 +- Client/Domain/DTO/Message.cs | 18 +++ Client/Domain/Entities/Drop.cs | 24 ++++ Client/Domain/Entities/EntityInterface.cs | 13 +++ Client/Domain/Entities/Hero.cs | 36 ++++++ Client/Domain/Enums/ClassEnum.cs | 102 ++++++++++++++++ Client/Domain/Enums/MessageOperationEnum.cs | 13 +++ Client/Domain/Enums/MessageTypeEnum.cs | 22 ++++ Client/Domain/Enums/RaceEnum.cs | 18 +++ Client/Domain/Exception/ParserException.cs | 12 ++ .../Factories/EntityFactoryInterface.cs | 15 +++ .../EntityHandlerFactoryInterface.cs | 15 +++ .../Domain/Parsers/MessageParserInterface.cs | 13 +++ Client/Domain/Service/EntityHandler.cs | 52 +++++++++ Client/Domain/Service/HandlerInterface.cs | 15 +++ .../Domain/Transports/TransportInterface.cs | 20 ++++ Client/Domain/ValueObjects/ExperienceInfo.cs | 16 +++ Client/Domain/ValueObjects/FullName.cs | 14 +++ Client/Domain/ValueObjects/InventoryInfo.cs | 16 +++ Client/Domain/ValueObjects/PermanentStats.cs | 22 ++++ Client/Domain/ValueObjects/Phenotype.cs | 20 ++++ Client/Domain/ValueObjects/Reputation.cs | 20 ++++ Client/Domain/ValueObjects/Transform.cs | 18 +++ Client/Domain/ValueObjects/VariableStats.cs | 28 +++++ Client/Domain/ValueObjects/Vector3.cs | 16 +++ Client/Domain/ValueObjects/VitalStats.cs | 22 ++++ .../Infrastructure/Factories/EntityFactory.cs | 27 +++++ .../Factories/EntityHandlerFactory.cs | 44 +++++++ .../Parsers/Converters/BooleanConverter.cs | 33 ++++++ .../Parsers/Converters/RawConverter.cs | 30 +++++ .../Parsers/JsonMessageParser.cs | 65 +++++++++++ .../Infrastructure/Parsers/Objects/Message.cs | 21 ++++ .../Transports/NamedPipeTransport.cs | 109 ++++++++++++++++++ Client/MainWindow.xaml | 12 ++ Client/MainWindow.xaml.cs | 28 +++++ L2Bot.sln | 26 ++--- TestClient/Program.cs | 72 ------------ TestClient/TestClient.csproj | 11 -- 43 files changed, 1142 insertions(+), 98 deletions(-) create mode 100644 Client/App.xaml create mode 100644 Client/App.xaml.cs create mode 100644 Client/Application.cs create mode 100644 Client/AssemblyInfo.cs create mode 100644 Client/Client.csproj rename {TestClient => Client}/Directory.Build.Props (83%) create mode 100644 Client/Domain/DTO/Message.cs create mode 100644 Client/Domain/Entities/Drop.cs create mode 100644 Client/Domain/Entities/EntityInterface.cs create mode 100644 Client/Domain/Entities/Hero.cs create mode 100644 Client/Domain/Enums/ClassEnum.cs create mode 100644 Client/Domain/Enums/MessageOperationEnum.cs create mode 100644 Client/Domain/Enums/MessageTypeEnum.cs create mode 100644 Client/Domain/Enums/RaceEnum.cs create mode 100644 Client/Domain/Exception/ParserException.cs create mode 100644 Client/Domain/Factories/EntityFactoryInterface.cs create mode 100644 Client/Domain/Factories/EntityHandlerFactoryInterface.cs create mode 100644 Client/Domain/Parsers/MessageParserInterface.cs create mode 100644 Client/Domain/Service/EntityHandler.cs create mode 100644 Client/Domain/Service/HandlerInterface.cs create mode 100644 Client/Domain/Transports/TransportInterface.cs create mode 100644 Client/Domain/ValueObjects/ExperienceInfo.cs create mode 100644 Client/Domain/ValueObjects/FullName.cs create mode 100644 Client/Domain/ValueObjects/InventoryInfo.cs create mode 100644 Client/Domain/ValueObjects/PermanentStats.cs create mode 100644 Client/Domain/ValueObjects/Phenotype.cs create mode 100644 Client/Domain/ValueObjects/Reputation.cs create mode 100644 Client/Domain/ValueObjects/Transform.cs create mode 100644 Client/Domain/ValueObjects/VariableStats.cs create mode 100644 Client/Domain/ValueObjects/Vector3.cs create mode 100644 Client/Domain/ValueObjects/VitalStats.cs create mode 100644 Client/Infrastructure/Factories/EntityFactory.cs create mode 100644 Client/Infrastructure/Factories/EntityHandlerFactory.cs create mode 100644 Client/Infrastructure/Parsers/Converters/BooleanConverter.cs create mode 100644 Client/Infrastructure/Parsers/Converters/RawConverter.cs create mode 100644 Client/Infrastructure/Parsers/JsonMessageParser.cs create mode 100644 Client/Infrastructure/Parsers/Objects/Message.cs create mode 100644 Client/Infrastructure/Transports/NamedPipeTransport.cs create mode 100644 Client/MainWindow.xaml create mode 100644 Client/MainWindow.xaml.cs delete mode 100644 TestClient/Program.cs delete mode 100644 TestClient/TestClient.csproj diff --git a/Client/App.xaml b/Client/App.xaml new file mode 100644 index 0000000..bf04aa9 --- /dev/null +++ b/Client/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/Client/App.xaml.cs b/Client/App.xaml.cs new file mode 100644 index 0000000..69ae0db --- /dev/null +++ b/Client/App.xaml.cs @@ -0,0 +1,69 @@ +using Client.Domain.Factories; +using Client.Infrastructure.Factories; +using Client.Domain.Parsers; +using Client.Infrastructure.Parsers; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System.Windows; +using Client.Domain.Transports; +using Client.Infrastructure.Transports; +using Client.Domain.Entities; +using Client.Domain.Service; +using BaseApp = System.Windows.Application; + +namespace Client +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : BaseApp + { + public static IHost? AppHost { get; private set; } + + public App() + { + AppHost = Host.CreateDefaultBuilder() + .ConfigureServices((hostContext, services) => { + services + .AddSingleton() + .AddSingleton( + typeof(Application), + x => new Application( + x.GetRequiredService(), + x.GetRequiredService(), + x.GetRequiredService(), + "L2BotDll.dll" + ) + ) + .AddSingleton(typeof(EntityHandlerFactoryInterface), typeof(EntityHandlerFactory)) + .AddSingleton(typeof(MessageParserInterface), typeof(JsonMessageParser)) + .AddSingleton(typeof(TransportInterface), x => new NamedPipeTransport("PipeL2Bot")) + .AddTransient(typeof(EntityFactoryInterface), typeof(EntityFactory)) + .AddTransient(typeof(EntityFactoryInterface), typeof(EntityFactory)) + .AddSingleton>() + .AddSingleton>(); + }) + .Build(); + } + + protected override async void OnStartup(StartupEventArgs e) + { + await AppHost!.StartAsync(); + + var startupForm = AppHost.Services.GetRequiredService(); + startupForm.Show(); + + var application = AppHost.Services.GetRequiredService(); + application.StartAsync(); + + base.OnStartup(e); + } + + protected override async void OnExit(ExitEventArgs e) + { + await AppHost!.StopAsync(); + + base.OnExit(e); + } + } +} diff --git a/Client/Application.cs b/Client/Application.cs new file mode 100644 index 0000000..134162e --- /dev/null +++ b/Client/Application.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using Client.Domain.Factories; +using Client.Domain.Parsers; +using Client.Domain.Transports; + +namespace Client +{ + public class Application + { + [DllImport("kernel32.dll", EntryPoint = "LoadLibrary", SetLastError = true)] + static extern int LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpLibFileName); + + private readonly TransportInterface transport; + private readonly MessageParserInterface messageParser; + private readonly EntityHandlerFactoryInterface entityHandlerFactory; + private readonly string dllName; + + public Application(TransportInterface transport, MessageParserInterface messageParser, EntityHandlerFactoryInterface entityHandlerFactory, string dllName) + { + this.transport = transport; + this.messageParser = messageParser; + this.entityHandlerFactory = entityHandlerFactory; + this.dllName = dllName; + } + + public async void StartAsync() + { + int hDll = LoadLibrary(dllName); + + if (hDll == 0) + { + throw new Exception("Unable to load library " + dllName + ": " + Marshal.GetLastWin32Error().ToString()); + } + + Debug.WriteLine(dllName + " loaded\n"); + transport.Message += OnMessage; + + while (true) + { + await transport.ConnectAsync(); + await transport.StartReceiveAsync(); + } + } + + private void OnMessage(string args) + { + try + { + var message = messageParser.Parse(args); + Debug.WriteLine(message); + + try + { + var handler = entityHandlerFactory.GetHandler(message.Type); + handler.Update(message.Operation, message.Content); + } + catch (Exception ex) + { + Debug.WriteLine("Exception: " + ex.Message); + } + } + catch (Domain.Exception.ParserException) + { + Debug.WriteLine("Unable to parse message: " + args); + } + } + } +} diff --git a/Client/AssemblyInfo.cs b/Client/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/Client/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/Client/Client.csproj b/Client/Client.csproj new file mode 100644 index 0000000..896b649 --- /dev/null +++ b/Client/Client.csproj @@ -0,0 +1,17 @@ + + + + WinExe + net6.0-windows + enable + true + x86 + + + + + + + + + diff --git a/TestClient/Directory.Build.Props b/Client/Directory.Build.Props similarity index 83% rename from TestClient/Directory.Build.Props rename to Client/Directory.Build.Props index 85c3e5d..1a87000 100644 --- a/TestClient/Directory.Build.Props +++ b/Client/Directory.Build.Props @@ -3,8 +3,8 @@ false false $(SolutionDir)$(Configuration)\bin\ - $(SolutionDir)$(Configuration)\$(MSBuildProjectName)\obj\ - $(SolutionDir)$(Configuration)\$(MSBuildProjectName)\ext\ + $(SolutionDir)$(Configuration)\$(ProjectName)\obj\ + $(SolutionDir)$(Configuration)\$(ProjectName)\ext\ $(BaseOutputPath) $(BaseOutputPath) $(BaseIntermediateOutputPath) diff --git a/Client/Domain/DTO/Message.cs b/Client/Domain/DTO/Message.cs new file mode 100644 index 0000000..e6eb81a --- /dev/null +++ b/Client/Domain/DTO/Message.cs @@ -0,0 +1,18 @@ +using Client.Domain.Enums; + +namespace Client.Domain.DTO +{ + public class Message + { + public readonly MessageTypeEnum Type; + public readonly MessageOperationEnum Operation; + public readonly string Content; + + public Message(MessageTypeEnum type, MessageOperationEnum operation, string content) + { + Type = type; + Operation = operation; + Content = content; + } + } +} diff --git a/Client/Domain/Entities/Drop.cs b/Client/Domain/Entities/Drop.cs new file mode 100644 index 0000000..8f14c49 --- /dev/null +++ b/Client/Domain/Entities/Drop.cs @@ -0,0 +1,24 @@ +using Client.Domain.ValueObjects; + +namespace Client.Domain.Entities +{ + public class Drop : EntityInterface + { + public uint Id { get; set; } + public Transform Transform { get; set; } + public uint ItemId { get; set; } + public uint Amount { get; set; } + public string Name { get; set; } + public string IconName { get; set; } + + public Drop(uint id, Transform transform, uint itemId, uint amount, string name, string iconName) + { + Id = id; + Transform = transform; + ItemId = itemId; + Amount = amount; + Name = name; + IconName = iconName; + } + } +} diff --git a/Client/Domain/Entities/EntityInterface.cs b/Client/Domain/Entities/EntityInterface.cs new file mode 100644 index 0000000..90a7a8d --- /dev/null +++ b/Client/Domain/Entities/EntityInterface.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Client.Domain.Entities +{ + public interface EntityInterface + { + public uint Id { get; set; } + } +} diff --git a/Client/Domain/Entities/Hero.cs b/Client/Domain/Entities/Hero.cs new file mode 100644 index 0000000..addefe4 --- /dev/null +++ b/Client/Domain/Entities/Hero.cs @@ -0,0 +1,36 @@ +using Client.Domain.ValueObjects; + +namespace Client.Domain.Entities +{ + public class Hero : EntityInterface + { + public uint Id { get; set; } + public Transform Transform { get; set; } + public FullName FullName { get; set; } + public VitalStats VitalStats { get; set; } + public Phenotype Phenotype { get; set; } + public ExperienceInfo ExperienceInfo { get; set; } + public PermanentStats PermanentStats { get; set; } + public VariableStats VariableStats { get; set; } + public Reputation Reputation { get; set; } + public InventoryInfo InventoryInfo { get; set; } + public uint TargetId { get; set; } + public bool IsStanding { get; set; } + + 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) + { + Id = id; + Transform = transform; + FullName = fullName; + VitalStats = vitalStats; + Phenotype = phenotype; + ExperienceInfo = experienceInfo; + PermanentStats = permanentStats; + VariableStats = variableStats; + Reputation = reputation; + InventoryInfo = inventoryInfo; + TargetId = targetId; + IsStanding = isStanding; + } + } +} diff --git a/Client/Domain/Enums/ClassEnum.cs b/Client/Domain/Enums/ClassEnum.cs new file mode 100644 index 0000000..ed84276 --- /dev/null +++ b/Client/Domain/Enums/ClassEnum.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Client.Domain.Enums +{ + public enum ClassEnum : uint + { + None = 255, + HumanFighter = 0, + Warrior, + Gladiator, + Warlord, + HumanKnight, + Paladin, + DarkAvenger, + Rogue, + TreasureHunter, + Hawkeye, + HumanMystic, + HumanWizard, + Sorceror, + Necromancer, + Warlock, + Cleric, + Bishop, + Prophet, + ElvenFighter, + ElvenKnight, + TempleKnight, + Swordsinger, + ElvenScout, + PlainsWalker, + SilverRanger, + ElvenMystic, + ElvenWizard, + Spellsinger, + ElementalSummoner, + ElvenOracle, + ElvenElder, + DarkElvenFighter, + PalusKnight, + ShillienKnight, + Bladedancer, + Assassin, + AbyssWalker, + PhantomRanger, + DarkElvenMystic, + DarkElvenWizard, + Spellhowler, + PhantomSummoner, + ShillienOracle, + ShillienElder, + OrcFighter, + OrcRaider, + Destroyer, + OrcMonk, + Tyrant, + OrcMystic, + OrcShaman, + Overlord, + Warcryer, + DwarvenFighter, + DwarvenScavenger, + BountyHunter, + DwarvenArtisan, + Warsmith, + Duelist = 88, + Dreadnought, + PhoenixKnight, + HellKnight, + Sagittarius, + Adventurer, + Archmage, + Soultaker, + ArcanaLord, + Cardinal, + Hierophant, + EvaTemplar, + SwordMuse, + WindRider, + MoonlightSentinel, + MysticMuse, + ElementalMaster, + EvaSaint, + ShillienTemplar, + SpectralDancer, + GhostHunter, + GhostSentinel, + StormScreamer, + SpectralMaster, + ShillienSaint, + Titan, + GrandKhauatari, + Dominator, + Doomcryer, + FortuneSeeker, + Maestro + } +} diff --git a/Client/Domain/Enums/MessageOperationEnum.cs b/Client/Domain/Enums/MessageOperationEnum.cs new file mode 100644 index 0000000..77bdedc --- /dev/null +++ b/Client/Domain/Enums/MessageOperationEnum.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Client.Domain.Enums +{ + public enum MessageOperationEnum + { + None, Create, Update, Delete + } +} diff --git a/Client/Domain/Enums/MessageTypeEnum.cs b/Client/Domain/Enums/MessageTypeEnum.cs new file mode 100644 index 0000000..f66e6a9 --- /dev/null +++ b/Client/Domain/Enums/MessageTypeEnum.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Client.Domain.Entities; + +namespace Client.Domain.Enums +{ + public enum MessageTypeEnum + { + None, + Hero, + Drop, + NPC, + Player, + Skill, + Item, + AbnormalEffect, + Chat + } +} diff --git a/Client/Domain/Enums/RaceEnum.cs b/Client/Domain/Enums/RaceEnum.cs new file mode 100644 index 0000000..88d8efe --- /dev/null +++ b/Client/Domain/Enums/RaceEnum.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Client.Domain.Enums +{ + public enum RaceEnum : uint + { + None = 255, + DarkElf = 2, + Dwarf = 4, + Elf = 1, + Human = 0, + Orc = 3 + } +} diff --git a/Client/Domain/Exception/ParserException.cs b/Client/Domain/Exception/ParserException.cs new file mode 100644 index 0000000..7f8400a --- /dev/null +++ b/Client/Domain/Exception/ParserException.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Client.Domain.Exception +{ + public class ParserException : System.Exception + { + } +} diff --git a/Client/Domain/Factories/EntityFactoryInterface.cs b/Client/Domain/Factories/EntityFactoryInterface.cs new file mode 100644 index 0000000..e236453 --- /dev/null +++ b/Client/Domain/Factories/EntityFactoryInterface.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Client.Domain.Entities; + +namespace Client.Domain.Factories +{ + public interface EntityFactoryInterface + { + public T? Create(string data); + public void Update(T entity, string data); + } +} diff --git a/Client/Domain/Factories/EntityHandlerFactoryInterface.cs b/Client/Domain/Factories/EntityHandlerFactoryInterface.cs new file mode 100644 index 0000000..e166e61 --- /dev/null +++ b/Client/Domain/Factories/EntityHandlerFactoryInterface.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Client.Domain.Enums; +using Client.Domain.Service; + +namespace Client.Domain.Factories +{ + public interface EntityHandlerFactoryInterface + { + HandlerInterface GetHandler(MessageTypeEnum type); + } +} diff --git a/Client/Domain/Parsers/MessageParserInterface.cs b/Client/Domain/Parsers/MessageParserInterface.cs new file mode 100644 index 0000000..ef9f164 --- /dev/null +++ b/Client/Domain/Parsers/MessageParserInterface.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Client.Domain.Parsers +{ + public interface MessageParserInterface + { + DTO.Message Parse(string message); + } +} diff --git a/Client/Domain/Service/EntityHandler.cs b/Client/Domain/Service/EntityHandler.cs new file mode 100644 index 0000000..b3dd3de --- /dev/null +++ b/Client/Domain/Service/EntityHandler.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Client.Domain.DTO; +using Client.Domain.Entities; +using Client.Domain.Enums; +using Client.Domain.Factories; + +namespace Client.Domain.Service +{ + public class EntityHandler : HandlerInterface where T : EntityInterface + { + public void Update(MessageOperationEnum operation, string content) + { + var entity = factory.Create(content); + if (operation == MessageOperationEnum.Create) + { + if (entity == null) + { + throw new ArgumentNullException(nameof(entity)); + } + entities[entity.Id] = entity; + + + } + else if (operation == MessageOperationEnum.Update) + { + if (entity != null && entities.ContainsKey(entity.Id)) + { + factory.Update(entities[entity.Id], content); + } + } + else if (operation == MessageOperationEnum.Delete) + { + if (entity != null) + { + entities.Remove(entity.Id); + } + } + } + + public EntityHandler(EntityFactoryInterface factory) + { + this.factory = factory; + } + + private readonly EntityFactoryInterface factory; + private Dictionary entities = new Dictionary(); + } +} diff --git a/Client/Domain/Service/HandlerInterface.cs b/Client/Domain/Service/HandlerInterface.cs new file mode 100644 index 0000000..2c09a47 --- /dev/null +++ b/Client/Domain/Service/HandlerInterface.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Client.Domain.DTO; +using Client.Domain.Enums; + +namespace Client.Domain.Service +{ + public interface HandlerInterface + { + void Update(MessageOperationEnum operation, string content); + } +} diff --git a/Client/Domain/Transports/TransportInterface.cs b/Client/Domain/Transports/TransportInterface.cs new file mode 100644 index 0000000..da67ded --- /dev/null +++ b/Client/Domain/Transports/TransportInterface.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Client.Domain.Transports +{ + public interface TransportInterface + { + public event DelegateMessage Message; + + bool IsConnected(); + Task ConnectAsync(); + Task SendAsync(string data); + Task StartReceiveAsync(); + + public delegate void DelegateMessage(string args); + } +} diff --git a/Client/Domain/ValueObjects/ExperienceInfo.cs b/Client/Domain/ValueObjects/ExperienceInfo.cs new file mode 100644 index 0000000..324c4bb --- /dev/null +++ b/Client/Domain/ValueObjects/ExperienceInfo.cs @@ -0,0 +1,16 @@ +namespace Client.Domain.ValueObjects +{ + public class ExperienceInfo + { + public uint Level { get; set; } + public uint Exp { get; set; } + public uint Sp { get; set; } + + public ExperienceInfo(uint level, uint exp, uint sp) + { + Level = level; + Exp = exp; + Sp = sp; + } + } +} diff --git a/Client/Domain/ValueObjects/FullName.cs b/Client/Domain/ValueObjects/FullName.cs new file mode 100644 index 0000000..7f54102 --- /dev/null +++ b/Client/Domain/ValueObjects/FullName.cs @@ -0,0 +1,14 @@ +namespace Client.Domain.ValueObjects +{ + public class FullName + { + public string Nickname { get; set; } + public string Title { get; set; } + + public FullName(string nickname, string title) + { + Nickname = nickname; + Title = title; + } + } +} diff --git a/Client/Domain/ValueObjects/InventoryInfo.cs b/Client/Domain/ValueObjects/InventoryInfo.cs new file mode 100644 index 0000000..0b8f2a4 --- /dev/null +++ b/Client/Domain/ValueObjects/InventoryInfo.cs @@ -0,0 +1,16 @@ +namespace Client.Domain.ValueObjects +{ + public class InventoryInfo + { + public uint MaxWeight { get; set; } + public uint Weight { get; set; } + public uint Slots { get; set; } + + public InventoryInfo(uint maxWeight, uint weight, uint slots) + { + MaxWeight = maxWeight; + Weight = weight; + Slots = slots; + } + } +} diff --git a/Client/Domain/ValueObjects/PermanentStats.cs b/Client/Domain/ValueObjects/PermanentStats.cs new file mode 100644 index 0000000..5cea04d --- /dev/null +++ b/Client/Domain/ValueObjects/PermanentStats.cs @@ -0,0 +1,22 @@ +namespace Client.Domain.ValueObjects +{ + public class PermanentStats + { + public uint Str { get; set; } + public uint Dex { get; set; } + public uint Con { get; set; } + public uint Int { get; set; } + public uint Men { get; set; } + public uint Wit { get; set; } + + public PermanentStats(uint str, uint dex, uint con, uint @int, uint men, uint wit) + { + Str = str; + Dex = dex; + Con = con; + Int = @int; + Men = men; + Wit = wit; + } + } +} diff --git a/Client/Domain/ValueObjects/Phenotype.cs b/Client/Domain/ValueObjects/Phenotype.cs new file mode 100644 index 0000000..50f3720 --- /dev/null +++ b/Client/Domain/ValueObjects/Phenotype.cs @@ -0,0 +1,20 @@ +using Client.Domain.Enums; + +namespace Client.Domain.ValueObjects +{ + public class Phenotype + { + public RaceEnum Race { get; set; } + public bool IsMale { get; set; } + public ClassEnum Class { get; set; } + public ClassEnum ActiveClass { get; set; } + + public Phenotype(RaceEnum race, bool isMale, ClassEnum @class, ClassEnum activeClass) + { + Race = race; + IsMale = isMale; + Class = @class; + ActiveClass = activeClass; + } + } +} diff --git a/Client/Domain/ValueObjects/Reputation.cs b/Client/Domain/ValueObjects/Reputation.cs new file mode 100644 index 0000000..c6f91aa --- /dev/null +++ b/Client/Domain/ValueObjects/Reputation.cs @@ -0,0 +1,20 @@ +namespace Client.Domain.ValueObjects +{ + public class Reputation + { + public uint Karma { get; set; } + public uint PkKills { get; set; } + public uint PvpKills { get; set; } + public uint RecRemaining { get; set; } + public uint EvalScore { get; set; } + + public Reputation(uint karma, uint pkKills, uint pvpKills, uint recRemaining, uint evalScore) + { + Karma = karma; + PkKills = pkKills; + PvpKills = pvpKills; + RecRemaining = recRemaining; + EvalScore = evalScore; + } + } +} diff --git a/Client/Domain/ValueObjects/Transform.cs b/Client/Domain/ValueObjects/Transform.cs new file mode 100644 index 0000000..7cd95c6 --- /dev/null +++ b/Client/Domain/ValueObjects/Transform.cs @@ -0,0 +1,18 @@ +namespace Client.Domain.ValueObjects +{ + public class Transform + { + public Vector3 Position { get; set; } + public Vector3 Rotation { get; set; } + public Vector3 Velocity { get; set; } + public Vector3 Acceleration { get; set; } + + public Transform(Vector3 position, Vector3 rotation, Vector3 velocity, Vector3 acceleration) + { + Position = position; + Rotation = rotation; + Velocity = velocity; + Acceleration = acceleration; + } + } +} diff --git a/Client/Domain/ValueObjects/VariableStats.cs b/Client/Domain/ValueObjects/VariableStats.cs new file mode 100644 index 0000000..799ff23 --- /dev/null +++ b/Client/Domain/ValueObjects/VariableStats.cs @@ -0,0 +1,28 @@ +namespace Client.Domain.ValueObjects +{ + public class VariableStats + { + public uint Accuracy { get; set; } + public uint CritRate { get; set; } + public uint PAttack { get; set; } + public uint AttackSpeed { get; set; } + public uint PDefense { get; set; } + public uint Evasion { get; set; } + public uint MAttack { get; set; } + public uint MDefense { get; set; } + public uint CastingSpeed { get; set; } + + public VariableStats(uint accuracy, uint critRate, uint pAttack, uint attackSpeed, uint pDefense, uint evasion, uint mAttack, uint mDefense, uint castingSpeed) + { + Accuracy = accuracy; + CritRate = critRate; + PAttack = pAttack; + AttackSpeed = attackSpeed; + PDefense = pDefense; + Evasion = evasion; + MAttack = mAttack; + MDefense = mDefense; + CastingSpeed = castingSpeed; + } + } +} diff --git a/Client/Domain/ValueObjects/Vector3.cs b/Client/Domain/ValueObjects/Vector3.cs new file mode 100644 index 0000000..c25ed2b --- /dev/null +++ b/Client/Domain/ValueObjects/Vector3.cs @@ -0,0 +1,16 @@ +namespace Client.Domain.ValueObjects +{ + public class Vector3 + { + public float X { get; set; } + public float Y { get; set; } + public float Z { get; set; } + + public Vector3(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } + } +} diff --git a/Client/Domain/ValueObjects/VitalStats.cs b/Client/Domain/ValueObjects/VitalStats.cs new file mode 100644 index 0000000..adc11ce --- /dev/null +++ b/Client/Domain/ValueObjects/VitalStats.cs @@ -0,0 +1,22 @@ +namespace Client.Domain.ValueObjects +{ + public class VitalStats + { + public uint Hp { get; set; } + public uint MaxHp { get; set; } + public uint Mp { get; set; } + public uint MaxMp { get; set; } + public uint Cp { get; set; } + public uint MaxCp { get; set; } + + public VitalStats(uint hp, uint maxHp, uint mp, uint maxMp, uint cp, uint maxCp) + { + Hp = hp; + MaxHp = maxHp; + Mp = mp; + MaxMp = maxMp; + Cp = cp; + MaxCp = maxCp; + } + } +} diff --git a/Client/Infrastructure/Factories/EntityFactory.cs b/Client/Infrastructure/Factories/EntityFactory.cs new file mode 100644 index 0000000..ed90dfd --- /dev/null +++ b/Client/Infrastructure/Factories/EntityFactory.cs @@ -0,0 +1,27 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Client.Domain.Entities; +using Client.Domain.Factories; +using Client.Infrastructure.Parsers.Converters; + +namespace Client.Infrastructure.Factories +{ + public class EntityFactory : EntityFactoryInterface where T : EntityInterface + { + public T? Create(string data) + { + return JsonConvert.DeserializeObject(data, settings); + } + + public void Update(T entity, string data) + { + JsonConvert.PopulateObject(data, entity, settings); + } + + private JsonSerializerSettings settings = new JsonSerializerSettings { Converters = { new BooleanConverter() } }; + } +} diff --git a/Client/Infrastructure/Factories/EntityHandlerFactory.cs b/Client/Infrastructure/Factories/EntityHandlerFactory.cs new file mode 100644 index 0000000..5577663 --- /dev/null +++ b/Client/Infrastructure/Factories/EntityHandlerFactory.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Client.Domain.Entities; +using Client.Domain.Enums; +using Client.Domain.Factories; +using Client.Domain.Service; + +namespace Client.Infrastructure.Factories +{ + public class EntityHandlerFactory : EntityHandlerFactoryInterface + { + private readonly IServiceProvider serviceProvider; + + public HandlerInterface GetHandler(MessageTypeEnum type) + { + HandlerInterface? result = null; + + switch (type) + { + case MessageTypeEnum.Hero: + result = (HandlerInterface?)serviceProvider.GetService(typeof(EntityHandler)); + break; + case MessageTypeEnum.Drop: + result = (HandlerInterface?)serviceProvider.GetService(typeof(EntityHandler)); + break; + } + + if (result == null) + { + throw new ArgumentException("Handler not found " + type.ToString()); + } + + return result; + } + + public EntityHandlerFactory(IServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; + } + } +} diff --git a/Client/Infrastructure/Parsers/Converters/BooleanConverter.cs b/Client/Infrastructure/Parsers/Converters/BooleanConverter.cs new file mode 100644 index 0000000..2cdaf31 --- /dev/null +++ b/Client/Infrastructure/Parsers/Converters/BooleanConverter.cs @@ -0,0 +1,33 @@ +using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Client.Infrastructure.Parsers.Converters +{ + public class BooleanConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(bool); + } + + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + var value = reader.Value; + if (value == null) + { + return null; + } + return value?.ToString()?.Trim('0') != ""; + } + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + writer.WriteRawValue(value == null ? null : (string)value); + } + } +} diff --git a/Client/Infrastructure/Parsers/Converters/RawConverter.cs b/Client/Infrastructure/Parsers/Converters/RawConverter.cs new file mode 100644 index 0000000..a83ac95 --- /dev/null +++ b/Client/Infrastructure/Parsers/Converters/RawConverter.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; + +namespace Client.Infrastructure.Parsers.Converters +{ + public class RawConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return true; + } + + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + { + return null; + } + + var raw = JRaw.Create(reader); + return raw.ToString(); + } + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + writer.WriteRawValue(value == null ? null : (string)value); + } + } +} diff --git a/Client/Infrastructure/Parsers/JsonMessageParser.cs b/Client/Infrastructure/Parsers/JsonMessageParser.cs new file mode 100644 index 0000000..4c36c7f --- /dev/null +++ b/Client/Infrastructure/Parsers/JsonMessageParser.cs @@ -0,0 +1,65 @@ +using Newtonsoft.Json; +using Client.Domain.Enums; + +namespace Client.Infrastructure.Parsers +{ + public class JsonMessageParser : Domain.Parsers.MessageParserInterface + { + public Domain.DTO.Message Parse(string message) + { + try + { + var obj = JsonConvert.DeserializeObject(message); + if (obj == null) + { + throw new Domain.Exception.ParserException(); + } + return new Domain.DTO.Message(GetType(obj.Type), GetOperation(obj.Operation), obj.Content ?? ""); + } + catch(JsonException) + { + throw new Domain.Exception.ParserException(); + } + } + + private MessageTypeEnum GetType(string? type) + { + switch (type) + { + case "hero": + return MessageTypeEnum.Hero; + case "drop": + return MessageTypeEnum.Drop; + case "npc": + return MessageTypeEnum.NPC; + case "player": + return MessageTypeEnum.Player; + case "skill": + return MessageTypeEnum.Skill; + case "item": + return MessageTypeEnum.Item; + case "abnormalEffect": + return MessageTypeEnum.AbnormalEffect; + case "chat": + return MessageTypeEnum.Chat; + } + + return MessageTypeEnum.None; + } + + private MessageOperationEnum GetOperation(string? type) + { + switch (type) + { + case "create": + return MessageOperationEnum.Create; + case "update": + return MessageOperationEnum.Update; + case "delete": + return MessageOperationEnum.Delete; + } + + return MessageOperationEnum.None; + } + } +} diff --git a/Client/Infrastructure/Parsers/Objects/Message.cs b/Client/Infrastructure/Parsers/Objects/Message.cs new file mode 100644 index 0000000..327ec1d --- /dev/null +++ b/Client/Infrastructure/Parsers/Objects/Message.cs @@ -0,0 +1,21 @@ +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 Message + { + [JsonProperty] + public string? Type { get; private set; } + [JsonProperty] + public string? Operation { get; private set; } + [JsonProperty] + [JsonConverter(typeof(RawConverter))] + public string? Content { get; private set; } + } +} diff --git a/Client/Infrastructure/Transports/NamedPipeTransport.cs b/Client/Infrastructure/Transports/NamedPipeTransport.cs new file mode 100644 index 0000000..b28d18c --- /dev/null +++ b/Client/Infrastructure/Transports/NamedPipeTransport.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.IO; +using System.IO.Pipes; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Client.Domain.Transports.TransportInterface; + +namespace Client.Infrastructure.Transports +{ + public class NamedPipeTransport : Domain.Transports.TransportInterface, IDisposable + { + public event DelegateMessage? Message; + + public async Task ConnectAsync() + { + if (!IsConnected()) + { + Disconnect(); + + connectionPipe = new NamedPipeClientStream(this.pipeName); + await connectionPipe.ConnectAsync(); + connectionPipe.ReadMode = PipeTransmissionMode.Message; + Debug.WriteLine("Connected to connection pipe"); + + byte[] buffer = new byte[16384 * 2]; + int read = connectionPipe.Read(buffer, 0, buffer.Length); + + string pipeName = Encoding.Unicode.GetString(buffer).TrimEnd('\0'); + + if (pipeName == "") + { + return; + } + + Debug.WriteLine("Received connection pipe name " + pipeName); + + mainPipe = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous); + await mainPipe.ConnectAsync(); + mainPipe.ReadMode = PipeTransmissionMode.Message; + Debug.WriteLine("Connected to main pipe\n"); + } + } + public async Task StartReceiveAsync() + { + while (IsConnected()) + { + byte[] buffer = new byte[16384 * 2]; + int readBytes = await mainPipe!.ReadAsync(buffer, 0, buffer.Length); + + if (readBytes != 0) + { + string text = Encoding.Unicode.GetString(buffer).TrimEnd('\0'); + Message?.Invoke(text); + } + } + } + + public async Task SendAsync(string data) + { + if (IsConnected()) + { + var buffer = Encoding.Unicode.GetBytes(data); + + await mainPipe!.WriteAsync(buffer, 0, buffer.Length); + } + } + + public bool IsConnected() + { + return connectionPipe != null && connectionPipe.IsConnected && mainPipe != null && mainPipe.IsConnected; + } + + public void Dispose() + { + Disconnect(); + } + + public NamedPipeTransport(string pipeName) + { + this.pipeName = pipeName; + } + + private void Disconnect() + { + if (mainPipe != null) + { + Debug.WriteLine("Disconnected from main pipe"); + mainPipe.Close(); + mainPipe.Dispose(); + mainPipe = null; + } + if (connectionPipe != null) + { + Debug.WriteLine("Disconnected from connection pipe"); + connectionPipe.Close(); + connectionPipe.Dispose(); + connectionPipe = null; + } + } + + private string pipeName; + private NamedPipeClientStream? connectionPipe; + private NamedPipeClientStream? mainPipe; + } +} diff --git a/Client/MainWindow.xaml b/Client/MainWindow.xaml new file mode 100644 index 0000000..0a31cd2 --- /dev/null +++ b/Client/MainWindow.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/Client/MainWindow.xaml.cs b/Client/MainWindow.xaml.cs new file mode 100644 index 0000000..87700ee --- /dev/null +++ b/Client/MainWindow.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Client +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + } +} diff --git a/L2Bot.sln b/L2Bot.sln index 8681104..a7cdf31 100644 --- a/L2Bot.sln +++ b/L2Bot.sln @@ -12,7 +12,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "L2BotDll", "L2BotDll\L2BotD EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InjectionLibrary", "InjectionLibrary\InjectionLibrary.vcxproj", "{54FBE631-3F9B-458C-9DB2-43A868CDB806}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestClient", "TestClient\TestClient.csproj", "{D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -60,18 +60,18 @@ Global {54FBE631-3F9B-458C-9DB2-43A868CDB806}.Release|x64.Build.0 = Release|x64 {54FBE631-3F9B-458C-9DB2-43A868CDB806}.Release|x86.ActiveCfg = Release|Win32 {54FBE631-3F9B-458C-9DB2-43A868CDB806}.Release|x86.Build.0 = Release|Win32 - {D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Debug|x64.ActiveCfg = Debug|Any CPU - {D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Debug|x64.Build.0 = Debug|Any CPU - {D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Debug|x86.ActiveCfg = Debug|Any CPU - {D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Debug|x86.Build.0 = Debug|Any CPU - {D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Release|Any CPU.Build.0 = Release|Any CPU - {D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Release|x64.ActiveCfg = Release|Any CPU - {D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Release|x64.Build.0 = Release|Any CPU - {D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Release|x86.ActiveCfg = Release|Any CPU - {D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Release|x86.Build.0 = Release|Any CPU + {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Debug|Any CPU.Build.0 = Debug|Any CPU + {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Debug|x64.ActiveCfg = Debug|Any CPU + {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Debug|x64.Build.0 = Debug|Any CPU + {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Debug|x86.ActiveCfg = Debug|Any CPU + {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Debug|x86.Build.0 = Debug|Any CPU + {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Release|Any CPU.ActiveCfg = Release|Any CPU + {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Release|Any CPU.Build.0 = Release|Any CPU + {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Release|x64.ActiveCfg = Release|Any CPU + {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Release|x64.Build.0 = Release|Any CPU + {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Release|x86.ActiveCfg = Release|Any CPU + {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/TestClient/Program.cs b/TestClient/Program.cs deleted file mode 100644 index c9aa14a..0000000 --- a/TestClient/Program.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.IO; -using System.IO.Pipes; -using System.Runtime.InteropServices; -using System.Text; - - -internal class Program -{ - [DllImport("kernel32.dll", EntryPoint = "LoadLibrary", SetLastError = true)] - static extern int LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpLibFileName); - - private static void Main(string[] args) - { - int hDll = LoadLibrary("L2BotDll.dll"); - - if (hDll == 0) - { - Console.WriteLine("Unable to load library L2BotDll.dll: " + Marshal.GetLastWin32Error().ToString()); - Console.ReadLine(); - return; - } - - Console.WriteLine("L2BotDll.dll loaded\n"); - - while (true) - { - var clientPipe = new NamedPipeClientStream("PipeL2Bot"); - clientPipe.Connect(); - clientPipe.ReadMode = PipeTransmissionMode.Message; - - Console.WriteLine("Connected to connection pipe"); - - byte[] buffer = new byte[16384 * 2]; - int read = clientPipe.Read(buffer, 0, buffer.Length); - - if (clientPipe.IsConnected) - { - string pipeName = Encoding.Unicode.GetString(buffer).TrimEnd('\0'); - Console.WriteLine("Received connection pipe name " + pipeName); - - var mainPipe = new NamedPipeClientStream(pipeName); - mainPipe.Connect(); - mainPipe.ReadMode = PipeTransmissionMode.Message; - - Console.WriteLine("Connected to main pipe\n"); - - while (true) - { - byte[] buffer1 = new byte[16384 * 2]; - int read1 = mainPipe.Read(buffer1, 0, buffer1.Length); - - if (mainPipe.IsConnected) - { - string message = Encoding.Unicode.GetString(buffer1).TrimEnd('\0'); - Console.WriteLine(message); - } - else - { - Console.WriteLine("\nDisconnected from main pipe"); - Console.WriteLine("Disconnected from connection pipe\n\n"); - - mainPipe.Close(); - mainPipe.Dispose(); - clientPipe.Close(); - clientPipe.Dispose(); - break; - } - } - } - } - } -} \ No newline at end of file diff --git a/TestClient/TestClient.csproj b/TestClient/TestClient.csproj deleted file mode 100644 index 38cb7be..0000000 --- a/TestClient/TestClient.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - Exe - net6.0 - enable - enable - x86 - - -