~ruther/NosTale-Gfless

fc51a68e949a505ac95fe9b5e7363245d2b539d8 — František Boháček 4 years ago
Initial commit
37 files changed, 1887 insertions(+), 0 deletions(-)

A .gitignore
A .idea/.idea.NosTaleGfless/.idea/.gitignore
A .idea/.idea.NosTaleGfless/.idea/.name
A .idea/.idea.NosTaleGfless/.idea/indexLayout.xml
A .idea/.idea.NosTaleGfless/.idea/misc.xml
A .idea/.idea.NosTaleGfless/.idea/vcs.xml
A .idea/.idea.NosTaleGfless/riderModule.iml
A NosTaleGfless.sln
A NosTaleGfless/.idea/.idea.NosTaleGfless/.idea/contentModel.xml
A NosTaleGfless/.idea/.idea.NosTaleGfless/.idea/workspace.xml
A NosTaleGfless/GameforgeAuthenticator.cs
A NosTaleGfless/GameforgeLauncher.cs
A NosTaleGfless/NosTaleGfless.csproj
A NosTaleGfless/NostaleLauncher.cs
A NosTaleGfless/NostalePipeServer.cs
A NosTaleGfless/NostaleProcess.cs
A NosTaleGfless/Pipes/IdMessage.cs
A NosTaleGfless/Pipes/ParamsMessage.cs
A NosTaleGfless/Pipes/ResultMessage.cs
A NosTaleGfless/Pipes/SessionParams.cs
A NostaleAuth/Api/AuthorizedGameforgeApi.cs
A NostaleAuth/Api/GameforgeApi.cs
A NostaleAuth/Extensions/DictionaryExtension.cs
A NostaleAuth/Extensions/StringExtensions.cs
A NostaleAuth/Models/AuthRequest.cs
A NostaleAuth/Models/GameforgeAccount.cs
A NostaleAuth/Models/GameforgeRequest.cs
A NostaleAuth/Models/Locales.cs
A NostaleAuth/Models/RegionType.cs
A NostaleAuth/Models/SessionRequest.cs
A NostaleAuth/NostaleAuth.csproj
A NostaleAuth/Utils/Cryptography.cs
A NostaleGfless.Example/NostaleGfless.Example.csproj
A NostaleGfless.Example/Options.cs
A NostaleGfless.Example/Program.cs
A NostaleGfless.Example/Properties/AssemblyInfo.cs
A NostaleGfless.Example/app.manifest
A  => .gitignore +442 -0
@@ 1,442 @@

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

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

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.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, .xml, .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

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

### DotnetCore ###
# .NET Core build folders
bin/
obj/

# Common node modules locations
/node_modules
/wwwroot/node_modules

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

# 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

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

A  => .idea/.idea.NosTaleGfless/.idea/.gitignore +13 -0
@@ 1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/projectSettingsUpdater.xml
/contentModel.xml
/modules.xml
/.idea.NosTaleGfless.iml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

A  => .idea/.idea.NosTaleGfless/.idea/.name +1 -0
@@ 1,1 @@
NosTaleGfless
\ No newline at end of file

A  => .idea/.idea.NosTaleGfless/.idea/indexLayout.xml +8 -0
@@ 1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ContentModelUserStore">
    <attachedFolders />
    <explicitIncludes />
    <explicitExcludes />
  </component>
</project>
\ No newline at end of file

A  => .idea/.idea.NosTaleGfless/.idea/misc.xml +6 -0
@@ 1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="JavaScriptSettings">
    <option name="languageLevel" value="ES6" />
  </component>
</project>
\ No newline at end of file

A  => .idea/.idea.NosTaleGfless/.idea/vcs.xml +7 -0
@@ 1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="VcsDirectoryMappings">
    <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
    <mapping directory="$PROJECT_DIR$" vcs="Git" />
  </component>
</project>
\ No newline at end of file

A  => .idea/.idea.NosTaleGfless/riderModule.iml +7 -0
@@ 1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="RIDER_MODULE" version="4">
  <component name="NewModuleRootManager">
    <content url="file://$MODULE_DIR$/../.." />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>
\ No newline at end of file

