diff --git a/.gitignore b/.gitignore index e88c4d1..1824ab0 100644 --- a/.gitignore +++ b/.gitignore @@ -451,5 +451,7 @@ $RECYCLE.BIN/ .vscode/* !.vscode/settings.json !.vscode/tasks.json -!.vscode/launch.json !.vscode/extensions.json + +## Additions +Wauncher/Properties/launchSettings.json diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..89dc443 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,6 @@ + + + enable + 11.1.0 + + diff --git a/Launcher.sln b/Launcher.sln index dc375c3..4ff6f00 100644 --- a/Launcher.sln +++ b/Launcher.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Launcher", "Launcher\Launch EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wauncher", "Wauncher\Wauncher.csproj", "{6F2F5730-8F26-498D-BB71-F0068EB6870B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -17,6 +19,10 @@ Global {C52CA2D0-3034-4F68-A523-BD7AED0A7479}.Debug|Any CPU.Build.0 = Debug|Any CPU {C52CA2D0-3034-4F68-A523-BD7AED0A7479}.Release|Any CPU.ActiveCfg = Release|Any CPU {C52CA2D0-3034-4F68-A523-BD7AED0A7479}.Release|Any CPU.Build.0 = Release|Any CPU + {6F2F5730-8F26-498D-BB71-F0068EB6870B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6F2F5730-8F26-498D-BB71-F0068EB6870B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6F2F5730-8F26-498D-BB71-F0068EB6870B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6F2F5730-8F26-498D-BB71-F0068EB6870B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Launcher/Launcher.csproj b/Launcher/Launcher.csproj index 16b3e92..1654e97 100644 --- a/Launcher/Launcher.csproj +++ b/Launcher/Launcher.csproj @@ -19,12 +19,17 @@ true false win-x64 + assets\Launcher.ico + + + + diff --git a/Launcher/Utils/Argument.cs b/Launcher/Utils/Argument.cs index 29670fc..9b5332e 100644 --- a/Launcher/Utils/Argument.cs +++ b/Launcher/Utils/Argument.cs @@ -11,7 +11,8 @@ public static class Argument "--patch-only", "--gc", "--disable-rpc", - "--install-dependencies" + "--install-dependencies", + "--protocol-command" }; private static List _additionalArguments = new(); @@ -39,7 +40,19 @@ public static List GenerateGameArguments(bool passLauncherArguments = fa List gameArguments = new(); foreach (string arg in launcherArguments) - if ((passLauncherArguments || !_launcherArguments.Contains(arg.ToLowerInvariant())) + if (arg.StartsWith("cc://")) + { + string protocolArgument = arg.Replace("cc://", ""); + string[] protocolArguments = protocolArgument.Split('/'); + switch (protocolArguments[0]) + { + case "connect": + gameArguments.Add("+" + protocolArguments[0]); + gameArguments.Add(protocolArguments[1]); + break; + } + } + else if ((passLauncherArguments || !_launcherArguments.Contains(arg.ToLowerInvariant())) && !arg.EndsWith(".exe")) gameArguments.Add(arg.ToLowerInvariant()); diff --git a/Launcher/Utils/Console.cs b/Launcher/Utils/Console.cs index 5824787..5599cd7 100644 --- a/Launcher/Utils/Console.cs +++ b/Launcher/Utils/Console.cs @@ -10,7 +10,11 @@ public static class ConsoleManager [DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + [DllImport("user32.dll", CharSet = CharSet.Auto)] + private static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type); + private const int SW_HIDE = 0; + private const uint MB_ICONERROR = 0x00000010; private static IntPtr ConsoleHandle = GetConsoleWindow(); @@ -18,5 +22,14 @@ public static void HideConsole() { ShowWindow(ConsoleHandle, SW_HIDE); } + + public static void ShowError(string message) + { + if (OperatingSystem.IsWindows()) + { + MessageBox(IntPtr.Zero, message, "ClassicCounter Error", MB_ICONERROR); + } + } } } + diff --git a/Launcher/Utils/Discord.cs b/Launcher/Utils/Discord.cs index 188ce66..f6535b4 100644 --- a/Launcher/Utils/Discord.cs +++ b/Launcher/Utils/Discord.cs @@ -1,6 +1,7 @@ using DiscordRPC; using DiscordRPC.Logging; using DiscordRPC.Message; +using System; namespace Launcher.Utils { @@ -10,6 +11,8 @@ public static class Discord private static DiscordRpcClient _client = new DiscordRpcClient(_appId); private static RichPresence _presence = new RichPresence(); public static string? CurrentUserId { get; private set; } // ! DEPRECATED ! for whitelist check + public static string? CurrentUserAvatar { get; private set; } + public static string? CurrentUserUsername { get; private set; } public static void Init() { @@ -58,9 +61,16 @@ public static void SetSmallArtwork(string? key) private static void OnReady(object sender, ReadyMessage e) { CurrentUserId = e.User.ID.ToString(); // ! DEPRECATED ! for passing current uid to api + CurrentUserAvatar = e.User.GetAvatarURL(User.AvatarFormat.PNG); + CurrentUserUsername = e.User.Username; + OnAvatarUpdate?.Invoke(CurrentUserAvatar); + OnUsernameUpdate?.Invoke(CurrentUserUsername); if (Debug.Enabled()) Terminal.Debug($"Discord RPC: User is ready => @{e.User.Username} ({e.User.ID})"); } + + public static event Action? OnAvatarUpdate; + public static event Action? OnUsernameUpdate; } } diff --git a/Launcher/Utils/Game.cs b/Launcher/Utils/Game.cs index e1488e9..fc004e6 100644 --- a/Launcher/Utils/Game.cs +++ b/Launcher/Utils/Game.cs @@ -37,6 +37,7 @@ public static async Task Launch() _listener.NewGameState += OnNewGameState; _listener.Start(); + try { await File.WriteAllTextAsync(gameStatePath, @"""ClassicCounter"" { @@ -61,6 +62,11 @@ await File.WriteAllTextAsync(gameStatePath, } }" ); + } + catch + { + Terminal.Error($"(!) \"/csgo/cfg/gamestate_integration_cc.cfg\" not found in the current directory!"); + } } else if (File.Exists(gameStatePath)) File.Delete(gameStatePath); @@ -74,7 +80,15 @@ await File.WriteAllTextAsync(gameStatePath, _process.StartInfo.FileName = $"{directory}\\{gameExe}"; _process.StartInfo.Arguments = string.Join(" ", arguments); + if (!File.Exists(_process.StartInfo.FileName)) + { + Terminal.Error($"(!) {gameExe} not found in the current directory!"); + ConsoleManager.ShowError($"{gameExe} not found in the current directory!\n\nPlease make sure the launcher and game files are in the same folder."); + return false; + } + return _process.Start(); + } public static async Task Monitor() diff --git a/Launcher/Utils/Patch.cs b/Launcher/Utils/Patch.cs index c05a410..472ee57 100644 --- a/Launcher/Utils/Patch.cs +++ b/Launcher/Utils/Patch.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using System.Collections.Concurrent; using System.Security.Cryptography; namespace Launcher.Utils @@ -152,23 +153,31 @@ public static async Task ValidatePatches(bool validateAll = false) needPak01Update = true; } - if (needPak01Update) + if (!needPak01Update) { patches.Remove(dirPatch); } } - foreach (Patch patch in patches) + var concurrentMissing = new ConcurrentBag(); + var concurrentOutdated = new ConcurrentBag(); + + var parallelOptions = new ParallelOptions + { + MaxDegreeOfParallelism = 4 + }; + + await Parallel.ForEachAsync(patches, parallelOptions, async (patch, cancellationToken) => { string originalFileName = GetOriginalFileName(patch.File); // skip dir file (we already checked it) if (originalFileName.Contains("pak01_dir.vpk")) - continue; + return; // are you a pak01 file? bool isPak01File = originalFileName.Contains("pak01_"); - string path = $"{Directory.GetCurrentDirectory()}/{originalFileName}"; + string path = Path.Combine(Directory.GetCurrentDirectory(), originalFileName); if (isPak01File && !needPak01Update && !Argument.Exists("--validate-all")) { @@ -177,14 +186,14 @@ public static async Task ValidatePatches(bool validateAll = false) if (Debug.Enabled()) Terminal.Debug($"Missing: {originalFileName}"); - missing.Add(patch); - continue; + concurrentMissing.Add(patch); + return; } if (Debug.Enabled()) Terminal.Debug($"Skipping hash check for: {originalFileName} (pak01_dir.vpk up to date)"); - continue; + return; } if (!File.Exists(path)) @@ -192,8 +201,8 @@ public static async Task ValidatePatches(bool validateAll = false) if (Debug.Enabled()) Terminal.Debug($"Missing: {originalFileName}"); - missing.Add(patch); - continue; + concurrentMissing.Add(patch); + return; } if (Debug.Enabled()) @@ -206,9 +215,12 @@ public static async Task ValidatePatches(bool validateAll = false) Terminal.Debug($"Outdated: {originalFileName}"); File.Delete(path); - outdated.Add(patch); + concurrentOutdated.Add(patch); } - } + }); + + missing.AddRange(concurrentMissing); + outdated.AddRange(concurrentOutdated); // if pak01_dir.vpk needs update, move it to end of lists if (needPak01Update && dirPatch != null) diff --git a/Launcher/assets/Launcher.ico b/Launcher/assets/Launcher.ico new file mode 100644 index 0000000..d1657df Binary files /dev/null and b/Launcher/assets/Launcher.ico differ diff --git a/Wauncher/App.axaml b/Wauncher/App.axaml new file mode 100644 index 0000000..19649f3 --- /dev/null +++ b/Wauncher/App.axaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Wauncher/App.axaml.cs b/Wauncher/App.axaml.cs new file mode 100644 index 0000000..ebaafb8 --- /dev/null +++ b/Wauncher/App.axaml.cs @@ -0,0 +1,75 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Data.Core.Plugins; +using Avalonia.Markup.Xaml; +using CommunityToolkit.Mvvm.Input; +using Launcher.Utils; +using Wauncher.Utils; +using Wauncher.ViewModels; +using Wauncher.Views; + +namespace Wauncher +{ + public partial class App : Application + { + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + Discord.Init(); + ProtocolManager.RegisterURIHandler(); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + // Avoid duplicate validations from both Avalonia and the CommunityToolkit. + // More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins + DisableAvaloniaDataAnnotationValidation(); + desktop.MainWindow = new MainWindow + { + DataContext = new MainWindowViewModel(), + }; + } + + base.OnFrameworkInitializationCompleted(); + } + + private void DisableAvaloniaDataAnnotationValidation() + { + // Get an array of plugins to remove + var dataValidationPluginsToRemove = + BindingPlugins.DataValidators.OfType().ToArray(); + + // remove each entry found + foreach (var plugin in dataValidationPluginsToRemove) + { + BindingPlugins.DataValidators.Remove(plugin); + } + } + + + [RelayCommand] + public void TrayIconClicked() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop && desktop.MainWindow != null) + { + desktop.MainWindow.Show(); + desktop.MainWindow.Activate(); + } + } + + public void ExitApplication_Click(object? sender, System.EventArgs e) + { + switch (ApplicationLifetime) + { + case IClassicDesktopStyleApplicationLifetime desktopLifetime: + desktopLifetime.TryShutdown(); + break; + case IControlledApplicationLifetime controlledLifetime: + controlledLifetime.Shutdown(); + break; + } + } + } +} \ No newline at end of file diff --git a/Wauncher/Assets/CS-logo.svg b/Wauncher/Assets/CS-logo.svg new file mode 100644 index 0000000..42ade88 --- /dev/null +++ b/Wauncher/Assets/CS-logo.svg @@ -0,0 +1,3 @@ + + + diff --git a/Wauncher/Assets/Styles.axaml b/Wauncher/Assets/Styles.axaml new file mode 100644 index 0000000..c0d156b --- /dev/null +++ b/Wauncher/Assets/Styles.axaml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Wauncher/Assets/Wauncher.ico b/Wauncher/Assets/Wauncher.ico new file mode 100644 index 0000000..cc20e3f Binary files /dev/null and b/Wauncher/Assets/Wauncher.ico differ diff --git a/Wauncher/Program.cs b/Wauncher/Program.cs new file mode 100644 index 0000000..b17b8c2 --- /dev/null +++ b/Wauncher/Program.cs @@ -0,0 +1,60 @@ +using Avalonia; +using Wauncher.Utils; + +namespace Wauncher +{ + internal sealed class Program + { + public static EventWaitHandle ProgramStarted; + + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) + { + if (OnStartup(args) == false) + { + Environment.Exit(0); + return; + } + + BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + } + + // Reference (COPYPASTA) + // https://github.com/2dust/v2rayN/blob/d9843dc77502454b1ec48cec6244e115f1abd082/v2rayN/v2rayN.Desktop/Program.cs#L25-L52 + private static bool OnStartup(string[]? Args) + { + + if (Services.IsWindows()) + { + var exePathKey = Services.GetMd5(Services.GetExePath()); + var rebootas = (Args ?? []).Any(t => t == "rebootas"); + ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, exePathKey, out var bCreatedNew); + if (!rebootas && !bCreatedNew) + { + ProgramStarted.Set(); + return false; + } + } + else + { + _ = new Mutex(true, "Wauncher", out var bOnlyOneInstance); + if (!bOnlyOneInstance) + { + return false; + } + } + return true; + } + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace(); + } +} diff --git a/Wauncher/Utils/ProtocolManager.cs b/Wauncher/Utils/ProtocolManager.cs new file mode 100644 index 0000000..b81f5ea --- /dev/null +++ b/Wauncher/Utils/ProtocolManager.cs @@ -0,0 +1,49 @@ +using Microsoft.Win32; + +namespace Wauncher.Utils +{ + public class ProtocolManager + { + public static void RegisterURIHandler() + { + var appCurrentLocation = Path.Combine(new FileInfo(System.Environment.ProcessPath).Directory.FullName, "wauncher.exe"); + EnsureKeyExists(Registry.CurrentUser, "Software/Classes/cc", "ClassicCounter"); + SetValue(Registry.CurrentUser, "Software/Classes/cc", "URL Protocol", string.Empty); + EnsureKeyExists(Registry.CurrentUser, "Software/Classes/cc/DefaultIcon", $"{appCurrentLocation},1"); + EnsureKeyExists(Registry.CurrentUser, "Software/Classes/cc/shell/open/command", $"\"{appCurrentLocation}\" --protocol-command \"%1\""); + } + + private static void SetValue(RegistryKey rootKey, string keys, string valueName, string value) + { + var key = EnsureKeyExists(rootKey, keys); + key.SetValue(valueName, value); + } + + private static RegistryKey EnsureKeyExists(RegistryKey rootKey, string keys, string defaultValue = null) + { + if (rootKey == null) + { + throw new Exception("Root key is (null)"); + } + + var currentKey = rootKey; + foreach (var key in keys.Split('/')) + { + currentKey = currentKey.OpenSubKey(key, RegistryKeyPermissionCheck.ReadWriteSubTree) + ?? currentKey.CreateSubKey(key, RegistryKeyPermissionCheck.ReadWriteSubTree); + + if (currentKey == null) + { + throw new Exception("Could not get or create key"); + } + } + + if (defaultValue != null) + { + currentKey.SetValue(string.Empty, defaultValue); + } + + return currentKey; + } + } +} diff --git a/Wauncher/Utils/Services.cs b/Wauncher/Utils/Services.cs new file mode 100644 index 0000000..bce55f6 --- /dev/null +++ b/Wauncher/Utils/Services.cs @@ -0,0 +1,39 @@ +using System.Diagnostics; +using System.Security.Cryptography; +using System.Text; + +namespace Wauncher.Utils +{ + public class Services + { + public static string GetMd5(string str) + { + if (String.IsNullOrEmpty(str)) + { + return string.Empty; + } + try + { + var byteOld = Encoding.UTF8.GetBytes(str); + var byteNew = MD5.HashData(byteOld); + StringBuilder sb = new(32); + foreach (var b in byteNew) + { + sb.Append(b.ToString("x2")); + } + + return sb.ToString(); + } + catch (Exception) + { + return string.Empty; + } + } + public static string GetExePath() + { + return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty; + } + + public static bool IsWindows() => OperatingSystem.IsWindows(); + } +} diff --git a/Wauncher/ViewLocator.cs b/Wauncher/ViewLocator.cs new file mode 100644 index 0000000..79ee347 --- /dev/null +++ b/Wauncher/ViewLocator.cs @@ -0,0 +1,32 @@ +using Avalonia.Controls; +using Avalonia.Controls.Templates; +using System; +using Wauncher.ViewModels; + +namespace Wauncher +{ + public class ViewLocator : IDataTemplate + { + + public Control? Build(object? param) + { + if (param is null) + return null; + + var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal); + var type = Type.GetType(name); + + if (type != null) + { + return (Control)Activator.CreateInstance(type)!; + } + + return new TextBlock { Text = "Not Found: " + name }; + } + + public bool Match(object? data) + { + return data is ViewModelBase; + } + } +} diff --git a/Wauncher/ViewModels/InfoWindowViewModel.cs b/Wauncher/ViewModels/InfoWindowViewModel.cs new file mode 100644 index 0000000..be05980 --- /dev/null +++ b/Wauncher/ViewModels/InfoWindowViewModel.cs @@ -0,0 +1,35 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Wauncher.ViewModels +{ + public partial class InfoWindowViewModel : ViewModelBase + { + [RelayCommand] + private void OpenUrl(string? url) + { + if (string.IsNullOrWhiteSpace(url)) + { + return; + } + + try + { + Process.Start(new ProcessStartInfo(url) { UseShellExecute = true }); + } + catch + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + Process.Start("xdg-open", url); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + Process.Start("open", url); + } + } + } + } +} \ No newline at end of file diff --git a/Wauncher/ViewModels/MainWindowViewModel.cs b/Wauncher/ViewModels/MainWindowViewModel.cs new file mode 100644 index 0000000..e64c68b --- /dev/null +++ b/Wauncher/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,45 @@ +using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; +using Launcher.Utils; + +namespace Wauncher.ViewModels +{ + public partial class MainWindowViewModel : ViewModelBase + { + public string GameStatus { get; private set; } = "Game Status: "; + + public string ProtocolManager { get; private set; } = "Selected server: "; + + [ObservableProperty] + private string _profilePicture = "https://avatars.githubusercontent.com/u/75831703?v=4"; + + [ObservableProperty] + private string _usernameGreeting = "Hello, username"; + + public string WhitelistStatus { get; set; } = "Gray"; + + public MainWindowViewModel() + { + if (Argument.Exists("--protocol-command")) + { + ProtocolManager = ProtocolManager + "Ready to Launch!"; + } + + Discord.OnAvatarUpdate += (avatarUrl) => + { + if (!string.IsNullOrEmpty(avatarUrl)) + { + Dispatcher.UIThread.Post(() => ProfilePicture = avatarUrl); + } + }; + + Discord.OnUsernameUpdate += (username) => + { + if (!string.IsNullOrEmpty(username)) + { + Dispatcher.UIThread.Post(() => UsernameGreeting = $"Hello, {username}"); + } + }; + } + } +} diff --git a/Wauncher/ViewModels/ViewModelBase.cs b/Wauncher/ViewModels/ViewModelBase.cs new file mode 100644 index 0000000..f39a365 --- /dev/null +++ b/Wauncher/ViewModels/ViewModelBase.cs @@ -0,0 +1,8 @@ +using CommunityToolkit.Mvvm.ComponentModel; + +namespace Wauncher.ViewModels +{ + public class ViewModelBase : ObservableObject + { + } +} diff --git a/Wauncher/Views/InfoWindow.axaml b/Wauncher/Views/InfoWindow.axaml new file mode 100644 index 0000000..d43fb24 --- /dev/null +++ b/Wauncher/Views/InfoWindow.axaml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + Thank You for playing ClassicCounter and using Wauncher. + Special thanks to h4rmy, heapy and eddies for maintaining this project. + + Built using: + + and + + + + by + + + + Suggest via + + or + + + Something is not working? Read + + + + + + + + + diff --git a/Wauncher/Views/InfoWindow.axaml.cs b/Wauncher/Views/InfoWindow.axaml.cs new file mode 100644 index 0000000..1d6a8a7 --- /dev/null +++ b/Wauncher/Views/InfoWindow.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia.Controls; +using Wauncher.ViewModels; + +namespace Wauncher; + +public partial class InfoWindow : Window +{ + public InfoWindow() + { + InitializeComponent(); + DataContext = new InfoWindowViewModel(); + } +} \ No newline at end of file diff --git a/Wauncher/Views/MainWindow.axaml b/Wauncher/Views/MainWindow.axaml new file mode 100644 index 0000000..a9e454f --- /dev/null +++ b/Wauncher/Views/MainWindow.axaml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wauncher/Views/MainWindow.axaml.cs b/Wauncher/Views/MainWindow.axaml.cs new file mode 100644 index 0000000..d5a312f --- /dev/null +++ b/Wauncher/Views/MainWindow.axaml.cs @@ -0,0 +1,35 @@ +using Avalonia.Controls; +using Launcher.Utils; + +namespace Wauncher.Views +{ + public partial class MainWindow : Window + { + private InfoWindow? _infoWindow = null; + public MainWindow() + { + InitializeComponent(); + } + + private async void Button_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + await Game.Launch(); + Discord.SetDetails("In Main Menu"); + Discord.Update(); + await Game.Monitor(); + } + private void Button_Info(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + if (_infoWindow == null) + { + _infoWindow = new InfoWindow(); + _infoWindow.Closed += (s, e) => _infoWindow = null; + _infoWindow.Show(this); + } + else + { + _infoWindow.Activate(); + } + } + } +} \ No newline at end of file diff --git a/Wauncher/Wauncher.csproj b/Wauncher/Wauncher.csproj new file mode 100644 index 0000000..27333d1 --- /dev/null +++ b/Wauncher/Wauncher.csproj @@ -0,0 +1,53 @@ + + + + WinExe + net8.0-windows7.0 + win-x64 + enable + enable + true + app.manifest + true + + true + true + false + 3.0.0 + $(Version) + $(Version) + wauncher + ClassicCounter Wauncher + ClassicCounter Team + koolych + Assets\Wauncher.ico + + + + + + + + + + + + + + + + + + + + None + All + + + + + + + + + diff --git a/Wauncher/app.manifest b/Wauncher/app.manifest new file mode 100644 index 0000000..9bc1866 --- /dev/null +++ b/Wauncher/app.manifest @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/publish.bat b/publish.bat index 72eef09..e3789b1 100644 --- a/publish.bat +++ b/publish.bat @@ -1,3 +1,15 @@ -dotnet publish -c Release +@echo off +for /f %%a in ('echo prompt $E^| cmd') do set "ESC=%%a" +echo ============================= +echo %ESC%[42mBuilding...%ESC%[0m +dotnet publish Launcher -c Release +dotnet publish Wauncher -c Release +echo ============================= +echo %ESC%[41mHashing...%ESC%[0m certutil -hashfile "Launcher\bin\Release\net8.0-windows7.0\win-x64\publish\launcher.exe" MD5 -pause \ No newline at end of file +certutil -hashfile "Wauncher\bin\Release\net8.0-windows7.0\win-x64\publish\wauncher.exe" MD5 +echo ============================= +echo %ESC%[1;43mCopying...%ESC%[0m +set /p "destination=Copying destination (in quotations): " +xcopy "Wauncher\bin\Release\net8.0-windows7.0\win-x64\publish\" %destination% /e /y +timeout /t 5 \ No newline at end of file