Commiting launcher 1.0.1.3 modified version as init commit

This commit is contained in:
Mael-fixe 2018-08-26 02:35:36 +02:00
parent c7489e94d1
commit be651ac44e
52 changed files with 4326 additions and 10 deletions

41
.gitignore vendored Normal file
View File

@ -0,0 +1,41 @@
# Autosave files
*~
# build
[Oo]bj/
[Bb]in/
TestResults/
# globs
Makefile.in
*.DS_Store
*.sln.cache
*.suo
*.cache
*.pidb
*.userprefs
*.usertasks
config.log
config.make
config.status
aclocal.m4
install-sh
autom4te.cache/
*.user
*.tar.gz
tarballs/
test-results/
Thumbs.db
.vs/
packages/
# Mac bundle stuff
*.dmg
*.app
# resharper
*_Resharper.*
*.Resharper
# dotCover
*.dotCover

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
</configuration>

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" 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>{8E7856FD-FA68-4356-9C88-54C9EF5A9D20}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>CleanAndLaunch</RootNamespace>
<AssemblyName>CleanAndLaunch</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</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.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

120
CleanAndLaunch/Program.cs Normal file
View File

@ -0,0 +1,120 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Timers;
// The goal of this application is just to clean old files in the system and launch the new launcher... EZ RIGHT ? The app is called after the self updater included in the whole NaturalLauncher.
// This is not used anymore. Meh !
namespace CleanAndLaunch
{
class Program
{
public static string curDir = Directory.GetCurrentDirectory();
public static string ProcessName = "NaturalLauncher.exe";
static void Main(string[] args)
{
Thread.Sleep(1000);
DeleteOldFiles();
System.Timers.Timer ReLaunchTimer = new System.Timers.Timer();
ReLaunchTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
ReLaunchTimer.Interval = 100;
ReLaunchTimer.Enabled = true;
Console.Read();
}
public static void OnTimedEvent(object source, ElapsedEventArgs e)
{
if (IsProcessOpen(ProcessName)==false)
{
Launch();
}
}
static void Launch()
{
Console.WriteLine("Launching...");
Process myprocess = new Process();
myprocess.StartInfo.FileName = curDir + Path.DirectorySeparatorChar + ProcessName;
try
{
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.WorkingDirectory = curDir;
processInfo.FileName = ProcessName;
processInfo.ErrorDialog = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardOutput = true;
processInfo.RedirectStandardError = true;
Process proc = Process.Start(processInfo);
Environment.Exit(0);
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
Console.ReadKey();
}
}
public static bool IsProcessOpen(string name)
{
foreach (Process clsProcess in Process.GetProcesses())
{
if (clsProcess.ProcessName.Contains(name))
{
return true;
}
}
return false;
}
public static void DeleteOldFiles()
{
Console.WriteLine("Cleaning old and update files ...");
foreach (string file in Directory.GetFiles(curDir))
{
// Cleaning BAK files
if (Path.GetExtension(file) == ".bak")
{
File.Delete(file);
}
string localPath = ToLocalPath(curDir, file);
// Cleaning UpdateLogs files
if (localPath.StartsWith("/UpdateLog"))
{
File.Delete(file);
}
}
}
public static string ToLocalPath(string root, string dir)
{
return dir.Replace(root, "").Replace("\\", "/");
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Les informations générales relatives à un assembly dépendent de
// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
// associées à un assembly.
[assembly: AssemblyTitle("CleanAndLaunch")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CleanAndLaunch")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly
// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de
// COM, affectez la valeur true à l'attribut ComVisible sur ce type.
[assembly: ComVisible(false)]
// Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM
[assembly: Guid("8e7856fd-fa68-4356-9c88-54c9ef5a9d20")]
// Les informations de version pour un assembly se composent des quatre valeurs suivantes :
//
// Version principale
// Version secondaire
// Numéro de build
// Révision
//
// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
// en utilisant '*', comme indiqué ci-dessous :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

25
LICENSE
View File

@ -1,16 +1,15 @@
MIT License
This programm is an updater to keep your Natural Selection 1 mod folder up with the latest updates.
Copyright (c) 2018 ENSL
Copyright (C) <2018> <Mael "Khelben" Vignaux>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. Commercial use is prohibited.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@ -19,3 +18,9 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
</configuration>

View File

@ -0,0 +1,40 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using System.Collections.Generic;
namespace ManifestBuilder
{
class LauncherManifest
{
public LauncherManifest()
{
Files = new Dictionary<string, string>();
}
public Dictionary<string, string> Files
{
get;
set;
}
}
}

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" 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>{6A7DBE40-6BFB-49F5-BFC1-9F0752EC31BE}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>ManifestBuilder</RootNamespace>
<AssemblyName>ManifestBuilder</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</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="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="LauncherManifest.cs" />
<Compile Include="ManifestBuildor.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,86 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using Newtonsoft.Json;
using System.IO;
using System;
using System.Security.Cryptography;
namespace ManifestBuilder
{
class ManifestBuildor
{
public static string ManifestName = "Manifest.txt";
public static void BuildManifest(string directory)
{
LauncherManifest manifest = new LauncherManifest();
md5 = MD5.Create();
RecursiveBuildManifest(directory, "", manifest);
string ManifestPath = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + ManifestName;
File.WriteAllText(ManifestPath, JsonConvert.SerializeObject(manifest, Formatting.Indented));
}
private static MD5 md5;
private static void RecursiveBuildManifest(string projectRoot, string dir, LauncherManifest manifest)
{
string path = projectRoot + dir;
foreach (string file in Directory.GetFiles(path))
{
string localPath = ToLocalPath(projectRoot, file);
string hash = ComputeMD5(file);
if(!localPath.EndsWith("_.cfg") && localPath != "/ManifestBuilder.exe" && localPath != "/Manifest.txt"
&& localPath != "/Newtonsoft.Json.dll") //we don't want cfg files to get updated here cept config.cfg which is in ignore.list
manifest.Files[localPath] = hash;
}
foreach (string nextDir in Directory.GetDirectories(path))
{
RecursiveBuildManifest(projectRoot, ToLocalPath(projectRoot, nextDir), manifest);
}
}
private static string ToLocalPath(string root, string dir)
{
return dir.Replace(root, "").Replace("\\", "/");
}
public static string ComputeMD5(string file)
{
MD5 md5 = MD5.Create();
string hash = "";
using (var stream = File.OpenRead(file))
{
hash = BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "");
}
return hash;
}
}
}

View File

@ -0,0 +1,39 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ManifestBuilder
{
class Program
{
static void Main(string[] args)
{
string curDir = Directory.GetCurrentDirectory();
Console.WriteLine("Building manifest in : " + curDir);
ManifestBuildor.BuildManifest(curDir);
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Les informations générales relatives à un assembly dépendent de
// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
// associées à un assembly.
[assembly: AssemblyTitle("ManifestBuilder")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ManifestBuilder")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly
// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de
// COM, affectez la valeur true à l'attribut ComVisible sur ce type.
[assembly: ComVisible(false)]
// Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM
[assembly: Guid("6a7dbe40-6bfb-49f5-bfc1-9f0752ec31be")]
// Les informations de version pour un assembly se composent des quatre valeurs suivantes :
//
// Version principale
// Version secondaire
// Numéro de build
// Révision
//
// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
// en utilisant '*', comme indiqué ci-dessous :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="11.0.2" targetFramework="net462" />
</packages>

37
NaturalLauncher.sln Normal file
View File

@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2042
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NaturalLauncher", "NaturalLauncher\NaturalLauncher.csproj", "{0138DD06-7386-4820-9BCE-3F8412CAD801}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManifestBuilder", "ManifestBuilder\ManifestBuilder.csproj", "{6A7DBE40-6BFB-49F5-BFC1-9F0752EC31BE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanAndLaunch", "CleanAndLaunch\CleanAndLaunch.csproj", "{8E7856FD-FA68-4356-9C88-54C9EF5A9D20}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0138DD06-7386-4820-9BCE-3F8412CAD801}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0138DD06-7386-4820-9BCE-3F8412CAD801}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0138DD06-7386-4820-9BCE-3F8412CAD801}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0138DD06-7386-4820-9BCE-3F8412CAD801}.Release|Any CPU.Build.0 = Release|Any CPU
{6A7DBE40-6BFB-49F5-BFC1-9F0752EC31BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A7DBE40-6BFB-49F5-BFC1-9F0752EC31BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A7DBE40-6BFB-49F5-BFC1-9F0752EC31BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A7DBE40-6BFB-49F5-BFC1-9F0752EC31BE}.Release|Any CPU.Build.0 = Release|Any CPU
{8E7856FD-FA68-4356-9C88-54C9EF5A9D20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8E7856FD-FA68-4356-9C88-54C9EF5A9D20}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E7856FD-FA68-4356-9C88-54C9EF5A9D20}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E7856FD-FA68-4356-9C88-54C9EF5A9D20}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {06E5B626-B631-47BF-84D5-A157442007E0}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="NaturalLauncher.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
<userSettings>
<NaturalLauncher.Properties.Settings>
<setting name="ConfigurationUrl" serializeAs="String">
<value>http://ensl.gk-servers.de/</value>
</setting>
<setting name="IndexURL" serializeAs="String">
<value>http://ensl.gk-servers.de/</value>
</setting>
<setting name="CreditURL" serializeAs="String">
<value>http://ensl.gk-servers.de/</value>
</setting>
<setting name="GameUrl" serializeAs="String">
<value>http://ensl.gk-servers.de/ns</value>
</setting>
<setting name="GatherURL" serializeAs="String">
<value>https://www.ensl.org/gathers/latest/ns1</value>
</setting>
<setting name="NineLegendUrl" serializeAs="String">
<value>http://www.elseware-experience.com/vignauxmael/NaturalLauncher/NLPack</value>
</setting>
<setting name="LauncherUrl" serializeAs="String">
<value>http://ensl.gk-servers.de/Launcher/</value>
</setting>
</NaturalLauncher.Properties.Settings>
</userSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-11.0.0.0" newVersion="11.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

9
NaturalLauncher/App.xaml Normal file
View File

@ -0,0 +1,9 @@
<Application x:Class="NaturalLauncher.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:NaturalLauncher"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

View File

@ -0,0 +1,12 @@

using System.Windows;
namespace NaturalLauncher
{
/// <summary>
/// Logique d'interaction pour App.xaml
/// </summary>
public partial class App : Application
{
}
}

View File

@ -0,0 +1,123 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
namespace NaturalLauncher
{
[SuppressUnmanagedCodeSecurity]
public static class ConsoleManager
{
private const string Kernel32_DllName = "kernel32.dll";
[DllImport(Kernel32_DllName)]
private static extern bool AllocConsole();
[DllImport(Kernel32_DllName)]
private static extern bool FreeConsole();
[DllImport(Kernel32_DllName)]
private static extern IntPtr GetConsoleWindow();
[DllImport(Kernel32_DllName)]
private static extern int GetConsoleOutputCP();
public static bool HasConsole
{
get { return GetConsoleWindow() != IntPtr.Zero; }
}
/// <summary>
/// Creates a new console instance if the process is not attached to a console already.
/// </summary>
public static void Show()
{
//#if DEBUG
if (!HasConsole)
{
AllocConsole();
InvalidateOutAndError();
}
//#endif
}
/// <summary>
/// If the process has a console attached to it, it will be detached and no longer visible. Writing to the System.Console is still possible, but no output will be shown.
/// </summary>
public static void Hide()
{
//#if DEBUG
if (HasConsole)
{
SetOutAndErrorNull();
FreeConsole();
}
//#endif
}
public static void Toggle()
{
if (HasConsole)
{
Hide();
}
else
{
Show();
}
}
static void InvalidateOutAndError()
{
Type type = typeof(System.Console);
System.Reflection.FieldInfo _out = type.GetField("_out",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
System.Reflection.FieldInfo _error = type.GetField("_error",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
System.Reflection.MethodInfo _InitializeStdOutError = type.GetMethod("InitializeStdOutError",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
Debug.Assert(_out != null);
Debug.Assert(_error != null);
Debug.Assert(_InitializeStdOutError != null);
_out.SetValue(null, null);
_error.SetValue(null, null);
_InitializeStdOutError.Invoke(null, new object[] { true });
}
static void SetOutAndErrorNull()
{
Console.SetOut(TextWriter.Null);
Console.SetError(TextWriter.Null);
}
}
}

275
NaturalLauncher/Launcher.cs Normal file
View File

@ -0,0 +1,275 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using System;
using System.IO;
using System.Diagnostics;
using System.Net;
using System.Windows;
using DiscordRPC;
using Newtonsoft.Json;
using System.Windows.Forms;
namespace NaturalLauncher
{
class Launcher
{
public static string curDir = Directory.GetCurrentDirectory();
public static Uri MainPageURL = new Uri(Properties.Settings.Default.IndexURL);
public static Uri CreditPageURL = new Uri(Properties.Settings.Default.CreditURL);
public static string HLFolder = "";
public static string NSFolder;
public static string VersionFileName = "app.version";
public static string ManifestName = "Manifest.txt";
public static string NLManifestName = "NLManifest.txt";
public static string configName = "Launcher.xml";
public static bool keepLauncherAlive = true;
public static DateTime LAUNCHTIME = System.DateTime.UtcNow;
public static string discordCustomStatus = "Currently In The Launcher";
public static void PlayGame()
{
LAUNCHTIME = System.DateTime.UtcNow; //new time is launch time
UpdateDiscord(true); //doesnt work cause the timer set it back to false. need static var TODO
Process.Start("steam://rungameid/17558255459196993606");
//Environment.Exit(0); // not stopping the process to let discord rpc live
if (!keepLauncherAlive)
Environment.Exit(0);
}
internal static void UpdateDiscord(bool InGame)
{
int gatherPlayers = Util.ReadGathererCount();
UpdatePubServ(out int pubPlayers, out int maxPlayers);
int displayPlayers = pubPlayers; //by default
string discordState = "Players in public";
if (gatherPlayers > 6)
{
displayPlayers = gatherPlayers;
discordState = "Gather forming";
}
if (!InGame)
{
MainWindow.Discordclient.SetPresence(new RichPresence()
{
Details = discordCustomStatus,
State = discordState,
/*Secrets = new Secrets()
{
JoinSecret = "MTI4NzM0OjFpMmhuZToxMjMxMjM",
},*/
Party = new Party()
{
ID = "ae488379 - 351d - 4a4f - ad32 - 2b9b01c91657",
Size = displayPlayers,
Max = 12,
},
Timestamps = new Timestamps()
{
Start = LAUNCHTIME,
},
Assets = new Assets()
{
LargeImageKey = "portrait_png",
LargeImageText = "Natural Selection Enhanced Launcher",
SmallImageKey = "skulku_png",
},
});
}
if (InGame)
{
MainWindow.Discordclient.SetPresence(new RichPresence()
{
Details = "In Game",
State = "Next gather",
Party = new Party()
{
ID = "ae488379 - 351d - 4a4f - ad32 - 2b9b01c91657",
Size = Util.ReadGathererCount(),
Max = 12,
},
Timestamps = new Timestamps()
{
Start = LAUNCHTIME,
},
Assets = new Assets()
{
LargeImageKey = "portrait_png",
LargeImageText = "Natural Selection Enhanced Launcher",
SmallImageKey = "skulku_png",
},
});
}
}
public static void LaunchWebsite(string Url)
{
Process.Start(Url);
}
public static void RefreshInternetPageAsync(string whichPage)
{
using (var webClient = new WebClient())
{
if(whichPage == "Main")
{
string FileName = "index.html";
webClient.DownloadFileAsync(MainPageURL, FileName);
}
if (whichPage == "Credit")
{
string CreditFileName = "credit.html";
webClient.DownloadFileAsync(CreditPageURL, CreditFileName);
}
}
}
public static void CheckInstallDirectory()
{
bool NeedDirectory = false;
if (File.Exists(curDir + Path.DirectorySeparatorChar + configName))
{
string IndicatedFolder = "";
bool IsNLPack = false;
XmlBuilder.ReadConfigXml(out IndicatedFolder, out IsNLPack, out string discordStatus, out bool keepAlive);
if (IndicatedFolder.Length >0)
{
HLFolder = IndicatedFolder;
discordCustomStatus = discordStatus;
keepLauncherAlive = keepAlive;
}
else
NeedDirectory = true;
if (!Directory.Exists(IndicatedFolder))
NeedDirectory = true;
}
else
NeedDirectory = true;
if (NeedDirectory)
{
string folderPath = Util.AskForHLFolder();
if (folderPath!=null)
{
HLFolder = folderPath;
NSFolder = HLFolder + Path.DirectorySeparatorChar + "ns";
XmlBuilder.CreateConfigXml();
if (Directory.Exists(NSFolder))
{
if(System.Windows.Forms.MessageBox.Show("Warning, you are updating an existing NS installation: "
+ Environment.NewLine + "A backup of your old ns folder can be made under the name ns_saved.zip"
+ Environment.NewLine + "Please choose if you want to backup your current ns folder.", "", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1)== DialogResult.Yes)
{ Util.ZipDirectory(NSFolder); }
}
else
{
Directory.CreateDirectory(NSFolder);
}
}
else
{
Environment.Exit(0); //stop the process
}
}
NSFolder = HLFolder + Path.DirectorySeparatorChar + "ns";
}
public static bool IsNLPack()
{
bool Result = false; //by default
if (File.Exists(curDir + Path.DirectorySeparatorChar + configName))
{
string IndicatedFolder = "";
XmlBuilder.ReadConfigXml(out IndicatedFolder, out Result, out string plop, out bool noob);
}
else
{
Util.PlaySoundFX("error");
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("Launcher Config file not found");
CheckInstallDirectory();
return false;
}
return Result;
}
public static void SetIsNLPack(bool IsNlPack)
{
XmlBuilder.CreateConfigXml();
}
public static void AddToIgnoreList()
{
Util.GetIgnoreManifest(true); //let's verify we have a ignore list from the start
string IgnorePath = curDir + Path.DirectorySeparatorChar + "customignore.list";
string IgnoreString = File.ReadAllText(IgnorePath);
LauncherManifest IgnoreManifest = JsonConvert.DeserializeObject<LauncherManifest>(IgnoreString);// then get it
var dialog = new System.Windows.Forms.OpenFileDialog();
dialog.InitialDirectory = NSFolder;
dialog.Multiselect = true;
dialog.Title = "Please indicate what file(s) to add in the ignore list !";
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
foreach(string file in dialog.FileNames)
{
string localPath = Util.ToLocalPath(NSFolder, file);
IgnoreManifest.Files[localPath] = "1"; //we using the launchermanifest but set "1" to ignore verify and update ("0" is ignore only update)
}
File.WriteAllText(IgnorePath, JsonConvert.SerializeObject(IgnoreManifest, Formatting.Indented));
}
}
internal static void UpdatePubServ(out int publicPlayers, out int maxPlayers)
{
// TO BE CONTINUED but so far we can retrieve pub serv info...
string serverIP = "104.156.251.121"; //public us
int port = 27015;
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(serverIP), port);
var ServInfo = new ServerChecker.A2S_INFO(remoteEP);
publicPlayers = ServInfo.Players; //out
maxPlayers = ServInfo.MaxPlayers; //out
// Check for the launcher to self update
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using System.Collections.Generic;
namespace NaturalLauncher
{
class LauncherManifest
{
public LauncherManifest()
{
Files = new Dictionary<string, string>();
}
public Dictionary<string, string> Files
{
get;
set;
}
}
}

View File

@ -0,0 +1,76 @@
<Window x:Name="Launcher_Window" x:Class="NaturalLauncher.MainWindow"
Closed="MainWindow_Closed"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:NaturalLauncher"
mc:Ignorable="d"
Title="Natural Launcher v ...." Height="615.5" Width="930" MinWidth="930" MinHeight="550" BorderThickness="0,0,0,0">
<Window.TaskbarItemInfo>
<TaskbarItemInfo Description="The Natural Launcher"
ProgressValue="0" ProgressState="Normal"/>
</Window.TaskbarItemInfo>
<Window.ContextMenu>
<ContextMenu>
<MenuItem Header="Open Natural Selection Folder" Click="OpenNSFolder"/>
<MenuItem Header="Check for updaters update" Click="CheckLauncherUpdate"/>
<MenuItem Header="Add files to ignore list" Click="AddToIgnore"/>
<Separator />
<MenuItem Header="Join the official Discord !" Click="JoinDiscord"/>
<MenuItem Header="Credits" Click="SeeCredit"/>
<Separator />
<MenuItem Header="Build Manifest (dev)" Click="BuildManifest"/>
</ContextMenu>
</Window.ContextMenu>
<Window.Icon>
<ImageSource>Ressources/nsl_icon.ico</ImageSource>
</Window.Icon>
<Window.Background>
<ImageBrush ImageSource="Ressources/background_blur.png"/>
</Window.Background>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="9*"/>
<ColumnDefinition Width="598*"/>
<ColumnDefinition Width="268*"/>
<ColumnDefinition Width="47*"/>
</Grid.ColumnDefinitions>
<Label x:Name="TitleLabel" Content="Natural Selection Launcher" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" FontSize="24" FontFamily="Britannic Bold" FontWeight="Bold" Height="32" Width="336" Foreground="#FFEEC160" RenderTransformOrigin="0.5,0.5" Grid.Column="1">
<Label.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform Angle="-0.229"/>
<TranslateTransform/>
</TransformGroup>
</Label.RenderTransform>
</Label>
<Rectangle Fill="#A50D0D0C" Margin="0,0,10,32" Stroke="Black" Grid.ColumnSpan="3" Height="46" VerticalAlignment="Bottom" Grid.Column="1"/>
<Label x:Name="VersionLabel" Content="checking" Margin="341,10,0,0" VerticalAlignment="Top" FontStyle="Italic" Background="#00000000" Foreground="#FF5ACAFF" Height="38" Grid.Column="1" FontWeight="Bold" FontSize="14" HorizontalAlignment="Left" Width="74" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/>
<WebBrowser x:Name="MainWebBrowser" Margin="0,47,10,83" UseLayoutRounding="False" RenderTransformOrigin="0.498,0.492" Grid.ColumnSpan="3" Grid.Column="1"/>
<Button x:Name="StartButton" Content="Start" Margin="0,0,10,32" FontWeight="Bold" FontSize="24" Background="#A5151513" Padding="1,1,1,3" Height="46" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="296" Click="Start_Click" Grid.Column="2" BorderBrush="#FF5A71FF" Foreground="#FF2149D3" BorderThickness="2,1" Grid.ColumnSpan="2"/>
<Button x:Name="WebsiteButton" Content="Join Gather" HorizontalAlignment="Left" Margin="0,0,0,32" Width="218" FontSize="18" Background="#A5151513" Padding="1,1,1,3" Height="46" VerticalAlignment="Bottom" Click="Website_Click" BorderBrush="#FFCD6E52" Grid.Column="1" Foreground="#FF2EB2F0" FontWeight="Bold"/>
<Button x:Name="SettingButton" Content="Settings" Margin="223,0,0,32" FontSize="18" Background="#A5151513" Padding="1,1,1,3" Height="46" VerticalAlignment="Bottom" Click="Setting_Click" Grid.Column="1" BorderBrush="#FF787539" HorizontalAlignment="Left" Width="180" Foreground="#FF2EB2F0" FontWeight="Bold"/>
<ProgressBar x:Name="UpdateProgressBar" Margin="0,0,0,6" Grid.ColumnSpan="2" Height="21" VerticalAlignment="Bottom" Foreground="#FF8CC197" Grid.Column="1">
<ProgressBar.Background>
<SolidColorBrush Color="#FFD8D8D8" Opacity="0.6"/>
</ProgressBar.Background>
</ProgressBar>
<Label x:Name="ProgressLabel" Content="" Margin="48,0" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Grid.ColumnSpan="2" Height="32" VerticalAlignment="Bottom" Foreground="Black" Grid.Column="1" FontWeight="Bold" FontSize="14"/>
<Button x:Name="VerifyButton" Content="Verify" Margin="408,0,0,32" FontSize="18" Background="#A5151513" Padding="1,1,1,3" Height="46" VerticalAlignment="Bottom" Click="Verify_Click" Grid.Column="1" BorderBrush="#FF239758" HorizontalAlignment="Left" Width="180" Foreground="#FF2EB2F0" FontWeight="Bold"/>
<Button x:Name="PauseButton" Content="" Grid.Column="3" Margin="5,0,10,6" FontWeight="Bold" FontStyle="Italic" FontSize="14" BorderBrush="#FF5993E6" Height="21" VerticalAlignment="Bottom" Click="Pause_Click">
<Button.Background>
<ImageBrush ImageSource="Ressources/pauseimage.png" Stretch="Uniform"/>
</Button.Background>
</Button>
<Image Grid.Column="2" Margin="9,24,0,0" Source="Ressources/steam_icon.png" Stretch="Fill" Height="18" VerticalAlignment="Top" HorizontalAlignment="Left" Width="25"/>
<Label x:Name="ServInfoLabel" Content="Public Server :" Grid.Column="2" HorizontalAlignment="Left" Margin="34,20,0,0" VerticalAlignment="Top" Foreground="White" FontFamily="Segoe WP Black" Width="224">
<Label.ContextMenu>
<ContextMenu>
<MenuItem Header="Join the server" Click="JoinPublicServer"/>
</ContextMenu>
</Label.ContextMenu>
</Label>
</Grid>
</Window>

View File

@ -0,0 +1,661 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using System;
using System.ComponentModel;
using System.Windows;
using System.Security.Cryptography;
using System.IO;
using System.Net;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Threading;
using DiscordRPC;
using System.Timers;
using System.Diagnostics;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Resources;
namespace NaturalLauncher
{
/// <summary>
/// Logique d'interaction pour MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
// TODO We need to know if ns files are being updated to lock the verify/update functions if so (with a file on the main serv).
public static bool IsDebugMode = false; //no use anymore, but stay here just in case I need him
public static bool IsVerification = true; //true by default since it's more commun to verify than to update
public static Settings sw;
public static string versionNumber;
public static string remoteVersionNumber;
public static bool downloadCancelled = false;
public BackgroundWorker backgroundWorker;
public static DiscordRpcClient Discordclient;
Uri LocalIndexURL = new Uri(String.Format("file:///{0}/index.html", Launcher.curDir));
private static string LogReportPath = Launcher.curDir;
TextWriter UpdateLog;
public void MainWindow_Closed(object sender, EventArgs e)
{
if (sw != null)
{
sw.Close();
}
}
public MainWindow()
{
InitializeComponent();
#if DEBUG
IsDebugMode = true;
#endif
SelfUpdater.DeleteOldFiles(); // not really needed since CleanAndLaunch.exe
SelfUpdater TheSelfUpdater = new SelfUpdater();
TheSelfUpdater.SetMainWindowRef(this);
TheSelfUpdater.UpdateLauncher();
if (SelfUpdater.LaucherRemoteVNumber != SelfUpdater.LaucherLocalVNumber && SelfUpdater.isSelfUpdating)
{
this.Hide();
}
else
{
// Set the title of the window with the correct launcher version
if (SelfUpdater.isSelfUpdating)
Launcher_Window.Title = "Natural Launcher v " + SelfUpdater.LaucherLocalVNumber;
else
Launcher_Window.Title = "Natural Launcher";
// CHECK THE HL AND NS INSTALL DIR AND WRITE IT IN THE LAUNCHER XML
Launcher.CheckInstallDirectory();
//Util.ChangeAValueInCfg("net_graph", "2"); //this is not useful but might be someday, that's why I still let it live
// WE SET DISCORD PRESENCE
string ApplicationID = "474144509048127503";
Discordclient = new DiscordRpcClient(ApplicationID);
Discordclient.Initialize();
OnlineStatusAtLaunch();
System.Timers.Timer PresenceTimer = new System.Timers.Timer();
PresenceTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
PresenceTimer.Enabled = true;
PresenceTimer.Interval = 5000;
// *** Get the main index.html if connected *** \\
if (Util.CheckForInternetConnection(Launcher.MainPageURL.AbsoluteUri)) //if we are connected
{
Launcher.RefreshInternetPageAsync("Main"); // we refresh the page
MainWebBrowser.Source = Launcher.MainPageURL; // and display it from source
}
else // if not simply show the saved file
{
MainWebBrowser.Navigate(LocalIndexURL.AbsolutePath);
}
// CHECK APP.VERSION NUMBER
Check_Version();
if (versionNumber != remoteVersionNumber && versionNumber != "0.0.0.0")
{
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("Update Needed !", "Update", MessageBoxButton.OK, MessageBoxImage.Exclamation);
StartButton.Content = "Please Update";
IsVerification = false;
}
if (versionNumber == "0.0.0.0")
{
StartButton.Content = "Verify";
IsVerification = false;
}
if (versionNumber == remoteVersionNumber && versionNumber != "0.0.0.0")
{
StartButton.Content = "Play"; // TODO The algorithm to verify btween local and remote manifest
}
}
}
private void ReadyLauncherForUpdate(string FirstLogLine)
{
StartButton.IsEnabled = false;
VerifyButton.IsEnabled = false;
SettingButton.IsEnabled = false;
UpdateLog = new StreamWriter(LogReportPath + Path.DirectorySeparatorChar + "UpdateLog_" + Util.GetLongTimeString() + ".txt", true); // dt forget to close()
UpdateLog.WriteLine(Util.GetShortTimeString() + FirstLogLine);
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
Launcher.UpdateDiscord(false);
Delegate myDelegate = (Action)Update_gatherButton;
Delegate secondDelegate = (Action)Update_ServLabel;
WebsiteButton.Dispatcher.Invoke(myDelegate);
ServInfoLabel.Dispatcher.Invoke(secondDelegate);
}
private void OnlineStatusAtLaunch()
{
Launcher.UpdateDiscord(false);
Delegate myDelegate = (Action)Update_gatherButton;
Delegate secondDelegate = (Action)Update_ServLabel;
WebsiteButton.Dispatcher.Invoke(myDelegate);
ServInfoLabel.Dispatcher.Invoke(secondDelegate);
}
private void Update_gatherButton()
{
if(Util.ReadGathererCount()>0)
WebsiteButton.Content = "Join Gather ( " + Util.ReadGathererCount() + " / 12 )";
else
WebsiteButton.Content = "Join Gather";
}
private void Update_ServLabel()
{
Launcher.UpdatePubServ(out int pubPlayers, out int maxPlayers);
ServInfoLabel.Content = "Public Server : " + pubPlayers + " / " + maxPlayers;
}
private void Check_Version()
{
// *** Get the version number *** \\
versionNumber = Util.LocalVersion(Launcher.curDir + Path.DirectorySeparatorChar + Launcher.VersionFileName);
remoteVersionNumber = Util.RemoteVersion(Properties.Settings.Default.IndexURL + Launcher.VersionFileName);
if (versionNumber != null)
{
VersionLabel.Content = versionNumber;
}
else //if it doesn exist, we need to inform the user
{
versionNumber = "0.0.0.0";
VersionLabel.Content = "Verify";
StartButton.Content = "Verify";
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("Please verify the installation" + Environment.NewLine
+ "This message will show up if this is the first time you launch this software"
, "Alert", MessageBoxButton.OK, MessageBoxImage.Exclamation); //not true anymore
SettingButton.IsEnabled = false;
IsVerification = false;
}
}
#region clicks
private void Start_Click(object sender, RoutedEventArgs e)
{
if (SelfUpdater.CheckOneFileSignature("NaturalLauncher.exe") || !SelfUpdater.isSelfUpdating)
{
if (versionNumber != remoteVersionNumber || versionNumber == "0.0.0.0")
{
ReadyLauncherForUpdate("Start Update from play button");
StartButton.Content = "Verifying...";
IsVerification = false;
UpdateGame(); //verify the game with the right click context menu
}
else
{
Launcher.PlayGame();
Util.PlaySoundFX("finish");
}
}
else
{
Util.PlaySoundFX("error");
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("Your launcher is corrupted or out of date, please relaunch" + Environment.NewLine
+ "if the problem persist, please redownload the launcher from an official source (ensl.org)");
File.Delete(Launcher.curDir + Path.DirectorySeparatorChar + "launcher.version");
Environment.Exit(0);
}
}
private void Website_Click(object sender, RoutedEventArgs e)
{
Launcher.LaunchWebsite(Properties.Settings.Default.GatherURL);
}
private void Setting_Click(object sender, RoutedEventArgs e)
{
if (sw == null)
{
sw = new Settings();
}
sw.SetMainWindowRef(this);
sw.Show();
}
private void Verify_Click(object sender, RoutedEventArgs e)
{
ReadyLauncherForUpdate("Verification started from launcher");
if (versionNumber != remoteVersionNumber || versionNumber == "0.0.0.0")
{
IsVerification = false;
UpdateLog.WriteLine(Util.GetShortTimeString() + "but it's an update");
}
else
{
IsVerification = true;
}
UpdateGame(); //verify the game with the right click context menu
}
private void Pause_Click(object sender, RoutedEventArgs e)
{
var brush = new ImageBrush();
try
{
if (!downloadCancelled)
{
downloadCancelled = true;
backgroundWorker.CancelAsync();
Uri resourceUri = new Uri("Ressources/playimage.png", UriKind.Relative); //"pack://application:,,,/NaturalLauncher;component/Images/Resource_Image.png"
StreamResourceInfo streamInfo = Application.GetResourceStream(resourceUri);
BitmapFrame temp = BitmapFrame.Create(streamInfo.Stream);
brush.ImageSource = temp;
PauseButton.Background = brush;
}
else
{
ReadyLauncherForUpdate("Verification resumed from launcher");
UpdateGame(); //verify the game with the right click context menu
Uri resourceUri = new Uri("Ressources/pauseimage.png", UriKind.Relative);
StreamResourceInfo streamInfo = Application.GetResourceStream(resourceUri);
BitmapFrame temp = BitmapFrame.Create(streamInfo.Stream);
brush.ImageSource = temp;
PauseButton.Background = brush;
}
}
catch
{
downloadCancelled = false;
Uri resourceUri = new Uri("Ressources/pauseimage.png", UriKind.Relative);
StreamResourceInfo streamInfo = Application.GetResourceStream(resourceUri);
BitmapFrame temp = BitmapFrame.Create(streamInfo.Stream);
brush.ImageSource = temp;
PauseButton.Background = brush;
} //I don't give a f if it doesnt catch shit
}
#endregion
#region ContextMenu
private void BuildManifest(object sender, RoutedEventArgs e)
{
ManifestBuilder.BuildManifest(Launcher.NSFolder); // build the manifest of the file to update
}
private void VerifyTheGame(object sender, RoutedEventArgs e)
{
/*UpdateLog = new StreamWriter(LogReportPath + Path.DirectorySeparatorChar + "UpdateLog_" + Util.GetLongTimeString() + ".txt", true); // dt forget to close()
UpdateLog.WriteLine(Util.GetShortTimeString() + "Verification started from context menu");
UpdateGame(); //verify the game with the right click context menu*/ //not used anymore
}
private void CheckLauncherUpdate(object sender, RoutedEventArgs e)
{
SelfUpdater TheSelfUpdater = new SelfUpdater();
TheSelfUpdater.allowMessage = true;
TheSelfUpdater.UpdateLauncher();
}
private void JoinDiscord(object sender, RoutedEventArgs e)
{
Process.Start("https://discord.gg/ZUSSBUA");
}
private void SeeCredit(object sender, RoutedEventArgs e)
{
Process.Start("https://discord.gg/ZUSSBUA");
}
private void JoinPublicServer(object sender, RoutedEventArgs e)
{
Process.Start("steam://connect/104.156.251.121:27015");
}
private void AddToIgnore(object sender, RoutedEventArgs e)
{
Launcher.AddToIgnoreList();
}
private void OpenNSFolder(object sender, RoutedEventArgs e)
{
Process.Start(Launcher.NSFolder);
}
#endregion
#region UpdateMaelAlgo
public void UpdateGame()
{
Util.PlaySoundFX("start");
TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal;
downloadCancelled = false;
backgroundWorker = new System.ComponentModel.BackgroundWorker();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.DoWork += UpdateGame_Worker;
backgroundWorker.ProgressChanged += UpdateGame_ProgressChanged;
backgroundWorker.RunWorkerCompleted += UpdateGame_RunWorkerCompleted;
backgroundWorker.RunWorkerAsync();
}
public void CallUpdateGame() //same as updategame for now
{
ReadyLauncherForUpdate("update Called from a setting's change");
UpdateGame();
}
public void UpdateGame_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
StartButton.Content = "Error";
UpdateProgressBar.Value = 0;
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("Error while downloading, please try again");
ProgressLabel.Content = "Error while downloading, please try again";
TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Error;
return;
}
if (downloadCancelled)
{
ProgressLabel.Content = "Paused !";
UpdateLog.WriteLine(Util.GetShortTimeString() + "Stop requested by the user...");
TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Paused; //yellow thing
}
else
{
ProgressLabel.Content = "Up to date !";
StartButton.Content = "Play";
UpdateLog.WriteLine(Util.GetShortTimeString() + "Completed the update or verify work");
TaskbarItemInfo.ProgressValue = 0;
TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal;
Util.CreateLocalVersionFile(Launcher.curDir, Launcher.VersionFileName, remoteVersionNumber); //update the version with the new one
Check_Version(); // we should have a changed app.version file to check
}
UpdateLog.Close();
backgroundWorker.Dispose();
Util.PlaySoundFX("finish");
StartButton.IsEnabled = true;
SettingButton.IsEnabled = true;
VerifyButton.IsEnabled = true;
}
public void UpdateGame_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ProgressLabel.Content = e.UserState as string;
UpdateProgressBar.Value = e.ProgressPercentage;
TaskbarItemInfo.ProgressValue = (double)((float)e.ProgressPercentage / 100f);
}
public void UpdateGame_Worker(object sender, DoWorkEventArgs e)
{
backgroundWorker.ReportProgress(0, "Downloading Manifest...");
string ManifestURL = Launcher.MainPageURL.AbsoluteUri + Launcher.ManifestName;
WebClient webClient = new WebClient();
webClient.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
webClient.DownloadProgressChanged += webClient_DownloadProgressChanged;
webClient.DownloadFileCompleted += webClient_DownloadFileCompleted;
string manifest = webClient.DownloadString(ManifestURL);
LauncherManifest RemoteManifest = JsonConvert.DeserializeObject<LauncherManifest>(manifest);
if (Launcher.IsNLPack())
{
string NLManifestURL = Launcher.MainPageURL.AbsoluteUri + Launcher.NLManifestName;
string NLmanifest = webClient.DownloadString(NLManifestURL);
LauncherManifest NLManifest = JsonConvert.DeserializeObject<LauncherManifest>(NLmanifest);
RemoteManifest = Util.CleanManifestWithOptions(RemoteManifest, NLManifest); //cleaning the manifest hash consequently
}
LauncherManifest IgnoreManifest = Util.GetIgnoreManifest(IsVerification); //attention, might not exist, if so it has to be downloaded, if not let's use it !
string gameInstallDir = Launcher.NSFolder;
UpdateLog.WriteLine(Util.GetShortTimeString() + "Install Directory located in : " + gameInstallDir);
UpdateLog.WriteLine(Util.GetShortTimeString() + "NL Pack installed : " + Launcher.IsNLPack().ToString());
UpdateLog.WriteLine(Util.GetShortTimeString() + "Distant Manifest located at : " + ManifestURL);
var md5 = MD5.Create();
int totalFiles = RemoteManifest.Files.Count;
UpdateLog.WriteLine(Util.GetShortTimeString() + "Total file to update : " + totalFiles);
int curFile = 0;
// Update the standard files
foreach (KeyValuePair<string, string> kv in RemoteManifest.Files)
{
bool ShouldDownload = false;
string gameFilePath = gameInstallDir + kv.Key.Replace("/", Path.DirectorySeparatorChar.ToString());
IgnoreManifest.Files.TryGetValue(kv.Key, out string IgnoreValue); //get the ignore file value in manifest ("0" ignore only verif, "1" ignore verif + update)
bool Condition1 = File.Exists(gameFilePath) && IgnoreManifest.Files.ContainsKey(kv.Key) == false;//if the file exists and not in the ignore manifest, let's have it !
bool Condition2 = File.Exists(gameFilePath) && IgnoreManifest.Files.ContainsKey(kv.Key) && IgnoreValue == "0" && !IsVerification; //if the file exists, is in the ignore manifest, but is updatable and... it's update time !
if (Condition1 || Condition2)
{
int progress = (int)(((float)curFile / (float)totalFiles) * 100);
backgroundWorker.ReportProgress(progress, "(" + (curFile) + " / " + totalFiles + ") Checking " + kv.Key);
//Check its md5 hash
using (var stream = File.OpenRead(gameFilePath))
{
var hash = Util.ComputeMD5(gameFilePath);
if (hash != kv.Value)
{
UpdateLog.WriteLine(Util.GetShortTimeString() + gameFilePath + " needs to be updated");
ShouldDownload = true;
}
}
}
if (!File.Exists(gameFilePath))
{
UpdateLog.WriteLine(Util.GetShortTimeString() + gameFilePath + " not existing, needs downloading");
ShouldDownload = true;
}
if (File.Exists(gameFilePath) && IgnoreManifest.Files.ContainsKey(kv.Key) && IgnoreValue == "1") // ignore everything
{
UpdateLog.WriteLine(Util.GetShortTimeString() + gameFilePath + " Is Ignored for update, not checking");
ShouldDownload = false;
}
if (File.Exists(gameFilePath) && IgnoreManifest.Files.ContainsKey(kv.Key) && IsVerification && IgnoreValue == "0") //if we need to ignore update and it's verification, we ignore !
{
UpdateLog.WriteLine(Util.GetShortTimeString() + gameFilePath + " Is Ignored for verifications, not checking");
ShouldDownload = false;
}
if (ShouldDownload)
{
DownloadFile(curFile, totalFiles, kv, RemoteManifest, gameFilePath, Properties.Settings.Default.GameUrl, webClient);
var hash = Util.ComputeMD5(gameFilePath);
if (hash != kv.Value)
{
//MessageBox.Show("Failed Validating " + kv.Key + " : Redownloading"); //problem with double validation, is it too soon in the chain of event ?
UpdateLog.WriteLine(Util.GetShortTimeString() + "failed to verify newly downloaded file, redownloading");
DownloadFile(curFile, totalFiles, kv, RemoteManifest, gameFilePath, Properties.Settings.Default.GameUrl, webClient);
}
UpdateLog.WriteLine(Util.GetShortTimeString() + "Download complete for file: " + kv.Key + " with new hash :" + hash + " for manifest hash : " + kv.Value);
}
if (backgroundWorker.CancellationPending)
{
UpdateLog.WriteLine(Util.GetShortTimeString() + "Update cancelled");
return;
}
curFile++;
}
// Update the NineLegend pack files if requiered
/*if (Launcher.IsNLPack())
{
string NLManifestURL = Launcher.MainPageURL.AbsoluteUri + Launcher.NLManifestName;
string NLmanifest = webClient.DownloadString(NLManifestURL);
LauncherManifest NLManifest = JsonConvert.DeserializeObject<LauncherManifest>(NLmanifest);
curFile = curFile - NLManifest.Files.Count;
foreach (KeyValuePair<string, string> kv in NLManifest.Files)
{
bool ShouldDownload = false;
string gameFilePath = gameInstallDir + kv.Key.Replace("/", Path.DirectorySeparatorChar.ToString());
if (File.Exists(gameFilePath))
{
int progress = (int)(((float)curFile / (float)totalFiles) * 100);
backgroundWorker.ReportProgress(progress, "(" + (curFile) + " / " + totalFiles + ") Checking " + kv.Key);
//Check its md5 hash
using (var stream = File.OpenRead(gameFilePath))
{
var hash = Util.ComputeMD5(gameFilePath);
if (hash != kv.Value)
{
UpdateLog.WriteLine(Util.GetShortTimeString() + gameFilePath + " needs to be updated");
ShouldDownload = true;
}
}
}
else
{
UpdateLog.WriteLine(Util.GetShortTimeString() + gameFilePath + " not existing, needs downloading");
ShouldDownload = true;
}
if (ShouldDownload)
{
DownloadFile(curFile, totalFiles, kv, NLManifest, gameFilePath, Properties.Settings.Default.NineLegendUrl, webClient);
var hash = Util.ComputeMD5(gameFilePath);
if (hash != kv.Value)
{
//MessageBox.Show("Failed Validating " + kv.Key + " : Redownloading"); //problem with double validation, is it too soon in the chain of event ?
UpdateLog.WriteLine(Util.GetShortTimeString() + "failed to verify newly downloaded file, redownloading");
DownloadFile(curFile, totalFiles, kv, NLManifest, gameFilePath, Properties.Settings.Default.NineLegendUrl, webClient);
}
UpdateLog.WriteLine(Util.GetShortTimeString() + "Download complete for NineLegend file: " + kv.Key + " with new hash :" + hash + " for manifest hash : " + kv.Value);
}
if (backgroundWorker.CancellationPending)
{
UpdateLog.WriteLine(Util.GetShortTimeString() + "Update cancelled");
return;
}
curFile++;
}
}*/
backgroundWorker.ReportProgress(100, "Writing Local Manifest");
/* string manifestDirectory = Launcher.curDir + Path.DirectorySeparatorChar + Launcher.ManifestName;
File.WriteAllText(manifestDirectory, manifest); // replace all with function in util */
}
private void DownloadFile(int curFile, int totalFiles, KeyValuePair<string, string> kv, LauncherManifest RemoteManifest, string gameFilePath, string folderURL, WebClient webClient)
{
int progress = (int)(((float)curFile / (float)totalFiles) * 100);
string status = "(" + (curFile) + " / " + totalFiles + ") Downloading: " + kv.Key;
UpdateLog.WriteLine(Util.GetShortTimeString() + "Downloading file: " + kv.Key);
backgroundWorker.ReportProgress(progress, status);
string remoteFile = (folderURL + "/" + kv.Key.Substring(1));
Directory.CreateDirectory(Path.GetDirectoryName(gameFilePath));
if (File.Exists(gameFilePath))
{
UpdateLog.WriteLine(Util.GetShortTimeString() + "File exist, deleting old file");
File.Delete(gameFilePath);
}
try
{
webClient.DownloadFileAsync(new Uri(remoteFile), gameFilePath, status);
}
catch (Exception e)
{
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("new file not found");
UpdateLog.WriteLine(Util.GetShortTimeString() + "Failed Downloading file: " + kv.Key + "with message : " + e.Message);
backgroundWorker.CancelAsync();
}
while (webClient.IsBusy)
{
Thread.Sleep(1);
}
}
void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
string status = e.UserState as string + " ( " + Util.Size(e.BytesReceived) + " / " + Util.Size(e.TotalBytesToReceive) + " )";
backgroundWorker.ReportProgress(e.ProgressPercentage, status);
}
void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
System.Windows.MessageBox.Show(e.Error.ToString());
backgroundWorker.CancelAsync();
}
}
#endregion
}
}