A  => NosTaleGfless.sln +28 -0
@@ 1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NosTaleGfless", "NosTaleGfless\NosTaleGfless.csproj", "{A3F83A69-3981-4C18-953D-DFC7384E041E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NostaleAuth", "NostaleAuth\NostaleAuth.csproj", "{63031600-41E1-4B37-A9C5-90CFF5196806}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NostaleGfless.Example", "NostaleGfless.Example\NostaleGfless.Example.csproj", "{66C5FF7F-E7A3-404D-A84A-4B91C1A12980}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{A3F83A69-3981-4C18-953D-DFC7384E041E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{A3F83A69-3981-4C18-953D-DFC7384E041E}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{A3F83A69-3981-4C18-953D-DFC7384E041E}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{A3F83A69-3981-4C18-953D-DFC7384E041E}.Release|Any CPU.Build.0 = Release|Any CPU
		{63031600-41E1-4B37-A9C5-90CFF5196806}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{63031600-41E1-4B37-A9C5-90CFF5196806}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{63031600-41E1-4B37-A9C5-90CFF5196806}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{63031600-41E1-4B37-A9C5-90CFF5196806}.Release|Any CPU.Build.0 = Release|Any CPU
		{66C5FF7F-E7A3-404D-A84A-4B91C1A12980}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{66C5FF7F-E7A3-404D-A84A-4B91C1A12980}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{66C5FF7F-E7A3-404D-A84A-4B91C1A12980}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{66C5FF7F-E7A3-404D-A84A-4B91C1A12980}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
EndGlobal

A  => NosTaleGfless/.idea/.idea.NosTaleGfless/.idea/contentModel.xml +10 -0
@@ 1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ContentModelStore">
    <e p="C:\Users\rutherther\AppData\Local\JetBrains\Rider2020.1\extResources" t="IncludeRecursive" />
    <e p="C:\Users\rutherther\AppData\Local\JetBrains\Rider2020.1\resharper-host\Local\Transient\ReSharperHost\v201\SolutionCaches\_NosTaleGfless.-1343962422.00" t="ExcludeRecursive" />
    <e p="D:\Shared\Documents\MyProjects\NosTale-Gfless\NosTaleGfless" t="IncludeFlat">
      <e p="NosTaleGfless.sln" t="IncludeFlat" />
    </e>
  </component>
</project>
\ No newline at end of file

A  => NosTaleGfless/.idea/.idea.NosTaleGfless/.idea/workspace.xml +302 -0
@@ 1,302 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="BranchesTreeState">
    <expand>
      <path>
        <item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
        <item name="LOCAL_ROOT" type="e8cecc67:BranchNodeDescriptor" />
      </path>
    </expand>
    <select />
  </component>
  <component name="ChangeListManager">
    <list default="true" id="9efab84a-974d-4724-aa45-bdafec9fbff4" name="Default Changelist" comment="" />
    <option name="SHOW_DIALOG" value="false" />
    <option name="HIGHLIGHT_CONFLICTS" value="true" />
    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
    <option name="LAST_RESOLUTION" value="IGNORE" />
  </component>
  <component name="Git.Settings">
    <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
  </component>
  <component name="HighlightingSettingsPerFile">
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/16134578-226E-4E40-9ECB-DD10473CF8F2/B/OptionAttribute.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/9F899CB3-1EF6-467B-88D2-84237882BBF6/77/7cd2a670/NamedPipeServerStream.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/6DADD22E-0197-42CE-80AA-EFEF99855BE0/04/e93a37ae/CancellationTokenSource.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/731A2A5A-918C-4C46-9DA9-A4D2DF1FBD9B/03/1b5548b3/ExceptionDispatchInfo.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/2A8642DF-3638-4AB1-A1EF-B0E2D98B1551/31/5f29bb8f/__Error.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/6DADD22E-0197-42CE-80AA-EFEF99855BE0/64/8ad61822/ManualResetEvent.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/11BD515F-D2A0-4526-8509-D23726DE0F46/cf/7ff4c00d/Registry.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/6DADD22E-0197-42CE-80AA-EFEF99855BE0/e5/c0bfd2d0/EventWaitHandle.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/4D2BFBF9-FE2D-4F09-A5E4-07C05B2285C6/11/Process.cs" root0="FORCE_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/25C40285-458E-4E0A-BB79-9A5EA25AD92C/F/PipeStream.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/25C40285-458E-4E0A-BB79-9A5EA25AD92C/C/NamedPipeServerStream.cs" root0="FORCE_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/6DADD22E-0197-42CE-80AA-EFEF99855BE0/d9/9e4623e0/Encoding.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/6DADD22E-0197-42CE-80AA-EFEF99855BE0/bc/31b0d013/CancellationToken.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/25C40285-458E-4E0A-BB79-9A5EA25AD92C/D/NamedPipeServerStream.Windows.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/6DADD22E-0197-42CE-80AA-EFEF99855BE0/58/6acf49a1/Stream.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/SourcesCache/25C40285-458E-4E0A-BB79-9A5EA25AD92C/0/PipeTransmissionMode.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/731A2A5A-918C-4C46-9DA9-A4D2DF1FBD9B/bc/9937044d/CancellationToken.cs" root0="SKIP_HIGHLIGHTING" />
    <setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/731A2A5A-918C-4C46-9DA9-A4D2DF1FBD9B/f2/d96f327a/CancellationTokenSource.cs" root0="SKIP_HIGHLIGHTING" />
  </component>
  <component name="IdeDocumentHistory">
    <option name="CHANGED_PATHS">
      <list>
        <option value="$PROJECT_DIR$/NostaleAuth/Class1.cs" />
        <option value="$PROJECT_DIR$/NostaleAuth/SessionRequest.cs" />
        <option value="$PROJECT_DIR$/NostaleAuth/Models/GameforgeAccount.cs" />
        <option value="$PROJECT_DIR$/NostaleAuth/Extensions/DictionaryExtension.cs" />
        <option value="$PROJECT_DIR$/NostaleAuth/Api/GameforgeApi.cs" />
        <option value="$PROJECT_DIR$/NostaleAuth/Extensions/StringExtensions.cs" />
        <option value="$PROJECT_DIR$/NosTaleGfless/Pipes/SessionParams.cs" />
        <option value="$PROJECT_DIR$/NosTaleGfless/Pipes/ParamsMessage.cs" />
        <option value="$PROJECT_DIR$/NosTaleGfless/Pipes/IdMessage.cs" />
        <option value="$PROJECT_DIR$/NosTaleGfless/Pipes/ResultMessage.cs" />
        <option value="$PROJECT_DIR$/NostaleGfless.Example/Options.cs" />
        <option value="$PROJECT_DIR$/NosTaleGfless/GameforgeAuthenticator.cs" />
        <option value="$PROJECT_DIR$/NostaleGfless.Example/app.manifest" />
        <option value="$PROJECT_DIR$/NostaleGfless.Example/NostaleGfless.Example.csproj" />
        <option value="$PROJECT_DIR$/NostaleAuth/Api/AuthorizedGameforgeApi.cs" />
        <option value="$PROJECT_DIR$/NosTaleGfless/GameforgeLauncher.cs" />
        <option value="$PROJECT_DIR$/NostaleGfless.Example/Program.cs" />
        <option value="$PROJECT_DIR$/NosTaleGfless/NostaleProcess.cs" />
        <option value="$PROJECT_DIR$/NosTaleGfless/NostalePipeServer.cs" />
        <option value="$PROJECT_DIR$/NosTaleGfless/NostaleLauncher.cs" />
      </list>
    </option>
  </component>
  <component name="ProjectId" id="1gd9VgUUhcTAwqGfk6FhOLgAbUR" />
  <component name="ProjectViewState">
    <option name="hideEmptyMiddlePackages" value="true" />
    <option name="showLibraryContents" value="true" />
  </component>
  <component name="PropertiesComponent">
    <property name="DebuggerViewTab_PTCS_FirstProportionKey" value="0.34994584" />
    <property name="DebuggerViewTab_PTCS_LastProportionKey" value="0.30010834" />
    <property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
    <property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
    <property name="WebServerToolWindowFactoryState" value="false" />
    <property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
    <property name="nodejs_npm_path_reset_for_default_project" value="true" />
    <property name="settings.editor.selected.configurable" value="project.propDebugger" />
  </component>
  <component name="RunManager">
    <configuration name="NostaleGfless.Example" type="DotNetProject" factoryName=".NET Project">
      <option name="EXE_PATH" value="$PROJECT_DIR$/NostaleGfless.Example/bin/Debug/NostaleGfless.Example.exe" />
      <option name="PROGRAM_PARAMETERS" value="-n &quot;C:\Program Files\NosTale\cs-CZ&quot; mynosbots+1@gmail.com Testtesttest1" />
      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/NostaleGfless.Example/bin/Debug" />
      <option name="PASS_PARENT_ENVS" value="1" />
      <option name="USE_EXTERNAL_CONSOLE" value="0" />
      <option name="USE_MONO" value="0" />
      <option name="RUNTIME_ARGUMENTS" value="" />
      <option name="PROJECT_PATH" value="$PROJECT_DIR$/NostaleGfless.Example/NostaleGfless.Example.csproj" />
      <option name="PROJECT_EXE_PATH_TRACKING" value="1" />
      <option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
      <option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
      <option name="PROJECT_KIND" value="Console" />
      <option name="PROJECT_TFM" value=".NETFramework,Version=v4.7.2" />
      <method v="2">
        <option name="Build" />
      </method>
    </configuration>
  </component>
  <component name="SvnConfiguration">
    <configuration />
  </component>
  <component name="TaskManager">
    <task active="true" id="Default" summary="Default task">
      <changelist id="9efab84a-974d-4724-aa45-bdafec9fbff4" name="Default Changelist" comment="" />
      <created>1598433628509</created>
      <option name="number" value="Default" />
      <option name="presentableId" value="Default" />
      <updated>1598433628509</updated>
      <workItem from="1598433640361" duration="14770000" />
      <workItem from="1598457034927" duration="113000" />
      <workItem from="1598457456670" duration="364000" />
      <workItem from="1598457886071" duration="951000" />
      <workItem from="1598458994382" duration="3974000" />
      <workItem from="1598463306639" duration="13000" />
      <workItem from="1598463571017" duration="2479000" />
    </task>
    <servers />
  </component>
  <component name="TypeScriptGeneratedFilesManager">
    <option name="version" value="2" />
  </component>
  <component name="UnityProjectConfiguration" hasMinimizedUI="false" />
  <component name="UnityUnitTestConfiguration" currentTestLauncher="NUnit" />
  <component name="Vcs.Log.Tabs.Properties">
    <option name="TAB_STATES">
      <map>
        <entry key="MAIN">
          <value>
            <State />
          </value>
        </entry>
      </map>
    </option>
    <option name="oldMeFiltersMigrated" value="true" />
  </component>
  <component name="WindowStateProjectService">
    <state x="414" y="180" key="#com.intellij.execution.impl.EditConfigurationsDialog" timestamp="1598457568498">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state x="414" y="180" key="#com.intellij.execution.impl.EditConfigurationsDialog/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598457568498" />
    <state width="441" height="646" key="DebuggerActiveHint" timestamp="1598462171926">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="441" height="646" key="DebuggerActiveHint/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462171926" />
    <state width="1877" height="278" key="GridCell.Tab.0.bottom" timestamp="1598466051966">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1892" height="284" key="GridCell.Tab.0.bottom/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973110" />
    <state width="1877" height="278" key="GridCell.Tab.0.bottom/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051966" />
    <state width="1877" height="370" key="GridCell.Tab.0.bottom/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458550186" />
    <state width="1877" height="278" key="GridCell.Tab.0.center" timestamp="1598466051966">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1892" height="284" key="GridCell.Tab.0.center/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973110" />
    <state width="1877" height="278" key="GridCell.Tab.0.center/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051966" />
    <state width="1877" height="370" key="GridCell.Tab.0.center/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458550186" />
    <state width="1877" height="278" key="GridCell.Tab.0.left" timestamp="1598466051966">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1892" height="284" key="GridCell.Tab.0.left/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973110" />
    <state width="1877" height="278" key="GridCell.Tab.0.left/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051966" />
    <state width="1877" height="370" key="GridCell.Tab.0.left/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458550186" />
    <state width="1877" height="278" key="GridCell.Tab.0.right" timestamp="1598466051966">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1892" height="284" key="GridCell.Tab.0.right/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973110" />
    <state width="1877" height="278" key="GridCell.Tab.0.right/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051966" />
    <state width="1877" height="370" key="GridCell.Tab.0.right/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458550186" />
    <state width="1877" height="376" key="GridCell.Tab.1.bottom" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.1.bottom/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.1.bottom/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.1.bottom/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458541426" />
    <state width="1877" height="376" key="GridCell.Tab.1.center" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.1.center/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973103" />
    <state width="1877" height="376" key="GridCell.Tab.1.center/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.1.center/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458541426" />
    <state width="1877" height="376" key="GridCell.Tab.1.left" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.1.left/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973103" />
    <state width="1877" height="376" key="GridCell.Tab.1.left/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.1.left/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458541426" />
    <state width="1877" height="376" key="GridCell.Tab.1.right" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.1.right/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.1.right/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.1.right/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458541426" />
    <state width="1877" height="376" key="GridCell.Tab.2.bottom" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.2.bottom/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.2.bottom/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.2.bottom/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458540112" />
    <state width="1877" height="376" key="GridCell.Tab.2.center" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.2.center/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.2.center/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.2.center/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458540112" />
    <state width="1877" height="376" key="GridCell.Tab.2.left" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.2.left/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.2.left/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.2.left/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458540112" />
    <state width="1877" height="376" key="GridCell.Tab.2.right" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.2.right/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.2.right/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.2.right/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458540112" />
    <state width="1877" height="376" key="GridCell.Tab.3.bottom" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.3.bottom/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.3.bottom/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.3.bottom/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458540112" />
    <state width="1877" height="376" key="GridCell.Tab.3.center" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.3.center/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.3.center/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.3.center/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458540112" />
    <state width="1877" height="376" key="GridCell.Tab.3.left" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.3.left/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.3.left/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.3.left/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458540112" />
    <state width="1877" height="376" key="GridCell.Tab.3.right" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.3.right/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.3.right/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.3.right/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458540112" />
    <state width="1877" height="376" key="GridCell.Tab.4.bottom" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.4.bottom/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.4.bottom/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.4.bottom/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458540113" />
    <state width="1877" height="376" key="GridCell.Tab.4.center" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.4.center/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.4.center/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.4.center/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458540113" />
    <state width="1877" height="376" key="GridCell.Tab.4.left" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.4.left/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.4.left/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.4.left/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458540112" />
    <state width="1877" height="376" key="GridCell.Tab.4.right" timestamp="1598466051962">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="1877" height="376" key="GridCell.Tab.4.right/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462973104" />
    <state width="1877" height="376" key="GridCell.Tab.4.right/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598466051962" />
    <state width="1877" height="370" key="GridCell.Tab.4.right/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458540113" />
    <state x="552" y="257" key="Rider.ProjectTemplateDialog.Size" timestamp="1598435747023">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state x="552" y="257" key="Rider.ProjectTemplateDialog.Size/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598435747023" />
    <state x="829" y="120" key="RiderGenerateDialog" timestamp="1598446235379">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state x="829" y="120" key="RiderGenerateDialog/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598446235379" />
    <state x="461" y="170" key="SettingsEditor" timestamp="1598457132814">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state x="461" y="170" key="SettingsEditor/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598457132814" />
    <state width="968" height="533" key="XDebugger.FullValuePopup" timestamp="1598460847201">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state width="968" height="533" key="XDebugger.FullValuePopup/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598460847201" />
    <state x="511" y="172" key="com.intellij.xdebugger.impl.breakpoints.ui.BreakpointsDialogFactory$2" timestamp="1598460337494">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state x="511" y="172" key="com.intellij.xdebugger.impl.breakpoints.ui.BreakpointsDialogFactory$2/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598460337494" />
    <state x="511" y="172" key="com.intellij.xdebugger.impl.breakpoints.ui.BreakpointsDialogFactory$2/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598457063299" />
    <state x="632" y="242" width="655" height="566" key="find.popup" timestamp="1598464150047">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state x="632" y="242" width="655" height="566" key="find.popup/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598462300518" />
    <state x="632" y="242" width="655" height="566" key="find.popup/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598464150047" />
    <state x="623" y="227" width="672" height="678" key="search.everywhere.popup" timestamp="1598464113438">
      <screen x="0" y="0" width="1920" height="1050" />
    </state>
    <state x="623" y="227" width="672" height="678" key="search.everywhere.popup/-1920.0.1920.1050/0.0.1920.1050/1920.0.1920.1050@0.0.1920.1050" timestamp="1598461162143" />
    <state x="623" y="227" width="672" height="678" key="search.everywhere.popup/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@0.0.1920.1050" timestamp="1598464113438" />
    <state x="2543" y="227" width="672" height="678" key="search.everywhere.popup/0.0.1920.1050/1920.0.1920.1050/-1920.0.1920.1050@1920.0.1920.1050" timestamp="1598458243786" />
  </component>
</project>
\ No newline at end of file

A  => NosTaleGfless/GameforgeAuthenticator.cs +34 -0
@@ 1,34 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NostaleAuth.Api;
using NostaleAuth.Models;

namespace NosTaleGfless
{
    public class GameforgeAuthenticator
    {
        public GameforgeAuthenticator(GameforgeApi api = null, Locales locale = null, Guid? installationId = null)
        {
            Api = api ?? new GameforgeApi();
            InstallationId = installationId;
            Locale = locale ?? Locales.Germany;
        }
        
        public Guid? InstallationId { get; set; }
        
        public Locales Locale { get; set; }
        
        public GameforgeApi Api { get; }
        
        public async Task<GameforgeLauncher> Authenticate(string email, string password)
        {
            Guid installationId = InstallationId ?? Api.GenerateIntallationId(email, password);
            AuthorizedGameforgeApi authorizedGameforgeApi = await Api.Login(email, password, Locale, installationId);

            IEnumerable<GameforgeAccount> accounts = await authorizedGameforgeApi.GetAccounts();
            
            return new GameforgeLauncher(authorizedGameforgeApi, accounts, email);
        }
    }
}
\ No newline at end of file

A  => NosTaleGfless/GameforgeLauncher.cs +77 -0
@@ 1,77 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NostaleAuth.Api;
using NostaleAuth.Models;

namespace NosTaleGfless
{
    public class GameforgeLauncher : IDisposable
    {
        private Timer _watchTimer;
        
        public GameforgeLauncher(AuthorizedGameforgeApi api, IEnumerable<GameforgeAccount> accounts, string email)
        {
            Accounts = accounts.ToList().AsReadOnly();
            Email = email;
            Launcher = new NostaleLauncher();
            Api = api;
            
            ActiveProcesses = new ObservableCollection<NostaleProcess>();
        }
        
        public string Email { get; }
        
        public ReadOnlyCollection<GameforgeAccount> Accounts { get; }
        
        public AuthorizedGameforgeApi Api { get; }
        
        public NostaleLauncher Launcher { get; set; }
        
        public ObservableCollection<NostaleProcess> ActiveProcesses { get; }

        public async Task<NostaleProcess> Launch(GameforgeAccount account, string nostalePath)
        {
            NostaleProcess process = await Launcher.Launch(account, await Api.GetSessionToken(account, true), nostalePath);
            if (process != null)
            {
                ActiveProcesses.Add(process);
            }

            return process;
        }

        public void StartProcessWatch()
        {
            StopProcessWatch();
            
            _watchTimer = new Timer((state) =>
            {
                foreach (var process in ActiveProcesses
                    .Where(x => x.HasExited)
                    .ToArray())
                {
                    ActiveProcesses.Remove(process);
                }
            }, null, 1000, 1000);
        }

        public void StopProcessWatch()
        {
            if (_watchTimer != null)
            {
                _watchTimer.Dispose();
                _watchTimer = null;
            }
        }

        public void Dispose()
        {
            StopProcessWatch();
        }
    }
}
\ No newline at end of file

A  => NosTaleGfless/NosTaleGfless.csproj +11 -0
@@ 1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
    </PropertyGroup>

    <ItemGroup>
      <ProjectReference Include="..\NostaleAuth\NostaleAuth.csproj" />
    </ItemGroup>

</Project>

A  => NosTaleGfless/NostaleLauncher.cs +74 -0
@@ 1,74 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using NostaleAuth.Models;

namespace NosTaleGfless
{
    public class NostaleLauncher
    {
        private readonly object _lock;
        
        public NostaleLauncher()
        {
            _lock = new object();
        }
        
        public Task<NostaleProcess> Launch(GameforgeAccount account, string sessionToken, string nostalePath)
        {
            return Task.Run(() =>
            {
                lock (_lock)
                {
                    NostaleProcess process = RunProcess(account, nostalePath);
                    process.Initialized = ProcessPipeServer(process, sessionToken).GetAwaiter().GetResult();

                    return process;
                }
            });
        }
        
        public NostaleProcess RunProcess(GameforgeAccount account, string nostalePath)
        {
            Guid sessionId = Guid.NewGuid();
            
            Environment.SetEnvironmentVariable("_TNT_CLIENT_APPLICATION_ID", "d3b2a0c1-f0d0-4888-ae0b-1c5e1febdafb");
            Environment.SetEnvironmentVariable("_TNT_SESSION_ID", sessionId.ToString());
            
            string path = GetNostaleClientPath(nostalePath);
            Process process = Process.Start(path, $"gf {(int)account.GetRegionType()}");

            return new NostaleProcess(process, account)
            {
                SessionId = sessionId
            };
        }
        
        public async Task<bool> ProcessPipeServer(NostaleProcess process, string sessionToken)
        {
            var pipeServer = new NostalePipeServer(process, sessionToken);
            await pipeServer.Start();

            return pipeServer.Successful;
        }

        private string GetNostaleClientPath(string nostalePath)
        {
            if (Directory.Exists(nostalePath))
            {
                nostalePath = Path.Combine(nostalePath, "NostaleClientX.exe");
            }

            if (!File.Exists(nostalePath))
            {
                throw new InvalidOperationException("Nostale was not found.");
            }

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

A  => NosTaleGfless/NostalePipeServer.cs +128 -0
@@ 1,128 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.SymbolStore;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using NosTaleGfless.Pipes;

namespace NosTaleGfless
{
    public class NostalePipeServer
    {
        protected string _sessionToken;
        protected CancellationTokenSource _cancellationTokenSource;

        public NostalePipeServer(NostaleProcess process, string sessionToken)
        {
            _sessionToken = sessionToken;
            Process = process;
            _cancellationTokenSource = new CancellationTokenSource();

            Process.Process.Exited += OnNostaleExit;
        }

        public bool Successful { get; protected set; }

        public NostaleProcess Process { get; }

        public async Task Start()
        {
            byte[] buffer = new byte[1024];
            List<NamedPipeServerStream> servers = new List<NamedPipeServerStream>();
            servers.Add(CreateServer());
            
            while (!Successful)
            {
                NamedPipeServerStream serverStream = servers.Last();
                try
                {
                    await serverStream.WaitForConnectionAsync(_cancellationTokenSource.Token);
                }
                catch (OperationCanceledException)
                {
                    serverStream.Dispose();
                    break;
                }

                int read = await serverStream.ReadAsync(buffer, 0, 1024);
                ParamsMessage message = ParseMessage(buffer, read);

                string output = null;
                switch (message.Method)
                {
                    case "ClientLibrary.isClientRunning":
                        output = CreateResult<bool, ResultMessage<bool>>(message, true);
                        break;
                    case "ClientLibrary.initSession":
                        output = CreateResult<string, ResultMessage<string>>(message, message.Params.SessionId);
                        break;
                    case "ClientLibrary.queryAuthorizationCode":
                        output = CreateResult<string, ResultMessage<string>>(message, _sessionToken);
                        _sessionToken = null;
                        break;
                    case "ClientLibrary.queryGameAccountName":
                        output = CreateResult<string, ResultMessage<string>>(message, Process.Account.Name);
                        Process.Process.Exited -= OnNostaleExit;
                        Successful = true;
                        break;
                }

                if (!Successful)
                {
                    servers.Add(CreateServer());
                }

                if (output != null)
                {
                    byte[] data = Encoding.ASCII.GetBytes(output);
                    serverStream.Write(data, 0, data.Length);
                }
            }

            foreach (NamedPipeServerStream server in servers)
            {
                server.Dispose();
            }
        }

        protected NamedPipeServerStream CreateServer()
        {
            return new NamedPipeServerStream("GameforgeClientJSONRPC", PipeDirection.InOut, 254,
                PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
        }

        protected ParamsMessage ParseMessage(byte[] data, int count)
        {
            return JsonConvert.DeserializeObject<ParamsMessage>(Encoding.ASCII.GetString(data, 0, count));
        }

        protected string SerializeResult<T>(ResultMessage<T> result)
        {
            return JsonConvert.SerializeObject(result);
            ;
        }

        protected string CreateResult<T, U>(ParamsMessage receivedMessage, T result)
            where U : ResultMessage<T>, new()
        {
            return SerializeResult(new U
            {
                Id = receivedMessage.Id,
                Jsonrpc = receivedMessage.Jsonrpc,
                Result = result
            });
        }

        protected void OnNostaleExit(object sender, EventArgs args)
        {
            Process.Process.Exited -= OnNostaleExit;
            _cancellationTokenSource.Cancel();
        }
    }
}
\ No newline at end of file

A  => NosTaleGfless/NostaleProcess.cs +29 -0
@@ 1,29 @@
using System;
using System.Diagnostics;
using NostaleAuth.Models;

namespace NosTaleGfless
{
    public class NostaleProcess
    {
        public NostaleProcess(Process process, GameforgeAccount account)
        {
            Account = account;
            Process = process;
        }
        
        public Process Process { get; }

        public int ProcessId => Process.Id;
        
        public string SessionToken { get; set; }
        
        public GameforgeAccount Account { get; }
        
        public Guid? SessionId { get; internal set; }
        
        public bool Initialized { get; internal set; }

        public bool HasExited => Process.HasExited;
    }
}
\ No newline at end of file

A  => NosTaleGfless/Pipes/IdMessage.cs +13 -0
@@ 1,13 @@
using Newtonsoft.Json;

namespace NosTaleGfless.Pipes
{
    public class IdMessage
    {
        [JsonProperty("id")]
        public int Id { get; set; }

        [JsonProperty("jsonrpc")]
        public double Jsonrpc { get; set; } = 2.0;
    }
}
\ No newline at end of file

A  => NosTaleGfless/Pipes/ParamsMessage.cs +13 -0
@@ 1,13 @@
using Newtonsoft.Json;

namespace NosTaleGfless.Pipes
{
    public class ParamsMessage : IdMessage
    {
        [JsonProperty("method")]
        public string Method { get; set; }
        
        [JsonProperty("params")]
        public SessionParams Params { get; set; }
    }
}
\ No newline at end of file

A  => NosTaleGfless/Pipes/ResultMessage.cs +10 -0
@@ 1,10 @@
using Newtonsoft.Json;

namespace NosTaleGfless.Pipes
{
    public class ResultMessage<T> : IdMessage
    {
        [JsonProperty("result")]
        public T Result { get; set; }
    }
}
\ No newline at end of file

A  => NosTaleGfless/Pipes/SessionParams.cs +10 -0
@@ 1,10 @@
using Newtonsoft.Json;

namespace NosTaleGfless.Pipes
{
    public class SessionParams
    {
        [JsonProperty("sessionId")]
        public string SessionId { get; set; }
    }
}
\ No newline at end of file

A  => NostaleAuth/Api/AuthorizedGameforgeApi.cs +62 -0
@@ 1,62 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using NostaleAuth.Extensions;
using NostaleAuth.Models;

namespace NostaleAuth.Api
{
    public class AuthorizedGameforgeApi
    {
        private List<GameforgeAccount> _accounts;
        
        public AuthorizedGameforgeApi(string authToken, Guid installationId)
        {
            AuthToken = authToken;
            InstallationId = installationId;
        }
        
        public Guid InstallationId { get; set; }
        
        public string AuthToken { get; }
        
        public async Task<IEnumerable<GameforgeAccount>> GetAccounts(bool cache = true)
        {
            if (cache && _accounts != null)
            {
                return _accounts;
            }
            
            var request = new GameforgeRequest<GameforgeAccount>(HttpMethod.Get, "/user/accounts", InstallationId, AuthToken);
            Dictionary<string, GameforgeAccount> response = await request.Send();

            if (response == null)
            {
                return new List<GameforgeAccount>();
            }
            
            _accounts = new List<GameforgeAccount>(response.Values);
            return _accounts;
        }

        public async Task<string> GetSessionToken(GameforgeAccount gameforgeAccount, bool raw = false)
        {
            var request = new GameforgeRequest<SessionRequest, string>(HttpMethod.Post, "/auth/thin/codes", InstallationId, AuthToken);
            var sessionRequest = new SessionRequest
            {
                PlatformGameAccountId = gameforgeAccount.Id
            };
            
            Dictionary<string, string> response = await request.Send(sessionRequest);

            if (response == null)
            {
                return string.Empty;
            }

            string data = (response.GetValueOrDefault("code") ?? string.Empty);
            return raw ? data : data.ToHex();
        }
    }
}
\ No newline at end of file

A  => NostaleAuth/Api/GameforgeApi.cs +60 -0
@@ 1,60 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using NostaleAuth.Extensions;
using NostaleAuth.Models;
using NostaleAuth.Utils;

namespace NostaleAuth.Api
{
    public class GameforgeApi
    {
        private readonly HttpClient _httpClient;

        public GameforgeApi()
        {
            _httpClient = new HttpClient();
        }

        public Guid GenerateIntallationId(string email, string password)
        {
            return Guid.Parse(Cryptography.ToMd5(email + password));
        }

        public async Task<int> GetLatestVersion()
        {
            var request = new GameforgeRequest<int>(HttpMethod.Get, "/patching/download/nostale/default?branchToken");
            Dictionary<string, int> response = await request.Send();

            return response.GetValueOrDefault("latest");
        }

        public async Task<AuthorizedGameforgeApi> Login(string email, string password, Locales locale, Guid installationId)
        {
            var request = new GameforgeRequest<AuthRequest, string>(HttpMethod.Post, "/auth/sessions", installationId);
            
            var authRequest = new AuthRequest
            {
                Locale = locale.Value,
                Email = email,
                Password = password
            };

            Dictionary<string, string> response = await request.Send(authRequest);
            if (response == null)
            {
                return null;
            }
            
            string authToken = response.GetValueOrDefault("token") ?? string.Empty;
            
            return new AuthorizedGameforgeApi(authToken, installationId);
        }

        public Task<AuthorizedGameforgeApi> Login(string email, string password, Locales locale)
        {
            return Login(email, password, locale, GenerateIntallationId(email, password));
        }
    }
}

A  => NostaleAuth/Extensions/DictionaryExtension.cs +10 -0
@@ 1,10 @@
using System.Collections.Generic;

namespace NostaleAuth.Extensions
{
    public static class DictionaryExtension
    {
        public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dictionary, K key, V value) => dictionary.TryGetValue(key, out V result) ? result : value;
        public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dictionary, K key) => dictionary.GetValueOrDefault(key, default);
    }
}
\ No newline at end of file

A  => NostaleAuth/Extensions/StringExtensions.cs +11 -0
@@ 1,11 @@
using System;
using System.Linq;

namespace NostaleAuth.Extensions
{
    public static class StringExtensions
    {
        public static string ToHex(this string input)
            => String.Concat(input.Select(x => ((int)x).ToString("X2")));
    }
}
\ No newline at end of file

A  => NostaleAuth/Models/AuthRequest.cs +16 -0
@@ 1,16 @@
using Newtonsoft.Json;

namespace NostaleAuth.Models
{
    public class AuthRequest
    {
        [JsonProperty("locale")]
        public string Locale { get; set; }

        [JsonProperty("email")]
        public string Email { get; set; }

        [JsonProperty("password")]
        public string Password { get; set; }
    }
}

A  => NostaleAuth/Models/GameforgeAccount.cs +23 -0
@@ 1,23 @@
using System;
using Newtonsoft.Json;

namespace NostaleAuth.Models
{
    public sealed class GameforgeAccount
    {
        public string Id { get; set; }

        [JsonProperty("displayName")]
        public string Name { get; set; }

        [JsonProperty("accountGroup")]
        public string Region { get; set; }

        public override string ToString() => $"{nameof(Id)}: {Id}, {nameof(Name)}: {Name}";

        public RegionType GetRegionType()
        {
            return (RegionType) Enum.Parse(typeof(RegionType), Region.ToUpper());
        }
    }
}

A  => NostaleAuth/Models/GameforgeRequest.cs +111 -0
@@ 1,111 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace NostaleAuth.Models
{
    public class GameforgeRequest
    {
        protected const string Url = "https://spark.gameforge.com/api/v1";
        protected static string UserAgent = "GameforgeClient/2.1.12";
        protected const string MediaType = "application/json";

        public static void SetVersion(string version)
        {
            if (!string.IsNullOrEmpty(version))
            {
                UserAgent = "GameforgeClient/" + version;
            }
        }   
    }
    
    public class GameforgeRequest<T> : GameforgeRequest
    {
        private static readonly HttpClient _httpClient = new HttpClient();

        public GameforgeRequest(HttpMethod method, string path, Guid? installationId, string bearerToken)
        {
            Method = method;
            Path = path;
            InstallationId = installationId;
            BearerToken = bearerToken;
        }

        public GameforgeRequest(HttpMethod method, string path, Guid? installationId)
            : this(method, path, installationId, null)
        {
        }
        
        public GameforgeRequest(HttpMethod method, string path)
            : this(method, path, null, null)
        {
        }

        public string Path { get; set; }

        public Guid? InstallationId { get; set; }
        public HttpMethod Method { get; set; }

        public string BearerToken { get; set; }

        public async Task<Dictionary<string, T>> Send()
        {
            using (HttpRequestMessage request = PrepareRequest())
            {
                return await GetResponse(request);
            }
        }

        protected async Task<Dictionary<string, T>> GetResponse(HttpRequestMessage request)
        {
            HttpResponseMessage response = await _httpClient.SendAsync(request);
            
            if (!response.IsSuccessStatusCode)
            {
                return null;
            }
            
            string content = await response.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<Dictionary<string, T>>(content);
        }

        protected HttpRequestMessage PrepareRequest()
        {
            var request = new HttpRequestMessage(Method, $"{Url}" + Path);
            if (InstallationId != null)
            {
                request.Headers.Add("TNT-Installation-Id", InstallationId.ToString());
            }

            request.Headers.Add("User-Agent", UserAgent);

            if (BearerToken != null)
            {
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", BearerToken);
            }

            return request;
        }
    }

    public class GameforgeRequest<T, TU> : GameforgeRequest<TU>
    {
        public GameforgeRequest(HttpMethod method, string path, Guid installationId, string bearerToken = null)
            : base(method, path, installationId, bearerToken)
        {
        }

        public async Task<Dictionary<string, TU>> Send(T body)
        {
            using (HttpRequestMessage request = PrepareRequest())
            {
                request.Content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, MediaType);
                return await GetResponse(request);
            }
        }
    }
}
\ No newline at end of file

A  => NostaleAuth/Models/Locales.cs +14 -0
@@ 1,14 @@
namespace NostaleAuth.Models
{
    public class Locales
    {
        public Locales(string value) { Value = value; }

        public string Value { get; }

        public static Locales Czech => new Locales("cs_CZ");
        public static Locales UnitedKingdom => new Locales("en_UK");
        public static Locales Poland => new Locales("pl_PL");
        public static Locales Germany => new Locales("de_DE");
    }
}
\ No newline at end of file

A  => NostaleAuth/Models/RegionType.cs +15 -0
@@ 1,15 @@
namespace NostaleAuth.Models
{
    public enum RegionType
    {
        EN,
        DE,
        FR,
        IT,
        PL,
        ES,
        RU,
        CZ,
        TR,
    }
}
\ No newline at end of file

A  => NostaleAuth/Models/SessionRequest.cs +10 -0
@@ 1,10 @@
using Newtonsoft.Json;

namespace NostaleAuth.Models
{
    public sealed class SessionRequest
    {
        [JsonProperty("platformGameAccountId")]
        public string PlatformGameAccountId { get; set; }
    }
}

A  => NostaleAuth/NostaleAuth.csproj +11 -0
@@ 1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
    </ItemGroup>

</Project>

A  => NostaleAuth/Utils/Cryptography.cs +36 -0
@@ 1,36 @@
using System.Security.Cryptography;
using System.Text;

namespace NostaleAuth.Utils
{
    public static class Cryptography
    {
        public static string ToMd5(string value)
        {
            using (var md5 = MD5.Create())
            {
                return Hash(value, md5);
            }
        }

        public static string ToSha512(string value)
        {
            using (var sha512 = SHA512.Create())
            {
                return Hash(value, sha512);
            }
        }
    
        private static string Hash(string value, HashAlgorithm hash)
        {
            byte[] bytes = hash.ComputeHash(Encoding.ASCII.GetBytes(value));
            var sb = new StringBuilder();
        
            foreach (byte b in bytes)
            {
                sb.Append(b.ToString("X2"));
            }
            return sb.ToString();
        }
    }
}
\ No newline at end of file

A  => NostaleGfless.Example/NostaleGfless.Example.csproj +72 -0
@@ 1,72 @@
<?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>{66C5FF7F-E7A3-404D-A84A-4B91C1A12980}</ProjectGuid>
    <OutputType>Exe</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>NostaleGfless.Example</RootNamespace>
    <AssemblyName>NostaleGfless.Example</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="Options.cs" />
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="CommandLineParser" Version="2.8.0" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\NostaleAuth\NostaleAuth.csproj">
      <Project>{63031600-41e1-4b37-a9c5-90cff5196806}</Project>
      <Name>NostaleAuth</Name>
    </ProjectReference>
    <ProjectReference Include="..\NosTaleGfless\NosTaleGfless.csproj">
      <Project>{a3f83a69-3981-4c18-953d-dfc7384e041e}</Project>
      <Name>NosTaleGfless</Name>
    </ProjectReference>
  </ItemGroup>
  <ItemGroup>
    <Content Include="app.manifest" />
  </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>
    -->
  <PropertyGroup>
    <ApplicationManifest>app.manifest</ApplicationManifest>
  </PropertyGroup>
</Project>
\ No newline at end of file

A  => NostaleGfless.Example/Options.cs +23 -0
@@ 1,23 @@
using CommandLine;
using Newtonsoft.Json;

namespace NostaleGfless.Example
{
    public class Options
    {
        [Option('i', "installation", Required = false, HelpText = "Installation guid. Can be obtained from regedit.")]
        public string InstallationId { get; set; }

        [Option('n', "nostale", Required = true, HelpText = "Path to nostale folder or NostaleClientX.exe")]
        public string NostalePath { get; set; }

        [Option('a', "account", Required = false, HelpText = "Name of the account to connect to. Otherwise the first one will be used.")]
        public string AccountName { get; set; }

        [Value(0, MetaName = "Email", Required = true, HelpText = "Gameforge account email")]
        public string Email { get; set; }

        [Value(1, MetaName = "Password", Required = true, HelpText = "Gameforge account password")]
        public string Password { get; set; }
    }
}
\ No newline at end of file

A  => NostaleGfless.Example/Program.cs +79 -0
@@ 1,79 @@
using System;
using System.Linq;
using System.Threading;
using CommandLine;
using Microsoft.Win32;
using NostaleAuth.Models;
using NosTaleGfless;

namespace NostaleGfless.Example
{
    internal class Program
    {
        static EventWaitHandle ewh = new ManualResetEvent(false);
        
        public static void Main(string[] args)
        {
            string installationIdString = (string)Registry.GetValue(@"HKEY_CURRENT_USER\Software\Gameforge4d\TNTClient\MainApp",
                "InstallationId", null);
            
            Guid? installationId = null;
            if (installationIdString != null)
            {
                installationId = Guid.Parse(installationIdString);
            }
            
            Parser.Default.ParseArguments<Options>(args).WithParsed(async options =>
            {
                if (options.InstallationId != null)
                {
                    installationId = Guid.Parse(options.InstallationId);
                }
                
                var authenticator = new GameforgeAuthenticator();
                authenticator.InstallationId = installationId;
                var launcher  = await authenticator.Authenticate(options.Email, options.Password);

                GameforgeAccount account = launcher.Accounts.FirstOrDefault();
                if (account == null)
                {
                    throw new InvalidOperationException("There are no nostale account on the gameforge account");
                }

                if (options.AccountName != null)
                {
                    account = launcher.Accounts.FirstOrDefault(x => x.Name == options.AccountName);

                    if (account == null)
                    {
                        account = launcher.Accounts.FirstOrDefault(x => x.Name.Contains(options.AccountName));

                        if (account == null)
                        {
                            throw new InvalidOperationException("Account not found");
                        }
                    }
                }
                
                Console.WriteLine($"Selected account: {account.Name}");
                Console.WriteLine("Launching nostale with the selected account ...");
                    
                Console.WriteLine("Waiting for nostale ...");
                var result = await launcher.Launch(account, options.NostalePath);

                if (result != null && result.Initialized)
                {
                    Console.WriteLine($"Nostale launched successfully. Process id: {result.ProcessId}, Session id: {result.SessionId}");
                }
                else
                {
                    Console.WriteLine("There was an error launching nostale");
                }

                ewh.Set();
            });
            
            ewh.WaitOne();
        }
    }
}
\ No newline at end of file

A  => NostaleGfless.Example/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("NostaleGfless.Example")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("NostaleGfless.Example")]
[assembly: AssemblyCopyright("Copyright ©  2020")]
[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("66C5FF7F-E7A3-404D-A84A-4B91C1A12980")]

// 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  => NostaleGfless.Example/app.manifest +76 -0
@@ 1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
    <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
        <security>
            <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
                <!-- UAC Manifest Options
                     If you want to change the Windows User Account Control level replace the 
                     requestedExecutionLevel node with one of the following.
        
                <requestedExecutionLevel  level="asInvoker" uiAccess="false" />
                <requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />
                <requestedExecutionLevel  level="highestAvailable" uiAccess="false" />
        
                    Specifying requestedExecutionLevel element will disable file and registry virtualization. 
                    Remove this element if your application requires this virtualization for backwards
                    compatibility.
                -->
                <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
            </requestedPrivileges>
        </security>
    </trustInfo>

    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
            <!-- A list of the Windows versions that this application has been tested on
                 and is designed to work with. Uncomment the appropriate elements
                 and Windows will automatically select the most compatible environment. -->

            <!-- Windows Vista -->
            <!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->

            <!-- Windows 7 -->
            <!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->

            <!-- Windows 8 -->
            <!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->

            <!-- Windows 8.1 -->
            <!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->

            <!-- Windows 10 -->
            <!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->

        </application>
    </compatibility>

    <!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
         DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need 
         to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should 
         also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. -->
    <!--
    <application xmlns="urn:schemas-microsoft-com:asm.v3">
      <windowsSettings>
        <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
      </windowsSettings>
    </application>
    -->

    <!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
    <!--
    <dependency>
      <dependentAssembly>
        <assemblyIdentity
            type="win32"
            name="Microsoft.Windows.Common-Controls"
            version="6.0.0.0"
            processorArchitecture="*"
            publicKeyToken="6595b64144ccf1df"
            language="*"
          />
      </dependentAssembly>
    </dependency>
    -->

</assembly>

Do not follow this link