feat: create window client app

This commit is contained in:
k0t9i 2023-01-28 14:54:49 +04:00
parent 1d77bceeff
commit 42d594bbbb
43 changed files with 1142 additions and 98 deletions

8
Client/App.xaml Normal file
View File

@ -0,0 +1,8 @@
<Application x:Class="Client.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Client">
<Application.Resources>
</Application.Resources>
</Application>

69
Client/App.xaml.cs Normal file
View File

@ -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
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : BaseApp
{
public static IHost? AppHost { get; private set; }
public App()
{
AppHost = Host.CreateDefaultBuilder()
.ConfigureServices((hostContext, services) => {
services
.AddSingleton<MainWindow>()
.AddSingleton(
typeof(Application),
x => new Application(
x.GetRequiredService<TransportInterface>(),
x.GetRequiredService<MessageParserInterface>(),
x.GetRequiredService<EntityHandlerFactoryInterface>(),
"L2BotDll.dll"
)
)
.AddSingleton(typeof(EntityHandlerFactoryInterface), typeof(EntityHandlerFactory))
.AddSingleton(typeof(MessageParserInterface), typeof(JsonMessageParser))
.AddSingleton(typeof(TransportInterface), x => new NamedPipeTransport("PipeL2Bot"))
.AddTransient(typeof(EntityFactoryInterface<Hero>), typeof(EntityFactory<Hero>))
.AddTransient(typeof(EntityFactoryInterface<Drop>), typeof(EntityFactory<Drop>))
.AddSingleton<EntityHandler<Hero>>()
.AddSingleton<EntityHandler<Drop>>();
})
.Build();
}
protected override async void OnStartup(StartupEventArgs e)
{
await AppHost!.StartAsync();
var startupForm = AppHost.Services.GetRequiredService<MainWindow>();
startupForm.Show();
var application = AppHost.Services.GetRequiredService<Application>();
application.StartAsync();
base.OnStartup(e);
}
protected override async void OnExit(ExitEventArgs e)
{
await AppHost!.StopAsync();
base.OnExit(e);
}
}
}

74
Client/Application.cs Normal file
View File

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

10
Client/AssemblyInfo.cs Normal file
View File

@ -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)
)]

17
Client/Client.csproj Normal file
View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>
</Project>

View File

@ -3,8 +3,8 @@
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath> <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<BaseOutputPath>$(SolutionDir)$(Configuration)\bin\</BaseOutputPath> <BaseOutputPath>$(SolutionDir)$(Configuration)\bin\</BaseOutputPath>
<BaseIntermediateOutputPath>$(SolutionDir)$(Configuration)\$(MSBuildProjectName)\obj\</BaseIntermediateOutputPath> <BaseIntermediateOutputPath>$(SolutionDir)$(Configuration)\$(ProjectName)\obj\</BaseIntermediateOutputPath>
<MSBuildProjectExtensionsPath>$(SolutionDir)$(Configuration)\$(MSBuildProjectName)\ext\</MSBuildProjectExtensionsPath> <MSBuildProjectExtensionsPath>$(SolutionDir)$(Configuration)\$(ProjectName)\ext\</MSBuildProjectExtensionsPath>
<PackageOutputPath>$(BaseOutputPath)</PackageOutputPath> <PackageOutputPath>$(BaseOutputPath)</PackageOutputPath>
<OutputPath>$(BaseOutputPath)</OutputPath> <OutputPath>$(BaseOutputPath)</OutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)</IntermediateOutputPath> <IntermediateOutputPath>$(BaseIntermediateOutputPath)</IntermediateOutputPath>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
{
}
}

View File

@ -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<T>
{
public T? Create(string data);
public void Update(T entity, string data);
}
}

View File

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

View File

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

View File

@ -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<T> : 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<T> factory)
{
this.factory = factory;
}
private readonly EntityFactoryInterface<T> factory;
private Dictionary<uint, T> entities = new Dictionary<uint, T>();
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<T> : EntityFactoryInterface<T> where T : EntityInterface
{
public T? Create(string data)
{
return JsonConvert.DeserializeObject<T>(data, settings);
}
public void Update(T entity, string data)
{
JsonConvert.PopulateObject(data, entity, settings);
}
private JsonSerializerSettings settings = new JsonSerializerSettings { Converters = { new BooleanConverter() } };
}
}

View File

@ -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<Hero>));
break;
case MessageTypeEnum.Drop:
result = (HandlerInterface?)serviceProvider.GetService(typeof(EntityHandler<Drop>));
break;
}
if (result == null)
{
throw new ArgumentException("Handler not found " + type.ToString());
}
return result;
}
public EntityHandlerFactory(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
}
}

View File

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

View File

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

View File

@ -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<Objects.Message>(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;
}
}
}

View File

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

View File

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

12
Client/MainWindow.xaml Normal file
View File

@ -0,0 +1,12 @@
<Window x:Class="Client.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Client"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>

28
Client/MainWindow.xaml.cs Normal file
View File

@ -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
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}

View File

@ -12,7 +12,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "L2BotDll", "L2BotDll\L2BotD
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InjectionLibrary", "InjectionLibrary\InjectionLibrary.vcxproj", "{54FBE631-3F9B-458C-9DB2-43A868CDB806}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InjectionLibrary", "InjectionLibrary\InjectionLibrary.vcxproj", "{54FBE631-3F9B-458C-9DB2-43A868CDB806}"
EndProject 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 EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution 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|x64.Build.0 = Release|x64
{54FBE631-3F9B-458C-9DB2-43A868CDB806}.Release|x86.ActiveCfg = Release|Win32 {54FBE631-3F9B-458C-9DB2-43A868CDB806}.Release|x86.ActiveCfg = Release|Win32
{54FBE631-3F9B-458C-9DB2-43A868CDB806}.Release|x86.Build.0 = 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 {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Debug|Any CPU.Build.0 = Debug|Any CPU {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Debug|x64.ActiveCfg = Debug|Any CPU {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Debug|x64.ActiveCfg = Debug|Any CPU
{D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Debug|x64.Build.0 = Debug|Any CPU {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Debug|x64.Build.0 = Debug|Any CPU
{D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Debug|x86.ActiveCfg = Debug|Any CPU {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Debug|x86.ActiveCfg = Debug|Any CPU
{D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Debug|x86.Build.0 = Debug|Any CPU {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Debug|x86.Build.0 = Debug|Any CPU
{D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Release|Any CPU.ActiveCfg = Release|Any CPU {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Release|Any CPU.Build.0 = Release|Any CPU {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Release|Any CPU.Build.0 = Release|Any CPU
{D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Release|x64.ActiveCfg = Release|Any CPU {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Release|x64.ActiveCfg = Release|Any CPU
{D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Release|x64.Build.0 = Release|Any CPU {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Release|x64.Build.0 = Release|Any CPU
{D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Release|x86.ActiveCfg = Release|Any CPU {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Release|x86.ActiveCfg = Release|Any CPU
{D3E7234A-C1B0-4CA8-B9D2-04BF9DD991D2}.Release|x86.Build.0 = Release|Any CPU {93FD20EE-CDBF-4FC2-B8F4-85528A45FD94}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

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

View File

@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
</Project>