~ruther/NosSmooth

c9c40f75322299bb020274ace6eb79e59718885b — František Boháček 3 years ago f23353c
feat: add name changer packet interceptor sample
M NosSmooth.sln => NosSmooth.sln +36 -1
@@ 36,6 36,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".metadata", ".metadata", "{
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleChat", "Samples\SimpleChat\SimpleChat.csproj", "{4017A4F4-5E59-48AA-A7D0-A8518148933A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tets", "Tets", "{C6A8760D-92CB-4307-88A7-36CCAEBA4AD1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NosCore.Packets.Tests", "libs\NosCore.Packets\test\NosCore.Packets.Tests\NosCore.Packets.Tests.csproj", "{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InterceptNameChanger", "Samples\InterceptNameChanger\InterceptNameChanger.csproj", "{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LowLevel", "LowLevel", "{9025731C-084E-4E82-8CD4-0F52D3AA1F54}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU


@@ 164,6 172,30 @@ Global
		{4017A4F4-5E59-48AA-A7D0-A8518148933A}.Release|x64.Build.0 = Release|Any CPU
		{4017A4F4-5E59-48AA-A7D0-A8518148933A}.Release|x86.ActiveCfg = Release|Any CPU
		{4017A4F4-5E59-48AA-A7D0-A8518148933A}.Release|x86.Build.0 = Release|Any CPU
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}.Debug|x64.ActiveCfg = Debug|Any CPU
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}.Debug|x64.Build.0 = Debug|Any CPU
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}.Debug|x86.ActiveCfg = Debug|Any CPU
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}.Debug|x86.Build.0 = Debug|Any CPU
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}.Release|Any CPU.Build.0 = Release|Any CPU
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}.Release|x64.ActiveCfg = Release|Any CPU
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}.Release|x64.Build.0 = Release|Any CPU
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}.Release|x86.ActiveCfg = Release|Any CPU
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0}.Release|x86.Build.0 = Release|Any CPU
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}.Debug|x64.ActiveCfg = Debug|Any CPU
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}.Debug|x64.Build.0 = Debug|Any CPU
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}.Debug|x86.ActiveCfg = Debug|Any CPU
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}.Debug|x86.Build.0 = Debug|Any CPU
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}.Release|Any CPU.Build.0 = Release|Any CPU
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}.Release|x64.ActiveCfg = Release|Any CPU
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}.Release|x64.Build.0 = Release|Any CPU
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}.Release|x86.ActiveCfg = Release|Any CPU
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A}.Release|x86.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE


@@ 177,7 209,10 @@ Global
		{63E97FF3-7E40-44DE-9E91-F5DEE79AF95F} = {6078AE6E-7CD0-48E4-84E0-EB164D8881DA}
		{27DF38DF-AC58-4039-A91C-824D829ECECD} = {01B5E872-271F-4D30-A1AA-AD48D81840C5}
		{945E9248-C150-4617-AB0F-1450561859E3} = {01B5E872-271F-4D30-A1AA-AD48D81840C5}
		{4017A4F4-5E59-48AA-A7D0-A8518148933A} = {F20FE754-FDEA-4F3A-93D4-0750CB9EBB33}
		{726188BA-F0EA-4ECA-ACF4-CCC066464FF0} = {C6A8760D-92CB-4307-88A7-36CCAEBA4AD1}
		{9025731C-084E-4E82-8CD4-0F52D3AA1F54} = {F20FE754-FDEA-4F3A-93D4-0750CB9EBB33}
		{F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A} = {9025731C-084E-4E82-8CD4-0F52D3AA1F54}
		{4017A4F4-5E59-48AA-A7D0-A8518148933A} = {9025731C-084E-4E82-8CD4-0F52D3AA1F54}
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {C5F46653-4DEC-429B-8580-4ED18ED9B4CA}