View File

@ -0,0 +1,74 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using Newtonsoft.Json;
using System.IO;
using System.Security.Cryptography;
namespace NaturalLauncher
{
class ManifestBuilder
{
private static MD5 md5;
public static void BuildManifest(string directory)
{
LauncherManifest manifest = new LauncherManifest();
md5 = MD5.Create();
RecursiveBuildManifest(directory, "", manifest);
/*SaveFileDialog dialog = new SaveFileDialog(); // commented but needed when you want to save a manifest somewhere else (could be usefull for a manifest builder console app
dialog.InitialDirectory = Environment.CurrentDirectory;
dialog.FileName = "Manifest.txt";
if (dialog.ShowDialog() == DialogResult.OK)
{
File.WriteAllText(dialog.FileName, JsonConvert.SerializeObject(manifest, Formatting.Indented));
}*/
string ManifestPath = Launcher.curDir + Path.DirectorySeparatorChar + Launcher.ManifestName;
File.WriteAllText(ManifestPath, JsonConvert.SerializeObject(manifest, Formatting.Indented));
}
private static void RecursiveBuildManifest(string projectRoot, string dir, LauncherManifest manifest)
{
string path = projectRoot + dir;
foreach (string file in Directory.GetFiles(path))
{
string localPath = Util.ToLocalPath(projectRoot, file);
string hash = Util.ComputeMD5(file);
if (!localPath.EndsWith("_.cfg") && localPath != "/Manifest.txt" && localPath != "/ManifestBuilder.exe"
&& localPath != "/Newtonsoft.Json.dll") //we don't want cfg files to get updated here cept config.cfg which is in ignore.list
manifest.Files[localPath] = hash;
}
foreach (string nextDir in Directory.GetDirectories(path))
{
RecursiveBuildManifest(projectRoot, Util.ToLocalPath(projectRoot, nextDir), manifest);
}
}
}
}

