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