~ruther/NosSmooth

040e6825fc3889fdb41ffa1554b74c2cf5857a9f — František Boháček 3 years ago
Initial commit
76 files changed, 3713 insertions(+), 0 deletions(-)

A .gitignore
A .gitmodules
A Core/NosSmooth.Core/Client/BaseNostaleClient.cs
A Core/NosSmooth.Core/Client/INostaleClient.cs
A Core/NosSmooth.Core/Commands/CommandProcessor.cs
A Core/NosSmooth.Core/Commands/ICommand.cs
A Core/NosSmooth.Core/Commands/ICommandHandler.cs
A Core/NosSmooth.Core/Commands/WalkCommand.cs
A Core/NosSmooth.Core/Errors/CommandHandlerNotFound.cs
A Core/NosSmooth.Core/Extensions/ServiceCollectionExtensions.cs
A Core/NosSmooth.Core/NosSmooth.Core.csproj
A Core/NosSmooth.Core/Packets/IPacketHandler.cs
A Core/NosSmooth.Core/Packets/IPacketResponder.cs
A Core/NosSmooth.Core/Packets/IPacketSerializer.cs
A Core/NosSmooth.Core/Packets/PacketHandler.cs
A Core/NosSmooth.Core/Packets/PacketSerializer.cs
A Core/NosSmooth.Core/Packets/PacketSerializerProvider.cs
A Core/NosSmooth.Core/RecordFix.cs
A Core/NosSmooth.Extensions/Events/GMJoinedMap.cs
A Core/NosSmooth.Extensions/NosSmooth.Extensions.csproj
A Core/NosSmooth.Game/NosSmooth.Game.csproj
A Core/NosSmooth.Language/NosSmooth.Language.csproj
A DllExport.bat
A Local/NosSmooth.LocalClient/CommandHandlers/WalkCommandHandler.cs
A Local/NosSmooth.LocalClient/Extensions/ServiceCollectionExtensions.cs
A Local/NosSmooth.LocalClient/NosSmooth.LocalClient.csproj
A Local/NosSmooth.LocalClient/NostaleLocalClient.cs
A Local/NosSmooth.LocalClient/NostaleWindow.cs
A Local/NosSmooth.LocalCore/Character.cpp
A Local/NosSmooth.LocalCore/Character.h
A Local/NosSmooth.LocalCore/ModuleHook.cpp
A Local/NosSmooth.LocalCore/ModuleHook.h
A Local/NosSmooth.LocalCore/ModuleHook.ixx
A Local/NosSmooth.LocalCore/Network.cpp
A Local/NosSmooth.LocalCore/Network.h
A Local/NosSmooth.LocalCore/NetworkUnmanaged.cpp
A Local/NosSmooth.LocalCore/NetworkUnmanaged.h
A Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj
A Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj.filters
A Local/NosSmooth.LocalCore/NosSmoothCore.cpp
A Local/NosSmooth.LocalCore/NosSmoothCore.h
A Local/NosSmooth.LocalCore/NostaleString.h
A Local/NosSmooth.LocalCore/packages.config
A NosSmooth.sln
A Remote/NosSmooth.Cryptography/EncryptionProvider.cs
A Remote/NosSmooth.Cryptography/IDecryptor.cs
A Remote/NosSmooth.Cryptography/IEncryptor.cs
A Remote/NosSmooth.Cryptography/NosSmooth.Cryptography.csproj
A Remote/NosSmooth.Cryptography/WorldDecryptor.cs
A Remote/NosSmooth.Cryptography/WorldEncryptor.cs
A Remote/NosSmooth.RemoteClient/NosSmooth.RemoteClient.csproj
A Remote/NosSmooth.RemoteClient/Properties/AssemblyInfo.cs
A Samples/DamageCounter/App.xaml
A Samples/DamageCounter/App.xaml.cs
A Samples/DamageCounter/AssemblyInfo.cs
A Samples/DamageCounter/DamageCounter.csproj
A Samples/DamageCounter/MainWindow.xaml
A Samples/DamageCounter/MainWindow.xaml.cs
A Samples/PacketInterceptor/DummyNostaleClient.cs
A Samples/PacketInterceptor/PacketInterceptor.csproj
A Samples/PacketInterceptor/Program.cs
A Samples/PacketInterceptor/TestResponder.cs
A Samples/PacketLogger/App.xaml
A Samples/PacketLogger/App.xaml.cs
A Samples/PacketLogger/AssemblyInfo.cs
A Samples/PacketLogger/MainWindow.xaml
A Samples/PacketLogger/MainWindow.xaml.cs
A Samples/PacketLogger/PacketLogger.csproj
A Samples/PacketLogger/Packets/PacketLoggerResponder.cs
A Samples/Test/DllMain.cs
A Samples/Test/Test - Backup.csproj
A Samples/Test/Test.csproj
A Samples/testapp/Program.cs
A Samples/testapp/testapp.csproj
A libs/NosCore.Packets
A libs/NosCore.Shared
A  => .gitignore +679 -0
@@ 1,679 @@

# Created by https://www.toptal.com/developers/gitignore/api/csharp,c++,visualstudio,rider
# Edit at https://www.toptal.com/developers/gitignore?templates=csharp,c++,visualstudio,rider

### C++ ###
# Prerequisites
*.d

# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod
*.smod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app

### Csharp ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Mono auto generated files
mono_crash.*

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# ASP.NET Scaffolding
ScaffoldingReadMe.txt

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.iobj
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Nuget personal access tokens and Credentials
# nuget.config

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# CodeRush personal settings
.cr/personal

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/

# Local History for Visual Studio
.localhistory/

# BeatPulse healthcheck temp database
healthchecksdb

# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/

# Fody - auto-generated XML schema
FodyWeavers.xsd

# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace

# Local History for Visual Studio Code
.history/

# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp

# JetBrains Rider
.idea/
*.sln.iml

### Rider ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# AWS User-specific
.idea/**/aws.xml

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn.  Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

### VisualStudio ###

# User-specific files

# User-specific files (MonoDevelop/Xamarin Studio)

# Mono auto generated files

# Build results

# Visual Studio 2015/2017 cache/options directory
# Uncomment if you have tasks that create the project's static files in wwwroot

# Visual Studio 2017 auto generated files

# MSTest test Results

# NUnit

# Build Results of an ATL Project

# Benchmark Results

# .NET Core

# ASP.NET Scaffolding

# StyleCop

# Files built by Visual Studio

# Chutzpah Test files

# Visual C++ cache files

# Visual Studio profiler

# Visual Studio Trace Files

# TFS 2012 Local Workspace

# Guidance Automation Toolkit

# ReSharper is a .NET coding add-in

# TeamCity is a build add-in

# DotCover is a Code Coverage Tool

# AxoCover is a Code Coverage Tool

# Coverlet is a free, cross platform Code Coverage Tool

# Visual Studio code coverage results

# NCrunch

# MightyMoose

# Web workbench (sass)

# Installshield output folder

# DocProject is a documentation generator add-in

# Click-Once directory

# Publish Web Output
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted

# NuGet Packages
# NuGet Symbol Packages
# The packages folder can be ignored because of Package Restore
# except build/, which is used as an MSBuild target.
# Uncomment if necessary however generally it will be regenerated when needed
# NuGet v3's project.json files produces more ignorable files

# Nuget personal access tokens and Credentials
# nuget.config

# Microsoft Azure Build Output

# Microsoft Azure Emulator

# Windows Store app package directories and files

# Visual Studio cache files
# files ending in .cache can be ignored
# but keep track of directories ending in .cache

# Others

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)

# RIA/Silverlight projects

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)

# SQL Server files

# Business Intelligence projects

# Microsoft Fakes

# GhostDoc plugin setting file

# Node.js Tools for Visual Studio

# Visual Studio 6 build log

# Visual Studio 6 workspace options file

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)

# Visual Studio LightSwitch build output

# Paket dependency manager

# FAKE - F# Make

# CodeRush personal settings

# Python Tools for Visual Studio (PTVS)

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio

# Telerik's JustMock configuration file

# BizTalk build output

# OpenCover UI analysis results

# Azure Stream Analytics local run output

# MSBuild Binary and Structured Log

# NVidia Nsight GPU debugger configuration file

# MFractors (Xamarin productivity tool) working folder

# Local History for Visual Studio

# BeatPulse healthcheck temp database

# Backup folder for Package Reference Convert tool in Visual Studio 2017

# Ionide (cross platform F# VS Code tools) working folder

# Fody - auto-generated XML schema

# VS Code files for those working on multiple tools

# Local History for Visual Studio Code

# Windows Installer files from build outputs

# JetBrains Rider

### VisualStudio Patch ###
# Additional files built by Visual Studio

# End of https://www.toptal.com/developers/gitignore/api/csharp,c++,visualstudio,rider

A  => .gitmodules +6 -0
@@ 1,6 @@
[submodule "libs/NosCore.Packets"]
	path = libs/NosCore.Packets
	url = https://github.com/Rutherther/NosCore.Packets.git
[submodule "libs/NosCore.Shared"]
	path = libs/NosCore.Shared
	url = https://github.com/Rutherther/NosCore.Shared.git

A  => Core/NosSmooth.Core/Client/BaseNostaleClient.cs +49 -0
@@ 1,49 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NosCore.Packets;
using NosCore.Packets.Interfaces;
using NosCore.Packets.ServerPackets.Event;
using NosSmooth.Core.Commands;
using NosSmooth.Core.Packets;
using Remora.Results;

namespace NosSmooth.Core.Client;

public abstract class BaseNostaleClient : INostaleClient
{
    protected readonly CommandProcessor _commandProcessor;
    protected readonly IPacketSerializer _packetSerializer;

    protected BaseNostaleClient(CommandProcessor commandProcessor, IPacketSerializer packetSerializer)
    {
        _commandProcessor = commandProcessor;
        _packetSerializer = packetSerializer;
    }

    public abstract Task<Result> RunAsync(CancellationToken stopRequested = default);

    public virtual Task<Result> SendPacketAsync(IPacket packet, CancellationToken ct = default)
    {
        var serialized = _packetSerializer.Serialize(packet);

        return serialized.IsSuccess
            ? SendPacketAsync(serialized.Entity, ct) 
            : Task.FromResult(Result.FromError(serialized));
    }

    public abstract Task<Result> SendPacketAsync(string packetString, CancellationToken ct = default);
    public abstract Task<Result> ReceivePacketAsync(string packetString, CancellationToken ct = default);

    public virtual Task<Result> ReceivePacketAsync(IPacket packet, CancellationToken ct = default)
    {
        var serialized = _packetSerializer.Serialize(packet);

        return serialized.IsSuccess
            ? ReceivePacketAsync(serialized.Entity, ct) 
            : Task.FromResult(Result.FromError(serialized));
    }

    public Task<Result> SendCommandAsync(ICommand command, CancellationToken ct = default) =>
        _commandProcessor.ProcessCommand(command, ct);
}
\ No newline at end of file

A  => Core/NosSmooth.Core/Client/INostaleClient.cs +65 -0
@@ 1,65 @@
using System.Threading;
using System.Threading.Tasks;
using NosCore.Packets.Interfaces;
using NosSmooth.Core.Commands;
using Remora.Results;

namespace NosSmooth.Core.Client;

/// <summary>
/// Class representing nostale client that may send and receive packets as well as process commands.
/// </summary>
public interface INostaleClient
{
    /// <summary>
    /// Starts the client.
    /// </summary>
    /// <param name="stopRequested">A cancellation token for stopping the client.</param>
    /// <returns>The result that may or may not have succeeded.</returns>
    public Task<Result> RunAsync(CancellationToken stopRequested = default);
    
    /// <summary>
    /// Sends the given packet to the server.
    /// </summary>
    /// <param name="packet">The packet to send.</param>
    /// <param name="ct">The cancellation token for cancelling the operation.</param>
    /// <returns>A result that may or may not have succeeded.</returns>
    public Task<Result> SendPacketAsync(IPacket packet, CancellationToken ct = default);
    
    /// <summary>
    /// Sends the given raw packet string.
    /// </summary>
    /// <param name="packetString">The packed string to send in plain text.</param>
    /// <param name="ct">The cancellation token for cancelling the operation.</param>
    /// <returns>A result that may or may not have succeeded.</returns>
    public Task<Result> SendPacketAsync(string packetString, CancellationToken ct = default);

    /// <summary>
    /// Receives the given raw packet string.
    /// </summary>
    /// <param name="packetString">The packet to receive in plain text.</param>
    /// <param name="ct">The cancellation token for cancelling the operation.</param>
    /// <returns>A result that may or may not have succeeded.</returns>
    public Task<Result> ReceivePacketAsync(string packetString, CancellationToken ct = default);
    
    /// <summary>
    /// Receives the given packet. 
    /// </summary>
    /// <param name="packet">The packet to receive.</param>
    /// <param name="ct">The cancellation token for cancelling the operation.</param>
    /// <returns>A result that may or may not have succeeded.</returns>
    public Task<Result> ReceivePacketAsync(IPacket packet, CancellationToken ct = default);

    /// <summary>
    /// Sends the given command to the client.
    /// </summary>
    /// <remarks>
    /// Commands can be used for doing complex operations like walking that require sending multiple packets
    /// and/or calling some functions of the local client.
    /// This method will not return until the command is finished or it failed.
    /// </remarks>
    /// <param name="command">The command to send.</param>
    /// <param name="ct">The cancellation token for cancelling the operation.</param>
    /// <returns>A result that may or may not have succeeded.</returns>
    public Task<Result> SendCommandAsync(ICommand command, CancellationToken ct = default);
}
\ No newline at end of file

A  => Core/NosSmooth.Core/Commands/CommandProcessor.cs +50 -0
@@ 1,50 @@
using System;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using NosSmooth.Core.Errors;
using Remora.Results;

namespace NosSmooth.Core.Commands;

public class CommandProcessor
{
    private readonly IServiceProvider _provider;

    public CommandProcessor(IServiceProvider provider)
    {
        _provider = provider;
    }

    public Task<Result> ProcessCommand(ICommand command, CancellationToken ct = default)
    {
        var processMethod = GetType().GetMethod
        (
            nameof(DispatchCommandHandler),
            BindingFlags.NonPublic | BindingFlags.Instance
        );

        if (processMethod is null)
        {
            throw new InvalidOperationException("Could not find process command generic method in command processor.");
        }

        var boundProcessMethod = processMethod.MakeGenericMethod(command.GetType());

        return (Task<Result>)boundProcessMethod.Invoke(this, new object[] { command, ct })!;
    }

    private Task<Result> DispatchCommandHandler<TCommand>(TCommand command, CancellationToken ct = default)
        where TCommand : class, ICommand
    {
        using var scope = _provider.CreateScope();
        var commandHandler = scope.ServiceProvider.GetService<ICommandHandler<TCommand>>();
        if (commandHandler is null)
        {
            return Task.FromResult(Result.FromError(new CommandHandlerNotFound(command.GetType())));
        }

        return commandHandler.HandleCommand(command, ct);
    }
}
\ No newline at end of file

A  => Core/NosSmooth.Core/Commands/ICommand.cs +6 -0
@@ 1,6 @@
namespace NosSmooth.Core.Commands;

public interface ICommand
{
    
}
\ No newline at end of file