View File

@ -0,0 +1,211 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" 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>{0138DD06-7386-4820-9BCE-3F8412CAD801}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>NaturalLauncher</RootNamespace>
<AssemblyName>NaturalLauncher</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>true</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>true</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<TargetCulture>en</TargetCulture>
<ProductName>Natural Launcher</ProductName>
<PublisherName>Mael Vignaux</PublisherName>
<MinimumRequiredVersion>1.0.0.0</MinimumRequiredVersion>
<OpenBrowserOnPublish>false</OpenBrowserOnPublish>
<AutorunEnabled>true</AutorunEnabled>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
<BootstrapperEnabled>true</BootstrapperEnabled>
</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>
<PropertyGroup>
<ApplicationIcon>Ressources\nsl_icon.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<ManifestCertificateThumbprint>D8B30162E74CFDDB757978150D09F39672490FAC</ManifestCertificateThumbprint>
</PropertyGroup>
<PropertyGroup>
<ManifestKeyFile>NaturalLauncher_TemporaryKey.pfx</ManifestKeyFile>
</PropertyGroup>
<PropertyGroup>
<GenerateManifests>true</GenerateManifests>
</PropertyGroup>
<PropertyGroup>
<SignManifests>true</SignManifests>
</PropertyGroup>
<ItemGroup>
<Reference Include="DiscordRPC, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\DiscordRPC.dll</HintPath>
</Reference>
<Reference Include="HtmlAgilityPack, Version=1.8.5.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
<HintPath>..\packages\HtmlAgilityPack.1.8.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Numerics" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="ConsoleManager.cs" />
<Compile Include="LauncherManifest.cs" />
<Compile Include="ManifestBuilder.cs" />
<Compile Include="ProjectSettings.cs" />
<Compile Include="SelfUpdater.cs" />
<Compile Include="ServerChecker.cs" />
<Compile Include="Settings.xaml.cs">
<DependentUpon>Settings.xaml</DependentUpon>
</Compile>
<Compile Include="Util.cs" />
<Compile Include="XmlBuilder.cs" />
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Launcher.cs" />
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="Settings.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="NaturalLauncher_TemporaryKey.pfx" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Resource Include="Ressources\Commande.lex" />
</ItemGroup>
<ItemGroup>
<None Include="App.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<Resource Include="Ressources\background.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Ressources\small_discordicon.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Ressources\nsl_icon.ico" />
</ItemGroup>
<ItemGroup>
<Resource Include="nsl_icon.ico" />
</ItemGroup>
<ItemGroup>
<Resource Include="Ressources\background_blur.png" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.6.2">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.6.2 %28x86 et x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<Resource Include="Ressources\pauseimage.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Ressources\playimage.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Ressources\sdx_error.wav" />
<Resource Include="Ressources\sdx_finished.wav" />
<Resource Include="Ressources\sdx_started.wav" />
</ItemGroup>
<ItemGroup>
<Resource Include="Ressources\steam_icon.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2042
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NaturalLauncher", "NaturalLauncher\NaturalLauncher.csproj", "{0138DD06-7386-4820-9BCE-3F8412CAD801}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManifestBuilder", "ManifestBuilder\ManifestBuilder.csproj", "{6A7DBE40-6BFB-49F5-BFC1-9F0752EC31BE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanAndLaunch", "CleanAndLaunch\CleanAndLaunch.csproj", "{8E7856FD-FA68-4356-9C88-54C9EF5A9D20}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0138DD06-7386-4820-9BCE-3F8412CAD801}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0138DD06-7386-4820-9BCE-3F8412CAD801}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0138DD06-7386-4820-9BCE-3F8412CAD801}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0138DD06-7386-4820-9BCE-3F8412CAD801}.Release|Any CPU.Build.0 = Release|Any CPU
{6A7DBE40-6BFB-49F5-BFC1-9F0752EC31BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A7DBE40-6BFB-49F5-BFC1-9F0752EC31BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A7DBE40-6BFB-49F5-BFC1-9F0752EC31BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A7DBE40-6BFB-49F5-BFC1-9F0752EC31BE}.Release|Any CPU.Build.0 = Release|Any CPU
{8E7856FD-FA68-4356-9C88-54C9EF5A9D20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8E7856FD-FA68-4356-9C88-54C9EF5A9D20}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E7856FD-FA68-4356-9C88-54C9EF5A9D20}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E7856FD-FA68-4356-9C88-54C9EF5A9D20}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {06E5B626-B631-47BF-84D5-A157442007E0}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,30 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
namespace ArtefactsLauncher
{
public class ProjectSettings
{
// Attention, it is very important to keep the exact same names as in the json
public float ScreenPercentage;
public float BeeFactor;
}
}

