diff --git a/Partypacker/INIFile.cs b/Partypacker/INIFile.cs
new file mode 100644
index 0000000..d7e2af0
--- /dev/null
+++ b/Partypacker/INIFile.cs
@@ -0,0 +1,275 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.IO;
+
+namespace Partypacker
+{
+ public class INIFile
+ {
+ private string _File;
+
+ ///
+ /// Call the constructor creates a new object of the INIFile class to work with INI files.
+ ///
+ /// Name of INI file, which you want to access.
+ /// Specifies whether the INI file should be created if it does not exist.
+ public INIFile(string file, bool createFile = false)
+ {
+ if (createFile == true && File.Exists(file) == false)
+ {
+ FileInfo fileInfo = new FileInfo(file);
+ FileStream fileStream = fileInfo.Create();
+ fileStream.Close();
+ }
+ _File = file;
+ }
+
+ #region Public Methods
+
+ ///
+ /// Removes all comments and empty lines from a complete section and returns the sections.
+ /// This method is not case-sensitive.
+ /// The return value does not contain any spaces at the beginning or at the end of a line.
+ ///
+ /// Name of the requested section.
+ /// Specifies whether comments should also be returned.
+ /// Returns the whole section.
+ public List GetSection(string section, bool includeComments = false)
+ {
+ section = CheckSection(section);
+
+ List completeSection = new List();
+ bool sectionStart = false;
+
+ string[] fileArray = File.ReadAllLines(_File);
+
+ foreach (var item in fileArray)
+ {
+ if (item.Length <= 0) continue;
+
+ // Beginning of section.
+ if (item.Replace(" ", "").ToLower() == section)
+ {
+ sectionStart = true;
+ }
+ // Beginning of next section.
+ if (sectionStart == true && item.Replace(" ", "").ToLower() != section && item.Replace(" ", "").Substring(0, 1) == "[" && item.Replace(" ", "").Substring(item.Length - 1, 1) == "]")
+ {
+ break;
+ }
+ if (sectionStart == true)
+ {
+ // Add the entry to the List completeSection, if it is not a comment or an empty entry.
+ if (includeComments == false
+ && item.Replace(" ", "").Substring(0, 1) != ";" && !string.IsNullOrWhiteSpace(item))
+ {
+ completeSection.Add(ReplaceSpacesAtStartAndEnd(item));
+ }
+ if (includeComments == true && !string.IsNullOrWhiteSpace(item))
+ {
+ completeSection.Add(ReplaceSpacesAtStartAndEnd(item));
+ }
+ }
+ }
+ return completeSection;
+ }
+
+ ///
+ /// The method returns a value for the associated key.
+ /// This method is not case-sensitive.
+ ///
+ /// Name of the requested section.
+ /// Name of the requested key.
+ /// If "true" is passed, the value will be returned in lowercase letters.
+ /// Returns the value for the specified key in the specified section, if available, otherwise null.
+ public string GetValue(string section, string key, bool convertValueToLower = false)
+ {
+ section = CheckSection(section);
+ key = key.ToLower();
+
+ List completeSection = GetSection(section);
+
+ foreach (var item in completeSection)
+ {
+ // Continue if entry is no key.
+ if (!item.Contains("=") && item.Contains("[") && item.Contains("]")) continue;
+
+ string[] keyAndValue = item.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
+ if (keyAndValue[0].ToLower() == key && keyAndValue.Count() > 1)
+ {
+ if (convertValueToLower == true)
+ {
+ keyAndValue[1] = keyAndValue[1].ToLower();
+ }
+ return keyAndValue[1];
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Set or add a value of the associated key in the specified section.
+ /// This method is not case-sensitive.
+ ///
+ /// Name of the section.
+ /// Name of the key.
+ /// Value to save.
+ /// If "true" is passed, the value will be saved in lowercase letters.
+ public void SetValue(string section, string key, string value, bool convertValueToLower = false)
+ {
+ section = CheckSection(section, false);
+ string sectionToLower = section.ToLower();
+
+ bool sectionFound = false;
+
+ List iniFileContent = new List();
+
+ string[] fileLines = File.ReadAllLines(_File);
+
+ // Creates a new INI file if none exists.
+ if (fileLines.Length <= 0)
+ {
+ iniFileContent = AddSection(iniFileContent, section, key, value, convertValueToLower);
+ WriteFile(iniFileContent);
+ return;
+ }
+
+ for (int i = 0; i < fileLines.Length; i++)
+ {
+ // Possibility 1: The desired section has not (yet) been found.
+ if (fileLines[i].Replace(" ", "").ToLower() != sectionToLower)
+ {
+ iniFileContent.Add(fileLines[i]);
+ // If a section does not exist, the section will be created.
+ if (i == fileLines.Length - 1 && fileLines[i].Replace(" ", "").ToLower() != sectionToLower && sectionFound == false)
+ {
+ iniFileContent.Add(null);
+ iniFileContent = AddSection(iniFileContent, section, key, value, convertValueToLower);
+ break;
+ }
+ continue;
+ }
+
+
+ // Possibility 2 -> Desired section was found.
+ sectionFound = true;
+
+ // Get the complete section in which the target key may be.
+ List targetSection = GetSection(sectionToLower, true);
+
+ for (int x = 0; x < targetSection.Count; x++)
+ {
+ string[] targetKey = targetSection[x].Split(new string[] { "=" }, StringSplitOptions.None);
+ // When the target key is found.
+ if (targetKey[0].ToLower() == key.ToLower())
+ {
+ if (convertValueToLower == true)
+ {
+ iniFileContent.Add(key + "=" + value.ToLower());
+ }
+ else
+ {
+ iniFileContent.Add(key + "=" + value);
+ }
+ i = i + x;
+ break;
+ }
+ else
+ {
+ iniFileContent.Add(targetSection[x]);
+ // If the target key is not found, it will be created.
+ if (x == targetSection.Count - 1 && targetKey[0].ToLower() != key.ToLower())
+ {
+ if (convertValueToLower == true)
+ {
+ iniFileContent.Add(key + "=" + value.ToLower());
+ }
+ else
+ {
+ iniFileContent.Add(key + "=" + value);
+ }
+ i = i + x;
+ break;
+ }
+ }
+ }
+ }
+
+ WriteFile(iniFileContent);
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ ///
+ /// Ensures that a section is always in the following format: [section].
+ ///
+ /// Section to be checked for correct format.
+ /// Specifies whether the section should be vonverted in lower case letters.
+ /// Returns section in this form: [section].
+ private string CheckSection(string section, bool convertToLower = true)
+ {
+ if (convertToLower == true)
+ {
+ section = section.ToLower();
+ }
+ if (!section.StartsWith("[") && !section.EndsWith("]"))
+ {
+ section = "[" + section + "]";
+ }
+ return section;
+ }
+
+ ///
+ /// Removes leading and trailing spaces from sections, keys and values.
+ ///
+ /// String to be trimmed.
+ /// Returns the trimmed string.
+ private string ReplaceSpacesAtStartAndEnd(string item)
+ {
+ // If the string has a key and a value.
+ if (item.Contains("=") && !item.Contains("[") && !item.Contains("]"))
+ {
+ string[] keyAndValue = item.Split(new string[] { "=" }, StringSplitOptions.None);
+ return keyAndValue[0].Trim() + "=" + keyAndValue[1].Trim();
+ }
+
+ return item.Trim();
+ }
+
+ ///
+ /// Adds a new section with key value pair.
+ ///
+ /// List iniFileContent from SetValue.
+ /// Section to be created.
+ /// Key to be added.
+ /// Value to be added.
+ /// Specifies whether the key and value should be saved in lower case letters.
+ /// Returns the new created section with key value pair.
+ private List AddSection(List iniFileContent, string section, string key, string value, bool convertValueToLower)
+ {
+ if (convertValueToLower == true)
+ {
+ value = value.ToLower();
+ }
+
+ iniFileContent.Add(section);
+ iniFileContent.Add($"{key}={value}");
+ return iniFileContent;
+ }
+
+ private void WriteFile(List content)
+ {
+ StreamWriter writer = new StreamWriter(_File);
+ foreach (var item in content)
+ {
+ writer.WriteLine(item);
+ }
+ writer.Close();
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Partypacker/MainWindow.xaml b/Partypacker/MainWindow.xaml
index f3a7828..c5e480d 100644
--- a/Partypacker/MainWindow.xaml
+++ b/Partypacker/MainWindow.xaml
@@ -31,9 +31,14 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/Partypacker/MainWindow.xaml.cs b/Partypacker/MainWindow.xaml.cs
index 30be79f..3b332bd 100644
--- a/Partypacker/MainWindow.xaml.cs
+++ b/Partypacker/MainWindow.xaml.cs
@@ -1,12 +1,16 @@
using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
using Partypacker.Core;
using Partypacker.Net;
using System.Diagnostics;
using System.Net;
using System.Text;
+using System.Text.RegularExpressions;
using System.Web;
using System.Windows;
using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
using WatsonWebserver;
namespace Partypacker
@@ -22,6 +26,7 @@ namespace Partypacker
static string Token;
static UserDetailObject UserDetails;
static Server sv;
+ static INIFile settings = new("settings.ini", true);
public MainWindow()
{
@@ -37,6 +42,11 @@ namespace Partypacker
}
DiscordAuthURL = DiscordURL.Value;
+
+ if (!string.IsNullOrWhiteSpace(settings.GetValue("Launcher", "token")))
+ {
+ AutoLogin();
+ }
}
void OnApplicationExit(object sender, ExitEventArgs e) => Proxx?.StopProxy();
@@ -47,9 +57,59 @@ namespace Partypacker
Port = P;
}
- void OnDashboard(object sender, RoutedEventArgs e) => Process.Start(new ProcessStartInfo { UseShellExecute = true, FileName = PartypackServer.DashboardURL });
+ void OnDashboard(object sender, MouseButtonEventArgs e) => Process.Start(new ProcessStartInfo { UseShellExecute = true, FileName = PartypackServer.DashboardURL + "/profile"});
- private static async Task DefaultRoute(HttpContext ctx)
+ private void UpdateUserUI()
+ {
+ this.Dispatcher.Invoke(() =>
+ {
+ UsernameTextBlock.Text = @$"{UserDetails.GlobalName} (@{UserDetails.Username})";
+ ProfilePictureImage.ImageSource = (ImageSource)new ImageSourceConverter().ConvertFromString(UserDetails.Avatar);
+ UsernameTextBlock.Visibility = Visibility.Visible;
+ PFPContainer.Visibility = Visibility.Visible;
+ });
+ }
+
+ void AutoLogin()
+ {
+ Token = settings.GetValue("Launcher", "token");
+ UserDetails = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(Convert.FromHexString(HttpUtility.UrlDecode(settings.GetValue("Launcher", "user")))));
+ UpdateUserUI();
+ Dispatcher.Invoke(() =>
+ {
+ LaunchButton.IsEnabled = true;
+ });
+ ConvertLoginToLogout();
+ }
+
+ private void ConvertLoginToLogout()
+ {
+ Dispatcher.Invoke(() =>
+ {
+ LoginButton.Content = "Log Out";
+ LoginButton.Click -= OnLoginUsingDiscord;
+ LoginButton.Click += OnLogout;
+ });
+ }
+
+ private void OnLogout(object sender, RoutedEventArgs e)
+ {
+ this.Dispatcher.Invoke(() =>
+ {
+ UsernameTextBlock.Visibility = Visibility.Hidden;
+ PFPContainer.Visibility = Visibility.Hidden;
+ UserDetails = null;
+ Token = "";
+ settings.SetValue("Launcher", "user", "");
+ settings.SetValue("Launcher", "token", "");
+
+ LoginButton.Content = "Log in using Discord";
+ LoginButton.Click += OnLoginUsingDiscord;
+ LoginButton.Click -= OnLogout;
+ });
+ }
+
+ private async Task DefaultRoute(HttpContext ctx)
{
string _Token = ctx.Request.Query.Elements["token"];
string _UserDetails = ctx.Request.Query.Elements["user"];
@@ -62,20 +122,33 @@ namespace Partypacker
Token = _Token;
UserDetails = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(Convert.FromHexString(HttpUtility.UrlDecode(_UserDetails))));
+ settings.SetValue("Launcher", "user", HttpUtility.UrlDecode(_UserDetails));
+ settings.SetValue("Launcher", "token", Token);
+ UpdateUserUI();
+ Dispatcher.Invoke(() =>
+ {
+ LaunchButton.IsEnabled = true;
+ });
+ ConvertLoginToLogout();
await ctx.Response.Send("All done! You can close this tab now.");
sv.Stop();
+ sv = null;
}
void OnLoginUsingDiscord(object sender, RoutedEventArgs e)
{
- Process.Start(new ProcessStartInfo { UseShellExecute = true, FileName = $"{DiscordAuthURL}&state={HttpUtility.UrlEncode(Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new
+ Process.Start(new ProcessStartInfo { UseShellExecute = true, FileName = $@"{DiscordAuthURL}&state={HttpUtility.UrlEncode(Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new
{
Client = "PartypackerDesktop"
- }))))}" });
- sv = new Server("127.0.0.1", 14968, false, DefaultRoute);
- sv.Start();
+ }))))}"});
+
+ if (sv == null)
+ {
+ sv = new Server("127.0.0.1", 14968, false, DefaultRoute);
+ sv.Start();
+ }
}
void OnLaunch(object sender, RoutedEventArgs e)
@@ -87,5 +160,11 @@ namespace Partypacker
//Process.Start(new ProcessStartInfo { UseShellExecute = true, FileName = "com.epicgames.launcher://apps/fn%3A4fe75bbc5a674f4f9b356b5c90567da5%3AFortnite?action=launch&silent=true" });
}
+
+ private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
+ {
+ Regex regex = new Regex("[^0-9]+");
+ e.Handled = regex.IsMatch(e.Text);
+ }
}
}
\ No newline at end of file
diff --git a/Partypacker/global.json b/Partypacker/global.json
new file mode 100644
index 0000000..fd157a8
--- /dev/null
+++ b/Partypacker/global.json
@@ -0,0 +1,6 @@
+{
+ "sdk": {
+ "version": "7.0.405",
+ "rollForward": "latestFeature"
+ }
+}
\ No newline at end of file