A  => Core/NosSmooth.Core/Commands/ICommandHandler.cs +13 -0
@@ 1,13 @@
using System.Threading;
using System.Threading.Tasks;
using Remora.Results;

namespace NosSmooth.Core.Commands;

public interface ICommandHandler {}

public interface ICommandHandler<TCommand> : ICommandHandler
    where TCommand : ICommand
{
    public Task<Result> HandleCommand(TCommand command, CancellationToken ct = default);
}
\ No newline at end of file

A  => Core/NosSmooth.Core/Commands/WalkCommand.cs +9 -0
@@ 1,9 @@
namespace NosSmooth.Core.Commands;

/// <summary>
/// Command that moves the player to the specified target position.
/// May be used only in world.
/// </summary>
/// <param name="TargetX">The x coordinate of the target position to move to.</param>
/// <param name="TargetY">The y coordinate of the target position to move to.</param>
public record WalkCommand(int TargetX, int TargetY) : ICommand;
\ No newline at end of file

A  => Core/NosSmooth.Core/Errors/CommandHandlerNotFound.cs +11 -0
@@ 1,11 @@
using System;
using Remora.Results;

namespace NosSmooth.Core.Errors;

/// <summary>
/// Represents an error that tells the user there is no handler for the specified command so it cannot be processed.
/// </summary>
/// <param name="CommandType">The type of the command.</param>
public record CommandHandlerNotFound(Type CommandType) : ResultError(
    $"Could not process the command of type {CommandType.FullName}, because there is not a handler for it.");
\ No newline at end of file

A  => Core/NosSmooth.Core/Extensions/ServiceCollectionExtensions.cs +145 -0
@@ 1,145 @@
using System;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using NosCore.Packets;
using NosCore.Packets.Attributes;
using NosCore.Packets.Enumerations;
using NosCore.Packets.Interfaces;
using NosSmooth.Core.Client;
using NosSmooth.Core.Commands;
using NosSmooth.Core.Packets;

namespace NosSmooth.Core.Extensions;

public static class ServiceCollectionExtensions
{
    /// <summary>
    /// Adds base packet and command handling for nostale client.
    /// </summary>
    /// <param name="serviceCollection">The service collection to register the responder to.</param>
    /// <param name="additionalPacketTypes">Custom types of packets to serialize and deserialize.</param>
    /// <returns>The collection.</returns>
    public static IServiceCollection AddNostaleCore(this IServiceCollection serviceCollection,
        params Type[] additionalPacketTypes)
    {
        serviceCollection
            .TryAddSingleton<IPacketHandler, PacketHandler>();

        var clientPacketTypes = typeof(IPacket).Assembly.GetTypes()
            .Where(p => (p.Namespace?.Contains("Client") ?? false) && p.GetInterfaces().Contains(typeof(IPacket)) && p.IsClass && !p.IsAbstract).ToList();
        var serverPacketTypes = typeof(IPacket).Assembly.GetTypes()
            .Where(p => (p.Namespace?.Contains("Server") ?? false) && p.GetInterfaces().Contains(typeof(IPacket)) && p.IsClass && !p.IsAbstract).ToList();

        if (additionalPacketTypes.Length != 0)
        {
            clientPacketTypes.AddRange(additionalPacketTypes);
        }

        serviceCollection.AddSingleton(_ =>
            new PacketSerializerProvider(clientPacketTypes, serverPacketTypes));
        serviceCollection.AddSingleton(p => p.GetRequiredService<PacketSerializerProvider>().GetServerSerializer());

        serviceCollection.AddSingleton<CommandProcessor>();

        return serviceCollection;
    }

    /// <summary>
    /// Adds the specified packet responder that will be called upon receiving the given event.
    /// </summary>
    /// <param name="serviceCollection">The service collection to register the responder to.</param>
    /// <typeparam name="TPacketResponder">The type of the responder.</typeparam>
    /// <exception cref="ArgumentException">Thrown if the type of the responder is incorrect.</exception>
    /// <returns>The collection.</returns>
    public static IServiceCollection AddPacketResponder<TPacketResponder>(
        this IServiceCollection serviceCollection)
        where TPacketResponder : class, IPacketResponder
    {
        return serviceCollection.AddPacketResponder(typeof(TPacketResponder));
    }

    /// <summary>
    /// Adds the specified packet responder that will be called upon receiving the given event.
    /// </summary>
    /// <param name="serviceCollection">The service collection to register the responder to.</param>
    /// <param name="responderType">The type of the responder.</param>
    /// <returns>The collection.</returns>
    /// <exception cref="ArgumentException">Thrown if the type of the responder is incorrect.</exception>
    public static IServiceCollection AddPacketResponder(this IServiceCollection serviceCollection, Type responderType)
    {
        if (responderType.GetInterfaces().Any(i => i == typeof(IEveryPacketResponder)))
        {
            return serviceCollection.AddScoped(typeof(IEveryPacketResponder), responderType);
        }
        
        if (!responderType.GetInterfaces().Any(
                i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketResponder<>)
            ))
        {
            throw new ArgumentException(
                $"{nameof(responderType)} should implement IPacketResponder.",
                nameof(responderType));
        }

        var responderTypeInterfaces = responderType.GetInterfaces();
        var responderInterfaces = responderTypeInterfaces.Where
        (
            r => r.IsGenericType && r.GetGenericTypeDefinition() == typeof(IPacketResponder<>)
        );

        foreach (var responderInterface in responderInterfaces)
        {
            serviceCollection.AddScoped(responderInterface, responderType);
        }

        return serviceCollection;
    }
    
    /// <summary>
    /// Adds the specified command handler.
    /// </summary>
    /// <param name="serviceCollection">The service collection to register the responder to.</param>
    /// <typeparam name="TCommandHandler">The type of the command.</typeparam>
    /// <exception cref="ArgumentException">Thrown if the type of the responder is incorrect.</exception>
    /// <returns>The collection.</returns>
    public static IServiceCollection AddCommandHandler<TCommandHandler>(
        this IServiceCollection serviceCollection)
        where TCommandHandler : class, ICommandHandler
    {
        return serviceCollection.AddCommandHandler(typeof(TCommandHandler));
    }

    /// <summary>
    /// Adds the specified command handler.
    /// </summary>
    /// <param name="serviceCollection">The service collection to register the responder to.</param>
    /// <param name="commandHandlerType">The type of the command handler.</param>
    /// <returns>The collection.</returns>
    /// <exception cref="ArgumentException">Thrown if the type of the responder is incorrect.</exception>
    public static IServiceCollection AddCommandHandler(this IServiceCollection serviceCollection, Type commandHandlerType)
    {
        if (!commandHandlerType.GetInterfaces().Any(
                i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICommandHandler<>)
            ))
        {
            throw new ArgumentException(
                $"{nameof(commandHandlerType)} should implement ICommandHandler.",
                nameof(commandHandlerType));
        }

        var handlerTypeInterfaces = commandHandlerType.GetInterfaces();
        var handlerInterfaces = handlerTypeInterfaces.Where
        (
            r => r.IsGenericType && r.GetGenericTypeDefinition() == typeof(ICommandHandler<>)
        );

        foreach (var handlerInterface in handlerInterfaces)
        {
            serviceCollection.AddScoped(handlerInterface, commandHandlerType);
        }

        return serviceCollection;
    }
}
\ No newline at end of file

A  => Core/NosSmooth.Core/NosSmooth.Core.csproj +17 -0
@@ 1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <Nullable>enable</Nullable>
        <LangVersion>10</LangVersion>
        <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="Remora.Results" Version="7.1.0" />
    </ItemGroup>

    <ItemGroup>
      <ProjectReference Include="..\..\libs\NosCore.Packets\src\NosCore.Packets\NosCore.Packets.csproj" />
    </ItemGroup>

</Project>

A  => Core/NosSmooth.Core/Packets/IPacketHandler.cs +28 -0
@@ 1,28 @@
using System.Threading;
using System.Threading.Tasks;
using NosCore.Packets.Interfaces;
using Remora.Results;

namespace NosSmooth.Core.Packets;

/// <summary>
/// Calls registered responders for the packet that should be handled.
/// </summary>
public interface IPacketHandler
{
    /// <summary>
    /// Calls a responder for the given packet.
    /// </summary>
    /// <param name="packet">The packet.</param>
    /// <param name="ct">The cancellation token for cancelling the operation.</param>
    /// <returns>A result that may or may not have succeeded.</returns>
    public Task<Result> HandleReceivedPacketAsync(IPacket packet, CancellationToken ct = default);

    /// <summary>
    /// Calls a responder for the given packet.
    /// </summary>
    /// <param name="packet">The packet.</param>
    /// <param name="ct">The cancellation token for cancelling the operation.</param>
    /// <returns>A result that may or may not have succeeded.</returns>
    public Task<Result> HandleSentPacketAsync(IPacket packet, CancellationToken ct = default);
}
\ No newline at end of file

A  => Core/NosSmooth.Core/Packets/IPacketResponder.cs +28 -0
@@ 1,28 @@
using System.Threading;
using System.Threading.Tasks;
using NosCore.Packets.Interfaces;
using Remora.Results;

namespace NosSmooth.Core.Packets;

public interface IPacketResponder
{
}

public interface IPacketResponder<TPacket> : IPacketResponder
    where TPacket : IPacket
{
    /// <summary>
    /// Respond to the given packet.
    /// </summary>
    /// <param name="packet">The packet to respond to.</param>
    /// <param name="ct">The cancellation token for cancelling the operation.</param>
    /// <returns></returns>
    public Task<Result> Respond(TPacket packet, CancellationToken ct = default);
}

public interface IEveryPacketResponder : IPacketResponder
{
    public Task<Result> Respond<TPacket>(TPacket packet, CancellationToken ct = default)
        where TPacket : IPacket;
}
\ No newline at end of file

A  => Core/NosSmooth.Core/Packets/IPacketSerializer.cs +12 -0
@@ 1,12 @@
using System.Threading.Tasks;
using NosCore.Packets.Interfaces;
using Remora.Results;

namespace NosSmooth.Core.Packets;

public interface IPacketSerializer
{
    public Result<string> Serialize(IPacket packet);

    public Result<IPacket> Deserialize(string packetString);
}
\ No newline at end of file

A  => Core/NosSmooth.Core/Packets/PacketHandler.cs +74 -0
@@ 1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using NosCore.Packets.Interfaces;
using Remora.Results;

namespace NosSmooth.Core.Packets;

/// <inheritdoc />
public class PacketHandler : IPacketHandler
{
    private readonly IServiceProvider _provider;

    public PacketHandler(IServiceProvider provider)
    {
        _provider = provider;
    }

    /// <inheritdoc />
    public Task<Result> HandleReceivedPacketAsync(IPacket packet, CancellationToken ct) => HandlePacketAsync(packet, ct);

    /// <inheritdoc />
    public Task<Result> HandleSentPacketAsync(IPacket packet, CancellationToken ct) => HandlePacketAsync(packet, ct);

    private Task<Result> HandlePacketAsync(IPacket packet, CancellationToken ct = default)
    {
        var processMethod = GetType().GetMethod
        (
            nameof(DispatchResponder),
            BindingFlags.NonPublic | BindingFlags.Instance
        );

        if (processMethod is null)
        {
            throw new InvalidOperationException("Could not find process command generic method in command processor.");
        }

        var boundProcessMethod = processMethod.MakeGenericMethod(packet.GetType());
        return (Task<Result>)boundProcessMethod.Invoke(this, new object[] { packet, ct })!;
    }

    private async Task<Result> DispatchResponder<TPacket>(TPacket packet, CancellationToken ct)
        where TPacket : class, IPacket
    {
        using var scope = _provider.CreateScope();
        var packetResponders = scope.ServiceProvider.GetServices<IPacketResponder<TPacket>>();
        var genericPacketResponders = scope.ServiceProvider.GetServices<IEveryPacketResponder>();

        var tasks = packetResponders.Select(responder => responder.Respond(packet, ct)).ToList();
        tasks.AddRange(genericPacketResponders.Select(responder => responder.Respond(packet, ct)));
        
        var results = await Task.WhenAll(tasks);
        
        var errors = new List<Result>();
        foreach (var result in results)
        {
            if (!result.IsSuccess)
            {
                errors.Add(result);
            }
        }

        return errors.Count switch
        {
            0 => Result.FromSuccess(),
            1 => errors[0],
            _ => new AggregateError(errors.Cast<IResult>().ToList())
        };
    }
}
\ No newline at end of file

A  => Core/NosSmooth.Core/Packets/PacketSerializer.cs +43 -0
@@ 1,43 @@
using System;
using System.Threading.Tasks;
using NosCore.Packets;
using NosCore.Packets.Interfaces;
using Remora.Results;

namespace NosSmooth.Core.Packets;

public class PacketSerializer : IPacketSerializer
{
    private readonly Serializer _serializer;
    private readonly Deserializer _deserializer;

    public PacketSerializer(Serializer serializer, Deserializer deserializer)
    {
        _serializer = serializer;
        _deserializer = deserializer;
    }

    public Result<string> Serialize(IPacket packet)
    {
        try
        {
            return _serializer.Serialize(packet);
        }
        catch (Exception e)
        {
            return e;
        }
    }

    public Result<IPacket> Deserialize(string packetString)
    {
        try
        {
            return Result<IPacket>.FromSuccess(_deserializer.Deserialize(packetString));
        }
        catch (Exception e)
        {
            return e;
        }
    }
}
\ No newline at end of file

A  => Core/NosSmooth.Core/Packets/PacketSerializerProvider.cs +42 -0
@@ 1,42 @@
using System;
using System.Collections.Generic;
using NosCore.Packets;

namespace NosSmooth.Core.Packets;

public class PacketSerializerProvider
{
    private readonly List<Type> _clientPacketTypes;
    private readonly List<Type> _serverPacketTypes;

    private IPacketSerializer? _serverSerializer;
    private IPacketSerializer? _clientSerializer;

    public PacketSerializerProvider(List<Type> clientPacketTypes, List<Type> serverPacketTypes)
    {
        _clientPacketTypes = clientPacketTypes;
        _serverPacketTypes = serverPacketTypes;
    }

    public IPacketSerializer GetServerSerializer()
    {
        if (_serverSerializer is null)
        {
            _serverSerializer =
                new PacketSerializer(new Serializer(_serverPacketTypes), new Deserializer(_serverPacketTypes));
        }

        return _serverSerializer;
    }

    public IPacketSerializer GetClientSerializer()
    {
        if (_clientSerializer is null)
        {
            _clientSerializer =
                new PacketSerializer(new Serializer(_clientPacketTypes), new Deserializer(_clientPacketTypes));
        }

        return _clientSerializer;
    }
}
\ No newline at end of file

A  => Core/NosSmooth.Core/RecordFix.cs +4 -0
@@ 1,4 @@
namespace System.Runtime.CompilerServices
{
    public class IsExternalInit { }
}
\ No newline at end of file

A  => Core/NosSmooth.Extensions/Events/GMJoinedMap.cs +7 -0
@@ 1,7 @@
namespace NosSmooth.Extensions.Events
{
    public class GMJoinedMap
    {
        
    }
}
\ No newline at end of file

A  => Core/NosSmooth.Extensions/NosSmooth.Extensions.csproj +13 -0
@@ 1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>

    <ItemGroup>
      <ProjectReference Include="..\NosSmooth.Game\NosSmooth.Game.csproj" />
    </ItemGroup>

