commit 8f3a3a24d6e6c2553827173289c29ade6603fc62 Author: Zsolt Zitting Date: Mon Apr 24 03:23:53 2023 -0600 Welcome to hell. diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,363 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/.idea/.idea.WACCALauncher.dir/.idea/.gitignore b/.idea/.idea.WACCALauncher.dir/.idea/.gitignore new file mode 100644 index 0000000..04a8467 --- /dev/null +++ b/.idea/.idea.WACCALauncher.dir/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/contentModel.xml +/.idea.WACCALauncher.iml +/projectSettingsUpdater.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.WACCALauncher.dir/.idea/indexLayout.xml b/.idea/.idea.WACCALauncher.dir/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.WACCALauncher.dir/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.WACCALauncher/.idea/.gitignore b/.idea/.idea.WACCALauncher/.idea/.gitignore new file mode 100644 index 0000000..e2687a9 --- /dev/null +++ b/.idea/.idea.WACCALauncher/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/contentModel.xml +/.idea.WACCALauncher.iml +/modules.xml +/projectSettingsUpdater.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.WACCALauncher/.idea/indexLayout.xml b/.idea/.idea.WACCALauncher/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.WACCALauncher/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..8aa2645 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) [year] [fullname] + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +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. diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs new file mode 100644 index 0000000..80b5ed7 --- /dev/null +++ b/MainForm.Designer.cs @@ -0,0 +1,72 @@ +namespace WACCALauncher +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.menuLabel = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // menuLabel + // + this.menuLabel.Anchor = System.Windows.Forms.AnchorStyles.Top; + this.menuLabel.Font = new System.Drawing.Font("Tahoma", 22.5F); + this.menuLabel.ForeColor = System.Drawing.Color.White; + this.menuLabel.Location = new System.Drawing.Point(287, 127); + this.menuLabel.Name = "menuLabel"; + this.menuLabel.Size = new System.Drawing.Size(500, 30); + this.menuLabel.TabIndex = 0; + this.menuLabel.Text = "MENU TITLE"; + this.menuLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.menuLabel.Visible = false; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Black; + this.ClientSize = new System.Drawing.Size(1080, 1080); + this.Controls.Add(this.menuLabel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.KeyPreview = true; + this.Name = "MainForm"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.Text = "WACCA Launcher"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); + this.Load += new System.EventHandler(this.Form1_Load); + this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.KeyPressed); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label menuLabel; + } +} + diff --git a/MainForm.cs b/MainForm.cs new file mode 100644 index 0000000..dfb4882 --- /dev/null +++ b/MainForm.cs @@ -0,0 +1,699 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Text; +using System.Windows.Forms; +using System.Drawing.Text; +using System.Timers; +using System.Diagnostics; +using IniParser; +using IniParser.Model; +using SharpDX.DirectInput; +using System.Collections; +using System.Linq; +using IniParser.Exceptions; + +namespace WACCALauncher +{ + public partial class MainForm : Form + { + private static System.Timers.Timer _delayTimer; + private readonly System.Windows.Forms.Timer _t = new System.Windows.Forms.Timer(); + + [System.Runtime.InteropServices.DllImport("gdi32.dll")] + private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, + IntPtr pdv, [System.Runtime.InteropServices.In] ref uint pcFonts); + + private readonly PrivateFontCollection _fonts = new PrivateFontCollection(); + private Label _loadingLabel; + + private Font _menuFont; + + private readonly DirectInput _input = new DirectInput(); + private Joystick _ioBoard; + + public readonly List Versions = new List(); + public Version DefaultVer; + + private readonly IniData _config; + private readonly FileIniDataParser _parser = new FileIniDataParser(); + + private readonly Process _gameProcess = new Process(); + private bool _gameRunning = false; + + public MainForm() + { + InitializeComponent(); + + _t.Tick += Tick; + _t.Interval = 20; + _t.Start(); + + _delayTimer = new System.Timers.Timer(5000); + _delayTimer.Elapsed += LaunchDefault; + + _delayTimer.Enabled = true; + + // Load embedded font into memory + + LoadFont(); + + try + { + _config = _parser.ReadFile("wacca.ini"); + } + catch (IniParser.Exceptions.ParsingException) + { + DisplayError("Config error", "wacca.ini could not be read, check for errors"); + } + + if (!Program.IsCorrectRes()) return; + var bounds = Program.CurrentScreen.Bounds; + this.SetBounds(bounds.X, bounds.Y + 362, Width, Height); + } + + private void LoadFont() + { + var fontData = Properties.Resources.menufont; + var fontPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(fontData.Length); + System.Runtime.InteropServices.Marshal.Copy(fontData, 0, fontPtr, fontData.Length); + uint dummy = 0; + _fonts.AddMemoryFont(fontPtr, Properties.Resources.menufont.Length); + AddFontMemResourceEx(fontPtr, (uint)Properties.Resources.menufont.Length, IntPtr.Zero, ref dummy); + System.Runtime.InteropServices.Marshal.FreeCoTaskMem(fontPtr); + + _menuFont = new Font(_fonts.Families[0], 22.5F); + } + + private bool[] _buttonStates; + private bool[] _lastButtonStates = new bool[4]; + + private bool _autoLaunch = true; + private int _currentMenuItem; + public ConfigMenu CurrentMenu; + + public readonly ConfigMenu MainMenu = new ConfigMenu("Launcher Settings", rootMenu: true) { + //new ConfigMenuItem("bruh"), + //new ConfigMenuItem("moments"), + //new ConfigMenuItem("of"), + //new ConfigMenuItem("history") + }; + + + + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (!_gameRunning) + { + if (keyData == Keys.Up) { CursorUp(); return true; } + else if (keyData == Keys.Down) { CursorDown(); return true; } + } + + return base.ProcessCmdKey(ref msg, keyData); + } + + private void KeyPressed(object sender, KeyPressEventArgs e) + { + if (_gameRunning) return; + switch ((Keys)e.KeyChar) + { + case Keys.Escape: + if (_autoLaunch) MenuShow(); + else MenuBack(); + e.Handled = true; + break; + case Keys.Enter: + MenuSelect(); + e.Handled = true; + break; + } + } + + private async void Tick(object sender, EventArgs e) + { + var gamepads = _input.GetDevices(DeviceClass.GameControl, DeviceEnumerationFlags.AttachedOnly); + + try + { + _gameRunning = _gameProcess.StartTime != null; + } + catch (InvalidOperationException) {} + + if (_ioBoard == null && gamepads.Count > 0) + { + Console.WriteLine("gamepad detected"); + // it will be the only gamepad on the system + var guid = gamepads[0].InstanceGuid; + _ioBoard = new Joystick(_input, guid); + _ioBoard.Acquire(); + } + else if (gamepads.Count > 0 && !_gameRunning) + { + _ioBoard.Poll(); + _buttonStates = _ioBoard.GetCurrentState().Buttons; + + // vol down + if (_buttonStates[0] && !_lastButtonStates[0]) + { + Console.WriteLine("vol down"); + CursorDown(); + } + + // vol up + if (_buttonStates[1] && !_lastButtonStates[1]) + { + Console.WriteLine("vol up"); + CursorUp(); + } + + // service + if (_buttonStates[6] && !_lastButtonStates[6]) + { + Console.WriteLine("service button"); + CursorDown(); + } + + // test + if (_buttonStates[9] && !_lastButtonStates[9]) + { + Console.WriteLine("test button"); + if(_autoLaunch) + { + MenuShow(); + } + else MenuSelect(); + } + + _lastButtonStates = _buttonStates; + } + } + + private void CursorUp() + { + // move cursor up + Console.WriteLine("CursorUp"); + CurrentMenu[_currentMenuItem].Deactivate(); + _currentMenuItem = ((_currentMenuItem - 1) + CurrentMenu.Count) % CurrentMenu.Count; + Console.WriteLine($"Item {_currentMenuItem}"); + RefreshMenu(); + } + + private void CursorDown() + { + // move cursor down + Console.WriteLine("CursorDown"); + CurrentMenu[_currentMenuItem].Deactivate(); + _currentMenuItem = (_currentMenuItem + 1) % CurrentMenu.Count; + Console.WriteLine($"Item {_currentMenuItem}"); + RefreshMenu(); + } + + public void MenuShow() + { + _delayTimer.Stop(); + _loadingLabel.Visible = false; + menuLabel.Visible = true; + GenerateMenu(MainMenu); + _autoLaunch = false; + } + + public void MenuHide() + { + _autoLaunch = true; + menuLabel.Hide(); + foreach (var item in CurrentMenu) + { + item.label.Dispose(); + } + _loadingLabel.Show(); + + _delayTimer = new System.Timers.Timer(5000); + _delayTimer.Elapsed += LaunchDefault; + + _delayTimer.Enabled = true; + } + + private void MenuSelect() + { + // select menu item + Console.WriteLine("MenuSelect"); + CurrentMenu[_currentMenuItem].Select(this, CurrentMenu); + } + + private void MenuBack() + { + // back from current menu item + Console.WriteLine("MenuBack"); + } + + private void MenuReturn() + { + GenerateMenu(MainMenu); + } + + public void RefreshMenu() + { + this.Controls.Remove(CurrentMenu[_currentMenuItem].label); + CurrentMenu[_currentMenuItem].Activate(); + this.Controls.Add(CurrentMenu[_currentMenuItem].label); + } + + private void Form1_Load(object sender, EventArgs e) + { + _loadingLabel = new Label(); + SuspendLayout(); + + _loadingLabel.Font = _menuFont; + _loadingLabel.ForeColor = Program.IsCorrectVer() ? Color.White : Color.DarkOrange; + _loadingLabel.Location = new Point(458, 525); + _loadingLabel.Name = "loadingLabel"; + _loadingLabel.Size = new Size(164, 30); + _loadingLabel.TabIndex = 0; + _loadingLabel.Text = "LOADING..."; + _loadingLabel.TextAlign = ContentAlignment.MiddleCenter; + + this.Controls.Add(_loadingLabel); + + LoadVersionsFromConfig(); + + var defVerMenu = new ConfigMenu("default version"); + + foreach (var ver in Versions) + { + var name = ver.GameVersion == VersionType.Custom ? ver.CustomName : ver.ToString(); + defVerMenu.Add(new ConfigMenuItem($"({(ver == DefaultVer ? 'X' : ' ')}) {name}", ConfigMenuAction.VersionSelect, version: ver)); + } + + defVerMenu.Add(new ConfigMenuItem("Return to settings", ConfigMenuAction.Return)); + + MainMenu.Add(new ConfigMenuItem("set default version", ConfigMenuAction.Submenu, submenu: defVerMenu)); + + MainMenu.Add(new ConfigMenuItem("launch game", ConfigMenuAction.Return)); + + _loadingLabel.Font = _menuFont; + menuLabel.Font = _menuFont; + } + + public void GenerateMenu(ConfigMenu menu, int selectedIndex = 0) + { + if (menu == null || menu == CurrentMenu) return; + if(CurrentMenu != null) + { + menu.ParentMenu = CurrentMenu; + foreach (var item in CurrentMenu) + { + item.label.Dispose(); + } + } + + CurrentMenu = menu; + _currentMenuItem = selectedIndex; + + menuLabel.Text = menu.Name.ToUpper(); + var menuIndex = 0; + + foreach (var item in menu) + { + item.label = new Label(); + item.label.Text = item.Name.ToUpper(); + item.label.ForeColor = Color.White; + item.label.TextAlign = ContentAlignment.MiddleLeft; + item.label.AutoSize = false; + item.label.Size = new Size(700, 30); + item.label.Font = _menuFont; + item.label.Location = new Point(200, 240 + (40 * menuIndex)); + item.label.Parent = this; + this.Controls.Add(item.label); + menuIndex++; + } + + RefreshMenu(); + } + + private static void KillExplorer() + { + Process.Start(@"C:\Windows\System32\taskkill.exe", @"/F /IM explorer.exe"); + } + + private static void OpenExplorer() + { + var processes = Process.GetProcessesByName("explorer"); + if (processes.Length == 0) Process.Start("explorer.exe"); + } + + private void LaunchGame(Version version) + { + Console.WriteLine("launching game"); + _gameProcess.StartInfo.FileName = version.BatchPath; + _gameProcess.EnableRaisingEvents = true; + + //this.Hide(); + _gameProcess.Exited += QuitLauncher; + _gameProcess.Start(); + //Application.Exit(); + } + + public void LaunchGame(VersionType type) + { + LaunchGame(Versions.Find(x => x.GameVersion == type)); + } + + public void LaunchGame(string gameId) + { + LaunchGame(Versions.Find(x => x.GameId == gameId)); + } + + private void QuitLauncher(Object source, EventArgs e) + { + // Only exit after the game has closed, so that the launcher doesn't keep opening when configured as a shell + Application.Exit(); + } + + private void LaunchDefault(Object source, ElapsedEventArgs e) + { + _delayTimer.Stop(); + KillExplorer(); + LaunchGame(DefaultVer); + } + + private void LoadVersionsFromConfig() + { + if (_config == null) return; + foreach (VersionType item in (VersionType[])Enum.GetValues(typeof(VersionType))) + { + var iniPath = _config["versions"][item.ToString().ToLower()]; + if (string.IsNullOrEmpty(iniPath)) continue; + Console.WriteLine($"Found path for {item.ToString().Replace('_', ' ')}: \"{iniPath}\""); + try + { + var version = new Version(iniPath, item); + if (!version.HasSegatools) + { + DisplayError("Segatools missing", $"Ensure segatools is present in the bin folder ({version})"); + return; + } + Versions.Add(version); + } + catch (Exception ex) when (ex is NotSupportedException || ex is DirectoryNotFoundException || ex is ArgumentException) + { + DisplayError($"Invalid path for {item.ToString().Replace('_', ' ')}", "Check the config paths for errors and try again"); + return; + } + } + + int num_customs; + if(int.TryParse(_config["general"]["num_customs"], out num_customs)) + { + for (var i = 1; i < num_customs + 1; i++) { + var customVer = _config[$"custom_{i}"]; + + var customPath = customVer["path"]; + var customName = customVer["name"]; + + if (string.IsNullOrEmpty(customPath)) continue; + try + { + var version = new Version(customPath, VersionType.Custom, $"custom_{i}", customName); + if (!version.HasSegatools) + { + DisplayError("Segatools missing", $"Ensure segatools is present in the bin folder ({version})"); + return; + } + Versions.Add(version); + Console.WriteLine($"Found path for {customName}: \"{customPath}\""); + } + catch (Exception ex) when (ex is NotSupportedException || ex is DirectoryNotFoundException || ex is ArgumentException) + { + DisplayError($"Invalid path for {customName}", "Check the config paths for errors and try again"); + return; + } + } + } + + + if (Versions.Count == 0) + { + DisplayError("No versions found", "Check the config paths for errors and try again"); + } + else + { + if (_config["general"]["default_ver"] == null || _config["general"]["default_ver"] == string.Empty) + { + SetDefaultVer(Versions.First()); + } + + DefaultVer = Versions.Find(x => x.GameId == _config["general"]["default_ver"]); + } + } + + public void SetDefaultVer(Version version) + { + DefaultVer = version; + _config["general"]["default_ver"] = DefaultVer.GameId; + _parser.WriteFile("wacca.ini", _config); + } + + private void DisplayError(string error, string description = "") + { + _delayTimer.Stop(); + _loadingLabel?.Hide(); + + var errorLabel = new Label(); + SuspendLayout(); + + errorLabel.Font = _menuFont; + errorLabel.ForeColor = Color.Red; + errorLabel.Location = new Point(90, 495); + errorLabel.AutoSize = false; + errorLabel.Name = "errorLabel"; + errorLabel.Size = new Size(900, 90); + var errorText = new StringBuilder(); + errorText.AppendLine("ERROR: " + error + "\n"); + if (description != string.Empty) errorText.AppendLine(description); + errorLabel.Text = errorText.ToString().ToUpper(); + errorLabel.TextAlign = ContentAlignment.MiddleCenter; + + Controls.Add(errorLabel); + } + + private void MainForm_FormClosing(object sender, FormClosingEventArgs e) + { + OpenExplorer(); + } + } + + public enum VersionType + { + Unknown = 0, + WACCA, + WACCA_S, + Lily, + Lily_R, + Reverse, + Custom = 10 + } + + public class Version + { + private readonly DirectoryInfo _dir; + + public DirectoryInfo GameDirectoryInfo => _dir; + public readonly VersionType GameVersion; + public readonly string GameId; + public readonly string CustomName; + public readonly bool HasSegatools = false; + public readonly string BatchPath = string.Empty; + + public Version(string path, VersionType version, string gameId = "", string customName = "") + { + this._dir = new DirectoryInfo(path); + if (!_dir.Exists) throw new DirectoryNotFoundException(); + + this.GameVersion = version; + this.GameId = gameId != string.Empty ? gameId : version.ToString().ToLower(); + if (customName != string.Empty) this.CustomName = customName; + var binPath = Path.Combine(_dir.FullName, "bin"); + + if (CheckForSegatools(binPath)) + { + HasSegatools = true; + BatchPath = Path.Combine(binPath, "start.bat"); + } + } + + private bool CheckForSegatools(string path) + { + return File.Exists(Path.Combine(path, "segatools.ini")) && + File.Exists(Path.Combine(path, "mercuryhook.dll")) && + File.Exists(Path.Combine(path, "inject.exe")); + } + + public override string ToString() + { + return GameVersion.ToString().Replace('_', ' '); + } + } + + public enum ConfigMenuAction + { + None = 0, + Command, + Submenu, + VersionSelect, + ItemSelect, + Return + } + + public class ConfigMenu : IList + { + public readonly string Name; + public bool RootMenu = false; + public ConfigMenu ParentMenu = null; + private readonly List _items = new List(); + + public ConfigMenu(string name, bool rootMenu = false) + { + this.Name = name; + this.RootMenu = rootMenu; + } + + public ConfigMenuItem this[int index] { get => _items[index]; set => _items[index] = value; } + + public int Count => _items.Count; + + public bool IsReadOnly => false; + + public void Add(ConfigMenuItem item) + { + _items.Add(item); + } + + public void Clear() + { + _items.Clear(); + } + + public bool Contains(ConfigMenuItem item) + { + return _items.Contains(item); + } + + public void CopyTo(ConfigMenuItem[] array, int arrayIndex) + { + _items.CopyTo(array, arrayIndex); + } + + public IEnumerator GetEnumerator() + { + return _items.GetEnumerator(); + } + + public int IndexOf(ConfigMenuItem item) + { + return _items.IndexOf(item); + } + + public void Insert(int index, ConfigMenuItem item) + { + _items.Insert(index, item); + } + + public bool Remove(ConfigMenuItem item) + { + return _items.Remove(item); + } + + public void RemoveAt(int index) + { + _items.RemoveAt(index); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _items.GetEnumerator(); + } + + public void Destroy() + { + Clear(); + } + } + + public class ConfigMenuItem + { + public readonly string Name; + private readonly ConfigMenuAction _action; + private readonly Action _method; + private readonly ConfigMenu _submenu; + private readonly List _options; + private readonly Version _version; + + public Label label; + + public ConfigMenuItem(string name, ConfigMenuAction action = ConfigMenuAction.None, Action method = null, ConfigMenu submenu = null, List options = null, Version version = null) { + this.Name = name; + this._action = action; + + if (action == ConfigMenuAction.Command && method == null) + throw new ArgumentException($"Menu item '{name}' was defined with Command type, but has no method associated."); + else if (action == ConfigMenuAction.Submenu && submenu == null) + throw new ArgumentException($"Menu item '{name}' was defined with Submenu type, but has no submenu associated."); + else if (action == ConfigMenuAction.ItemSelect && options == null) + throw new ArgumentException($"Menu item '{name}' was defined with ItemSelect type, but has no options associated."); + else if (action == ConfigMenuAction.VersionSelect && version == null) + throw new ArgumentException($"Menu item '{name}' was defined with VersionSelect type, but has no version associated."); + + this._method = method; + this._submenu = submenu; + this._options = options; + this._version = version; + } + + public void Activate() + { + label.ForeColor = Color.Red; + } + + public void Deactivate() + { + label.ForeColor = Color.White; + } + + public void Select(MainForm form, ConfigMenu menu) + { + if (_action == ConfigMenuAction.Command) + { + // only works with static methods, why + this._method(); + } + else if (_action == ConfigMenuAction.Submenu && _submenu != null) + { + Console.WriteLine("attempting submenu"); + form.GenerateMenu(_submenu); + } + else if (_action == ConfigMenuAction.ItemSelect && _options != null) + { + // generate list of options and cycle through them, complicated + return; + } + else if (_action == ConfigMenuAction.VersionSelect && _version != null) + { + Console.WriteLine($"setting default version to {_version}"); + form.SetDefaultVer(_version); + for (int i = 0; i < form.Versions.Count; i++) + { + var name = form.Versions[i].GameVersion == VersionType.Custom ? form.Versions[i].CustomName : form.Versions[i].ToString(); + menu[i].label.Text = $"({(form.Versions[i] == form.DefaultVer ? 'X' : ' ')}) {name}".ToUpper(); + } + form.RefreshMenu(); + } + else if (_action == ConfigMenuAction.Return) + if(form.CurrentMenu == form.MainMenu) + { + form.MenuHide(); + } + else form.GenerateMenu(form.CurrentMenu.ParentMenu); + } + } +} diff --git a/MainForm.resx b/MainForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/MainForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..ea64dfb --- /dev/null +++ b/Program.cs @@ -0,0 +1,51 @@ +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; + +namespace WACCALauncher +{ + internal static class Program + { + private static readonly RegistryKey WinVer = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"); + private static readonly int BuildNumber = int.Parse(WinVer.GetValue("CurrentBuild").ToString()); + private static readonly int ReleaseId = int.Parse(WinVer.GetValue("ReleaseId").ToString()); + + public static Screen CurrentScreen = Screen.PrimaryScreen; + + public static bool IsCorrectRes() + { + return CurrentScreen.Bounds.Width == 1080 + && CurrentScreen.Bounds.Height == 1920; + } + + public static bool IsCorrectVer() + { + // ensures Enterprise 2016 LTSB is used + return BuildNumber == 14393 && ReleaseId == 1607; + } + + public static bool IsWACCA() + { + return IsCorrectRes() && IsCorrectVer(); + } + + /// + /// The main entry point for the application. + /// + [STAThread] + private static void Main() + { + // for testing + if(Screen.AllScreens.Length > 1) + CurrentScreen = Screen.AllScreens[1]; + + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainForm()); + } + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d476f49 --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("WACCALauncher")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("YellowberryHN")] +[assembly: AssemblyProduct("WACCALauncher")] +[assembly: AssemblyCopyright("Copyright © YellowberryHN 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3b4099c2-66e5-4d56-89b1-e14cf8e11b6a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.0.2.0")] +[assembly: AssemblyFileVersion("0.0.2.0")] diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs new file mode 100644 index 0000000..628e4f3 --- /dev/null +++ b/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace WACCALauncher.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("WACCALauncher.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] menufont { + get { + object obj = ResourceManager.GetObject("menufont", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/Properties/Resources.resx b/Properties/Resources.resx new file mode 100644 index 0000000..1135b47 --- /dev/null +++ b/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\funny.ttf;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs new file mode 100644 index 0000000..a298a66 --- /dev/null +++ b/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace WACCALauncher.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.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; + } + } + } +} diff --git a/Properties/Settings.settings b/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..9176af5 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# WACCALauncher \ No newline at end of file diff --git a/Resources/funny.ttf b/Resources/funny.ttf new file mode 100644 index 0000000..f667cac Binary files /dev/null and b/Resources/funny.ttf differ diff --git a/WACCALauncher.csproj b/WACCALauncher.csproj new file mode 100644 index 0000000..07a157c --- /dev/null +++ b/WACCALauncher.csproj @@ -0,0 +1,101 @@ + + + + + Debug + AnyCPU + {3B4099C2-66E5-4D56-89B1-E14CF8E11B6A} + WinExe + WACCALauncher + WACCALauncher + v4.5.2 + 10.0 + 512 + true + + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + ..\WACCAHelper\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll + + + ..\WACCAHelper\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll + + + ..\WACCAHelper\packages\SharpDX.DirectInput.4.2.0\lib\net45\SharpDX.DirectInput.dll + + + + + + + + + + + + + + Form + + + MainForm.cs + + + + + MainForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/WACCALauncher.sln b/WACCALauncher.sln new file mode 100644 index 0000000..b3eab43 --- /dev/null +++ b/WACCALauncher.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33110.190 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WACCALauncher", "WACCALauncher.csproj", "{3B4099C2-66E5-4D56-89B1-E14CF8E11B6A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3B4099C2-66E5-4D56-89B1-E14CF8E11B6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B4099C2-66E5-4D56-89B1-E14CF8E11B6A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B4099C2-66E5-4D56-89B1-E14CF8E11B6A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B4099C2-66E5-4D56-89B1-E14CF8E11B6A}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0EE7A2E3-FF32-45AE-AF3E-1C452F1EA30D} + EndGlobalSection +EndGlobal diff --git a/WACCALauncherTemplating.pdn b/WACCALauncherTemplating.pdn new file mode 100644 index 0000000..68727db Binary files /dev/null and b/WACCALauncherTemplating.pdn differ diff --git a/app.config b/app.config new file mode 100644 index 0000000..ff99501 --- /dev/null +++ b/app.config @@ -0,0 +1,3 @@ + + + diff --git a/packages.config b/packages.config new file mode 100644 index 0000000..b801fba --- /dev/null +++ b/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file