chore: refactor project, bug fixes

This commit is contained in:
rjindael 2023-08-02 01:20:34 -07:00
parent 8dba3ab782
commit 10c2103762
No known key found for this signature in database
GPG Key ID: D069369C906CCF31
9 changed files with 190 additions and 185 deletions

View File

@ -9,7 +9,78 @@ namespace Kiseki.Launcher.Windows
{ {
public readonly static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2]; public readonly static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2];
#region IBootstrapper implementation private readonly string Payload;
private readonly Dictionary<string, string> Arguments = new();
public event EventHandler<string>? OnHeadingChange;
public event EventHandler<int>? OnProgressBarAdd;
public event EventHandler<Enums.ProgressBarState>? OnProgressBarStateChange;
public event EventHandler<string[]>? OnError;
public Bootstrapper(string payload)
{
Payload = payload;
}
public bool Initialize()
{
if (!Helpers.Base64.IsBase64String(Payload))
{
Error($"Failed to launch {Constants.PROJECT_NAME}", $"Try launching {Constants.PROJECT_NAME} from the website again.");
return false;
}
// mode, version, ticket, joinscript
string[] pieces = Helpers.Base64.ConvertBase64ToString(Payload).Split("|");
if (pieces.Length != 4)
{
Error($"Failed to launch {Constants.PROJECT_NAME}", $"Try launching {Constants.PROJECT_NAME} from the website again.");
return false;
}
Arguments["Mode"] = pieces[0];
Arguments["Version"] = pieces[1];
Arguments["Ticket"] = pieces[2];
Arguments["JoinScript"] = pieces[3];
return true;
}
public void Run()
{
//
}
public void Abort()
{
//
}
#region MainWindow
protected virtual void HeadingChange(string heading)
{
OnHeadingChange!.Invoke(this, heading);
}
protected virtual void ProgressBarAdd(int value)
{
OnProgressBarAdd!.Invoke(this, value);
}
protected virtual void ProgressBarStateChange(Enums.ProgressBarState state)
{
OnProgressBarStateChange!.Invoke(this, state);
}
protected virtual void Error(string heading, string text)
{
// ugly hack for now (I don't want to derive EventHandler just for this)
OnError!.Invoke(this, new string[] { heading, text });
}
#endregion
#region Installation
public static void Install() public static void Install()
{ {
@ -97,6 +168,9 @@ namespace Kiseki.Launcher.Windows
} }
} }
#endregion
#region Registration
public static void Register() public static void Register()
{ {
using RegistryKey uninstallKey = Registry.CurrentUser.CreateSubKey($@"Software\Microsoft\Windows\CurrentVersion\Uninstall\{Constants.PROJECT_NAME}"); using RegistryKey uninstallKey = Registry.CurrentUser.CreateSubKey($@"Software\Microsoft\Windows\CurrentVersion\Uninstall\{Constants.PROJECT_NAME}");
@ -136,7 +210,7 @@ namespace Kiseki.Launcher.Windows
#endregion #endregion
#region Licensing #region Licensing
public static void TryLoadLicense() public static void License()
{ {
if (!File.Exists(Directories.License)) if (!File.Exists(Directories.License))
{ {
@ -157,6 +231,14 @@ namespace Kiseki.Launcher.Windows
} }
} }
public static void Unlicense()
{
if (File.Exists(Directories.License))
{
File.Delete(Directories.License);
}
}
private static bool AskForLicense(string licensePath, bool showDialog = true) private static bool AskForLicense(string licensePath, bool showDialog = true)
{ {
DialogResult answer = showDialog ? MessageBox.Show($"{Constants.PROJECT_NAME} is currently under maintenance and requires a license in order to access games. Would you like to look for the license file now?", Constants.PROJECT_NAME, MessageBoxButtons.YesNo, MessageBoxIcon.Warning) : DialogResult.Yes; DialogResult answer = showDialog ? MessageBox.Show($"{Constants.PROJECT_NAME} is currently under maintenance and requires a license in order to access games. Would you like to look for the license file now?", Constants.PROJECT_NAME, MessageBoxButtons.YesNo, MessageBoxIcon.Warning) : DialogResult.Yes;

View File

@ -16,8 +16,7 @@ namespace Kiseki.Launcher.Windows
if (!Directory.Exists(Base)) if (!Directory.Exists(Base))
{ {
// just in case Directory.CreateDirectory(Base); // just in case
Directory.CreateDirectory(Base);
} }
Logs = Path.Combine(Base, "Logs"); Logs = Path.Combine(Base, "Logs");

View File

@ -7,16 +7,15 @@ namespace Kiseki.Launcher.Windows
{ {
private readonly TaskDialogButton CloseButton; private readonly TaskDialogButton CloseButton;
private readonly TaskDialogPage Page; private readonly TaskDialogPage Page;
private readonly Controller Controller; private readonly Bootstrapper Bootstrapper;
public MainWindow(string payload) public MainWindow(string payload)
{ {
Controller = new Controller(payload); Bootstrapper = new Bootstrapper(payload);
Controller.OnPageHeadingChange += Controller_PageHeadingChanged; Bootstrapper.OnHeadingChange += Bootstrapper_HeadingChanged;
Controller.OnProgressBarAdd += Controller_ProgressBarAdded; Bootstrapper.OnProgressBarAdd += Bootstrapper_ProgressBarAdded;
Controller.OnProgressBarStateChange += Controller_ProgressBarStateChanged; Bootstrapper.OnProgressBarStateChange += Bootstrapper_ProgressBarStateChanged;
Controller.OnErrorShow += Controller_ErrorShown; Bootstrapper.OnError += Bootstrapper_Errored;
Controller.OnLaunch += (s, e) => Environment.Exit(0);
CloseButton = TaskDialogButton.Close; CloseButton = TaskDialogButton.Close;
Page = new TaskDialogPage() Page = new TaskDialogPage()
@ -34,59 +33,51 @@ namespace Kiseki.Launcher.Windows
Page.Created += (s, e) => Page.Created += (s, e) =>
{ {
Controller.Start(); Bootstrapper.Run();
}; };
Page.Destroyed += (s, e) => ShowTaskDialog();
{
Controller.Dispose();
Environment.Exit(0);
};
ShowProgressDialog();
} }
private void CloseButton_Click(object? sender, EventArgs e) private void ShowTaskDialog()
{
Controller.Dispose();
Environment.Exit(0);
}
private void Controller_PageHeadingChanged(object? sender, string heading)
{
Page.Heading = heading;
}
private void Controller_ProgressBarAdded(object? sender, int value)
{
Page.ProgressBar!.Value += value;
}
private void Controller_ProgressBarStateChanged(object? sender, ProgressBarState state)
{
Page.ProgressBar!.State = state switch
{
ProgressBarState.Normal => TaskDialogProgressBarState.Normal,
ProgressBarState.Marquee => TaskDialogProgressBarState.Marquee,
_ => throw new NotImplementedException()
};
}
private void Controller_ErrorShown(object? sender, string[] texts)
{
Page.Icon = TaskDialogIcon.Error;
Page.Heading = texts[0];
Page.Text = texts[1];
Controller.Dispose();
}
private void ShowProgressDialog()
{ {
TaskDialogIcon logo = new(Resources.IconKiseki); TaskDialogIcon logo = new(Resources.IconKiseki);
Page.Icon = logo; Page.Icon = logo;
TaskDialog.ShowDialog(Page); TaskDialog.ShowDialog(Page);
} }
private void CloseButton_Click(object? sender, EventArgs e)
{
Bootstrapper.Abort();
Environment.Exit(0);
}
private void Bootstrapper_HeadingChanged(object? sender, string heading)
{
Page.Heading = heading;
}
private void Bootstrapper_ProgressBarAdded(object? sender, int value)
{
Page.ProgressBar!.Value += value;
}
private void Bootstrapper_ProgressBarStateChanged(object? sender, Enums.ProgressBarState state)
{
Page.ProgressBar!.State = state switch
{
Enums.ProgressBarState.Normal => TaskDialogProgressBarState.Normal,
Enums.ProgressBarState.Marquee => TaskDialogProgressBarState.Marquee,
_ => throw new NotImplementedException()
};
}
private void Bootstrapper_Errored(object? sender, string[] texts)
{
Page.Icon = TaskDialogIcon.Error;
Page.Heading = texts[0];
Page.Text = texts[1];
}
} }
} }

View File

@ -7,11 +7,12 @@ namespace Kiseki.Launcher.Windows
[STAThread] [STAThread]
static void Main(string[] args) static void Main(string[] args)
{ {
// Initialize directories
string parentFolder = Path.GetDirectoryName(Application.ExecutablePath)!; string parentFolder = Path.GetDirectoryName(Application.ExecutablePath)!;
if (Path.GetDirectoryName(parentFolder)!.ToLower().Contains(Constants.PROJECT_NAME.ToLower())) if (Path.GetDirectoryName(parentFolder)!.ToLower().Contains(Constants.PROJECT_NAME.ToLower()))
{ {
// Set to the current directory (either user-installed or default; it has "Kiseki" in the path, so that's good enough for us) // Set to the current directory (user likely has installed the launcher, seeing as parent folder name contains the project name)
Directories.Initialize(parentFolder); Directories.Initialize(parentFolder);
} }
else else
@ -23,40 +24,49 @@ namespace Kiseki.Launcher.Windows
bool isConnected = Web.Initialize(); bool isConnected = Web.Initialize();
if (!isConnected && Web.IsInMaintenance) if (!isConnected && Web.IsInMaintenance)
{ {
// Try again with the maintenance domain // Try licensing this launcher and attempt to connect again
Bootstrapper.TryLoadLicense(); Bootstrapper.License();
isConnected = Web.Initialize(); isConnected = Web.Initialize();
} }
if (!isConnected) if (!isConnected)
{ {
if (Web.IsInMaintenance)
{
// Unlicense this launcher
Bootstrapper.Unlicense();
}
MessageBox.Show($"Failed to connect to {Constants.PROJECT_NAME}. Please check your internet connection and try again.", Constants.PROJECT_NAME, MessageBoxButtons.OK, MessageBoxIcon.Error); MessageBox.Show($"Failed to connect to {Constants.PROJECT_NAME}. Please check your internet connection and try again.", Constants.PROJECT_NAME, MessageBoxButtons.OK, MessageBoxIcon.Error);
return; return;
} }
if (!File.Exists(Directories.Application)) if (!File.Exists(Directories.Application))
{ {
// The launcher is not installed, so let's run the install process - this will also exit the application
Bootstrapper.Install(); Bootstrapper.Install();
return;
} }
else
if (args.Length == 0)
{ {
if (args.Length == 0) // Nothing for us to do :P
Process.Start(new ProcessStartInfo()
{ {
// Nothing for us to do :P FileName = Web.Url("/games"),
Process.Start($"open {Web.Url("/games")}"); UseShellExecute = true
return; });
}
if (args[0] == "-uninstall") return;
{
Bootstrapper.Uninstall(args[0] == "-quiet");
return;
}
ApplicationConfiguration.Initialize();
Application.Run(new MainWindow(args[0]));
} }
if (args[0] == "-uninstall")
{
Bootstrapper.Uninstall(args[0] == "-quiet");
return;
}
ApplicationConfiguration.Initialize();
Application.Run(new MainWindow(args[0]));
} }
} }
} }