</Project>

A  => Core/NosSmooth.Game/NosSmooth.Game.csproj +10 -0
@@ 1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <LangVersion>10</LangVersion>
        <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
    </PropertyGroup>

</Project>

A  => Core/NosSmooth.Language/NosSmooth.Language.csproj +10 -0
@@ 1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <LangVersion>10</LangVersion>
        <TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>
    </PropertyGroup>

</Project>

A  => DllExport.bat +509 -0
@@ 1,509 @@
@echo off
:: Copyright (c) 2016-2021  Denis Kuzmin [x-3F@outlook.com] github/3F
:: https://github.com/3F/DllExport
if "%~1"=="/?" goto bq
set "aa=%~dpnx0"
set ab=%*
set ac=%*
if defined ab (
if defined __p_call (
set ac=%ac:^^=^%
) else (
set ab=%ab:^=^^%
)
)
set wMgrArgs=%ac%
set ad=%ab:!=^!%
setlocal enableDelayedExpansion
set "ae=^"
set "ad=!ad:%%=%%%%!"
set "ad=!ad:&=%%ae%%&!"
set "af=1.7.4"
set "wAction=Configure"
set "ag=DllExport"
set "ah=tools/net.r_eg.DllExport.Wizard.targets"
set "ai=packages"
set "aj=https://www.nuget.org/api/v2/package/"
set "ak=build_info.txt"
set "al=!aa!"
set "wRootPath=!cd!"
set /a wDxpOpt=0
set "am="
set "an="
set "ao="
set "ap="
set "aq="
set "ar="
set "as="
set "at="
set "au="
set "av="
set /a aw=0
if not defined ab (
if defined wAction goto br
goto bq
)
call :bs bk !ad! bl
goto bt
:bq
echo.
@echo .NET DllExport v1.7.4.29858+c1cc52f
@echo Copyright (c) 2009-2015  Robert Giesecke
@echo Copyright (c) 2016-2021  Denis Kuzmin ^<x-3F@outlook.com^> github/3F
echo.
echo MIT License
@echo https://github.com/3F/DllExport
echo Based on hMSBuild, MvsSln, +GetNuTool: https://github.com/3F
echo.
@echo.
@echo Usage: DllExport [args to DllExport] [args to GetNuTool] [args to hMSBuild]
echo ------
echo.
echo Arguments
echo ---------
echo -action {type} - Specified action for Wizard. Where {type}:
echo   * Configure - To configure DllExport for specific projects.
echo   * Update    - To update pkg reference for already configured projects.
echo   * Restore   - To restore configured DllExport.
echo   * Export    - To export configured projects data.
echo   * Recover   - To re-configure projects via predefined/exported data.
echo   * Unset     - To unset all data from specified projects.
echo   * Upgrade   - Aggregates an Update action with additions for upgrading.
echo.
echo -sln-dir {path}    - Path to directory with .sln files to be processed.
echo -sln-file {path}   - Optional predefined .sln file to be processed.
echo -metalib {path}    - Relative path to meta library.
echo -metacor {path}    - Relative path to meta core library.
echo -dxp-target {path} - Relative path to entrypoint wrapper of the main core.
echo -dxp-version {num} - Specific version of DllExport. Where {num}:
echo   * Versions: 1.7.3 ...
echo   * Keywords:
echo     `actual` - Unspecified local/latest remote version;
echo                ( Only if you know what you are doing )
echo.
echo -msb {path}           - Full path to specific msbuild.
echo -hMSBuild {args}      - Access to hMSBuild tool (packed) https://github.com/3F/hMSBuild
echo -packages {path}      - A common directory for packages.
echo -server {url}         - Url for searching remote packages.
echo -proxy {cfg}          - To use proxy. The format: [usr[:pwd]@]host[:port]
echo -pkg-link {uri}       - Direct link to package from the source via specified URI.
echo -force                - Aggressive behavior, e.g. like removing pkg when updating.
echo -no-mgr               - Do not use %~nx0 for automatic restore the remote package.
echo -mgr-up               - Updates %~nx0 to version from '-dxp-version'.
echo -wz-target {path}     - Relative path to entrypoint wrapper of the main wizard.
echo -pe-exp-list {module} - To list all available exports from PE32/PE32+ module.
echo -eng                  - Try to use english language for all build messages.
echo -GetNuTool {args}     - Access to GetNuTool (integrated) https://github.com/3F/GetNuTool
echo -debug                - To show additional information.
echo -version              - Displays version for which (together with) it was compiled.
echo -build-info           - Displays actual build information from selected DllExport.
echo -help                 - Displays this help. Aliases: -help -h
echo.
echo Flags
echo -----
echo  __p_call - To use the call-type logic when invoking %~nx0
echo.
echo Samples
echo -------
echo DllExport -action Configure -force -pkg-link http://host/v1.7.3.nupkg
echo DllExport -action Restore -sln-file "Conari.sln"
echo DllExport -proxy guest:1234@10.0.2.15:7428 -action Configure
echo.
echo DllExport -mgr-up -dxp-version 1.7.3
echo DllExport -action Upgrade -dxp-version 1.7.3
echo.
echo DllExport -GetNuTool /p:ngpackages="Conari;regXwild"
echo DllExport -pe-exp-list bin\Debug\regXwild.dll
goto bu
:bt
set /a ax=0
:bv
set ay=!bk[%ax%]!
if [!ay!]==[-help] ( goto bq ) else if [!ay!]==[-h] ( goto bq ) else if [!ay!]==[-?] ( goto bq )
if [!ay!]==[-debug] (
set am=1
goto bw
) else if [!ay!]==[-action] ( set /a "ax+=1" & call :bx bk[!ax!] v
set wAction=!v!
for %%g in (Restore, Configure, Update, Export, Recover, Unset, Upgrade, Default) do (
if "!v!"=="%%g" goto bw
)
echo Unknown -action !v!
exit/B 1
) else if [!ay!]==[-sln-dir] ( set /a "ax+=1" & call :bx bk[!ax!] v
set wSlnDir=!v!
goto bw
) else if [!ay!]==[-sln-file] ( set /a "ax+=1" & call :bx bk[!ax!] v
set wSlnFile=!v!
goto bw
) else if [!ay!]==[-metalib] ( set /a "ax+=1" & call :bx bk[!ax!] v
set wMetaLib=!v!
goto bw
) else if [!ay!]==[-metacor] ( set /a "ax+=1" & call :bx bk[!ax!] v
set wMetaCor=!v!
goto bw
) else if [!ay!]==[-dxp-target] ( set /a "ax+=1" & call :bx bk[!ax!] v
set wDxpTarget=!v!
goto bw
) else if [!ay!]==[-dxp-version] ( set /a "ax+=1" & call :bx bk[!ax!] v
set af=!v!
goto bw
) else if [!ay!]==[-msb] ( set /a "ax+=1" & call :bx bk[!ax!] v
set ao=!v!
goto bw
) else if [!ay!]==[-packages] ( set /a "ax+=1" & call :bx bk[!ax!] v
set ai=!v!
goto bw
) else if [!ay!]==[-server] ( set /a "ax+=1" & call :bx bk[!ax!] v
set aj=!v!
goto bw
) else if [!ay!]==[-proxy] ( set /a "ax+=1" & call :bx bk[!ax!] v
set at=!v!
set wProxy=!v!
goto bw
) else if [!ay!]==[-pkg-link] ( set /a "ax+=1" & call :bx bk[!ax!] v
set ap=!v!
set af=!ay!
goto bw
) else if [!ay!]==[-force] (
set ar=1
goto bw
) else if [!ay!]==[-no-mgr] (
set /a wDxpOpt^|=1
goto bw
) else if [!ay!]==[-mgr-up] (
set as=1
goto bw
) else if [!ay!]==[-wz-target] ( set /a "ax+=1" & call :bx bk[!ax!] v
set ah=!v!
goto bw
) else if [!ay!]==[-pe-exp-list] ( set /a "ax+=1" & call :bx bk[!ax!] v
set aq=!v!
goto bw
) else if [!ay!]==[-eng] (
chcp 437 >nul
goto bw
) else if [!ay!]==[-GetNuTool] (
call :by -GetNuTool 10
set /a aw=!ERRORLEVEL! & goto bu
) else if [!ay!]==[-hMSBuild] (
set av=1 & goto br
) else if [!ay!]==[-version] (
@echo v1.7.4.29858+c1cc52f  %__dxp_pv%
goto bu
) else if [!ay!]==[-build-info] (
set an=1
goto bw
) else if [!ay!]==[-tests] ( set /a "ax+=1" & call :bx bk[!ax!] v
set au=!v!
goto bw
) else (
echo Incorrect key: !ay!
set /a aw=1
goto bu
)
:bw
set /a "ax+=1" & if %ax% LSS !bl! goto bv
:br
call :bz "dxpName = " ag
call :bz "dxpVersion = " af
call :bz "-sln-dir = " wSlnDir
call :bz "-sln-file = " wSlnFile
call :bz "-metalib = " wMetaLib
call :bz "-metacor = " wMetaCor
call :bz "-dxp-target = " wDxpTarget
call :bz "-wz-target = " ah
call :bz "#opt " wDxpOpt
if defined af (
if "!af!"=="actual" (
set "af="
)
)
set wPkgVer=!af!
if z%wAction%==zUpgrade (
call :bz "Upgrade is on"
set as=1
set ar=1
)
call :b0 ai
set "ai=!ai!\\"
set "az=!ag!"
set "wPkgPath=!ai!!ag!"
if defined af (
set "az=!az!/!af!"
set "wPkgPath=!wPkgPath!.!af!"
)
if defined ar (
if exist "!wPkgPath!" (
call :bz "Removing old version before continue. '-force' key rule. " wPkgPath
rmdir /S/Q "!wPkgPath!"
)
)
set a0="!wPkgPath!\\!ah!"
call :bz "wPkgPath = " wPkgPath
if not exist !a0! (
if exist "!wPkgPath!" (
call :bz "Trying to replace obsolete version ... " wPkgPath
rmdir /S/Q "!wPkgPath!"
)
call :bz "-pkg-link = " ap
call :bz "-server = " aj
if defined ap (
set aj=!ap!
if "!aj::=!"=="!aj!" (
set aj=!cd!/!aj!
)
if "!wPkgPath::=!"=="!wPkgPath!" (
set "a1=../"
)
set "az=:!a1!!wPkgPath!|"
)
if defined ao (
set a2=-msbuild "!ao!"
)
set a3=!a2! /p:ngserver="!aj!" /p:ngpackages="!az!" /p:ngpath="!ai!" /p:proxycfg="!at! "
call :bz "GetNuTool call: " a3
if defined am (
call :b1 !a3!
) else (
call :b1 !a3! >nul
)
)
if defined av (
call :by -hMSBuild 9
set /a aw=!ERRORLEVEL! & goto bu
)
if defined aq (
"!wPkgPath!\\tools\\PeViewer.exe" -list -pemodule "!aq!"
set /a aw=%ERRORLEVEL%
goto bu
)
if defined an (
call :bz "buildInfo = " wPkgPath ak
if not exist "!wPkgPath!\\!ak!" (
echo information about build is not available.
set /a aw=2
goto bu
)
type "!wPkgPath!\\!ak!"
goto bu
)
if not exist !a0! (
echo Something went wrong. Try to use another keys.
set /a aw=2
goto bu
)
call :bz "wRootPath = " wRootPath
call :bz "wAction = " wAction
call :bz "wMgrArgs = " wMgrArgs
if defined ao (
call :bz "Use specific MSBuild tools: " ao
set a4="!ao!"
goto b2
)
call :b3 bm & set a4="!bm!"
if "!ERRORLEVEL!"=="0" goto b2
echo MSBuild tools was not found. Try with `-msb` key.
set /a aw=2
goto bu
:b2
if not defined a4 (
echo Something went wrong. Use `-debug` key for details.
set /a aw=2
goto bu
)
if not defined au (
if not defined ao if defined wPkgPath (
set a4="!wPkgPath!\\hMSBuild"
for /f "tokens=*" %%i in ('!a4! -version') do set a5=%%i
call :b4 !a5! bn
call :bz "hMSBuild -v" a5 bn
if !bn! GEQ 230 (
call :bz "2.3+"
set a4=!a4! -vsw-as "-requiresAny -requires Microsoft.NetCore.Component.SDK Microsoft.Net.Core.Component.SDK -products * -latest -prerelease"
)
)
call :bz "Target: " a4 a0
call !a4! /nologo /v:m /m:4 !a0!
)
:bu
if defined au (
echo Running Tests ... "!au!"
call :b3 bo
"!bo!" /nologo /v:m /m:4 "!au!"
exit/B 0
)
if defined as (
(copy /B/Y "!wPkgPath!\\DllExport.bat" "!al!" > nul) && ( echo Manager has been updated. & exit/B 0 ) || ( (echo -mgr-up failed:!aw! 1>&2) & exit/B 1 )
)
exit/B !aw!
:b4
set a6=%~1
for /f "tokens=1,2 delims=." %%a in ("!a6!") do (
set _=%%b & set /a _*=10 & set /a %2=%%a!_!
)
exit/B 0
:by
set ay=%~1
set /a a7=%~2
call :bz "accessing to !ay! ..."
for /L %%p IN (0,1,8181) DO (
if "!ad:~%%p,%a7%!"=="!ay!" (
set a8=!ad:~%%p!
set a9=!a8:~%a7%!
if defined av (
call "!wPkgPath!\\hMSBuild" !a9!
) else (
call :b1 !a9!
)
exit/B !ERRORLEVEL!
)
)
call :bz "!ay! is corrupted: " ad
exit/B 1
:b3
call :bz "Searching from .NET Framework - .NET 4.0, ..."
for %%v in (4.0, 3.5, 2.0) do (
call :b5 %%v Y & if defined Y (
set %1=!Y!
exit/B 0
)
)
call :bz "msb -netfx: not found"
set "%1="
exit/B 2
:b5
call :bz "check %1"
for /F "usebackq tokens=2* skip=2" %%a in (
`reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\%1" /v MSBuildToolsPath 2^> nul`
) do if exist %%b (
set a_=%%~b
call :bz ":msbfound " a_
call :b6 a_ bp
set %2=!bp!
exit/B 0
)
set "%2="
exit/B 0
:b6
set %2=!%~1!\MSBuild.exe
exit/B 0
:bz
if defined am (
set ba=%1
set ba=!ba:~0,-1!
set ba=!ba:~1!
echo.[%TIME% ] !ba! !%2! !%3!
)
exit/B 0
:b0
call :b7 %1
call :b8 %1
exit/B 0
:b7
call :b9 %1 "-=1"
exit/B 0
:b8
call :b9 %1 "+=1"
exit/B 0
:b9
set bb=z!%1!z
if "%~2"=="-=1" (set "bc=1") else (set "bc=")
if defined bc (
set /a "i=-2"
) else (
set /a "i=1"
)
:b_
if "!bb:~%i%,1!"==" " (
set /a "i%~2"
goto b_
)
if defined bc set /a "i+=1"
if defined bc (
set "%1=!bb:~1,%i%!"
) else (
set "%1=!bb:~%i%,-1!"
)
exit/B 0
:bs
set "bd=%~1"
set /a ax=-1
:ca
set /a ax+=1
set %bd%[!ax!]=%~2
shift & if not "%~3"=="" goto ca
set /a ax-=1
set %1=!ax!
exit/B 0
:bx
set %2=!%1!
exit/B 0
:b1
setlocal disableDelayedExpansion
@echo off
:: GetNuTool - Executable version
:: Copyright (c) 2015-2018,2020  Denis Kuzmin [ x-3F@outlook.com ]
:: https://github.com/3F/GetNuTool
set be=gnt.core
set bf="%temp%\%random%%random%%be%"
if "%~1"=="-unpack" goto cb
set bg=%*
if defined __p_call if defined bg set bg=%bg:^^=^%
set bh=%__p_msb%
if defined bh goto cc
if "%~1"=="-msbuild" goto cd
for %%v in (4.0, 14.0, 12.0, 3.5, 2.0) do (
for /F "usebackq tokens=2* skip=2" %%a in (
`reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\%%v" /v MSBuildToolsPath 2^> nul`
) do if exist %%b (
set bh="%%~b\MSBuild.exe"
goto cc
)
)
echo MSBuild was not found. Try -msbuild "fullpath" args 1>&2
exit/B 2
:cd
shift
set bh=%1
shift
set bi=%bg:!= #__b_ECL## %
setlocal enableDelayedExpansion
set bi=!bi:%%=%%%%!
:ce
for /F "tokens=1* delims==" %%a in ("!bi!") do (
if "%%~b"=="" (
call :cf !bi!
exit/B %ERRORLEVEL%
)
set bi=%%a #__b_EQ## %%b
)
goto ce
:cf
shift & shift
set "bg="
:cg
set bg=!bg! %1
shift & if not "%~2"=="" goto cg
set bg=!bg: #__b_EQ## ==!
setlocal disableDelayedExpansion
set bg=%bg: #__b_ECL## =!%
:cc
call :ch
call %bh% %bf% /nologo /p:wpath="%cd%/" /v:m /m:4 %bg%
set "bh="
set bj=%ERRORLEVEL%
del /Q/F %bf%
exit/B %bj%
:cb
set bf="%cd%\%be%"
echo Generating minified version in %bf% ...
:ch
<nul set /P ="">%bf%
set a=PropertyGroup&set b=Condition&set c=ngpackages&set d=Target&set e=DependsOnTargets&set f=TaskCoreDllPath&set g=MSBuildToolsPath&set h=UsingTask&set i=CodeTaskFactory&set j=ParameterGroup&set k=Reference&set l=Include&set m=System&set n=Using&set o=Namespace&set p=IsNullOrEmpty&set q=return&set r=string&set s=delegate&set t=foreach&set u=WriteLine&set v=Combine&set w=Console.WriteLine&set x=Directory&set y=GetNuTool&set z=StringComparison&set _=EXT_NUSPEC
<nul set /P =^<!-- GetNuTool - github.com/3F/GetNuTool --^>^<!-- Copyright (c) 2015-2018,2020  Denis Kuzmin [ x-3F@outlook.com ] --^>^<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"^>^<%a%^>^<ngconfig %b%="'$(ngconfig)'==''"^>packages.config^</ngconfig^>^<ngserver %b%="'$(ngserver)'==''"^>https://www.nuget.org/api/v2/package/^</ngserver^>^<%c% %b%="'$(%c%)'==''"^>^</%c%^>^<ngpath %b%="'$(ngpath)'==''"^>packages^</ngpath^>^</%a%^>^<%d% Name="get" BeforeTargets="Build" %e%="header"^>^<a^>^<Output PropertyName="plist" TaskParameter="Result"/^>^</a^>^<b plist="$(plist)"/^>^</%d%^>^<%d% Name="pack" %e%="header"^>^<c/^>^</%d%^>^<%a%^>^<%f% %b%="Exists('$(%g%)\Microsoft.Build.Tasks.v$(MSBuildToolsVersion).dll')"^>$(%g%)\Microsoft.Build.Tasks.v$(MSBuildToolsVersion).dll^</%f%^>^<%f% %b%="'$(%f%)'=='' and Exists('$(%g%)\Microsoft.Build.Tasks.Core.dll')"^>$(%g%)\Microsoft.Build.Tasks.Core.dll^</%f%^>^</%a%^>^<%h% TaskName="a" TaskFactory="%i%" AssemblyFile="$(%f%)"^>^<%j%^>^<Result Output="true"/^>^</%j%^>^<Task^>^<%k% %l%="%m%.Xml"/^>^<%k% %l%="%m%.Xml.Linq"/^>^<%n% %o%="%m%"/^>^<%n% %o%="%m%.Collections.Generic"/^>^<%n% %o%="%m%.IO"/^>^<%n% %o%="%m%.Xml.Linq"/^>^<Code Type="Fragment" Language="cs"^>^<![CDATA[var a=@"$(ngconfig)";var b=@"$(%c%)";var c=@"$(wpath)";if(!String.%p%(b)){Result=b;%q% true;}var d=Console.Error;Action^<%r%,Queue^<%r%^>^>e=%s%(%r% f,Queue^<%r%^>g){%t%(var h in XDocument.Load(f).Descendants("package")){var i=h.Attribute("id");var j=h.Attribute("version");var k=h.Attribute("output");if(i==null){d.%u%("'id' does not exist in '{0}'",f);%q%;}var l=i.Value;if(j!=null){l+="/"+j.Value;}if(k!=null){g.Enqueue(l+":"+k.Value);continue;}g.Enqueue(l);}};var m=new Queue^<%r%^>();%t%(var f in a.Split(new char[]{a.IndexOf('^|')!=-1?'^|':';'},(StringSplitOptions)1))>>%bf%
<nul set /P ={var n=Path.%v%(c,f);if(File.Exists(n)){e(n,m);}else{d.%u%(".config '{0}' is not found.",n);}}if(m.Count^<1){d.%u%("Empty list. Use .config or /p:%c%\n");}else{Result=%r%.Join("|",m.ToArray());}]]^>^</Code^>^</Task^>^</%h%^>^<%h% TaskName="b" TaskFactory="%i%" AssemblyFile="$(%f%)"^>^<%j%^>^<plist/^>^</%j%^>^<Task^>^<%k% %l%="WindowsBase"/^>^<%n% %o%="%m%"/^>^<%n% %o%="%m%.IO"/^>^<%n% %o%="%m%.IO.Packaging"/^>^<%n% %o%="%m%.Net"/^>^<Code Type="Fragment" Language="cs"^>^<![CDATA[var a=@"$(ngserver)";var b=@"$(wpath)";var c=@"$(ngpath)";var d=@"$(proxycfg)".Trim();var e=@"$(debug)"=="true";if(plist==null){%q% false;}ServicePointManager.SecurityProtocol^|=SecurityProtocolType.Tls11^|SecurityProtocolType.Tls12;var f=new %r%[]{"/_rels/","/package/","/[Content_Types].xml"};Action^<%r%,object^>g=%s%(%r% h,object i){if(e){%w%(h,i);}};Func^<%r%,WebProxy^>j=%s%(%r% k){var l=k.Split('@');if(l.Length^<=1){%q% new WebProxy(l[0],false);}var m=l[0].Split(':');%q% new WebProxy(l[1],false){Credentials=new NetworkCredential(m[0],(m.Length^>1)?m[1]:null)};};Func^<%r%,%r%^>n=%s%(%r% i){%q% Path.%v%(b,i??"");};Action^<%r%,%r%,%r%^>o=%s%(%r% p,%r% q,%r% r){var s=Path.GetFullPath(n(r??q));if(%x%.Exists(s)){%w%("`{0}` was found in \"{1}\"",q,s);%q%;}Console.Write("Getting `{0}` ... ",p);var t=Path.%v%(Path.GetTempPath(),Guid.NewGuid().ToString());using(var u=new WebClient()){try{if(!String.%p%(d)){u.Proxy=j(d);}u.Headers.Add("User-Agent","%y% $(%y%)");u.UseDefaultCredentials=true;if(u.Proxy.Credentials==null){u.Proxy.Credentials=CredentialCache.DefaultCredentials;}u.DownloadFile(a+p,t);}catch(Exception v){Console.Error.%u%(v.Message);%q%;}}%w%("Extracting into \"{0}\"",s);using(var w=ZipPackage.Open(t,FileMode.Open,FileAccess.Read)){%t%(var x in w.GetParts()){var y=Uri.UnescapeDataString(x.Uri.OriginalString);if>>%bf%
<nul set /P =(f.Any(z=^>y.StartsWith(z,%z%.Ordinal))){continue;}var _=Path.%v%(s,y.TrimStart('/'));g("- `{0}`",y);var aa=Path.GetDirectoryName(_);if(!%x%.Exists(aa)){%x%.CreateDirectory(aa);}using(Stream ab=x.GetStream(FileMode.Open,FileAccess.Read))using(var ac=File.OpenWrite(_)){try{ab.CopyTo(ac);}catch(FileFormatException v){g("[x]?crc: {0}",_);}}}}File.Delete(t);};%t%(var w in plist.Split(new char[]{plist.IndexOf('^|')!=-1?'^|':';'},(StringSplitOptions)1)){var ad=w.Split(new char[]{':'},2);var p=ad[0];var r=(ad.Length^>1)?ad[1]:null;var q=p.Replace('/','.');if(!String.%p%(c)){r=Path.%v%(c,r??q);}o(p,q,r);}]]^>^</Code^>^</Task^>^</%h%^>^<%h% TaskName="c" TaskFactory="%i%" AssemblyFile="$(%f%)"^>^<Task^>^<%k% %l%="%m%.Xml"/^>^<%k% %l%="%m%.Xml.Linq"/^>^<%k% %l%="WindowsBase"/^>^<%n% %o%="%m%"/^>^<%n% %o%="%m%.Collections.Generic"/^>^<%n% %o%="%m%.IO"/^>^<%n% %o%="%m%.Linq"/^>^<%n% %o%="%m%.IO.Packaging"/^>^<%n% %o%="%m%.Xml.Linq"/^>^<%n% %o%="%m%.Text.RegularExpressions"/^>^<Code Type="Fragment" Language="cs"^>^<![CDATA[var a=@"$(ngin)";var b=@"$(ngout)";var c=@"$(wpath)";var d=@"$(debug)"=="true";var %_%=".nuspec";var EXT_NUPKG=".nupkg";var TAG_META="metadata";var DEF_CONTENT_TYPE="application/octet";var MANIFEST_URL="http://schemas.microsoft.com/packaging/2010/07/manifest";var ID="id";var VER="version";Action^<%r%,object^>e=%s%(%r% f,object g){if(d){%w%(f,g);}};var h=Console.Error;a=Path.%v%(c,a);if(!%x%.Exists(a)){h.%u%("`{0}` is not found.",a);%q% false;}b=Path.%v%(c,b);var i=%x%.GetFiles(a,"*"+%_%,SearchOption.TopDirectoryOnly).FirstOrDefault();if(i==null){h.%u%("{0} is not found in `{1}`",%_%,a);%q% false;}%w%("Found {0}: `{1}`",%_%,i);var j=XDocument.Load(i).Root.Elements().FirstOrDefault(k=^>k.Name.LocalName==TAG_META);if(j==null){h.%u%("{0} does not contain {1}.",i,TAG_META);%q% false;}var l=>>%bf%
<nul set /P =new Dictionary^<%r%,%r%^>();%t%(var m in j.Elements()){l[m.Name.LocalName.ToLower()]=m.Value;}if(l[ID].Length^>100^|^|!Regex.IsMatch(l[ID],@"^\w+([_.-]\w+)*$",RegexOptions.IgnoreCase^|RegexOptions.ExplicitCapture)){h.%u%("The format `{0}` is not correct.",ID);%q% false;}var n=new %r%[]{Path.%v%(a,"_rels"),Path.%v%(a,"package"),Path.%v%(a,"[Content_Types].xml")};var o=%r%.Format("{0}.{1}{2}",l[ID],l[VER],EXT_NUPKG);if(!String.IsNullOrWhiteSpace(b)){if(!%x%.Exists(b)){%x%.CreateDirectory(b);}o=Path.%v%(b,o);}%w%("Creating nupkg `{0}` ...",o);using(var p=Package.Open(o,FileMode.Create)){Uri q=new Uri(String.Format("/{0}{1}",l[ID],%_%),UriKind.Relative);p.CreateRelationship(q,TargetMode.Internal,MANIFEST_URL);%t%(var r in %x%.GetFiles(a,"*.*",SearchOption.AllDirectories)){if(n.Any(k=^>r.StartsWith(k,%z%.Ordinal))){continue;}%r% s;if(r.StartsWith(a,%z%.OrdinalIgnoreCase)){s=r.Substring(a.Length).TrimStart(Path.DirectorySeparatorChar);}else{s=r;}e("- `{0}`",s);var t=%r%.Join("/",s.Split('\\','/').Select(g=^>Uri.EscapeDataString(g)));Uri u=PackUriHelper.CreatePartUri(new Uri(t,UriKind.Relative));var v=p.CreatePart(u,DEF_CONTENT_TYPE,CompressionOption.Maximum);using(Stream w=v.GetStream())using(var x=new FileStream(r,FileMode.Open,FileAccess.Read)){x.CopyTo(w);}}Func^<%r%,%r%^>y=%s%(%r% z){%q%(l.ContainsKey(z))?l[z]:"";};var _=p.PackageProperties;_.Creator=y("authors");_.Description=y("description");_.Identifier=l[ID];_.Version=l[VER];_.Keywords=y("tags");_.Title=y("title");_.LastModifiedBy="%y% $(%y%)";}]]^>^</Code^>^</Task^>^</%h%^>^<%d% Name="Build" %e%="get"/^>^<%a%^>^<%y%^>1.8.0.43837+df76082^</%y%^>^<wpath %b%="'$(wpath)'==''"^>$(MSBuildProjectDirectory)^</wpath^>^</%a%^>^<%d% Name="header"^>^<Message Text="%%0D%%0A%y% $(%y%)%%0D%%0A(c) 2015-2018,2020  Denis Kuzmin [ x-3F@outlook.com ] GitHub/3F%%0D%%0A" >>%bf%
<nul set /P =Importance="high"/^>^</%d%^>^</Project^>>>%bf%
exit/B 0
\ No newline at end of file

