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