Skip to content
This repository has been archived by the owner on Nov 30, 2024. It is now read-only.

Commit

Permalink
Merge pull request #152 from 0blu/new_command_line_parser
Browse files Browse the repository at this point in the history
New command line parser and default spell delay to ~30ms
  • Loading branch information
0blu authored Dec 1, 2022
2 parents 3cd6081 + 8565d5d commit 0473c03
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 93 deletions.
11 changes: 7 additions & 4 deletions HermesProxy/Auth/AuthClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
using Framework;
using Framework.IO;
using Framework.Logging;
using Framework.Networking;

namespace HermesProxy.Auth
{
Expand Down Expand Up @@ -59,10 +60,11 @@ public AuthResult ConnectToAuthServer(string username, string password, string l

try
{
Log.PrintNet(LogType.Network, LogNetDir.P2S, $"Connecting to auth server... (realmlist addr: {Settings.ServerAddress}:{Settings.ServerPort})");
var serverIpAddress = NetworkUtils.ResolveOrDirectIp(Settings.ServerAddress);
Log.PrintNet(LogType.Network, LogNetDir.P2S, $"Connecting to auth server... (realmlist addr: {Settings.ServerAddress}:{Settings.ServerPort}) (resolved as: {serverIpAddress}:{Settings.ServerPort})");
_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Connect to the specified host.
var endPoint = new IPEndPoint(IPAddress.Parse(Settings.ServerAddress), Settings.ServerPort);
var endPoint = new IPEndPoint(serverIpAddress, Settings.ServerPort);
_clientSocket.BeginConnect(endPoint, ConnectCallback, null);
}
catch (Exception ex)
Expand All @@ -83,10 +85,11 @@ public AuthResult Reconnect()

try
{
Log.PrintNet(LogType.Network, LogNetDir.P2S, $"Re-Connecting to auth server... (realmlist addr: {Settings.ServerAddress}:{Settings.ServerPort})");
var serverIpAddress = NetworkUtils.ResolveOrDirectIp(Settings.ServerAddress);
Log.PrintNet(LogType.Network, LogNetDir.P2S, $"Connecting to auth server... (realmlist addr: {Settings.ServerAddress}:{Settings.ServerPort}) (resolved as: {serverIpAddress}:{Settings.ServerPort})");
_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Connect to the specified host.
var endPoint = new IPEndPoint(IPAddress.Parse(Settings.ServerAddress), Settings.ServerPort);
var endPoint = new IPEndPoint(serverIpAddress, Settings.ServerPort);
_clientSocket.BeginConnect(endPoint, ConnectCallback, null);
}
catch (Exception ex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,20 @@
using System.IO;
using Framework.Logging;


namespace Framework
namespace HermesProxy.Configuration
{
public class Configuration
public class ConfigurationParser
{
private const string DEFAULT_CONFIG_FILE = "HermesProxy.config";
private readonly KeyValueConfigurationCollection _settingsCollection;

public Configuration(KeyValueConfigurationCollection configCollection)
public ConfigurationParser(KeyValueConfigurationCollection configCollection)
{
_settingsCollection = configCollection;
}

public static Configuration LoadDefaultConfiguration()
public static ConfigurationParser ParseFromFile(string configFile, Dictionary<string, string> overwrittenValues)
{
var args = Environment.GetCommandLineArgs();
var opts = new Dictionary<string, string>();

string configFile = DEFAULT_CONFIG_FILE;
KeyValueConfigurationCollection settings;

for (int i = 1; i < args.Length - 1; ++i)
{
string opt = args[i];
if (!opt.StartsWith("--", StringComparison.CurrentCultureIgnoreCase))
break;

// analyze options
string optname = opt.Substring(2);
switch (optname)
{
case "ConfigFile":
configFile = args[i + 1];
break;
default:
opts.Add(optname, args[i + 1]);
break;
}
++i;
}

try
{
if (!File.Exists(configFile))
Expand All @@ -62,13 +35,13 @@ public static Configuration LoadDefaultConfiguration()
}

// override config options with options from command line
foreach (var pair in opts)
foreach (var pair in overwrittenValues)
{
settings.Remove(pair.Key);
settings.Add(pair.Key, pair.Value);
}

return new Configuration(settings);
return new ConfigurationParser(settings);
}

public string GetString(string key, string defValue)
Expand Down
60 changes: 41 additions & 19 deletions HermesProxy/Configuration/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,53 @@
using System.Text;
using System.Net;
using Framework.Logging;
using Framework.Networking;
using HermesProxy.Configuration;

namespace Framework
{
public static class Settings
{
static readonly Configuration Conf = Configuration.LoadDefaultConfiguration();
public static readonly byte[] ClientSeed = Conf.GetByteArray("ClientSeed", "179D3DC3235629D07113A9B3867F97A7".ParseAsByteArray());
public static readonly ClientVersionBuild ClientBuild = Conf.GetEnum("ClientBuild", ClientVersionBuild.V2_5_2_40892);
public static readonly ClientVersionBuild ServerBuild = Conf.GetEnum("ServerBuild", ClientVersionBuild.V2_4_3_8606);
public static readonly string ServerAddress = Dns.GetHostAddresses(Conf.GetString("ServerAddress", "127.0.0.1")).First().ToString();
public static readonly int ServerPort = Conf.GetInt("ServerPort", 3724);
public static readonly string ReportedOS = Conf.GetString("ReportedOS", "OSX");
public static readonly string ReportedPlatform = Conf.GetString("ReportedPlatform", "x86");
public static readonly string ExternalAddress = Conf.GetString("ExternalAddress", "127.0.0.1");
public static readonly int RestPort = Conf.GetInt("RestPort", 8081);
public static readonly int BNetPort = Conf.GetInt("BNetPort", 1119);
public static readonly int RealmPort = Conf.GetInt("RealmPort", 8084);
public static readonly int InstancePort = Conf.GetInt("InstancePort", 8086);
public static readonly bool DebugOutput = Conf.GetBoolean("DebugOutput", false);
public static readonly bool PacketsLog = Conf.GetBoolean("PacketsLog", true);
public static readonly bool RememberLastCharacter = Conf.GetBoolean("RememberLastCharacter", true);
public static readonly int ServerSpellDelay = Conf.GetInt("ServerSpellDelay", 0);
public static readonly int ClientSpellDelay = Conf.GetInt("ClientSpellDelay", 0);
public static byte[] ClientSeed;
public static ClientVersionBuild ClientBuild;
public static ClientVersionBuild ServerBuild;
public static string ServerAddress;
public static int ServerPort;
public static string ReportedOS;
public static string ReportedPlatform;
public static string ExternalAddress;
public static int RestPort;
public static int BNetPort;
public static int RealmPort;
public static int InstancePort;
public static bool DebugOutput;
public static bool PacketsLog;
public static int ServerSpellDelay;
public static int ClientSpellDelay;

public static bool VerifyConfig()
public static bool LoadAndVerifyFrom(ConfigurationParser config)
{
ClientSeed = config.GetByteArray("ClientSeed", "179D3DC3235629D07113A9B3867F97A7".ParseAsByteArray());
ClientBuild = config.GetEnum("ClientBuild", ClientVersionBuild.V2_5_2_40892);
ServerBuild = config.GetEnum("ServerBuild", ClientVersionBuild.V2_4_3_8606);
ServerAddress = config.GetString("ServerAddress", "127.0.0.1");
ServerPort = config.GetInt("ServerPort", 3724);
ReportedOS = config.GetString("ReportedOS", "OSX");
ReportedPlatform = config.GetString("ReportedPlatform", "x86");
ExternalAddress = config.GetString("ExternalAddress", "127.0.0.1");
RestPort = config.GetInt("RestPort", 8081);
BNetPort = config.GetInt("BNetPort", 1119);
RealmPort = config.GetInt("RealmPort", 8084);
InstancePort = config.GetInt("InstancePort", 8086);
DebugOutput = config.GetBoolean("DebugOutput", false);
PacketsLog = config.GetBoolean("PacketsLog", true);
ServerSpellDelay = config.GetInt("ServerSpellDelay", 0);
ClientSpellDelay = config.GetInt("ClientSpellDelay", 0);

return VerifyConfig();
}

private static bool VerifyConfig()
{

if (ClientSeed.Length != 16)
Expand Down
15 changes: 4 additions & 11 deletions HermesProxy/HermesProxy.config
Original file line number Diff line number Diff line change
Expand Up @@ -89,28 +89,21 @@
Default: "true"
-->
<add key="PacketsLog" value="true" />
<!--
Option: RememberLastCharacter
Description: Saves the last selected realm/character for each account in an extra file.
So that the realmlist does not show up everytime you log in.
Default: "true"
-->
<add key="RememberLastCharacter" value="true" />
<!--
Option: ServerSpellDelay
Description: The amount of spell delay for Proxy <=> ModernClient in milliseconds (0 = disabled).
If you experience "stuck" spell animations/sounds try values above 0. (Like 20)
Warning: Adding a delay might cause you to lose optimal DPS.
Default: "0"
Default: "15"
-->
<add key="ServerSpellDelay" value="0" />
<add key="ServerSpellDelay" value="15" />
<!--
Option: ClientSpellDelay
Description: The amount of spell delay for GameServer <=> Proxy in milliseconds (0 = disabled).
If you experience "stuck" spell animations/sounds try values above 0. (Like 20)
Warning: Adding a delay might cause you to lose optimal DPS.
Default: "0"
Default: "15"
-->
<add key="ClientSpellDelay" value="0" />
<add key="ClientSpellDelay" value="15" />
</appSettings>
</configuration>
8 changes: 7 additions & 1 deletion HermesProxy/HermesProxy.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<StartupObject>HermesProxy.Server</StartupObject>
<StartupObject>HermesProxy.Program</StartupObject>
<ApplicationIcon>Hermes.ico</ApplicationIcon>
<Copyright>Copyright © WowLegacyCore 2022</Copyright>
<Authors>WowLegacyCore</Authors>
Expand All @@ -21,12 +21,18 @@
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
</PropertyGroup>

<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Windows'))">
<DefineConstants>_WINDOWS</DefineConstants>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="DotNetZip" Version="1.15.0" />

<PackageReference Include="GitVersion.MsBuild" Version="5.10.3">
<PrivateAssets>All</PrivateAssets>
</PackageReference>

<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
</ItemGroup>

<ItemGroup>
Expand Down
152 changes: 152 additions & 0 deletions HermesProxy/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Parsing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;

namespace HermesProxy;

public class Program
{
public static int Main(string[] args)
{
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

var commandTree = new RootCommand("Hermes Proxy: Allows you to play on legacy WoW server with modern client")
{
CommandLineArgumentsTemplate.ConfigFileLocation,
CommandLineArgumentsTemplate.DisableVersionCheck,
CommandLineArgumentsTemplate.OverwrittenConfigValues,
};

var parser = new CommandLineBuilder(commandTree)
.UseHelp()
.UseParseErrorReporting()
.Build();

commandTree.SetHandler((ctx) =>
{
var result = ctx.ParseResult;
var commandLineArguments = new CommandLineArguments
{
ConfigFileLocation = result.GetValueForOption(CommandLineArgumentsTemplate.ConfigFileLocation),
DisableVersionCheck = result.GetValueForOption(CommandLineArgumentsTemplate.DisableVersionCheck),
OverwrittenConfigValues = ParseMultiArgument(result.GetValueForOption(CommandLineArgumentsTemplate.OverwrittenConfigValues)),
};
Server.ServerMain(commandLineArguments);
});

int exitCode = 1;
try
{
exitCode = parser.Invoke(args);
}
catch (Exception e)
{
Console.WriteLine($"Error occured: {e}");
}

if (OsSpecific.AreWeInOurOwnConsole())
{
// If we would exit immediately the console would close and the user cannot read the error
// The delay is there if for some reason STDIN is already closed
Thread.Sleep(TimeSpan.FromSeconds(5));

Console.WriteLine("Press any key to close");
Console.ReadLine();
}

return exitCode;
}

private static Dictionary<string, string> ParseMultiArgument(string[]? multiArgs)
{
if (multiArgs == null)
return new Dictionary<string, string>();

var result = new Dictionary<string, string>();
foreach (var arg in multiArgs)
{
var keyValue = arg.Split('=', 2);
if (keyValue.Length != 2)
throw new Exception($"Invalid argument '{arg}'");
result[keyValue[0]] = keyValue[1];
}
return result;
}

public static class CommandLineArgumentsTemplate
{
public static readonly Option<string?> ConfigFileLocation = new(
name: "--config",
description: "The config file that will be used",
isDefault: true, // Must be set so parseArgument can return default value
parseArgument: result =>
{
if (result.Tokens.Count == 0)
return "HermesProxy.config";

string? filePath = result.Tokens.Single().Value;
if (!File.Exists(filePath))
{
result.ErrorMessage = $"Error: config file '{filePath}' does not exist";
return null;
}

return filePath;
});
public static readonly Option<bool> DisableVersionCheck = new(
name: "--no-version-check",
description: "Disables the initial version update check"
);
public static readonly Option<string[]> OverwrittenConfigValues = new(
name: "--set",
description: "Overwrites a specific config value. Example: --set ServerAddress=logon.example.com"
) { AllowMultipleArgumentsPerToken = true };
}
}

public class CommandLineArguments
{
public string? ConfigFileLocation { init; get; }
public bool DisableVersionCheck { init; get; }
public Dictionary<string, string> OverwrittenConfigValues { init; get; }
}

internal static class OsSpecific
{
/// Checks whenever or not we are in our own console
/// For example on Windows you can just double click the exe which spawns a new Console Window Host
public static bool AreWeInOurOwnConsole()
{
try
{
#if _WINDOWS
var consoleWindowHandle = GetConsoleWindow();
GetWindowThreadProcessId(consoleWindowHandle, out var consoleWindowProcess);
var weAreTheOwner = (consoleWindowProcess == Environment.ProcessId);
return weAreTheOwner;
#else
return true;
#endif
}
catch
{
return false;
}
}

#if _WINDOWS
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();

[DllImport("user32.dll", SetLastError=true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
#endif
}
Loading

0 comments on commit 0473c03

Please sign in to comment.