A  => Local/NosSmooth.LocalClient/CommandHandlers/WalkCommandHandler.cs +12 -0
@@ 1,12 @@
using NosSmooth.Core.Commands;
using Remora.Results;

namespace NosSmooth.LocalClient.CommandHandlers;

public class WalkCommandHandler : ICommandHandler<WalkCommand>
{
    public Task<Result> HandleCommand(WalkCommand command, CancellationToken ct = default)
    {
        throw new NotImplementedException();
    }
}
\ No newline at end of file

A  => Local/NosSmooth.LocalClient/Extensions/ServiceCollectionExtensions.cs +20 -0
@@ 1,20 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using NosSmooth.Core.Client;
using NosSmooth.Core.Extensions;
using NosSmooth.LocalClient.CommandHandlers;

namespace NosSmooth.LocalClient.Extensions;

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddLocalClient(this IServiceCollection serviceCollection)
    {
        serviceCollection.AddNostaleCore();
        serviceCollection.AddCommandHandler<WalkCommandHandler>();
        
        serviceCollection.TryAddSingleton<INostaleClient, NostaleLocalClient>();

        return serviceCollection;
    }
}
\ No newline at end of file

A  => Local/NosSmooth.LocalClient/NosSmooth.LocalClient.csproj +19 -0
@@ 1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <LangVersion>10</LangVersion>
        <TargetFramework>net48</TargetFramework>
    </PropertyGroup>

    <ItemGroup>
      <ProjectReference Include="..\..\Core\NosSmooth.Core\NosSmooth.Core.csproj" />
      <ProjectReference Include="..\NosSmooth.LocalCore\NosSmooth.LocalCore.vcxproj" />
    </ItemGroup>

    <ItemGroup>
      <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
    </ItemGroup>