View File

@ -0,0 +1,53 @@
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
// Les informations générales relatives à un assembly dépendent de
// l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
// associées à un assembly.
[assembly: AssemblyTitle("NaturalLauncher")]
[assembly: AssemblyDescription("The launcher and updater for natural selection 1")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Mael Vignaux")]
[assembly: AssemblyProduct("NaturalLauncher")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly
// aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de
// COM, affectez la valeur true à l'attribut ComVisible sur ce type.
[assembly: ComVisible(false)]
//Pour commencer à générer des applications localisables, définissez
//<UICulture>CultureUtiliséePourCoder</UICulture> dans votre fichier .csproj
//dans <PropertyGroup>. Par exemple, si vous utilisez le français
//dans vos fichiers sources, définissez <UICulture> à fr-FR. Puis, supprimez les marques de commentaire de
//l'attribut NeutralResourceLanguage ci-dessous. Mettez à jour "fr-FR" dans
//la ligne ci-après pour qu'elle corresponde au paramètre UICulture du fichier projet.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //où se trouvent les dictionnaires de ressources spécifiques à un thème
//(utilisé si une ressource est introuvable dans la page,
// ou dictionnaires de ressources de l'application)
ResourceDictionaryLocation.SourceAssembly //où se trouve le dictionnaire de ressources générique
//(utilisé si une ressource est introuvable dans la page,
// dans l'application ou dans l'un des dictionnaires de ressources spécifiques à un thème)
)]
// Les informations de version pour un assembly se composent des quatre valeurs suivantes :
//
// Version principale
// Version secondaire
// Numéro de build
// Révision
//
// Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
// en utilisant '*', comme indiqué ci-dessous :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Ce code a été généré par un outil.
// Version du runtime :4.0.30319.42000
//
// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
// le code est régénéré.
// </auto-generated>
//------------------------------------------------------------------------------
namespace NaturalLauncher.Properties {
using System;
/// <summary>
/// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées.
/// </summary>
// Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder
// à l'aide d'un outil, tel que ResGen ou Visual Studio.
// Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen
// avec l'option /str ou régénérez votre projet VS.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Retourne l'instance ResourceManager mise en cache utilisée par cette classe.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NaturalLauncher.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Remplace la propriété CurrentUICulture du thread actuel pour toutes
/// les recherches de ressources à l'aide de cette classe de ressource fortement typée.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,110 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Ce code a été généré par un outil.
// Version du runtime :4.0.30319.42000
//
// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
// le code est régénéré.
// </auto-generated>
//------------------------------------------------------------------------------
namespace NaturalLauncher.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("http://ensl.gk-servers.de/")]
public string ConfigurationUrl {
get {
return ((string)(this["ConfigurationUrl"]));
}
set {
this["ConfigurationUrl"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("http://ensl.gk-servers.de/")]
public string IndexURL {
get {
return ((string)(this["IndexURL"]));
}
set {
this["IndexURL"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("http://ensl.gk-servers.de/")]
public string CreditURL {
get {
return ((string)(this["CreditURL"]));
}
set {
this["CreditURL"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("http://ensl.gk-servers.de/ns")]
public string GameUrl {
get {
return ((string)(this["GameUrl"]));
}
set {
this["GameUrl"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("https://www.ensl.org/gathers/latest/ns1")]
public string GatherURL {
get {
return ((string)(this["GatherURL"]));
}
set {
this["GatherURL"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("http://www.elseware-experience.com/vignauxmael/NaturalLauncher/NLPack")]
public string NineLegendUrl {
get {
return ((string)(this["NineLegendUrl"]));
}
set {
this["NineLegendUrl"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("http://ensl.gk-servers.de/Launcher/")]
public string LauncherUrl {
get {
return ((string)(this["LauncherUrl"]));
}
set {
this["LauncherUrl"] = value;
}
}
}
}

View File

@ -0,0 +1,27 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="NaturalLauncher.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="ConfigurationUrl" Type="System.String" Scope="User">
<Value Profile="(Default)">http://ensl.gk-servers.de/</Value>
</Setting>
<Setting Name="IndexURL" Type="System.String" Scope="User">
<Value Profile="(Default)">http://ensl.gk-servers.de/</Value>
</Setting>
<Setting Name="CreditURL" Type="System.String" Scope="User">
<Value Profile="(Default)">http://ensl.gk-servers.de/</Value>
</Setting>
<Setting Name="GameUrl" Type="System.String" Scope="User">
<Value Profile="(Default)">http://ensl.gk-servers.de/ns</Value>
</Setting>
<Setting Name="GatherURL" Type="System.String" Scope="User">
<Value Profile="(Default)">https://www.ensl.org/gathers/latest/ns1</Value>
</Setting>
<Setting Name="NineLegendUrl" Type="System.String" Scope="User">
<Value Profile="(Default)">http://www.elseware-experience.com/vignauxmael/NaturalLauncher/NLPack</Value>
</Setting>
<Setting Name="LauncherUrl" Type="System.String" Scope="User">
<Value Profile="(Default)">http://ensl.gk-servers.de/Launcher/</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@ -0,0 +1,144 @@
parameter
value
_snd_mixahead
ati_npatch
bgmvolume
bottomcolor
brightness
cl_allowdownload
cl_allowupload
cl_autohelp
cl_backspeed
cl_buildmessages
cl_centerentityid
cl_cmdbackup
cl_cmdrate
cl_cmhotkeys
cl_cross
cl_cross_alpha
cl_cross_bottom_line
cl_cross_color
cl_cross_dot_color
cl_cross_dot_outline
cl_cross_dot_size
cl_cross_gap
cl_cross_left_line
cl_cross_outline
cl_cross_outline_inner
cl_cross_right_line
cl_cross_size
cl_cross_thickness
cl_cross_top_line
cl_customcrosshair
cl_dlmax
cl_download_ingame
cl_dynamiclights
cl_forcedefaultfov
cl_forwardspeed
cl_gammaramp
cl_highdetail
cl_himodels
cl_hudmapzoom
cl_iconb
cl_icong
cl_iconr
cl_idealpitchscale
cl_labelhivesight
cl_labelmaps
cl_lc
cl_logocolor
cl_logofile
cl_lw
cl_mousegrab
cl_musicdelay
cl_musicdirectory
cl_musicenabled
cl_musicvolume
cl_particleinfo
cl_quickselecttime
cl_timeout
cl_updaterate
cl_vsmoothing
cl_widescreen
con_color
con_mono
console
crosshair
fps_max
gamma
gl_dither
gl_flipmatrix
gl_fog
gl_monolights
gl_overbright
gl_polyoffset
gl_vsync
hisound
hpk_maxsize
hud_capturemouse
hud_centerid
hud_classautokill
hud_draw
hud_fastswitch
hud_takesshots
joystick
lookspring
lookstrafe
m_customaccel
m_customaccel_exponent
m_customaccel_max
m_customaccel_scale
m_filter
m_forward
m_mousethread_sleep
m_pitch
m_rawinput
m_side
m_yaw
model
MP3FadeTime
MP3Volume
mp_decals
name
net_graph
net_scale
r_detailtextures
sensitivity
skin
suitvolume
sv_aim
sv_voiceenable
team
topcolor
viewsize
voice_enable
voice_forcemicrecord
voice_modenable
voice_scale
volume
sv_cheats
hud_style
cl_cmdrate
cl_updaterate
ex_extrapmax
cl_cmdbackup
rate
ex_interp
gl_wateramp
gl_zmax
gl_ztrick
r_drawviewmodel
r_mmx
r_dynamic
r_decals
r_mirroralpha
r_bmodelhighfrac
violence_ablood
violence_agibs
violence_hblood
violence_hgibs
cl_labelmaps
senslock
cl_ambientsound
cl_widescreen
sv_jumpmode

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,325 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace NaturalLauncher
{
class SelfUpdater
{
public static bool isSelfUpdating = true;
public static string LaucherLocalVNumber;
public static string LaucherRemoteVNumber;
public static string curDir = Directory.GetCurrentDirectory();
public static MainWindow MainWindowReference;
public static string LauncherFolderURL = Properties.Settings.Default.LauncherUrl;
public static string VersionFileName = "launcher.version";
public static string PublicKeyPath = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "NslKey.cer";
public static string manifestUrl = Properties.Settings.Default.IndexURL + "CryptoManifest.txt";
public static LauncherManifest CryptoManifest = new LauncherManifest();
public static int NumberOfFiles = 0;
public bool allowMessage=false;
public BackgroundWorker backgroundWorker;
public void SetMainWindowRef(MainWindow MainWindowRef)
{
MainWindowReference = MainWindowRef;
}
public void UpdateLauncher()
{
if(isSelfUpdating)
{
CheckUpdaterVersion();
DeleteOldFiles(); //delete all the updatelog and .bak files
if (LaucherLocalVNumber != LaucherRemoteVNumber)
{
UpdateCryptoManifest();
// Move the files in the launcher directory to a name with .bak
MoveLauncherFiles(); //Attention, non recursive !!!
// falsify all the buttons
MainWindowReference.StartButton.IsEnabled = false;
MainWindowReference.VerifyButton.IsEnabled = false;
MainWindowReference.SettingButton.IsEnabled = false;
// We gotta update the launcher !
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("The Launcher Will be self updating !" + Environment.NewLine + "It will restart itself once done..."); //not true anymore
ConsoleManager.Show();
// background worker download the files and switch the launcher when over
backgroundWorker = new System.ComponentModel.BackgroundWorker();
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.DoWork += UpdateLauncher_Worker;
backgroundWorker.RunWorkerCompleted += UpdateLauncher_RunWorkerCompleted;
backgroundWorker.RunWorkerAsync();
}
else
{
if (allowMessage) //inform the player we don't need update (only when using context menu so far)
{
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("No Update Required !");
}
}
}
}
private static void UpdateCryptoManifest()
{
using (WebClient webClient = new WebClient())
{
Console.WriteLine("Downloading the CryptoManifest");
string dasManifest = webClient.DownloadString(new Uri(manifestUrl));
CryptoManifest = JsonConvert.DeserializeObject<LauncherManifest>(dasManifest);
NumberOfFiles = CryptoManifest.Files.Count;
}
}
public static void CheckUpdaterVersion()
{
LaucherLocalVNumber = Util.LocalVersion(curDir + Path.DirectorySeparatorChar + VersionFileName);
Console.WriteLine("Checking launcher's Version ...");
Console.WriteLine("Local Version of the updater is :" + LaucherLocalVNumber);
if (LaucherLocalVNumber != null)
{
LaucherRemoteVNumber = Util.RemoteVersion(Launcher.MainPageURL + VersionFileName);
Console.WriteLine("Got the remote version with success :" + LaucherRemoteVNumber);
}
else //if it doesn exist, we need to inform the user
{
LaucherLocalVNumber = "0.0.0.0";
Util.PlaySoundFX("error");
LaucherRemoteVNumber = Util.RemoteVersion(Launcher.MainPageURL + VersionFileName);
Console.WriteLine("Couldnt find remote version number");
}
}
public static void MoveLauncherFiles()
{
foreach (KeyValuePair<string, string> kv in CryptoManifest.Files)
{
string fullpath = curDir + Path.DirectorySeparatorChar + kv.Key.Remove(0,1);
if (File.Exists(fullpath))
{
Console.WriteLine(fullpath + " : Changing to .bak extension ...");
System.IO.File.Move(fullpath, fullpath + ".bak");
}
}
}
/*public static void AddNewFilesToChangeList()
{
// Check the new files
List<string> NewFiles = Util.GetDirectoryFilesFromUrl(LauncherFolderURL);
// we add the new files into the changedlist
foreach (string file in NewFiles)
{
if (!ChangedFiles.Contains(file))
ChangedFiles.Add(file);
}
NumberOfFiles = ChangedFiles.Count;
}*/
public void UpdateLauncher_Worker(object sender, DoWorkEventArgs e)
{
WebClient webClient = new WebClient();
webClient.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
webClient.DownloadFileCompleted += webClient_DownloadFileCompleted;
// Download the changed files
foreach (KeyValuePair<string, string> kv in CryptoManifest.Files)
{
string smtg = kv.Key.Remove(0, 1);
DownloadLauncherFiles(kv.Key.Remove(0,1), webClient);
}
}
public void UpdateLauncher_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (!backgroundWorker.IsBusy && NumberOfFiles<=0) //double check but somehow it executed twice oO
{
CheckSignatureAndLaunch();
}
}
public void DownloadLauncherFiles(string file, WebClient webClient)
{
Console.WriteLine(file + " : Downloading ...");
webClient.DownloadFileAsync(new Uri(LauncherFolderURL+ file), curDir + Path.DirectorySeparatorChar + file);
while (webClient.IsBusy)
{
Thread.Sleep(1);
}
}
void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
System.Windows.MessageBox.Show(e.Error.ToString());
}
else
{
try
{
NumberOfFiles--;
Console.WriteLine("Downloaded !" + NumberOfFiles.ToString() + " more files to go !");
}
catch
{ }
}
}
public static void DeleteOldFiles()
{
Console.WriteLine("Cleaning old and update files ...");
foreach (string file in Directory.GetFiles(curDir))
{
// Cleaning BAK files
if(Path.GetExtension(file)==".bak")
{
File.Delete(file);
}
string localPath = Util.ToLocalPath(curDir, file);
// Cleaning UpdateLogs files
if (localPath.StartsWith("/UpdateLog"))
{
File.Delete(file);
}
}
}
public static void CheckSignatureAndLaunch()
{
Console.WriteLine("Starting signature check");
foreach (KeyValuePair<string, string> kv in CryptoManifest.Files)
{
string FullPath = curDir + Path.DirectorySeparatorChar + kv.Key.Remove(0, 1);
var stream = File.ReadAllBytes(FullPath);
string signatureHexaString = "";
CryptoManifest.Files.TryGetValue(kv.Key, out signatureHexaString);
if (!Verify(stream, PublicKeyPath, signatureHexaString))
{
Util.PlaySoundFX("error");
System.Windows.MessageBox.Show(kv.Key + " unvalidated. Your version is corrupted, please redownload the launcher from a trusted source (ensl.org)");
Console.WriteLine(kv.Key + " : UNVALIDATED and DELETED...");
File.Delete(FullPath);
Console.Read();
Environment.Exit(0);
}
else
Console.WriteLine(kv.Key + " : validated ...");
}
Task.Delay(10);
Console.WriteLine("Refreshing version Number");
Util.CreateLocalVersionFile(curDir, VersionFileName, LaucherRemoteVNumber);
Util.LaunchAgain(curDir + Path.DirectorySeparatorChar + "CleanAndLaunch.exe");
Environment.Exit(0);
}
public static bool Verify(byte[] data, string PublicKeyPath, string SignatureHexaString)
{
X509Certificate2 publicKey = LoadPublicKey(PublicKeyPath);
byte[] signature = StringToByte(SignatureHexaString);
if (data == null)
{
throw new ArgumentNullException("data");
}
if (publicKey == null)
{
throw new ArgumentNullException("publicKey");
}
if (signature == null)
{
throw new ArgumentNullException("signature");
}
var provider = (RSACryptoServiceProvider)publicKey.PublicKey.Key;
return provider.VerifyData(data, new SHA1CryptoServiceProvider(), signature);
}
public static X509Certificate2 LoadPublicKey(string PublicKeyPath)
{
return new X509Certificate2(PublicKeyPath);
}
public static byte[] StringToByte(string str)
{
String[] arr = str.Split('-');
byte[] array = new byte[arr.Length];
for (int i = 0; i < arr.Length; i++) array[i] = Convert.ToByte(arr[i], 16);
return array;
}
public static bool CheckOneFileSignature(string fileName)
{
UpdateCryptoManifest(); //first let's update the crypto manifest with latest values
foreach (KeyValuePair<string, string> kv in CryptoManifest.Files)
{
if (kv.Key.Remove(0, 1) == fileName) // we found the filename in the manifest
{
string FullPath = curDir + Path.DirectorySeparatorChar + kv.Key.Remove(0, 1);
var stream = File.ReadAllBytes(FullPath);
string signatureHexaString = "";
CryptoManifest.Files.TryGetValue(kv.Key, out signatureHexaString);
return Verify(stream, PublicKeyPath, signatureHexaString);
}
}
return false;
}
}
}

View File

@ -0,0 +1,183 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using System;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace NaturalLauncher
{
class ServerChecker
{
public class A2S_INFO
{
// \xFF\xFF\xFF\xFFTSource Engine Query\x00 because UTF-8 doesn't like to encode 0xFF
public static readonly byte[] REQUEST = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0x54, 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x45, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x00 };
#region Strong Typing Enumerators
[Flags]
public enum ExtraDataFlags : byte
{
GameID = 0x01,
SteamID = 0x10,
Keywords = 0x20,
Spectator = 0x40,
Port = 0x80
}
public enum VACFlags : byte
{
Unsecured = 0,
Secured = 1
}
public enum VisibilityFlags : byte
{
Public = 0,
Private = 1
}
public enum EnvironmentFlags : byte
{
Linux = 0x6C, //l
Windows = 0x77, //w
Mac = 0x6D, //m
MacOsX = 0x6F //o
}
public enum ServerTypeFlags : byte
{
Dedicated = 0x64, //d
Nondedicated = 0x6C, //l
SourceTV = 0x70 //p
}
#endregion
public byte Header { get; set; } // I
public byte Protocol { get; set; }
public string Name { get; set; }
public string Map { get; set; }
public string Folder { get; set; }
public string Game { get; set; }
public short ID { get; set; }
public byte Players { get; set; }
public byte MaxPlayers { get; set; }
public byte Bots { get; set; }
public ServerTypeFlags ServerType { get; set; }
public EnvironmentFlags Environment { get; set; }
public VisibilityFlags Visibility { get; set; }
public VACFlags VAC { get; set; }
public string Version { get; set; }
public ExtraDataFlags ExtraDataFlag { get; set; }
#region Extra Data Flag Members
public ulong GameID { get; set; } //0x01
public ulong SteamID { get; set; } //0x10
public string Keywords { get; set; } //0x20
public string Spectator { get; set; } //0x40
public short SpectatorPort { get; set; } //0x40
public short Port { get; set; } //0x80
#endregion
public A2S_INFO(IPEndPoint ep)
{
UdpClient udp = new UdpClient();
udp.Send(REQUEST, REQUEST.Length, ep);
MemoryStream ms = new MemoryStream(udp.Receive(ref ep)); // Saves the received data in a memory buffer
BinaryReader br = new BinaryReader(ms, Encoding.UTF8); // A binary reader that treats charaters as Unicode 8-bit
ms.Seek(4, SeekOrigin.Begin); // skip the 4 0xFFs
Header = br.ReadByte();
Protocol = br.ReadByte();
Name = ReadNullTerminatedString(ref br);
Map = ReadNullTerminatedString(ref br);
Folder = ReadNullTerminatedString(ref br);
Game = ReadNullTerminatedString(ref br);
ID = br.ReadInt16();
Players = br.ReadByte();
MaxPlayers = br.ReadByte();
Bots = br.ReadByte();
ServerType = (ServerTypeFlags)br.ReadByte();
Environment = (EnvironmentFlags)br.ReadByte();
Visibility = (VisibilityFlags)br.ReadByte();
VAC = (VACFlags)br.ReadByte();
Version = ReadNullTerminatedString(ref br);
ExtraDataFlag = (ExtraDataFlags)br.ReadByte();
#region These EDF readers have to be in this order because that's the way they are reported
if (ExtraDataFlag.HasFlag(ExtraDataFlags.Port))
Port = br.ReadInt16();
if (ExtraDataFlag.HasFlag(ExtraDataFlags.SteamID))
SteamID = br.ReadUInt64();
if (ExtraDataFlag.HasFlag(ExtraDataFlags.Spectator))
{
SpectatorPort = br.ReadInt16();
Spectator = ReadNullTerminatedString(ref br);
}
if (ExtraDataFlag.HasFlag(ExtraDataFlags.Keywords))
Keywords = ReadNullTerminatedString(ref br);
if (ExtraDataFlag.HasFlag(ExtraDataFlags.GameID))
GameID = br.ReadUInt64();
#endregion
br.Close();
ms.Close();
udp.Close();
}
/// <summary>Reads a null-terminated string into a .NET Framework compatible string.</summary>
/// <param name="input">Binary reader to pull the null-terminated string from. Make sure it is correctly positioned in the stream before calling.</param>
/// <returns>String of the same encoding as the input BinaryReader.</returns>
public static string ReadNullTerminatedString(ref BinaryReader input)
{
StringBuilder sb = new StringBuilder();
char read = input.ReadChar();
while (read != '\x00')
{
sb.Append(read);
read = input.ReadChar();
}
return sb.ToString();
}
// Handles IPv4 and IPv6 notation.
public static IPEndPoint CreateIPEndPoint(string endPoint)
{
string[] ep = endPoint.Split(':');
if (ep.Length < 2) throw new FormatException("Invalid endpoint format");
IPAddress ip;
if (ep.Length > 2)
{
if (!IPAddress.TryParse(string.Join(":", ep, 0, ep.Length - 1), out ip))
{
throw new FormatException("Invalid ip-adress");
}
}
else
{
if (!IPAddress.TryParse(ep[0], out ip))
{
throw new FormatException("Invalid ip-adress");
}
}
int port;
if (!int.TryParse(ep[ep.Length - 1], NumberStyles.None, NumberFormatInfo.CurrentInfo, out port))
{
throw new FormatException("Invalid port");
}
return new IPEndPoint(ip, port);
}
}
}
}

View File

@ -0,0 +1,43 @@
<Window x:Class="NaturalLauncher.Settings"
Closed="Window_Closed"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:NaturalLauncher"
mc:Ignorable="d"
Title="Settings" Height="350" Width="587" Background="#FF0D0D0C" MinWidth="568" MinHeight="280" MaxWidth="587" MaxHeight="350">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="95*"/>
<ColumnDefinition Width="97*"/>
<ColumnDefinition Width="195"/>
</Grid.ColumnDefinitions>
<Canvas Margin="10" Background="#FF1E1E1C" Grid.ColumnSpan="3">
<Label Content="Options :" Canvas.Left="10" Canvas.Top="9" Height="27" Width="516" Foreground="#FFEEA160" FontWeight="Bold"/>
<Label Content="Nine Legend Pack :" Canvas.Left="60" Canvas.Top="253" Height="27" Width="127" Foreground="#FF5ACAFF" FontWeight="Bold" IsEnabled="False" Visibility="Collapsed"/>
<Label Content="Advanced UserConfig :" Canvas.Left="44" Canvas.Top="310" Height="27" Width="143" Foreground="#FF5ACAFF" FontWeight="Bold" IsEnabled="False" Visibility="Collapsed"/>
<Label Content="Change HL Folder :" Canvas.Left="48" Canvas.Top="216" Height="27" Width="127" Foreground="#FF5ACAFF" FontWeight="Bold" HorizontalContentAlignment="Center"/>
<Button x:Name="NLInstallButton" Content="Install" Canvas.Left="208" Canvas.Top="250" Width="133" Height="33" Click="NLInstallButton_Click" IsEnabled="False" Visibility="Collapsed"/>
<Button x:Name="NLUnInstallButton" Content="Uninstall" Canvas.Left="367" Canvas.Top="250" Width="133" Height="33" Click="NLUnInstallButton_Click" IsEnabled="False" Visibility="Collapsed"/>
<Button x:Name="AdvSettingsInstallButton" Content="Install" Canvas.Left="208" Canvas.Top="307" Width="133" Height="33" Click="AdvSettingsInstallButton_Click" IsEnabled="False" Visibility="Collapsed"/>
<Button x:Name="AdvSettingsUnInstallButton" Content="Uninstall" Canvas.Left="367" Canvas.Top="307" Width="133" Height="33" Click="AdvSettingsUnInstallButton_Click" IsEnabled="False" Visibility="Collapsed"/>
<Button x:Name="BrowseHLFolderButton" Content="Browse" Canvas.Left="252" Canvas.Top="215" Width="221" Height="33" Click="BrowseHLFolderButton_Click"/>
<Label Content="Change cfg parameter :" Canvas.Left="38" Canvas.Top="82" Height="27" Width="147" Foreground="#FF5ACAFF" FontWeight="Bold" HorizontalContentAlignment="Center"/>
<TextBox x:Name="ParamNameTxtbox" Height="27" Canvas.Left="212" TextWrapping="Wrap" Text="Parameter" Canvas.Top="83" Width="121" Foreground="#FF2B2F30" FontWeight="Bold" Background="#BFFFFFFF" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/>
<TextBox x:Name="ParamValueTxtbox" Height="27" Canvas.Left="392" TextWrapping="Wrap" Text="Value" Canvas.Top="83" Width="81" Foreground="#FF2B2F30" FontWeight="Bold" Background="#BFFFFFFF" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/>
<Button x:Name="FindParamButton" Content="Find" Canvas.Left="338" Canvas.Top="83" Width="49" Height="27" Background="#19000000" BorderBrush="#FF5ACAFF" Foreground="#FF5ACAFF" Click="FindParameter_Click"/>
<Button x:Name="ChangeValueButton" Content="Change" Canvas.Left="479" Canvas.Top="83" Width="49" Height="27" Background="#19000000" BorderBrush="#FF5ACAFF" Foreground="#FF5ACAFF" Click="ChangeParameter_Click"/>
<Label Content="HUD Syle :" Canvas.Left="59" Canvas.Top="39" Height="27" Width="105" Foreground="#FF5ACAFF" FontWeight="Bold" HorizontalContentAlignment="Center"/>
<RadioButton x:Name="ClassicRadioButton" Content="Classic" Canvas.Left="240" Canvas.Top="45" Foreground="#FF5AFF5A" Checked="ClassicRadioButton_Checked"/>
<RadioButton x:Name="MinimalRadioButton" Content="Minimal" Canvas.Left="326" Canvas.Top="45" Foreground="#FF5ACAFF" Checked="MinimalRadioButton_Checked"/>
<RadioButton x:Name="NLRadioButton" Content="Nine Legend" Canvas.Left="417" Canvas.Top="45" Foreground="#FFFFA55A" Checked="NLRadioButton_Checked"/>
<Label Content="Add files to ignore list :" Canvas.Left="39" Canvas.Top="172" Height="27" Width="145" Foreground="#FF5ACAFF" FontWeight="Bold" HorizontalContentAlignment="Center"/>
<Button x:Name="BrowseHLFolderButton_Copy" Content="Add file(s)" Canvas.Left="252" Canvas.Top="169" Width="221" Height="33" Click="AddToIgnoreButton_Click"/>
<CheckBox x:Name="KeepAliveChecker" Content="Keep Launcher alive when playing (and discord status)" Canvas.Left="108" Canvas.Top="266" FontWeight="Bold" Foreground="#FF5ACAFF" Width="343" HorizontalContentAlignment="Center" Click="StopAfterLaunch_Click"/>
<Label Content="Custom discord status :" Canvas.Left="38" Canvas.Top="128" Height="27" Width="145" Foreground="#FF5ACAFF" FontWeight="Bold" HorizontalContentAlignment="Center"/>
<TextBox x:Name="DiscordTxtbox" Height="27" Canvas.Left="212" TextWrapping="Wrap" Text="status" Canvas.Top="127" Width="261" Foreground="#FF2B2F30" FontWeight="Bold" Background="#BFFFFFFF" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/>
<Button x:Name="ChangeDiscordButton" Content="Change" Canvas.Left="479" Canvas.Top="127" Width="49" Height="27" Background="#19000000" BorderBrush="#FF5ACAFF" Foreground="#FF5ACAFF" Click="ChangeDiscord_Click"/>
</Canvas>
</Grid>
</Window>

View File

@ -0,0 +1,259 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using System;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
namespace NaturalLauncher
{
/// <summary>
/// Logique d'interaction pour Settings.xaml
/// </summary>
public partial class Settings : Window
{
public static MainWindow MainWindowReference;
public static bool windowfullyopen = false;
public Settings()
{
InitializeComponent();
ParamNameTxtbox.SpellCheck.IsEnabled = true;
ParamNameTxtbox.SpellCheck.CustomDictionaries.Add(new Uri("pack://application:,,,/Ressources/Commande.lex")); //add the command custom dictonary
//RefreshNLInstallButtonState(); //nl pack based
Util.GetAValueInCfg("hud_style",out string HUDStyleparam);
switch(HUDStyleparam)
{
case "0":
ClassicRadioButton.IsChecked = true;
break;
case "1":
MinimalRadioButton.IsChecked = true;
break;
case "2":
NLRadioButton.IsChecked = true;
break;
}
XmlBuilder.ReadConfigXml(out string uno, out bool dos, out string discordStatus, out bool keepAlive);
Launcher.keepLauncherAlive = keepAlive;
DiscordTxtbox.Text = discordStatus;
KeepAliveChecker.IsChecked = keepAlive;
windowfullyopen = true;
}
public void SetMainWindowRef(MainWindow MainWindowRef)
{
MainWindowReference = MainWindowRef;
}
private void Window_Closed(object sender, EventArgs e)
{
MainWindow.sw = null;
windowfullyopen = false;
}
private void FindParameter_Click(object sender, RoutedEventArgs e)
{
try
{
Util.GetAValueInCfg(ParamNameTxtbox.Text,out string ParamValue);
ParamValueTxtbox.Text = ParamValue;
}
catch
{
ParamValueTxtbox.Text = "not found";
}
}
private void ChangeParameter_Click(object sender, RoutedEventArgs e)
{
try
{
if(ParamValueTxtbox.Text != "not found")
{
Util.ChangeAValueInCfg(ParamNameTxtbox.Text, ParamValueTxtbox.Text);
}
}
catch
{
}
}
private void RefreshNLInstallButtonState()
{
if (Launcher.IsNLPack())
{
NLInstallButton.IsEnabled = false;
NLUnInstallButton.IsEnabled = true;
}
else
{
NLInstallButton.IsEnabled = true;
NLUnInstallButton.IsEnabled = false;
}
}
private void NLInstallButton_Click(object sender, RoutedEventArgs e)
{
// TODO Install THE NL PACK, USING NL FOLDERS URL
Launcher.SetIsNLPack(true);
RefreshNLInstallButtonState();
MainWindowReference.CallUpdateGame();
MainWindowReference.SettingButton.IsEnabled = false;
this.Hide();
}
private void NLUnInstallButton_Click(object sender, RoutedEventArgs e)
{
// TODO REMOVE THE NL PACK FILES USING NL FOLDERS URL
// THEN REPAIR INSTALLATION
Launcher.SetIsNLPack(false);
RefreshNLInstallButtonState();
MainWindowReference.CallUpdateGame();
MainWindowReference.SettingButton.IsEnabled = false;
this.Hide();
}
private void AdvSettingsInstallButton_Click(object sender, RoutedEventArgs e)
{
// GET THE CONFIG FILES INSIDE THE GAME URL. SHOULDNT NEED A MANIFEST, JUST GET CFGs
try
{
if (System.Windows.Forms.MessageBox.Show("You are about to download a set of configuration files "
+ Environment.NewLine + "These files will override your current and existing configuration files if they exists."
+ Environment.NewLine + "Please chose if you want to continue.", "", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1) == System.Windows.Forms.DialogResult.Yes)
{
using (WebClient webClient = new WebClient()) // yeah I know it's brutal :D
{
webClient.DownloadFile(new Uri(Properties.Settings.Default.GameUrl + "/config.cfg"), Launcher.NSFolder + System.IO.Path.DirectorySeparatorChar + "config.cfg");
webClient.DownloadFile(new Uri(Properties.Settings.Default.GameUrl + "/userconfig.cfg"), Launcher.NSFolder + System.IO.Path.DirectorySeparatorChar + "userconfig.cfg");
webClient.DownloadFile(new Uri(Properties.Settings.Default.GameUrl + "/alien_.cfg"), Launcher.NSFolder + System.IO.Path.DirectorySeparatorChar + "alien_.cfg");
webClient.DownloadFile(new Uri(Properties.Settings.Default.GameUrl + "/pistol_.cfg"), Launcher.NSFolder + System.IO.Path.DirectorySeparatorChar + "pistol_.cfg");
webClient.DownloadFile(new Uri(Properties.Settings.Default.GameUrl + "/reset_.cfg"), Launcher.NSFolder + System.IO.Path.DirectorySeparatorChar + "reset_.cfg");
webClient.DownloadFile(new Uri(Properties.Settings.Default.GameUrl + "/rine_.cfg"), Launcher.NSFolder + System.IO.Path.DirectorySeparatorChar + "rine_.cfg");
}
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("Advanced settings Installed with success");
}
}
catch
{
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("Advanced settings failed to install");
}
}
private void AdvSettingsUnInstallButton_Click(object sender, RoutedEventArgs e)
{
// REMOVE THE CFG FILES. ENDWITH(config.cfg) AND ENDWITH(_.cfg). GAME SHOULD RECREATE THE CONFIG FILE
try
{
foreach (string file in Directory.GetFiles(Launcher.NSFolder))
{
if (file.EndsWith("_.cfg") || file.EndsWith("config.cfg"))
File.Delete(file);
}
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("Advanced settings Removed with success");
}
catch
{
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("Failed to remove settings");
}
}
private void BrowseHLFolderButton_Click(object sender, RoutedEventArgs e)
{
// BROWSE AND CHANGE THE FOLDER FILE. DONT FORGET TO UPDATE THE GLOBAL VARIABLE
bool IsItNLPack = Launcher.IsNLPack();
string folderPath = Util.AskForHLFolder();
if (folderPath!=null)
{
XmlBuilder.CreateConfigXml();
Launcher.HLFolder = folderPath;
Launcher.NSFolder = folderPath + System.IO.Path.DirectorySeparatorChar + "ns";
}
MainWindowReference.CallUpdateGame();
}
private void ClassicRadioButton_Checked(object sender, RoutedEventArgs e)
{
if(windowfullyopen)
{
ClassicRadioButton.IsChecked = true;
MinimalRadioButton.IsChecked = false;
NLRadioButton.IsChecked = false;
Util.ChangeAValueInCfg("hud_style", "0", true);
}
}
private void MinimalRadioButton_Checked(object sender, RoutedEventArgs e)
{
if (windowfullyopen)
{
ClassicRadioButton.IsChecked = false;
MinimalRadioButton.IsChecked = true;
NLRadioButton.IsChecked = false;
Util.ChangeAValueInCfg("hud_style", "1", true);
}
}
private void NLRadioButton_Checked(object sender, RoutedEventArgs e)
{
if (windowfullyopen)
{
ClassicRadioButton.IsChecked = false;
MinimalRadioButton.IsChecked = false;
NLRadioButton.IsChecked = true;
Util.ChangeAValueInCfg("hud_style", "2", true);
}
}
private void AddToIgnoreButton_Click(object sender, RoutedEventArgs e)
{
Launcher.AddToIgnoreList();
}
private void StopAfterLaunch_Click(object sender, RoutedEventArgs e)
{
Launcher.keepLauncherAlive = KeepAliveChecker.IsChecked.Value;
XmlBuilder.CreateConfigXml();
}
private void ChangeDiscord_Click(object sender, RoutedEventArgs e)
{
Launcher.discordCustomStatus = DiscordTxtbox.Text;
Launcher.UpdateDiscord(false);
XmlBuilder.CreateConfigXml();
}
}
}

665
NaturalLauncher/Util.cs Normal file
View File

@ -0,0 +1,665 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using HtmlAgilityPack;
using Microsoft.Win32;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.IO.Compression;
using System.Windows.Resources;
namespace NaturalLauncher
{
class Util
{
public static string ComputeMD5(string file)
{
MD5 md5 = MD5.Create();
string hash = "";
using (var stream = File.OpenRead(file))
{
hash = BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "");
}
return hash;
}
public static string LocalVersion(string path)
{
string lv = null;
if (string.IsNullOrEmpty(path)
|| System.IO.Path.GetInvalidPathChars().Intersect(
path.ToCharArray()).Count() != 0
|| !new System.IO.FileInfo(path).Exists)
{
lv = null;
}
else if (new System.IO.FileInfo(path).Exists)
{
string s = System.IO.File.ReadAllText(path);
if (ValidateFile(s)) {
lv = s;
}
else {
lv = null;
}
}
return lv;
}
public static string CreateLocalVersionFile(string folderPath,
string fileName, string version)
{
if (!new System.IO.DirectoryInfo(folderPath).Exists)
{
System.IO.Directory.CreateDirectory(folderPath);
}
string path = folderPath + Path.DirectorySeparatorChar + fileName;
if (new System.IO.FileInfo(path).Exists)
{
new System.IO.FileInfo(path).Delete();
}
if (!new System.IO.FileInfo(path).Exists)
{
System.IO.File.WriteAllText(path, version);
}
return path;
}
// method used to check internet connectivity
public static bool CheckForInternetConnection(string UrlToCheck)
{
try
{
using (var client = new WebClient())
using (client.OpenRead(UrlToCheck)) // or http://clients3.google.com/generate_204
{
return true;
}
}
catch
{
return false;
}
}
public static bool ValidateFile(string contents)
{
bool val = false;
if (!string.IsNullOrEmpty(contents))
{
string pattern = "^([0-9]*\\.){3}[0-9]*$";
System.Text.RegularExpressions.Regex re =
new System.Text.RegularExpressions.Regex(pattern);
val = re.IsMatch(contents);
}
return val;
}
public static string RemoteVersion(string url)
{
string rv = "";
try
{
System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)
System.Net.WebRequest.Create(url);
System.Net.HttpWebResponse response =
(System.Net.HttpWebResponse)req.GetResponse();
System.IO.Stream receiveStream = response.GetResponseStream();
System.IO.StreamReader readStream =
new System.IO.StreamReader(receiveStream, Encoding.UTF8);
string s = readStream.ReadToEnd();
response.Close();
if (ValidateFile(s))
{
rv = s;
}
}
catch (Exception)
{
// Anything could have happened here but
// we don't want to stop the user
// from using the application.
rv = null;
}
return rv;
}
public static string Size(long bytes)
{
if (bytes > 1000000000)
{
return ((float)bytes / 1000000000f).ToString("f") + " GB";
}
if (bytes > 1000000)
{
return ((float)bytes / 1000000f).ToString("f") + " MB";
}
if (bytes > 1000)
{
return ((float)bytes / 1000f).ToString("f") + " KB";
}
return ((float)bytes).ToString("f") + " B";
}
public static string ToLocalPath(string root, string dir)
{
return dir.Replace(root, "").Replace("\\", "/");
}
public static string GetLongTimeString()
{
var src = DateTime.Now;
string StringToReturn = src.Month + "_" + src.Day + "_" + src.Hour + "_" + src.Minute + "_" + src.Second;
return StringToReturn;
}
public static string GetShortTimeString()
{
var src = DateTime.Now;
string StringToReturn = "[ " + src.Hour + " : " + src.Minute + " : " + src.Second + " ] : ";
return StringToReturn;
}
public static string GetSteamFolder(bool WantCommon) //just testing if ever needed
{
string path = "";
// HKEY_CURRENT_USER/Software/Valve/Steam
try
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Valve\\Steam"))
{
if (key != null)
{
Object o = key.GetValue("SteamPath");
if (o != null)
{
path = o as String;
if(WantCommon)
path = path + "/steamapps/common";
path = Path.GetFullPath(path);
Console.WriteLine(path);
// NEEDS A NUGGET PACKAGE GAMELOOP.VDF TO READ
// To get full list of game folders : steamapps\libraryfolders.vdf
/*string LibraryFoldersPath = path + Path.DirectorySeparatorChar + "steamapps" + Path.DirectorySeparatorChar + "libraryfolders.vdf";
// we need a function to extract folder directory
dynamic FolderLibrary = VdfConvert.Deserialize(File.ReadAllText(LibraryFoldersPath));
var FolderLibraryValues = FolderLibrary.Value;
var importantJsonObject = FolderLibrary.ToJson();*/
}
}
}
}
catch
{
MessageBoxResult AlertBox = MessageBox.Show("Steam Folder not found");
path = "";
}
return path;
}
public static string GetHLFolder() //just testing if ever needed
{
string path = "";
// HKEY_CURRENT_USER/Software/Valve/Steam
try
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey("Software\\Valve\\Steam"))
{
if (key != null)
{
Object o = key.GetValue("ModInstallPath");
if (o != null)
{
path = o as String;
path = Path.GetFullPath(path);
Console.WriteLine(path);
}
}
}
}
catch
{
MessageBoxResult AlertBox = MessageBox.Show("HL Folder not found","Alert", MessageBoxButton.OK , MessageBoxImage.Error);
path = "";
}
return path;
}
public static int ReadGathererCount()
{
var url = Properties.Settings.Default.GatherURL;
var web = new HtmlWeb();
var doc = web.Load(url);
string htmlstring = doc.Text;
int Count = 0;
// need to retrieve this : <ul id="gatherers">
var nodal = doc.DocumentNode.Descendants("ul");
for(int i = 0; i < nodal.Count(); i++)
{
try
{
if (nodal.ElementAt(i).Id == "gatherers")
{
Count = nodal.ElementAt(i).SelectNodes("li").Count(); //and count the <li> inside
}
}
catch
{
Count = 0;
}
}
return Count;
}
// This function is here to compare the general "standard" ns install with the advanced "NlPack" install version
// If the user is using the NLPack then the manifest has to be updated consequently.
public static LauncherManifest CleanManifestWithOptions(LauncherManifest GeneralManifest, LauncherManifest NLManifest)
{
//string value = "";
foreach (KeyValuePair<string, string> kv in NLManifest.Files)
{
if (GeneralManifest.Files.ContainsKey(kv.Key))
{
// we should delete, not to verify this. Then a second period of the updater check changed with the nl folder and its own manifest.
// the following code is in case you want to change the value (commented)
/*NLManifest.Files.TryGetValue(kv.Key, out value);
GeneralManifest.Files[kv.Key] = value; */
GeneralManifest.Files.Remove(kv.Key);
}
}
return GeneralManifest;
}
public static bool RemoteFileExists(string url)
{
try
{
//Creating the HttpWebRequest
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
//Setting the Request method HEAD, you can also use GET too.
request.Method = "HEAD";
//Getting the Web Response.
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
//Returns TRUE if the Status code == 200
response.Close();
return (response.StatusCode == HttpStatusCode.OK);
}
catch
{
//Any exception will returns false.
return false;
}
}
public static List<string> TheDirectory = new List<string>();
public static List<string> GetDirectoryFilesFromUrl(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string html = reader.ReadToEnd();
Regex regex = new Regex(GetDirectoryListingRegexForUrl(url));
MatchCollection matches = regex.Matches(html);
if (matches.Count > 0)
{
foreach (Match match in matches)
{
if (match.Success)
{
TheDirectory.Add(match.Groups["name"].ToString());
}
}
}
}
}
TheDirectory.Remove("Parent Directory");
return TheDirectory;
}
public static string GetDirectoryListingRegexForUrl(string url)
{
if (url.Equals(url))
{
return "<a href=\".*\">(?<name>.*)</a>"; //problem with the .exe.config file
}
throw new NotSupportedException();
}
public static string AskForHLFolder()
{
string folderPath = "";
var dialog = new System.Windows.Forms.OpenFileDialog();
dialog.InitialDirectory = Util.GetHLFolder();
dialog.Filter = "Half life Executable|hl.exe";
dialog.Title = "Please indicate where is your Half Life steam executable !";
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = dialog.FileName;
folderPath = folderPath.Remove(folderPath.Length + 1 - 8);
return folderPath;
}
else
{
Util.PlaySoundFX("error");
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("This launcher need your half life directory in order to function. Please relaunch.", "Alert", MessageBoxButton.OK, MessageBoxImage.Error);
folderPath = null;
return folderPath;
}
}
public static LauncherManifest GetIgnoreManifest(bool isVerification)
{
// we first get the ignore.list used by dev
string IgnorePath = Launcher.curDir + Path.DirectorySeparatorChar + "ignore.list";
LauncherManifest NewManifest = new LauncherManifest();
if (File.Exists(IgnorePath) && isVerification) //then we can use the one in the folder. That's ok
{
string IgnoreString = File.ReadAllText(IgnorePath);
NewManifest = JsonConvert.DeserializeObject<LauncherManifest>(IgnoreString);
}
else
{
try
{
using (WebClient webClient = new WebClient()) // yeah I know it's brutal :D
{
webClient.DownloadFile(new Uri(Properties.Settings.Default.IndexURL + "/ignore.list"), IgnorePath);
}
string IgnoreString = File.ReadAllText(IgnorePath);
NewManifest = JsonConvert.DeserializeObject<LauncherManifest>(IgnoreString);
}
catch
{
/*MessageBoxResult AlertBox = System.Windows.MessageBox.Show("Could not retrieve a new ignore manifest file, Creating a void one...");
NewManifest.Files["/config.cfg"] = "";*/
Util.PlaySoundFX("error");
MessageBoxResult AlertBox = System.Windows.MessageBox.Show("Launcher couldn't find a correct ignore.list from online source, please verify you internet connection..."
, "Alert", MessageBoxButton.OK, MessageBoxImage.Error);
throw new Exception("Launcher couldn't find a correct ignore.list from online source, please verify you internet connection...");
}
}
// then we read the custom one on the disk
string CustomIgnorePath = Launcher.curDir + Path.DirectorySeparatorChar + "customignore.list";
LauncherManifest CustomignoreManifest = new LauncherManifest();
if (File.Exists(CustomIgnorePath))
{
string IgnoreString = File.ReadAllText(CustomIgnorePath);
CustomignoreManifest = JsonConvert.DeserializeObject<LauncherManifest>(IgnoreString);
}
else
{
CustomignoreManifest.Files["/exemple.xpl"] = "1";
File.WriteAllText(CustomIgnorePath, JsonConvert.SerializeObject(CustomignoreManifest, Formatting.Indented)); //write the new voidy ignore manifest
}
// then we add both manifest to return the ignore list
foreach(KeyValuePair<string, string> kv in CustomignoreManifest.Files)
{
NewManifest.Files.Add(kv.Key, kv.Value);
}
return NewManifest;
}
public static void CopyDirectory(string SourcePath, string DestinationPath) //not used anymore.
{
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(SourcePath, "*",
SearchOption.AllDirectories))
Directory.CreateDirectory(dirPath.Replace(SourcePath, DestinationPath));
ConsoleManager.Show();
//Copy all the files & Replaces any files with the same name
foreach (string newPath in Directory.GetFiles(SourcePath, "*.*",
SearchOption.AllDirectories))
{
/*string newdirr = Path.GetDirectoryName(newPath);
if (!newdirr.Contains("sound") || !newPath.Contains("maps") || !newPath.Contains("dlls") || !newPath.Contains("cl_dlls"))
{*/
Console.WriteLine(Path.GetFileName(newPath) + " being copied...");
File.Copy(newPath, newPath.Replace(SourcePath, DestinationPath), true);
//}
}
ConsoleManager.Hide();
}
public static void ZipDirectory(string SourceDirPath)
{
ConsoleManager.Show();
Console.WriteLine("Ziping directory...");
Console.WriteLine("This can take up to 2 minutes, please wait...");
ZipFile.CreateFromDirectory(SourceDirPath, SourceDirPath + "_saved.zip", CompressionLevel.Optimal,false);
Console.WriteLine("Ziping done !");
ConsoleManager.Hide();
}
public static bool GetAValueInCfg(string ValueName, out string Value)
{
string[] CfgLines = File.ReadAllLines(Launcher.NSFolder + Path.DirectorySeparatorChar + "config.cfg");
string[] UCfgLines = File.ReadAllLines(Launcher.NSFolder + Path.DirectorySeparatorChar + "userconfig.cfg");
bool found = false;
Value = "not found";
// first we look in the config.cfg then we will look in userconfig and keep its value if it exists (as it's the last cfg executed)
foreach (string Line in CfgLines)
{
if(Line.StartsWith(ValueName))
{
Value = Line.Remove(0, ValueName.Length + 2); //on enleve tout le debut et le premier guillemet
Value = Value.Remove(Value.Length - 1, 1); // et le dernier
found = true;
//initialInt = Convert.ToInt32(initialValue);
}
}
// if it's the userconfig, take that instead
foreach (string Line in UCfgLines)
{
if (Line.StartsWith(ValueName))
{
Value = Line.Remove(0, ValueName.Length + 2); //on enleve tout le debut et le premier guillemet
Value = Value.Remove(Value.Length - 1, 1); // et le dernier
found = true;
//initialInt = Convert.ToInt32(initialValue);
}
}
return found;
}
public static void ChangeAValueInCfg(string ValueName,string Value,bool isStrictToConfig = false)
{
string[] CfgLines = File.ReadAllLines(Launcher.NSFolder + Path.DirectorySeparatorChar + "config.cfg");
string[] UCfgLines = File.ReadAllLines(Launcher.NSFolder + Path.DirectorySeparatorChar + "userconfig.cfg");
bool cfgchange = false;
bool ucfgchange = false;
bool found = false;
int loopindex = 0;
// first we look in the config.cfg then we will look in userconfig and keep its value if it exists (as it's the last cfg executed)
foreach (string Line in CfgLines)
{
if (Line.StartsWith(ValueName))
{
CfgLines[loopindex] = ValueName + " " + "\"" + Value + "\"";
found = true;
cfgchange = true;
}
loopindex++;
}
if (isStrictToConfig) //if should only be in config.cfg, let's verify it's not in usercfg
{
loopindex = 0;
foreach (string Line in UCfgLines)
{
if (Line.StartsWith(ValueName))
{
UCfgLines[loopindex] = ""; //we remove the doublon
ucfgchange = true;
}
loopindex++;
}
}
if (!isStrictToConfig) //we can check usercfg
{
loopindex = 0;
foreach (string Line in UCfgLines)
{
if (Line.StartsWith(ValueName))
{
UCfgLines[loopindex] = ValueName + " " + "\"" + Value + "\"";
found = true;
ucfgchange = true;
}
loopindex++;
}
}
if (!found && !isStrictToConfig) //we didnt find it, let's add it to usercfg!
{
Array.Resize(ref UCfgLines, UCfgLines.Length + 1);
UCfgLines[UCfgLines.Length - 1] = ValueName + " " + "\"" + Value + "\"";
ucfgchange = true;
}
if (!found && isStrictToConfig) //we didnt find it, let's add it to config cfg !
{
Array.Resize(ref CfgLines, CfgLines.Length + 1);
CfgLines[CfgLines.Length - 1] = ValueName + " " + "\"" + Value + "\"";
cfgchange = true;
}
// ecrire le deux fichiers à l'emplacement source !
try
{
if(cfgchange)
{
File.WriteAllLines(Launcher.NSFolder + Path.DirectorySeparatorChar + "config.cfg", CfgLines);
}
}
catch
{
System.Windows.MessageBox.Show("Could not write config.cfg, please verify the file is not read only !", "Read only", MessageBoxButton.OK, MessageBoxImage.Error);
}
try
{
if (ucfgchange)
{
File.WriteAllLines(Launcher.NSFolder + Path.DirectorySeparatorChar + "userconfig.cfg", UCfgLines);
}
}
catch
{
System.Windows.MessageBox.Show("Could not write userconfig.cfg, please verify the file is not read only !" + Environment.NewLine +
"This problem may also be caused by a hud_style setting in your userconfig.cfg file !", "Read only", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public static void LaunchAgain(string PathToExe)
{
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.WorkingDirectory = Path.GetDirectoryName(PathToExe);
processInfo.FileName = Path.GetFileName(PathToExe);
processInfo.ErrorDialog = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardOutput = true;
processInfo.RedirectStandardError = true;
Process proc = Process.Start(processInfo);
}
public static void PlaySoundFX(string Type) //now only play when error because whiners
{
Uri resourceUri = new Uri("Ressources/sdx_error.wav", UriKind.Relative);
switch (Type)
{
case "error":
resourceUri = new Uri("Ressources/sdx_error.wav", UriKind.Relative);
StreamResourceInfo streamInfo = Application.GetResourceStream(resourceUri);
System.Media.SoundPlayer player = new System.Media.SoundPlayer(streamInfo.Stream);
player.Play();
break;
case "start":
resourceUri = new Uri("Ressources/sdx_started.wav", UriKind.Relative);
break;
case "finish":
resourceUri = new Uri("Ressources/sdx_finished.wav", UriKind.Relative);
break;
default:
resourceUri = new Uri("Ressources/sdx_error.wav", UriKind.Relative);
break;
}
}
}
}

View File

@ -0,0 +1,131 @@
/*
* Natural Launcher
Copyright (C) 2018 Mael "Khelben" Vignaux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact me with any question at the mail : mael.vignaux@elseware-experience.com
*/
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
namespace NaturalLauncher
{
class XmlBuilder
{
public static bool BuildXmlDocument(string ManifestRootPath)
{
DirectoryInfo dir = new DirectoryInfo(ManifestRootPath);
var doc = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"),
StartCreateXML(dir));
try
{
File.WriteAllText(ManifestRootPath + Path.DirectorySeparatorChar + "Manifest.xml", doc.ToString()); //write the new voidy ignore manifest
return true;
}
catch
{
return false;
}
}
public static XElement StartCreateXML(DirectoryInfo dir) // create a full directory xml
{
var xmlInfo = new XElement("MainDirectory");
//get all the files first
foreach (var file in dir.GetFiles())
{
xmlInfo.Add(new XElement("file", new XAttribute("name", file.Name)));
}
//get subdirectories
var subdirectories = dir.GetDirectories().ToList().OrderBy(d => d.Name);
foreach (var subDir in subdirectories)
{
xmlInfo.Add(CreateSubdirectoryXML(subDir));
}
return xmlInfo;
}
public static XElement CreateSubdirectoryXML(DirectoryInfo dir)
{
//get directories
var xmlInfo = new XElement("folder", new XAttribute("name", dir.Name));
//get all the files first
foreach (var file in dir.GetFiles())
{
xmlInfo.Add(new XElement("file", new XAttribute("name", file.Name)));
}
//get subdirectories
var subdirectories = dir.GetDirectories().ToList().OrderBy(d => d.Name);
foreach (var subDir in subdirectories)
{
xmlInfo.Add(CreateSubdirectoryXML(subDir));
}
return xmlInfo;
}
public static bool ReadConfigXml(out string HLFolder, out bool IsNlPack, out string customDiscordStatus, out bool keepLauncherAlive)
{
XmlDocument doc = new XmlDocument();
try
{
doc.Load(Launcher.curDir + Path.DirectorySeparatorChar + Launcher.configName);
XmlNodeList nodelist = doc.SelectNodes("/LauncherConfiguration");
HLFolder = doc.SelectSingleNode("//HLFolder").InnerText;
IsNlPack = doc.SelectSingleNode("//NLPack").InnerText == "True";
customDiscordStatus = doc.SelectSingleNode("//DiscordStatus").InnerText;
keepLauncherAlive = doc.SelectSingleNode("//keeplauncherAlive").InnerText == "True";
return true;
}
catch
{
HLFolder = "";
IsNlPack = false;
customDiscordStatus = "Gather forming";
keepLauncherAlive = true;
return false;
}
}
public static bool CreateConfigXml()
{
var xmlInfo = new XElement("LauncherConfiguration");
xmlInfo.Add(new XElement("HLFolder", Launcher.HLFolder));
xmlInfo.Add(new XElement("NLPack", "False"/*Launcher.IsNLPack().ToString()*/)); //doesnt matter anymore, also, can't use this function cause it asks for the config file...
xmlInfo.Add(new XElement("DiscordStatus", Launcher.discordCustomStatus));
xmlInfo.Add(new XElement("keeplauncherAlive", Launcher.keepLauncherAlive.ToString()));
var doc = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"), xmlInfo);
try
{
File.WriteAllText(Launcher.curDir + Path.DirectorySeparatorChar + Launcher.configName, doc.ToString()); //write the new voidy ignore manifest
return true;
}
catch
{
return false;
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="HtmlAgilityPack" version="1.8.5" targetFramework="net462" />
<package id="Newtonsoft.Json" version="11.0.2" targetFramework="net462" />
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net462" />
</packages>

BIN
NslKey.cer Normal file

Binary file not shown.

32
README.md Normal file
View File

@ -0,0 +1,32 @@
# NaturalLauncher
*Natural selection launcher and updater. Allows for quick update of the natural selection folder.
#TO BUILD FROM SOURCES
*If you are building from sources, I imagine you don't want the .exe file to permanantly check for online consistency (public key required) nor self update.
*In order to do so, simply go in SelfUpdater.cs and set the variable "isSelfUpdating" to false.
*You are basicaly good to go !
#CHANGE THE ONLINE FILES THE LAUNCHER REFERS TO
*If you want you own files online, simply change, in the configuration setting of the natural launcher projet in VS, the IndexURL to your custom URL
*as well as the GameUrl to the game URL (sounds logical enough ?)
#TO COMMIT A NEW NS VERSION / PATCH
##FROM THE LAUNCHER:
*1 - Launch the launcher (tricky sentence)
*2 - Verify it has the right half life folder target
*3 - Right click in the launcher
*4 - Build Manifest
##FROM THE MANIFESTBUILDER.EXE
*1 - Place the manifestbuilder.exe app in the correct folder
*2 - Execute it
*3 - Enjoy
*4 - Really do it
##THEN
*5 - Upload files in the "Game" Folder of the ftp
*6 - Upload the manifest in the root folder.
*7 - Update the app.version with the new number in root folder