View File

@ -1,112 +0,0 @@
using Kiseki.Launcher.Helpers;
namespace Kiseki.Launcher
{
public enum ProgressBarState
{
Normal,
Marquee
}
public class Controller
{
private readonly Dictionary<string, string> Arguments = new();
public event EventHandler<string>? OnPageHeadingChange;
public event EventHandler<int>? OnProgressBarAdd;
public event EventHandler<ProgressBarState>? OnProgressBarStateChange;
public event EventHandler<string[]>? OnErrorShow;
public event EventHandler? OnLaunch;
public Controller(string payload)
{
if (!Base64.IsBase64String(payload))
{
ErrorShow($"Failed to launch {Constants.PROJECT_NAME}", $"Try launching {Constants.PROJECT_NAME} from the website again.");
return;
}
// TODO: The payload will soon include more members; update this accordingly
payload = Base64.ConvertBase64ToString(payload);
if (payload.Split("|").Length != 2)
{
ErrorShow($"Failed to launch {Constants.PROJECT_NAME}", $"Try launching {Constants.PROJECT_NAME} from the website again.");
return;
}
Arguments["JoinScriptURL"] = payload.Split("|")[0];
Arguments["Ticket"] = payload.Split("|")[1];
}
public async void Start()
{
PageHeadingChange("Connecting to Kiseki...");
bool marquee = true;
await foreach (int progressValue in StreamBackgroundOperationProgressAsync())
{
if (marquee)
{
PageHeadingChange("Downloading Kiseki...");
ProgressBarStateChange(ProgressBarState.Normal);
marquee = false;
}
ProgressBarAdd(progressValue);
}
static async IAsyncEnumerable<int> StreamBackgroundOperationProgressAsync()
{
await Task.Delay(2800);
yield return 4;
await Task.Delay(200);
}
PageHeadingChange("Installing Kiseki...");
ProgressBarStateChange(ProgressBarState.Marquee);
await Task.Delay(2200);
PageHeadingChange("Configuring Kiseki...");
await Task.Delay(1200);
PageHeadingChange("Launching Kiseki...");
await Task.Delay(3000);
Launch();
}
public async void Dispose()
{
// TODO: This will only be called when the user closes the window OR we're done (i.e. the Launched event is called.)
}
protected virtual void PageHeadingChange(string heading)
{
OnPageHeadingChange!.Invoke(this, heading);
}
protected virtual void ProgressBarAdd(int value)
{
OnProgressBarAdd!.Invoke(this, value);
}
protected virtual void ProgressBarStateChange(ProgressBarState state)
{
OnProgressBarStateChange!.Invoke(this, state);
}
protected virtual void ErrorShow(string heading, string text)
{
// ugly hack for now (I don't want to derive EventHandler just for this)
OnErrorShow!.Invoke(this, new string[] { heading, text });
}
protected virtual void Launch()
{
OnLaunch!.Invoke(this, EventArgs.Empty);
}
}
}