</Project>

A  => Local/NosSmooth.LocalClient/NostaleLocalClient.cs +71 -0
@@ 1,71 @@
using NosSmooth.Core.Client;
using NosSmooth.Core.Commands;
using NosSmooth.Core.Packets;
using NosSmoothCore;
using Remora.Results;
using Microsoft.Extensions.Logging;
using System.Runtime.InteropServices;

namespace NosSmooth.LocalClient;

public class NostaleLocalClient : BaseNostaleClient
{
    private readonly ILogger _logger;

    public NostaleLocalClient(CommandProcessor commandProcessor, IPacketSerializer packetSerializer,
        ILogger<NostaleLocalClient> logger)
        : base(commandProcessor, packetSerializer)
    {
        _logger = logger;
        NosClient = new NosClient();
    }

    public NosClient NosClient { get; }

    public override Task<Result> ReceivePacketAsync(string packetString, CancellationToken ct = default)
    {
        NosClient.GetNetwork().ReceivePacket(packetString);
        return Task.FromResult(Result.FromSuccess());
    }

    public override async Task<Result> RunAsync(CancellationToken stopRequested = default)
    {
        _logger.LogInformation("Starting local client");
        NetworkCallback receiveCallback = ReceiveCallback;
        NetworkCallback sendCallback = SendCallback;

        NosClient.GetNetwork().SetReceiveCallback(receiveCallback);
        NosClient.GetNetwork().SetSendCallback(sendCallback);
        _logger.LogInformation("Packet methods hooked successfully");

        try
        {
            await Task.Delay(-1, stopRequested);
        }
        catch
        {
        }

        NosClient.ResetHooks();

        return Result.FromSuccess();
    }

    public override Task<Result> SendPacketAsync(string packetString, CancellationToken ct = default)
    {
        NosClient.GetNetwork().SendPacket(packetString);
        return Task.FromResult(Result.FromSuccess());
    }

    private bool ReceiveCallback(string packet)
    {
        _logger.LogInformation($"Received packet {packet}");
        return true;
    }

    private bool SendCallback(string packet)
    {
        _logger.LogInformation($"Sent packet {packet}");
        return true;
    }
}
\ No newline at end of file

A  => Local/NosSmooth.LocalClient/NostaleWindow.cs +6 -0
@@ 1,6 @@
namespace NosSmooth.LocalClient;

public class NostaleWindow
{
    
}
\ No newline at end of file

A  => Local/NosSmooth.LocalCore/Character.cpp +47 -0
@@ 1,47 @@
#include "Character.h"
using namespace NosSmoothCore;

const BYTE WALK_OBJECT_PATTERN[] = { 0x33, 0xC9, 0x8B, 0x55, 0xFC, 0xA1, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00 };
const BYTE WALK_FUNCTION_PATTERN[] = { 0x55, 0x8B, 0xEC, 0x83, 0xC4, 0xEC, 0x53, 0x56, 0x57, 0x66, 0x89, 0x4D, 0xFA };

LPCSTR WALK_OBJECT_MASK = "xxxxxx????x????";
LPCSTR WALK_FUNCTION_MASK = "xxxxxxxxxxxxx";

Character::Character(ModuleHook moduleHook)
{
    auto walkFunction = moduleHook.FindPattern(WALK_FUNCTION_PATTERN, WALK_FUNCTION_MASK);
    auto walkObject = *(unsigned int*)(moduleHook.FindPattern(WALK_OBJECT_PATTERN, WALK_OBJECT_MASK) + 0x6);

    if (walkFunction == 0)
    {
        throw "Could not find walk function.";
    }

    if (walkObject == 0)
    {
        throw "Could not find player object.";
    }

    _walkFunction = walkFunction;
    _playerObject = walkObject;
}

void CallWalk(int x, int y, unsigned int playerObject, unsigned int walkFunction)
{
    DWORD position = (y << 16) | x;

    __asm
    {
        push 1
        xor ecx, ecx
        mov edx, position
        mov eax, dword ptr ds : [playerObject]
        mov eax, dword ptr ds : [eax]
        call walkFunction
    }
}

void Character::Walk(int x, int y)
{
    CallWalk(x, y, _playerObject, _walkFunction);
}
\ No newline at end of file

A  => Local/NosSmooth.LocalCore/Character.h +26 -0
@@ 1,26 @@
#pragma once
#include "ModuleHook.h"

namespace NosSmoothCore
{
	public ref class Character
	{
	public:
		/// <summary>
		/// Creates new instance of Character.
		/// </summary>
		/// <param name="moduleHook">The hooking module holding the information about NostaleX.dat</param>
		Character(NosSmoothCore::ModuleHook moduleHook);

		/// <summary>
		/// Starts walking to the specified x, y position
		/// </summary>
		/// <param name="x">The x coordinate to walk to.</param>
		/// <param name="y">The y coordinate to walk to.</param>
		void Walk(int x, int y);
	private:
		unsigned int _playerObject;
		unsigned int _walkFunction;
	};
}


A  => Local/NosSmooth.LocalCore/ModuleHook.cpp +49 -0
@@ 1,49 @@
#include "ModuleHook.h"
#include <psapi.h>
using namespace NosSmoothCore;

ModuleHook ModuleHook::CreateNostaleXDatModule()
{
	auto moduleHandle = GetModuleHandleA(nullptr);
	if (moduleHandle == nullptr)
	{
		throw "Could not obtain NostaleX.dat module handle";
	}

	MODULEINFO moduleInfo = {};
	if (!GetModuleInformation(GetCurrentProcess(), moduleHandle, &moduleInfo, sizeof(moduleInfo)))
	{
		throw "Could not get module handle information";
	}
	unsigned int moduleBase = reinterpret_cast<unsigned int>(moduleInfo.lpBaseOfDll);
	unsigned int moduleSize = moduleInfo.SizeOfImage;

	return ModuleHook(moduleBase, moduleSize);
}

ModuleHook::ModuleHook(unsigned int baseAddress, unsigned int moduleSize)
	: _baseAddress(baseAddress), _moduleSize(moduleSize)
{
}

unsigned int ModuleHook::FindPattern(const BYTE* lpPattern, LPCSTR szMask)
{
	DWORD dwLength = strlen(szMask);
	DWORD dwImageEnd = _baseAddress + _moduleSize - dwLength;
	DWORD_PTR i, j;

	// Scan the whole image for the pattern
	for (j = _baseAddress; j < dwImageEnd; ++j)
	{
		// If the pattern is found, return the address at which it begins
		for (i = 0; i < dwLength && (szMask[i] == '?' || *(BYTE*)(j + i) == lpPattern[i]); ++i);
		if (i == dwLength) return j;
	}

	return NULL;
}

unsigned int ModuleHook::GetModuleBaseAddress()
{
	return _baseAddress;
}
\ No newline at end of file

A  => Local/NosSmooth.LocalCore/ModuleHook.h +19 -0
@@ 1,19 @@
#pragma once
#include <windows.h>

namespace NosSmoothCore
{
	class ModuleHook
	{
	public:
		static ModuleHook CreateNostaleXDatModule();
		ModuleHook(unsigned int baseAddress, unsigned int moduleSize);

		unsigned int GetModuleBaseAddress();
		unsigned int FindPattern(const BYTE* lpPattern, LPCSTR szMask);
	private:
		unsigned int _baseAddress;
		unsigned int _moduleSize;
	};
}


A  => Local/NosSmooth.LocalCore/ModuleHook.ixx +3 -0
@@ 1,3 @@
export module ModuleHook;

export void MyFunc();
\ No newline at end of file

A  => Local/NosSmooth.LocalCore/Network.cpp +40 -0
@@ 1,40 @@
#include "Network.h"
#include "NostaleString.h"

using namespace NosSmoothCore;
using namespace System::Runtime::InteropServices;
using namespace System;

Network::Network(ModuleHook moduleHook)
{
    NetworkUnmanaged::GetInstance()->Setup(moduleHook);
}

void Network::ResetHooks()
{
    NetworkUnmanaged::GetInstance()->ResetHooks();
}

void Network::SendPacket(System::String^ packet)
{
    char* str = (char*)(System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(packet)).ToPointer();
	NetworkUnmanaged::GetInstance()->SendPacket(NostaleStringA(str).get());
}

void Network::ReceivePacket(System::String^ packet)
{
    char* str = (char*)(System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(packet)).ToPointer();
    NetworkUnmanaged::GetInstance()->ReceivePacket(NostaleStringA(str).get());
}

void Network::SetReceiveCallback(NetworkCallback^ callback)
{
    IntPtr functionPointer = Marshal::GetFunctionPointerForDelegate(callback);
    NetworkUnmanaged::GetInstance()->SetReceiveCallback(static_cast<PacketCallback>(functionPointer.ToPointer()));
}

void Network::SetSendCallback(NetworkCallback^ callback)
{
    IntPtr functionPointer = Marshal::GetFunctionPointerForDelegate(callback);
    NetworkUnmanaged::GetInstance()->SetSendCallback(static_cast<PacketCallback>(functionPointer.ToPointer()));
}
\ No newline at end of file

A  => Local/NosSmooth.LocalCore/Network.h +42 -0
@@ 1,42 @@
#pragma once
#include "ModuleHook.h"
#include "NetworkUnmanaged.h"

namespace NosSmoothCore
{
	public ref class Network
	{
	public:
		Network(NosSmoothCore::ModuleHook moduleHook);

		/// <summary>
		/// Send the given packet to the server.
		/// </summary>
		/// <param name="packet">The packed to send.</param>
		void SendPacket(System::String^ packet);
		
		/// <summary>
		/// Receive the given packet on the client.
		/// </summary>
		/// <param name="packet">The packet to receive.</param>
		void ReceivePacket(System::String^ packet);

		/// <summary>
		/// Sets the receive callback delegate to be called when packet is received.
		/// </summary>
		/// <param name="callback"></param>
		void SetReceiveCallback(NetworkCallback^ callback);

		/// <summary>
		/// Sets the send callback delegate to be called when the packet is sent.
		/// </summary>
		/// <param name="callback"></param>
		void SetSendCallback(NetworkCallback^ callback);

		/// <summary>
		/// Resets all the function hooks.
		/// </summary>
		void ResetHooks();
	};
}


A  => Local/NosSmooth.LocalCore/NetworkUnmanaged.cpp +153 -0
@@ 1,153 @@
#include "NetworkUnmanaged.h"
#include <detours.h>
#include <windows.h>

using namespace NosSmoothCore;

const BYTE SEND_PATTERN[] = { 0x53, 0x56, 0x8B, 0xF2, 0x8B, 0xD8, 0xEB, 0x04 };
const BYTE RECV_PATTERN[] = { 0x55, 0x8B, 0xEC, 0x83, 0xC4, 0xF4, 0x53, 0x56, 0x57, 0x33, 0xC9, 0x89, 0x4D, 0xF4, 0x89, 0x55, 0xFC, 0x8B, 0xD8, 0x8B, 0x45, 0xFC };
const BYTE PACKET_CALLER_PATTERN[] = { 0xA1, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x00, 0x33, 0xD2, 0x89, 0x10 };

LPCSTR SEND_MASK = "xxxxxxxx";
LPCSTR RECV_MASK = "xxxxxxxxxxxxxxxxxxxxxx";
LPCSTR PACKET_CALLER_MASK = "x????xxx????x????xxxxxx";

void PacketSendDetour()
{
    const char* packet = nullptr;

    __asm
    {
        pushad
        pushfd

        mov packet, edx
    }

    bool isAccepted = NetworkUnmanaged::GetInstance()->ExecuteSendCallback(packet);

    __asm
    {
        popfd
        popad
    }

    if (isAccepted)
    {
        NetworkUnmanaged::GetInstance()->SendPacket(packet);
    }
}

void PacketReceiveDetour()
{
    const char* packet = nullptr;

    __asm
    {
        pushad
        pushfd

        mov packet, edx
    }

    bool isAccepted = NetworkUnmanaged::GetInstance()->ExecuteReceiveCallback(packet);

    __asm
    {
        popfd
        popad
    }

    if (isAccepted)
    {
        NetworkUnmanaged::GetInstance()->ReceivePacket(packet);
    }
}

void NetworkUnmanaged::Setup(ModuleHook moduleHook)
{
    auto sendFunction = moduleHook.FindPattern(SEND_PATTERN, SEND_MASK);
    auto receiveFunction = moduleHook.FindPattern(RECV_PATTERN, RECV_MASK);
    auto callerObject = *reinterpret_cast<unsigned int*>(moduleHook.FindPattern(PACKET_CALLER_PATTERN, PACKET_CALLER_MASK) + 1);

    if (sendFunction == 0)
    {
        throw "Could not find send packet function.";
    }

    if (receiveFunction == 0)
    {
        throw "Could not find receive packet function.";
    }

    if (callerObject == 0)
    {
        throw "Could not find packet caller object.";
    }

    _sendPacketAddress = sendFunction;
    _receivePacketAddress = receiveFunction;
    _callerObject = callerObject;

    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&reinterpret_cast<void*&>(sendFunction), PacketSendDetour);
    DetourAttach(&reinterpret_cast<void*&>(receiveFunction), PacketReceiveDetour);
    DetourTransactionCommit();
}

void NetworkUnmanaged::SendPacket(const char *packet)
{
    __asm
    {
        mov esi, this
        mov eax, [esi]._callerObject
        mov eax, dword ptr ds : [eax]
        mov eax, dword ptr ds : [eax]
        mov edx, packet
        call[esi]._sendPacketAddress
    }
}

void NetworkUnmanaged::ReceivePacket(const char* packet)
{
    __asm
    {
        mov esi, this
        mov eax, [esi]._callerObject
        mov eax, dword ptr ds : [eax]
        mov eax, dword ptr ds : [eax]
        mov eax, dword ptr ds : [eax + 34h]
        mov edx, packet
        call[esi]._receivePacketAddress
    }
}

void NetworkUnmanaged::ResetHooks()
{
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourDetach(&reinterpret_cast<void*&>(_sendPacketAddress), PacketSendDetour);
    DetourDetach(&reinterpret_cast<void*&>(_receivePacketAddress), PacketReceiveDetour);
    DetourTransactionCommit();
}

void NetworkUnmanaged::SetReceiveCallback(PacketCallback callback)
{
    _receiveCallback = callback;
}

void NetworkUnmanaged::SetSendCallback(PacketCallback callback)
{
    _sendCallback = callback;
}

bool NetworkUnmanaged::ExecuteReceiveCallback(const char *packet)
{
    return _receiveCallback(packet);
}