A Samples/InterceptNameChanger/DllMain.cs => Samples/InterceptNameChanger/DllMain.cs +46 -0
@@ 0,0 1,46 @@
//
//  DllMain.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace InterceptNameChanger
{
    /// <summary>
    /// The main entrypoint class of the dll.
    /// </summary>
    public class DllMain
    {
        [DllImport("kernel32")]
#pragma warning disable SA1600
        public static extern bool AllocConsole();
#pragma warning restore SA1600

        /// <summary>
        /// The main entrypoint method of the dll.
        /// </summary>
        /// <param name="handle">The handle of the module.</param>
        [DllExport]
        public static void Main(IntPtr handle)
        {
            AllocConsole();
            Console.WriteLine("Hello from InterceptNameChanger DllMain entry point.");

            new Thread(() =>
            {
                try
                {
                    new NameChanger().RunAsync().GetAwaiter().GetResult();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }).Start();
        }
    }
}
\ No newline at end of file

A Samples/InterceptNameChanger/FodyWeavers.xml => Samples/InterceptNameChanger/FodyWeavers.xml +3 -0
@@ 0,0 1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
  <Costura />
</Weavers>
\ No newline at end of file

A Samples/InterceptNameChanger/InterceptNameChanger.csproj => Samples/InterceptNameChanger/InterceptNameChanger.csproj +67 -0
@@ 0,0 1,67 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net48</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <LangVersion>10</LangVersion>
  </PropertyGroup>
  <PropertyGroup>
    <DllExportIdent>89E4EE92-5848-4390-A6A7-34972FE923F5</DllExportIdent>
    <DllExportMetaLibName>DllExport.dll</DllExportMetaLibName>
    <DllExportNamespace>InterceptNameChanger</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="Costura.Fody" Version="5.7.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="DllExport">
      <Version>1.7.4</Version>
      <Visible>false</Visible>
      <Wz>1</Wz>
    </PackageReference>
    <PackageReference Include="Fody" Version="6.6.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\..\Core\NosSmooth.Core\NosSmooth.Core.csproj" />
    <ProjectReference Include="..\..\Local\NosSmooth.LocalClient\NosSmooth.LocalClient.csproj" />
  </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/InterceptNameChanger/NameChangeInterceptor.cs => Samples/InterceptNameChanger/NameChangeInterceptor.cs +73 -0
@@ 0,0 1,73 @@
//
//  NameChangeInterceptor.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Extensions.Logging;
using NosCore.Packets.Enumerations;
using NosCore.Packets.ServerPackets.Chats;
using NosSmooth.Core.Client;
using NosSmooth.LocalClient;

namespace InterceptNameChanger
{
    /// <summary>
    /// Intercepts the packets so name in c_info may be replaced.
    /// </summary>
    public class NameChangeInterceptor : IPacketInterceptor
    {
        private readonly INostaleClient _client;
        private readonly ILogger<NameChangeInterceptor> _logger;
        private string _name = "Intercept";

        /// <summary>
        /// Initializes a new instance of the <see cref="NameChangeInterceptor"/> class.
        /// </summary>
        /// <param name="client">The nostale client.</param>
        /// <param name="logger">The logger.</param>
        public NameChangeInterceptor(INostaleClient client, ILogger<NameChangeInterceptor> logger)
        {
            _client = client;
            _logger = logger;
        }

        /// <inheritdoc/>
        public bool InterceptSend(ref string packet)
        {
            if (packet.StartsWith("say #"))
            {
                _name = packet.Substring(5).Replace(" ", "⠀"); // Mind the symbols!
                _logger.LogInformation("Name changed to {Name}", _name);
                _client.ReceivePacketAsync(new SayPacket()
                {
                    Message = $"Name changed to {_name}, change map for it to take effect.",
                    Type = SayColorType.Red
                }).GetAwaiter().GetResult();
                return false;
            }

            return true; // Accept the packet
        }

        /// <inheritdoc/>
        public bool InterceptReceive(ref string packet)
        {
            if (packet.StartsWith("c_info"))
            {
                var oldPart = packet.Substring(packet.IndexOf(' ', 7));
                var result = _client.ReceivePacketAsync($"c_info {_name} " + oldPart)
                    .GetAwaiter().GetResult(); // Change the name

                if (!result.IsSuccess)
                {
                    _logger.LogError("Could not send the c_info packet: {Reason}", result.Error.Message);
                    return true; // Accept the packet so client is not confused
                }
                return false; // Reject the packet
            }

            return true; // Accept the packet
        }
    }
}
\ No newline at end of file

A Samples/InterceptNameChanger/NameChanger.cs => Samples/InterceptNameChanger/NameChanger.cs +69 -0
@@ 0,0 1,69 @@
//
//  NameChanger.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using NosCore.Packets.Enumerations;
using NosCore.Packets.ServerPackets.Chats;
using NosCore.Shared.Enumerations;
using NosSmooth.Core.Client;
using NosSmooth.Core.Packets;
using NosSmooth.LocalClient;
using NosSmooth.LocalClient.Extensions;

namespace InterceptNameChanger
{
    /// <summary>
    /// Main class of name changer.
    /// </summary>
    public class NameChanger
    {
        /// <summary>
        /// Run the name changer.
        /// </summary>
        /// <returns>A task that may or may not have succeeded.</returns>
        public async Task RunAsync()
        {
            var provider = new ServiceCollection()
                .AddLocalClient()

                // .AddPacketResponder<SayResponder>()
                .AddLogging(b =>
                {
                    b.ClearProviders();
                    b.AddConsole();
                    b.SetMinimumLevel(LogLevel.Debug);
                })
                .Configure<LocalClientOptions>(o => o.AllowIntercept = true)
                .AddSingleton<IPacketInterceptor, NameChangeInterceptor>()
                .BuildServiceProvider();

            var dummy1 = provider.GetRequiredService<PacketSerializerProvider>().ServerSerializer;
            var dummy2 = provider.GetRequiredService<PacketSerializerProvider>().ClientSerializer;

            var logger = provider.GetRequiredService<ILogger<NameChanger>>();
            logger.LogInformation("Hello world from NameChanger!");

            var client = provider.GetRequiredService<INostaleClient>();

            var sayResult = await client.ReceivePacketAsync(new SayPacket()
            {
                Message = "The name may be changed by typing #{NewName} into the chat.",
                VisualType = VisualType.Map,
                Type = SayColorType.Red,
                VisualId = 1,
            });

            if (!sayResult.IsSuccess)
            {
                logger.LogError("Could not send say packet");
            }

            await client.RunAsync();
        }
    }
}
\ No newline at end of file

A Samples/InterceptNameChanger/Properties/AssemblyInfo.cs => Samples/InterceptNameChanger/Properties/AssemblyInfo.cs +41 -0
@@ 0,0 1,41 @@
//
//  AssemblyInfo.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.

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("InterceptNameChanger")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("InterceptNameChanger")]
[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("F96F3AA0-131E-4B6B-AB21-BBE2DEBCEF3A")]

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

Do not follow this link