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 "C:\Program Files\NosTale\cs-CZ" 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>