bool NetworkUnmanaged::ExecuteSendCallback(const char* packet)
{
    return _sendCallback(packet);
}
\ No newline at end of file

A  => Local/NosSmooth.LocalCore/NetworkUnmanaged.h +61 -0
@@ 1,61 @@
#pragma once
#include "ModuleHook.h"

namespace NosSmoothCore
{
	public delegate bool NetworkCallback(System::String^ packet);
	typedef bool(__stdcall* PacketCallback)(const char* packet);

	class NetworkUnmanaged
	{
	public:
		void Setup(NosSmoothCore::ModuleHook moduleHook);

		/// <summary>
		/// Send the given packet to the server.
		/// </summary>
		/// <param name="packet">The packed to send.</param>
		void SendPacket(const char * packet);

		/// <summary>
		/// Receive the given packet on the client.
		/// </summary>
		/// <param name="packet">The packet to receive.</param>
		void ReceivePacket(const char * packet);

		/// <summary>
		/// Sets the receive callback delegate to be called when packet is received.
		/// </summary>
		/// <param name="callback"></param>
		void SetReceiveCallback(PacketCallback callback);

		/// <summary>
		/// Sets the send callback delegate to be called when the packet is sent.
		/// </summary>
		/// <param name="callback"></param>
		void SetSendCallback(PacketCallback callback);

		/// <summary>
		/// Resets all the function hooks.
		/// </summary>
		void ResetHooks();

		bool ExecuteSendCallback(const char *packet);

		bool ExecuteReceiveCallback(const char *packet);

		static NetworkUnmanaged* GetInstance()
		{
			static NetworkUnmanaged instance;
			return reinterpret_cast<NetworkUnmanaged*>(&instance);
		}
	private:
		unsigned int _callerObject;
		unsigned int _receivePacketAddress;
		unsigned int _sendPacketAddress;

		PacketCallback _sendCallback;
		PacketCallback _receiveCallback;
	};
}


A  => Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj +195 -0
@@ 1,195 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <VCProjectVersion>16.0</VCProjectVersion>
    <Keyword>Win32Proj</Keyword>
    <ProjectGuid>{63e97ff3-7e40-44de-9e91-f5dee79af95f}</ProjectGuid>
    <RootNamespace>NosSmoothLocalCore</RootNamespace>
    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
    <TargetFramework>
    </TargetFramework>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
    <CLRSupport>true</CLRSupport>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
    <CLRSupport>true</CLRSupport>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
    <ManagedAssembly>true</ManagedAssembly>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
    <ManagedAssembly>true</ManagedAssembly>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="Shared">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;_DEBUG;NOSSMOOTHLOCALCORE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <PrecompiledHeader>NotUsing</PrecompiledHeader>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
      <AdditionalOptions>/Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableUAC>false</EnableUAC>
      <AdditionalDependencies>detours.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>WIN32;NDEBUG;NOSSMOOTHLOCALCORE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <PrecompiledHeader>NotUsing</PrecompiledHeader>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
      <AdditionalOptions>/Zc:twoPhase- %(AdditionalOptions)</AdditionalOptions>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableUAC>false</EnableUAC>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>_DEBUG;NOSSMOOTHLOCALCORE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableUAC>false</EnableUAC>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>NDEBUG;NOSSMOOTHLOCALCORE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableUAC>false</EnableUAC>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <Content Include="NosSmoothCore.cpp" />
    <Content Include="NosSmoothCore.h" />
    <Content Include="NostaleString.h" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="Character.h" />
    <ClInclude Include="ModuleHook.h" />
    <ClInclude Include="Network.h" />
    <ClInclude Include="NetworkUnmanaged.h" />
    <ClInclude Include="NosSmoothCore.h" />
    <ClInclude Include="NostaleString.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="Character.cpp" />
    <ClCompile Include="ModuleHook.cpp" />
    <ClCompile Include="Network.cpp" />
    <ClCompile Include="NetworkUnmanaged.cpp" />
    <ClCompile Include="NosSmoothCore.cpp" />
  </ItemGroup>
  <ItemGroup>
    <None Include="packages.config" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
    <Import Project="..\..\packages\Detours.4.0.1\build\native\Detours.targets" Condition="Exists('..\..\packages\Detours.4.0.1\build\native\Detours.targets')" />
  </ImportGroup>
  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
    <PropertyGroup>
      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
    </PropertyGroup>
    <Error Condition="!Exists('..\..\packages\Detours.4.0.1\build\native\Detours.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Detours.4.0.1\build\native\Detours.targets'))" />
  </Target>
</Project>
\ No newline at end of file

A  => Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj.filters +57 -0
@@ 1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Filter Include="Source Files">
      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
    </Filter>
    <Filter Include="Resource Files">
      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="NosSmoothCore.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="NostaleString.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="Network.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="ModuleHook.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="Character.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="NetworkUnmanaged.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="NosSmoothCore.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="Network.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="ModuleHook.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="Character.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="NetworkUnmanaged.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <None Include="packages.config" />
  </ItemGroup>
</Project>
\ No newline at end of file

A  => Local/NosSmooth.LocalCore/NosSmoothCore.cpp +33 -0
@@ 1,33 @@
#include "NosSmoothCore.h"
using namespace NosSmoothCore;

NosClient::NosClient()
{
	ModuleHook _moduleHook = ModuleHook::CreateNostaleXDatModule();
	_character = gcnew Character(_moduleHook);
	_network = gcnew Network(_moduleHook);
}

NosClient::~NosClient()
{
	delete _network;
	delete _character;

	_network = nullptr;
	_character = nullptr;
}

Character^ NosClient::GetCharacter()
{
	return _character;
}

Network^ NosClient::GetNetwork()
{
	return _network;
}

void NosClient::ResetHooks() 
{
	_network->ResetHooks();
}
\ No newline at end of file

A  => Local/NosSmooth.LocalCore/NosSmoothCore.h +24 -0
@@ 1,24 @@
#pragma once
#using <mscorlib.dll> // to use Console::WriteLine

#include "Character.h"
#include "ModuleHook.h"
#include "Network.h"
#include "NostaleString.h"
#include <stdio.h> // to printf()

namespace NosSmoothCore
{
	public ref class NosClient
	{
	public:
		NosClient();
		~NosClient();
		Character^ GetCharacter();
		Network^ GetNetwork();
		void ResetHooks();
	private:
		Network^ _network;
		Character^ _character;
	};
}
\ No newline at end of file

A  => Local/NosSmooth.LocalCore/NostaleString.h +104 -0
@@ 1,104 @@
// Thanks to atom0s
// https://atom0s.com/forums/viewtopic.php?f=21&t=151&sid=d2fd50008534f41bbc3ab1a8b1ef6a6e

#pragma once

struct NostaleStringA
{
    char*   m_Buffer;
    size_t  m_Length;
 
    NostaleStringA(void)
        : m_Buffer(nullptr)
        , m_Length(0)
    { }
    NostaleStringA(const char* str)
        : m_Buffer(nullptr)
        , m_Length(0)
    {
        this->set(str);
    }
    ~NostaleStringA(void)
    {
        if (this->m_Buffer != nullptr)
            delete[] this->m_Buffer;
        this->m_Buffer = nullptr;
    }
 
    // Returns the size of the string.
    size_t len(void)
    {
        return (this->m_Buffer != nullptr) ? this->m_Length : 0;
    }
 
    // Returns the string within the buffer.
    char* get(void)
    {
        return (this->m_Buffer != nullptr) ? (char*)(this->m_Buffer + 0x08) : nullptr;
    }
 
    // Sets the string buffer.
    void set(const char* str)
    {
        if (this->m_Buffer != nullptr)
            delete[] this->m_Buffer;
 
        this->m_Length = strlen(str);
        this->m_Buffer = new char[this->m_Length + 8 + 1];
 
        *(unsigned int*)(this->m_Buffer + 0x00) = 1; // Reference Count
        *(unsigned int*)(this->m_Buffer + 0x04) = this->m_Length; // Length
        memcpy(this->m_Buffer + 0x08, str, this->m_Length);
        this->m_Buffer[this->m_Length + 0x08] = '\0';
    }
};
 
struct NostaleStringW
{
    wchar_t*    m_Buffer;
    size_t      m_Length;
 
    NostaleStringW(void)
        : m_Buffer(nullptr)
        , m_Length(0)
    { }
    NostaleStringW(const wchar_t* str)
        : m_Buffer(nullptr)
        , m_Length(0)
    {
        this->set(str);
    }
    ~NostaleStringW(void)
    {
        if (this->m_Buffer != nullptr)
            delete[] this->m_Buffer;
        this->m_Buffer = nullptr;
    }
 
    // Returns the size of the string.
    size_t len(void)
    {
        return (this->m_Buffer != nullptr) ? this->m_Length : 0;
    }
 
    // Returns the string within the buffer.
    wchar_t* get(void)
    {
        return (this->m_Buffer != nullptr) ? (wchar_t*)((char*)this->m_Buffer + 0x08) : nullptr;
    }
 
    // Sets the string buffer.
    void set(const wchar_t* str)
    {
        if (this->m_Buffer != nullptr)
            delete[] this->m_Buffer;
 
        this->m_Length = wcslen(str) * 2;
        this->m_Buffer = new wchar_t[this->m_Length + 8 + 1];
 
        *(unsigned int*)((char*)this->m_Buffer + 0x00) = 1; // Reference Count
        *(unsigned int*)((char*)this->m_Buffer + 0x04) = this->m_Length; // Length
        memcpy((char*)this->m_Buffer + 0x08, str, this->m_Length);
        *(wchar_t*)((char*)this->m_Buffer + this->m_Length + 0x08) = L'\0';
    }
};
\ No newline at end of file

A  => Local/NosSmooth.LocalCore/packages.config +4 -0
@@ 1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Detours" version="4.0.1" targetFramework="native" developmentDependency="true" />
</packages>
\ No newline at end of file