View File

@ -0,0 +1,8 @@
namespace Kiseki.Launcher.Enums
{
public enum PackageType
{
Bootstrapper,
Client,
}
}

View File

@ -0,0 +1,8 @@
namespace Kiseki.Launcher.Enums
{
public enum ProgressBarState
{
Normal,
Marquee
}
}

View File

@ -2,9 +2,27 @@ namespace Kiseki.Launcher
{ {
public interface IBootstrapper public interface IBootstrapper
{ {
// These connect to MainWindow
event EventHandler<string>? OnHeadingChange;
event EventHandler<int>? OnProgressBarAdd;
event EventHandler<Enums.ProgressBarState>? OnProgressBarStateChange;
event EventHandler<string[]>? OnError;
// Actual bootstrapping
bool Initialize();
void Run();
void Abort();
// Installation (i.e. putting the launcher in the Kiseki folder)
static abstract void Install(); static abstract void Install();
static abstract void Uninstall(bool quiet = false); static abstract void Uninstall(bool quiet = false);
// Registering the launcher onto the system (as well as creating shortcuts)
static abstract void Register(); static abstract void Register();
static abstract void Unregister(); static abstract void Unregister();
// Licensing the launcher
static abstract void License();
static abstract void Unlicense();
} }
} }

View File

@ -1,5 +1,6 @@
namespace Kiseki.Launcher namespace Kiseki.Launcher
{ {
// This is responsible for handling registration of the Kiseki protcool handler
public interface IProtocol public interface IProtocol
{ {
static abstract void Register(); static abstract void Register();