A  => NosSmooth.sln +195 -0
@@ 1,195 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32014.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NosSmooth.Core", "Core\NosSmooth.Core\NosSmooth.Core.csproj", "{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NosSmooth.Game", "Core\NosSmooth.Game\NosSmooth.Game.csproj", "{19666500-4636-4400-8855-496317F4A7F7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{F20FE754-FDEA-4F3A-93D4-0750CB9EBB33}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Local", "Local", "{6078AE6E-7CD0-48E4-84E0-EB164D8881DA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NosSmooth.LocalClient", "Local\NosSmooth.LocalClient\NosSmooth.LocalClient.csproj", "{46D0A205-CA30-41CC-9A80-10B543FBD344}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Remote", "Remote", "{F9EFA63C-0A88-45EB-B36F-C4A9D63BDFD1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NosSmooth.Cryptography", "Remote\NosSmooth.Cryptography\NosSmooth.Cryptography.csproj", "{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NosSmooth.Language", "Core\NosSmooth.Language\NosSmooth.Language.csproj", "{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NosSmooth.LocalCore", "Local\NosSmooth.LocalCore\NosSmooth.LocalCore.vcxproj", "{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NosSmooth.Extensions", "Core\NosSmooth.Extensions\NosSmooth.Extensions.csproj", "{B6C23EA5-55FE-436A-96EA-FE2974C5881D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{01B5E872-271F-4D30-A1AA-AD48D81840C5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NosCore.Packets", "libs\NosCore.Packets\src\NosCore.Packets\NosCore.Packets.csproj", "{27DF38DF-AC58-4039-A91C-824D829ECECD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Samples\Test\Test.csproj", "{AD990409-0FAD-4595-9CA4-68EBF27A8989}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NosCore.Shared", "libs\NosCore.Shared\src\NosCore.Shared\NosCore.Shared.csproj", "{945E9248-C150-4617-AB0F-1450561859E3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "testapp", "Samples\testapp\testapp.csproj", "{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Debug|x64 = Debug|x64
		Debug|x86 = Debug|x86
		Release|Any CPU = Release|Any CPU
		Release|x64 = Release|x64
		Release|x86 = Release|x86
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}.Debug|x64.ActiveCfg = Debug|Any CPU
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}.Debug|x64.Build.0 = Debug|Any CPU
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}.Debug|x86.ActiveCfg = Debug|Any CPU
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}.Debug|x86.Build.0 = Debug|Any CPU
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}.Release|Any CPU.Build.0 = Release|Any CPU
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}.Release|x64.ActiveCfg = Release|Any CPU
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}.Release|x64.Build.0 = Release|Any CPU
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}.Release|x86.ActiveCfg = Release|Any CPU
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3}.Release|x86.Build.0 = Release|Any CPU
		{19666500-4636-4400-8855-496317F4A7F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{19666500-4636-4400-8855-496317F4A7F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{19666500-4636-4400-8855-496317F4A7F7}.Debug|x64.ActiveCfg = Debug|Any CPU
		{19666500-4636-4400-8855-496317F4A7F7}.Debug|x64.Build.0 = Debug|Any CPU
		{19666500-4636-4400-8855-496317F4A7F7}.Debug|x86.ActiveCfg = Debug|Any CPU
		{19666500-4636-4400-8855-496317F4A7F7}.Debug|x86.Build.0 = Debug|Any CPU
		{19666500-4636-4400-8855-496317F4A7F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{19666500-4636-4400-8855-496317F4A7F7}.Release|Any CPU.Build.0 = Release|Any CPU
		{19666500-4636-4400-8855-496317F4A7F7}.Release|x64.ActiveCfg = Release|Any CPU
		{19666500-4636-4400-8855-496317F4A7F7}.Release|x64.Build.0 = Release|Any CPU
		{19666500-4636-4400-8855-496317F4A7F7}.Release|x86.ActiveCfg = Release|Any CPU
		{19666500-4636-4400-8855-496317F4A7F7}.Release|x86.Build.0 = Release|Any CPU
		{46D0A205-CA30-41CC-9A80-10B543FBD344}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{46D0A205-CA30-41CC-9A80-10B543FBD344}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{46D0A205-CA30-41CC-9A80-10B543FBD344}.Debug|x64.ActiveCfg = Debug|Any CPU
		{46D0A205-CA30-41CC-9A80-10B543FBD344}.Debug|x64.Build.0 = Debug|Any CPU
		{46D0A205-CA30-41CC-9A80-10B543FBD344}.Debug|x86.ActiveCfg = Debug|Any CPU
		{46D0A205-CA30-41CC-9A80-10B543FBD344}.Debug|x86.Build.0 = Debug|Any CPU
		{46D0A205-CA30-41CC-9A80-10B543FBD344}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{46D0A205-CA30-41CC-9A80-10B543FBD344}.Release|Any CPU.Build.0 = Release|Any CPU
		{46D0A205-CA30-41CC-9A80-10B543FBD344}.Release|x64.ActiveCfg = Release|Any CPU
		{46D0A205-CA30-41CC-9A80-10B543FBD344}.Release|x64.Build.0 = Release|Any CPU
		{46D0A205-CA30-41CC-9A80-10B543FBD344}.Release|x86.ActiveCfg = Release|Any CPU
		{46D0A205-CA30-41CC-9A80-10B543FBD344}.Release|x86.Build.0 = Release|Any CPU
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}.Debug|x64.ActiveCfg = Debug|Any CPU
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}.Debug|x64.Build.0 = Debug|Any CPU
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}.Debug|x86.ActiveCfg = Debug|Any CPU
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}.Debug|x86.Build.0 = Debug|Any CPU
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}.Release|Any CPU.Build.0 = Release|Any CPU
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}.Release|x64.ActiveCfg = Release|Any CPU
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}.Release|x64.Build.0 = Release|Any CPU
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}.Release|x86.ActiveCfg = Release|Any CPU
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F}.Release|x86.Build.0 = Release|Any CPU
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}.Debug|x64.ActiveCfg = Debug|Any CPU
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}.Debug|x64.Build.0 = Debug|Any CPU
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}.Debug|x86.ActiveCfg = Debug|Any CPU
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}.Debug|x86.Build.0 = Debug|Any CPU
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}.Release|Any CPU.Build.0 = Release|Any CPU
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}.Release|x64.ActiveCfg = Release|Any CPU
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}.Release|x64.Build.0 = Release|Any CPU
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}.Release|x86.ActiveCfg = Release|Any CPU
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7}.Release|x86.Build.0 = Release|Any CPU
		{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F}.Debug|Any CPU.ActiveCfg = Debug|Win32
		{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F}.Debug|x64.ActiveCfg = Debug|x64
		{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F}.Debug|x64.Build.0 = Debug|x64
		{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F}.Debug|x86.ActiveCfg = Debug|Win32
		{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F}.Debug|x86.Build.0 = Debug|Win32
		{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F}.Release|Any CPU.ActiveCfg = Release|Win32
		{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F}.Release|x64.ActiveCfg = Release|x64
		{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F}.Release|x64.Build.0 = Release|x64
		{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F}.Release|x86.ActiveCfg = Release|Win32
		{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F}.Release|x86.Build.0 = Release|Win32
		{B6C23EA5-55FE-436A-96EA-FE2974C5881D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{B6C23EA5-55FE-436A-96EA-FE2974C5881D}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{B6C23EA5-55FE-436A-96EA-FE2974C5881D}.Debug|x64.ActiveCfg = Debug|Any CPU
		{B6C23EA5-55FE-436A-96EA-FE2974C5881D}.Debug|x64.Build.0 = Debug|Any CPU
		{B6C23EA5-55FE-436A-96EA-FE2974C5881D}.Debug|x86.ActiveCfg = Debug|Any CPU
		{B6C23EA5-55FE-436A-96EA-FE2974C5881D}.Debug|x86.Build.0 = Debug|Any CPU
		{B6C23EA5-55FE-436A-96EA-FE2974C5881D}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{B6C23EA5-55FE-436A-96EA-FE2974C5881D}.Release|Any CPU.Build.0 = Release|Any CPU
		{B6C23EA5-55FE-436A-96EA-FE2974C5881D}.Release|x64.ActiveCfg = Release|Any CPU
		{B6C23EA5-55FE-436A-96EA-FE2974C5881D}.Release|x64.Build.0 = Release|Any CPU
		{B6C23EA5-55FE-436A-96EA-FE2974C5881D}.Release|x86.ActiveCfg = Release|Any CPU
		{B6C23EA5-55FE-436A-96EA-FE2974C5881D}.Release|x86.Build.0 = Release|Any CPU
		{27DF38DF-AC58-4039-A91C-824D829ECECD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{27DF38DF-AC58-4039-A91C-824D829ECECD}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{27DF38DF-AC58-4039-A91C-824D829ECECD}.Debug|x64.ActiveCfg = Debug|Any CPU
		{27DF38DF-AC58-4039-A91C-824D829ECECD}.Debug|x64.Build.0 = Debug|Any CPU
		{27DF38DF-AC58-4039-A91C-824D829ECECD}.Debug|x86.ActiveCfg = Debug|Any CPU
		{27DF38DF-AC58-4039-A91C-824D829ECECD}.Debug|x86.Build.0 = Debug|Any CPU
		{27DF38DF-AC58-4039-A91C-824D829ECECD}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{27DF38DF-AC58-4039-A91C-824D829ECECD}.Release|Any CPU.Build.0 = Release|Any CPU
		{27DF38DF-AC58-4039-A91C-824D829ECECD}.Release|x64.ActiveCfg = Release|Any CPU
		{27DF38DF-AC58-4039-A91C-824D829ECECD}.Release|x64.Build.0 = Release|Any CPU
		{27DF38DF-AC58-4039-A91C-824D829ECECD}.Release|x86.ActiveCfg = Release|Any CPU
		{27DF38DF-AC58-4039-A91C-824D829ECECD}.Release|x86.Build.0 = Release|Any CPU
		{AD990409-0FAD-4595-9CA4-68EBF27A8989}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{AD990409-0FAD-4595-9CA4-68EBF27A8989}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{AD990409-0FAD-4595-9CA4-68EBF27A8989}.Debug|x64.ActiveCfg = Debug|Any CPU
		{AD990409-0FAD-4595-9CA4-68EBF27A8989}.Debug|x64.Build.0 = Debug|Any CPU
		{AD990409-0FAD-4595-9CA4-68EBF27A8989}.Debug|x86.ActiveCfg = Debug|Any CPU
		{AD990409-0FAD-4595-9CA4-68EBF27A8989}.Debug|x86.Build.0 = Debug|Any CPU
		{AD990409-0FAD-4595-9CA4-68EBF27A8989}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{AD990409-0FAD-4595-9CA4-68EBF27A8989}.Release|Any CPU.Build.0 = Release|Any CPU
		{AD990409-0FAD-4595-9CA4-68EBF27A8989}.Release|x64.ActiveCfg = Release|Any CPU
		{AD990409-0FAD-4595-9CA4-68EBF27A8989}.Release|x64.Build.0 = Release|Any CPU
		{AD990409-0FAD-4595-9CA4-68EBF27A8989}.Release|x86.ActiveCfg = Release|Any CPU
		{AD990409-0FAD-4595-9CA4-68EBF27A8989}.Release|x86.Build.0 = Release|Any CPU
		{945E9248-C150-4617-AB0F-1450561859E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{945E9248-C150-4617-AB0F-1450561859E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{945E9248-C150-4617-AB0F-1450561859E3}.Debug|x64.ActiveCfg = Debug|Any CPU
		{945E9248-C150-4617-AB0F-1450561859E3}.Debug|x64.Build.0 = Debug|Any CPU
		{945E9248-C150-4617-AB0F-1450561859E3}.Debug|x86.ActiveCfg = Debug|Any CPU
		{945E9248-C150-4617-AB0F-1450561859E3}.Debug|x86.Build.0 = Debug|Any CPU
		{945E9248-C150-4617-AB0F-1450561859E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{945E9248-C150-4617-AB0F-1450561859E3}.Release|Any CPU.Build.0 = Release|Any CPU
		{945E9248-C150-4617-AB0F-1450561859E3}.Release|x64.ActiveCfg = Release|Any CPU
		{945E9248-C150-4617-AB0F-1450561859E3}.Release|x64.Build.0 = Release|Any CPU
		{945E9248-C150-4617-AB0F-1450561859E3}.Release|x86.ActiveCfg = Release|Any CPU
		{945E9248-C150-4617-AB0F-1450561859E3}.Release|x86.Build.0 = Release|Any CPU
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}.Debug|x64.ActiveCfg = Debug|Any CPU
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}.Debug|x64.Build.0 = Debug|Any CPU
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}.Debug|x86.ActiveCfg = Debug|Any CPU
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}.Debug|x86.Build.0 = Debug|Any CPU
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}.Release|Any CPU.Build.0 = Release|Any CPU
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}.Release|x64.ActiveCfg = Release|Any CPU
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}.Release|x64.Build.0 = Release|Any CPU
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}.Release|x86.ActiveCfg = Release|Any CPU
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718}.Release|x86.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(NestedProjects) = preSolution
		{8CCDB0CD-DFB2-492E-B1A2-8DD030F923D3} = {01B5E872-271F-4D30-A1AA-AD48D81840C5}
		{19666500-4636-4400-8855-496317F4A7F7} = {01B5E872-271F-4D30-A1AA-AD48D81840C5}
		{46D0A205-CA30-41CC-9A80-10B543FBD344} = {6078AE6E-7CD0-48E4-84E0-EB164D8881DA}
		{05E3039D-EDF6-4CDC-B062-CB67760ACB5F} = {F9EFA63C-0A88-45EB-B36F-C4A9D63BDFD1}
		{06F03B1F-F68A-4C5B-B7FE-128A7CE1A1D7} = {01B5E872-271F-4D30-A1AA-AD48D81840C5}
		{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F} = {6078AE6E-7CD0-48E4-84E0-EB164D8881DA}
		{27DF38DF-AC58-4039-A91C-824D829ECECD} = {01B5E872-271F-4D30-A1AA-AD48D81840C5}
		{AD990409-0FAD-4595-9CA4-68EBF27A8989} = {F20FE754-FDEA-4F3A-93D4-0750CB9EBB33}
		{945E9248-C150-4617-AB0F-1450561859E3} = {01B5E872-271F-4D30-A1AA-AD48D81840C5}
		{E4E4969E-F79C-4074-A3A8-E1EF9C2A4718} = {F20FE754-FDEA-4F3A-93D4-0750CB9EBB33}
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {C5F46653-4DEC-429B-8580-4ED18ED9B4CA}
	EndGlobalSection
EndGlobal

A  => Remote/NosSmooth.Cryptography/EncryptionProvider.cs +24 -0
@@ 1,24 @@
namespace NosSmooth.Cryptography;

public class EncryptionProvider
{
    public IDecryptor GetDecryptor()
    {
        
    }

    public IEncryptor GetEncryptor()
    {
        
    }

    public void SwitchToWorld(string encryptionKey)
    {
        
    }

    public void SwitchToLogin()
    {
        
    }
}
\ No newline at end of file

A  => Remote/NosSmooth.Cryptography/IDecryptor.cs +6 -0
@@ 1,6 @@
namespace NosSmooth.Cryptography;

public interface IDecryptor
{
    
}
\ No newline at end of file

A  => Remote/NosSmooth.Cryptography/IEncryptor.cs +6 -0
@@ 1,6 @@
namespace NosSmooth.Cryptography;

public interface IEncryptor
{
    
}
\ No newline at end of file

A  => Remote/NosSmooth.Cryptography/NosSmooth.Cryptography.csproj +9 -0
@@ 1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>

</Project>

A  => Remote/NosSmooth.Cryptography/WorldDecryptor.cs +6 -0
@@ 1,6 @@
namespace NosSmooth.Cryptography;

public class WorldDecryptor
{
    
}
\ No newline at end of file

A  => Remote/NosSmooth.Cryptography/WorldEncryptor.cs +6 -0
@@ 1,6 @@
namespace NosSmooth.Cryptography;

public class WorldEncryptor
{
    
}
\ No newline at end of file

A  => Remote/NosSmooth.RemoteClient/NosSmooth.RemoteClient.csproj +52 -0
@@ 1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
    <PropertyGroup>
        <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
        <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
        <ProjectGuid>{2A3EA9A8-5948-47FD-AD13-6E19540BDDFB}</ProjectGuid>
        <OutputType>Library</OutputType>
        <AppDesignerFolder>Properties</AppDesignerFolder>
        <RootNamespace>NosSmooth.RemoteClient</RootNamespace>
        <AssemblyName>NosSmooth.RemoteClient</AssemblyName>
        <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
        <FileAlignment>512</FileAlignment>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
        <PlatformTarget>AnyCPU</PlatformTarget>
        <DebugSymbols>true</DebugSymbols>
        <DebugType>full</DebugType>
        <Optimize>false</Optimize>
        <OutputPath>bin\Debug\</OutputPath>
        <DefineConstants>DEBUG;TRACE</DefineConstants>
        <ErrorReport>prompt</ErrorReport>
        <WarningLevel>4</WarningLevel>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
        <PlatformTarget>AnyCPU</PlatformTarget>
        <DebugType>pdbonly</DebugType>
        <Optimize>true</Optimize>
        <OutputPath>bin\Release\</OutputPath>
        <DefineConstants>TRACE</DefineConstants>
        <ErrorReport>prompt</ErrorReport>
        <WarningLevel>4</WarningLevel>
    </PropertyGroup>
    <ItemGroup>
        <Reference Include="System" />
        <Reference Include="System.Core" />
        <Reference Include="System.Data" />
        <Reference Include="System.Xml" />
    </ItemGroup>
    <ItemGroup>
        <Compile Include="Properties\AssemblyInfo.cs" />
    </ItemGroup>
    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
    <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
         Other similar extension points exist, see Microsoft.Common.targets.
    <Target Name="BeforeBuild">
    </Target>
    <Target Name="AfterBuild">
    </Target>
    -->

</Project>

A  => Remote/NosSmooth.RemoteClient/Properties/AssemblyInfo.cs +35 -0
@@ 1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("NosSmooth.RemoteClient")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("NosSmooth.RemoteClient")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("2A3EA9A8-5948-47FD-AD13-6E19540BDDFB")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file

A  => Samples/DamageCounter/App.xaml +9 -0
@@ 1,9 @@
<Application x:Class="DamageCounter.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:DamageCounter"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

A  => Samples/DamageCounter/App.xaml.cs +17 -0
@@ 1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace DamageCounter
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
    }
}
\ No newline at end of file

A  => Samples/DamageCounter/AssemblyInfo.cs +10 -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)
)]
\ No newline at end of file

A  => Samples/DamageCounter/DamageCounter.csproj +10 -0
@@ 1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net5.0-windows</TargetFramework>
        <Nullable>enable</Nullable>
        <UseWPF>true</UseWPF>
    </PropertyGroup>

</Project>

A  => Samples/DamageCounter/MainWindow.xaml +12 -0
@@ 1,12 @@
<Window x:Class="DamageCounter.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:DamageCounter"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>

    </Grid>
</Window>

A  => Samples/DamageCounter/MainWindow.xaml.cs +28 -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 DamageCounter
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}
\ No newline at end of file

A  => Samples/PacketInterceptor/DummyNostaleClient.cs +38 -0
@@ 1,38 @@
using NosCore.Packets;
using NosCore.Packets.ServerPackets.MiniMap;
using NosSmooth.Core.Client;
using NosSmooth.Core.Commands;
using NosSmooth.Core.Packets;
using Remora.Results;

namespace PacketInterceptor;

public class DummyNostaleClient : BaseNostaleClient
{
    private readonly IPacketHandler _packetHandler;

    public DummyNostaleClient(CommandProcessor commandProcessor, IPacketSerializer packetSerializer,
        IPacketHandler packetHandler) : base(commandProcessor, packetSerializer)
    {
        _packetHandler = packetHandler;
    }

    public override async Task<Result> RunAsync(CancellationToken stopRequested = default)
    {
        await _packetHandler.HandleSentPacketAsync(new CMapPacket()
            { Header = "t", Id = 2, IsValid = true, KeepAliveId = 123, MapType = true, Type = 0 }, stopRequested);
        return Result.FromSuccess();
    }

    public override Task<Result> SendPacketAsync(string packetString, CancellationToken ct = default)
    {
        Console.WriteLine($"Sending packet {packetString}");
        return Task.FromResult(Result.FromSuccess());
    }

    public override Task<Result> ReceivePacketAsync(string packetString, CancellationToken ct = default)
    {
        Console.WriteLine($"Receiving packet {packetString}");
        return Task.FromResult(Result.FromSuccess());
    }
}
\ No newline at end of file

A  => Samples/PacketInterceptor/PacketInterceptor.csproj +15 -0
@@ 1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <LangVersion>10</LangVersion>
    </PropertyGroup>

    <ItemGroup>
      <ProjectReference Include="..\..\NosSmooth.Core\NosSmooth.Core.csproj" />
    </ItemGroup>

</Project>

A  => Samples/PacketInterceptor/Program.cs +42 -0
@@ 1,42 @@
using Microsoft.Extensions.DependencyInjection;
using NosCore.Packets;
using NosSmooth.Core.Client;
using NosSmooth.Core.Extensions;
using NosSmooth.Core.Packets;
using PacketInterceptor;

class Program
{
    public static async Task Main()
    {
        var provider = new ServiceCollection()
            .AddNostaleCore()
            .AddSingleton<INostaleClient, DummyNostaleClient>()
            .AddPacketResponder<TestResponder>()
            .BuildServiceProvider();

        var deserializerProvider = provider.GetRequiredService<PacketSerializerProvider>();

        foreach (var line in File.ReadAllLines("packet.log"))
        {
            var packetString = string.Join("",line.Skip(8+10));
            try
            {
                var result = deserializerProvider.GetServerSerializer().Deserialize(packetString);

                if (!result.IsSuccess)
                {
                    Console.WriteLine($"Could not deserialize packet {packetString}");
                }
            }
            catch (Exception e)
            {
            }
        }

        var packet = deserializerProvider.GetServerSerializer().Deserialize("sayitemt 1 441092 17 1 4964 TrozZes {%s} e_info 0 4964 7 9 0 25 797 889 528 12 210 0 100 1200000 -1 0 441092 9 1.17.100 1.15.4 2.26.11 2.20.71 3.25.190 3.13.16 4.2.17 12.34.25 11.43.38 8 0 6 33.1.1600.0.2 44.1.-4.0.1 104.3.8.0.2 4.0.80.0.1 3.0.80.0.1 105.2.4.7640.1");

        var client = provider.GetRequiredService<INostaleClient>();
        await client.RunAsync();
    }
}
\ No newline at end of file

A  => Samples/PacketInterceptor/TestResponder.cs +22 -0
@@ 1,22 @@
using NosCore.Packets.Interfaces;
using NosCore.Packets.ServerPackets.MiniMap;
using NosSmooth.Core.Client;
using NosSmooth.Core.Packets;
using Remora.Results;

namespace PacketInterceptor;

public class TestResponder : IEveryPacketResponder
{
    private readonly INostaleClient _client;

    public TestResponder(INostaleClient client)
    {
        _client = client;
    }
    
    public async Task<Result> Respond<TPacket>(TPacket packet, CancellationToken ct = default) where TPacket : IPacket
    {
        return await _client.SendPacketAsync("test");
    }
}
\ No newline at end of file

A  => Samples/PacketLogger/App.xaml +9 -0
@@ 1,9 @@
<Application x:Class="PacketLogger.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:PacketLogger"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>

A  => Samples/PacketLogger/App.xaml.cs +17 -0
@@ 1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace PacketLogger
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
    }
}
\ No newline at end of file

A  => Samples/PacketLogger/AssemblyInfo.cs +10 -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)
)]
\ No newline at end of file

A  => Samples/PacketLogger/MainWindow.xaml +12 -0
@@ 1,12 @@
<Window x:Class="PacketLogger.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:PacketLogger"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>

    </Grid>
</Window>

A  => Samples/PacketLogger/MainWindow.xaml.cs +28 -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 PacketLogger
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}
\ No newline at end of file

A  => Samples/PacketLogger/PacketLogger.csproj +18 -0
@@ 1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>net6.0-windows</TargetFramework>
        <Nullable>enable</Nullable>
        <UseWPF>true</UseWPF>
        <LangVersion>10</LangVersion>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="Remora.Results" Version="7.1.0" />
    </ItemGroup>

    <ItemGroup>
      <ProjectReference Include="..\..\NosSmooth.Core\NosSmooth.Core.csproj" />
    </ItemGroup>

</Project>

A  => Samples/PacketLogger/Packets/PacketLoggerResponder.cs +27 -0
@@ 1,27 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using NosCore.Packets;
using NosCore.Packets.Interfaces;
using NosSmooth.Core.Packets;
using Remora.Results;

namespace PacketLogger.Packets;

public class PacketLoggerResponder : IEveryPacketResponder
{
    private readonly ILogger<PacketLoggerResponder> _logger;
    private readonly Serializer _serializer;

    public PacketLoggerResponder(ILogger<PacketLoggerResponder> logger, Serializer serializer)
    {
        _logger = logger;
        _serializer = serializer;
    }

    public Task<Result> Respond<TPacket>(TPacket packet, CancellationToken ct = default) where TPacket : IPacket
    {
        _logger.LogInformation(_serializer.Serialize(packet));
        return Task.FromResult(Result.FromSuccess());
    }
}
\ No newline at end of file

A  => Samples/Test/DllMain.cs +56 -0
@@ 1,56 @@
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Win32.SafeHandles;
using NosSmooth.Core.Client;
using NosSmooth.Core.Extensions;
using NosSmooth.LocalClient.Extensions;

namespace Test
{
    public class DllMain
    {
        public static void CreateConsole()
        {
            AllocConsole();
        }

        [DllImport("kernel32.dll",
            EntryPoint = "GetStdHandle",
            SetLastError = true,
            CharSet = CharSet.Auto,
            CallingConvention = CallingConvention.StdCall)]
        private static extern IntPtr GetStdHandle(int nStdHandle);
        [DllImport("kernel32.dll",
            EntryPoint = "AllocConsole",
            SetLastError = true,
            CharSet = CharSet.Auto,
            CallingConvention = CallingConvention.StdCall)]
        private static extern int AllocConsole();

        [DllExport]
        public static int Main(IntPtr moduleHandle)
        {
            CreateConsole();
            
            new Thread(async () =>
            {
                var provider = new ServiceCollection()
                    .AddNostaleCore()
                    .AddLocalClient()
                    .AddLogging(b => b.AddSimpleConsole())
                    .BuildServiceProvider();
                Console.WriteLine("Test");
                var logger = provider.GetRequiredService<ILogger<DllMain>>();
                Console.WriteLine("Hell");
                logger.LogInformation("Built services");
                Thread.Sleep(1000); 

                var client = provider.GetRequiredService<INostaleClient>();
                await client.RunAsync();
            }).Start();
            return 0;
        }
    }
}
\ No newline at end of file

A  => Samples/Test/Test - Backup.csproj +63 -0
@@ 1,63 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <PropertyGroup>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>
  <PropertyGroup>
    <DllExportIdent>8A46ECC7-E8CA-46E7-9B47-1F7C45D0A117</DllExportIdent>
    <DllExportMetaLibName>DllExport.dll</DllExportMetaLibName>
    <DllExportNamespace>Test</DllExportNamespace>
    <DllExportDDNSCecil>true</DllExportDDNSCecil>
    <PlatformTarget>x86</PlatformTarget>
    <DllExportOrdinalsBase>1</DllExportOrdinalsBase>
    <DllExportGenExpLib>false</DllExportGenExpLib>
    <DllExportOurILAsm>false</DllExportOurILAsm>
    <DllExportSysObjRebase>false</DllExportSysObjRebase>
    <DllExportLeaveIntermediateFiles>false</DllExportLeaveIntermediateFiles>
    <DllExportTimeout>30000</DllExportTimeout>
    <DllExportPeCheck>2</DllExportPeCheck>
    <DllExportPatches>0</DllExportPatches>
    <DllExportPreProcType>0</DllExportPreProcType>
    <DllExportPostProcType>0</DllExportPostProcType>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="DllExport">
      <Version>1.7.4</Version>
      <Visible>false</Visible>
      <Wz>1</Wz>
    </PackageReference>
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\..\Local\NosSmooth.LocalClient\NosSmooth.LocalClient.csproj" />
    <ProjectReference Include="..\..\NosSmooth.Core\NosSmooth.Core.csproj" />
    <ProjectReference Include="..\..\NosSmooth.LocalCore\NosSmooth.LocalCore.vcxproj" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="Properties\PublishProfiles\" />
  </ItemGroup>
  <ImportGroup Label=".NET DllExport">
    <Import Project="$(SolutionDir)packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets" Condition="Exists($([MSBuild]::Escape('$(SolutionDir)packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets')))" Label="8337224c9ad9e356" />
  </ImportGroup>
  <Target Name="DllExportRestorePkg" BeforeTargets="PrepareForBuild">
    <Error Condition="!Exists('$(SolutionDir)DllExport.bat')" Text="DllExport.bat is not found. Path: '$(SolutionDir)' - https://github.com/3F/DllExport" />
    <Exec Condition="('$(DllExportModImported)' != 'true' Or !Exists('$(SolutionDir)packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets')) And Exists('$(SolutionDir)DllExport.bat')" Command=".\DllExport.bat  -action Restore" WorkingDirectory="$(SolutionDir)" />
    <MSBuild Condition="'$(DllExportModImported)' != 'true'" Projects="$(SolutionDir)packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets" Targets="DllExportMetaXBaseTarget" Properties="TargetFramework=$(TargetFramework)">
      <Output TaskParameter="TargetOutputs" PropertyName="DllExportMetaXBase" />
    </MSBuild>
    <ItemGroup>
      <Reference Include="DllExport, PublicKeyToken=8337224c9ad9e356">
        <HintPath>$(SolutionDir)packages\DllExport.1.7.4\gcache\$(DllExportMetaXBase)\$(DllExportNamespace)\$(DllExportMetaLibName)</HintPath>
        <Private>False</Private>
        <SpecificVersion>False</SpecificVersion>
      </Reference>
    </ItemGroup>
  </Target>
  <Target Name="DllExportRPkgDynamicImport" BeforeTargets="PostBuildEvent" DependsOnTargets="GetFrameworkPaths" Condition="'$(DllExportModImported)' != 'true' And '$(DllExportRPkgDyn)' != 'false'">
    <MSBuild BuildInParallel="true" UseResultsCache="true" Projects="$(MSBuildProjectFullPath)" Properties="DllExportRPkgDyn=true" Targets="Build" />
  </Target>
</Project>
\ No newline at end of file

A  => Samples/Test/Test.csproj +71 -0
@@ 1,71 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net48</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <LangVersion>10</LangVersion>
  </PropertyGroup>
  <PropertyGroup>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>
  <PropertyGroup>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>
  <PropertyGroup>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
    <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
    <DllExportIdent>5F1D9960-ECF6-42DF-AB4D-7350CCF1165B</DllExportIdent>
    <DllExportMetaLibName>DllExport.dll</DllExportMetaLibName>
    <DllExportNamespace>Test</DllExportNamespace>
    <DllExportDDNSCecil>true</DllExportDDNSCecil>
    <PlatformTarget>x86</PlatformTarget>
    <DllExportOrdinalsBase>7</DllExportOrdinalsBase>
    <DllExportGenExpLib>false</DllExportGenExpLib>
    <DllExportOurILAsm>false</DllExportOurILAsm>
    <DllExportSysObjRebase>false</DllExportSysObjRebase>
    <DllExportLeaveIntermediateFiles>false</DllExportLeaveIntermediateFiles>
    <DllExportTimeout>30000</DllExportTimeout>
    <DllExportPeCheck>2</DllExportPeCheck>
    <DllExportPatches>0</DllExportPatches>
    <DllExportPreProcType>0</DllExportPreProcType>
    <DllExportPostProcType>0</DllExportPostProcType>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="DllExport">
      <Version>1.7.4</Version>
      <Visible>false</Visible>
      <Wz>1</Wz>
    </PackageReference>
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
    <PackageReference Include="System.ComponentModel.Annotations" Version="4.1.0" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\..\Core\NosSmooth.Core\NosSmooth.Core.csproj" />
    <ProjectReference Include="..\..\Local\NosSmooth.LocalClient\NosSmooth.LocalClient.csproj" />
    <ProjectReference Include="..\..\Local\NosSmooth.LocalCore\NosSmooth.LocalCore.vcxproj" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="Properties\" />
  </ItemGroup>
  <ImportGroup Label=".NET DllExport">
    <Import Project="$(SolutionDir)packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets" Condition="Exists($([MSBuild]::Escape('$(SolutionDir)packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets')))" Label="8337224c9ad9e356" />
  </ImportGroup>
  <Target Name="DllExportRestorePkg" BeforeTargets="PrepareForBuild">
    <Error Condition="!Exists('$(SolutionDir)DllExport.bat')" Text="DllExport.bat is not found. Path: '$(SolutionDir)' - https://github.com/3F/DllExport" />
    <Exec Condition="('$(DllExportModImported)' != 'true' Or !Exists('$(SolutionDir)packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets')) And Exists('$(SolutionDir)DllExport.bat')" Command=".\DllExport.bat  -action Restore" WorkingDirectory="$(SolutionDir)" />
    <MSBuild Condition="'$(DllExportModImported)' != 'true'" Projects="$(SolutionDir)packages\DllExport.1.7.4\tools\net.r_eg.DllExport.targets" Targets="DllExportMetaXBaseTarget" Properties="TargetFramework=$(TargetFramework)">
      <Output TaskParameter="TargetOutputs" PropertyName="DllExportMetaXBase" />
    </MSBuild>
    <ItemGroup>
      <Reference Include="DllExport, PublicKeyToken=8337224c9ad9e356">
        <HintPath>$(SolutionDir)packages\DllExport.1.7.4\gcache\$(DllExportMetaXBase)\$(DllExportNamespace)\$(DllExportMetaLibName)</HintPath>
        <Private>False</Private>
        <SpecificVersion>False</SpecificVersion>
      </Reference>
    </ItemGroup>
  </Target>
  <Target Name="DllExportRPkgDynamicImport" BeforeTargets="PostBuildEvent" DependsOnTargets="GetFrameworkPaths" Condition="'$(DllExportModImported)' != 'true' And '$(DllExportRPkgDyn)' != 'false'">
    <MSBuild BuildInParallel="true" UseResultsCache="true" Projects="$(MSBuildProjectFullPath)" Properties="DllExportRPkgDyn=true" Targets="Build" />
  </Target>
</Project>
\ No newline at end of file

A  => Samples/testapp/Program.cs +28 -0
@@ 1,28 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;

namespace testapp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var provider = new ServiceCollection()
                .AddLogging(b =>
                {
                    b.ClearProviders();
                    b.AddConsole();
                    b.SetMinimumLevel(LogLevel.Debug);
                })
                .BuildServiceProvider();
            Console.WriteLine("Test");
            var logger = provider.GetRequiredService<ILogger<Program>>();
            Console.WriteLine("Hell");
            logger.LogError("Built services");
            Console.WriteLine("Hello World!");
            Thread.Sleep(1000);
        }
    }
}

A  => Samples/testapp/testapp.csproj +15 -0
@@ 1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net48</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
  </ItemGroup>

</Project>

A  => libs/NosCore.Packets +1 -0
@@ 1,1 @@
Subproject commit 3b321dc6307a102c808eb37d3cc11890af3c6540

A  => libs/NosCore.Shared +1 -0
@@ 1,1 @@
Subproject commit 05c3880af07154903c294a9cf715025b8649ad85

Do not follow this link