public MainWindow() { Icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location); Program.MainSynchronizationContext = SynchronizationContext.Current; Instance = this; InitializeComponent(); InstallDirectoryHelper.Initialize(GetGameDirectory()); SetupTabs(); Task.Run((Action)PopulateStartMenu); #if DEBUG var version = Assembly.GetExecutingAssembly().GetName().Version; #else var version = Assembly.GetExecutingAssembly().GetName().Version.ToString(3); #endif var gameName = InstallDirectoryHelper.GameType.GetFancyGameName(); var installDir = InstallDirectoryHelper.GameDirectory.FullName; Text = $"KK Manager {version} (New downloader edition) - [{gameName}] in {installDir}"; Console.WriteLine($"Game: {gameName} Path: {installDir}"); Settings.Default.Binder.BindControl(checkForUpdatesOnStartupToolStripMenuItem, settings => settings.AutoUpdateSearch, this); Settings.Default.Binder.SendUpdates(this); }
public MainWindow() { Icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location); Program.MainSynchronizationContext = SynchronizationContext.Current; Instance = this; InitializeComponent(); InstallDirectoryHelper.KoikatuDirectory = GetGameDirectory(); SetupTabs(); Task.Run((Action)PopulateStartMenu); #if DEBUG var version = Assembly.GetExecutingAssembly().GetName().Version; #else var version = Assembly.GetExecutingAssembly().GetName().Version.ToString(3); #endif Text = $"KK Manager {version} (HS2 support edition) - [{InstallDirectoryHelper.GetGameType().GetFancyGameName()}] in {InstallDirectoryHelper.KoikatuDirectory.FullName}"; Settings.Default.Binder.BindControl(checkForUpdatesOnStartupToolStripMenuItem, settings => settings.AutoUpdateSearch, this); Settings.Default.Binder.SendUpdates(this); }
private static string ShowInstallDirectoryDialog(string currentPath) { using (var fb = new CommonOpenFileDialog { IsFolderPicker = true, InitialDirectory = currentPath, AllowNonFileSystemItems = false, AddToMostRecentlyUsedList = false, EnsurePathExists = true, EnsureFileExists = true, Multiselect = false, Title = "Select the install directory of the game." }) { retryFolderSelect: if (fb.ShowDialog() == CommonFileDialogResult.Ok) { var path = fb.FileName; if (!InstallDirectoryHelper.IsValidGamePath(path)) { if (MessageBox.Show( "The selected directory doesn't seem to contain the game. Make sure the directory is correct and try again.", "Select install directory", MessageBoxButtons.OKCancel, MessageBoxIcon.Error) == DialogResult.OK) { goto retryFolderSelect; } } return(path); } return(null); } }
private void SetupTabs() { // Try to load saved state first, if that fails load defaults try { if (!string.IsNullOrWhiteSpace(Settings.Default.DockState)) { using (var s = new MemoryStream(Encoding.Unicode.GetBytes(Settings.Default.DockState))) { dockPanel.LoadFromXml(s, DeserializeTab); return; } } } catch (Exception ex) { Console.WriteLine("Failed to read opened tabs from config: " + ex); } OpenOrGetCardWindow(InstallDirectoryHelper.GetMaleCardDir()); OpenOrGetCardWindow(InstallDirectoryHelper.GetFemaleCardDir()); GetOrCreateWindow <SideloaderModsWindow>(); GetOrCreateWindow <PluginsWindow>(); dockPanel.DockRightPortion = 400; var propertiesToolWindow = GetOrCreateWindow <PropertiesToolWindow>(); propertiesToolWindow.DockState = DockState.DockRight; }
private IEnumerable <SideloaderUpdateItem> CollectTasks(List <INode> nodes, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var root = nodes.Single(x => x.Type == NodeType.Root); var modsDirPath = InstallDirectoryHelper.GetModsPath(); modsDirPath.Create(); var results = Enumerable.Empty <SideloaderUpdateItem>(); foreach (var remoteModpackDir in GetSubNodes(root).Where(x => x.Type == NodeType.Directory)) { cancellationToken.ThrowIfCancellationRequested(); if (remoteModpackDir.Name.StartsWith("Sideloader Modpack")) { var localModpackDir = new DirectoryInfo(Path.Combine(modsDirPath.FullName, remoteModpackDir.Name)); if (localModpackDir.Exists) { results = results.Concat(ProcessDirectory(remoteModpackDir, localModpackDir, cancellationToken)); } } else { Console.WriteLine("Skipping non-modpack directory " + remoteModpackDir.Name); } } return(results); }
private static string ShowInstallDirectoryDialog(string currentPath) { using (var fb = new FolderBrowserDialog()) { fb.RootFolder = Environment.SpecialFolder.MyComputer; fb.SelectedPath = currentPath ?? ""; fb.ShowNewFolderButton = false; fb.Description = "Select the install directory of the game."; retryFolderSelect: if (fb.ShowDialog() == DialogResult.OK) { var path = fb.SelectedPath; if (!InstallDirectoryHelper.IsValidGamePath(path)) { if (MessageBox.Show( "The selected directory doesn't seem to contain the game. Make sure the directory is correct and try again.", "Select install directory", MessageBoxButtons.OKCancel, MessageBoxIcon.Error) == DialogResult.OK) { goto retryFolderSelect; } } return(path); } return(null); } }
private async Task <bool> UpdateSingleItem(IGrouping <string, Tuple <UpdateInfo, IUpdateItem> > task) { var firstItem = task.First().Item2; var progress = new Progress <double>(d => labelPercent.Text = $"Downloaded {d:F1}% of {firstItem.ItemSize}. Overall: {_completedSize} / {_overallSize}."); SetStatus($"Updating {firstItem.TargetPath.Name}"); SetStatus($"Updating {InstallDirectoryHelper.GetRelativePath(firstItem.TargetPath)}", false, true); // todo move logging to update methods if (firstItem.TargetPath.Exists) { SetStatus($"Deleting old file {firstItem.TargetPath.FullName}", false, true); firstItem.TargetPath.Delete(); } var sourcesToAttempt = task.Where(x => !_badUpdateSources.Contains(x.Item1)).OrderByDescending(x => x.Item1.SourcePriority).ToList(); if (sourcesToAttempt.Count == 0) { Console.WriteLine("There are no working sources to download from. Check the log for reasons why the sources failed."); _failedItems.Add(task); return(false); } Exception ex = null; foreach (var source in sourcesToAttempt) { try { SetStatus($"Attempting download from source {source.Item1.Origin}", false, true); await RetryHelper.RetryOnExceptionAsync(() => source.Item2.Update(progress, _cancelToken.Token), 3, TimeSpan.FromSeconds(3), _cancelToken.Token); ex = null; break; } catch (Exception e) { Console.WriteLine($"Marking source {source.Item1.Origin} as broken because of exception: {e}"); ex = e; _badUpdateSources.Add(source.Item1); } } // Check if all sources failed if (ex != null) { Console.WriteLine("There are no working sources to download from. Check the log for reasons why the sources failed."); _failedItems.Add(task); _failedExceptions.Add(ex); return(false); } SetStatus($"Download OK {firstItem.ItemSize}", false, true); return(true); }
private static void Main(string[] args) { AppDomain.CurrentDomain.UnhandledException += (sender, arg) => Console.WriteLine("UNHANDLED EXCEPTION: " + arg.ExceptionObject); AppDomain.CurrentDomain.UnhandledException += NBug.Handler.UnhandledException; using (LogWriter.StartLogging()) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); const string guidValueName = "-guid:"; var silentInstallGuids = args.Where(x => x.StartsWith(guidValueName)).Select(x => x.Substring(guidValueName.Length).Trim(' ', '"')).ToArray(); args = args.Where(x => !x.StartsWith("-")).Where(x => !string.IsNullOrWhiteSpace(x)).ToArray(); if (args.Length == 0) { MessageBox.Show("Not enough arguments - the following arguments are supported:\n" + "Path to game root directory. This is mandatory and has to be the 1st argument.\n" + "One or more links to update sources. If no update source links are provided then UpdateSources file is used.\n\n" + "You can also add -guid:UPDATE_GUID arguments to not show the mod selection screen, and instead automatically install mods with the specified GUIDs.", "Invalid arguments", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } try { var gameDir = new DirectoryInfo(args[0]); if (!gameDir.Exists) { throw new IOException("Directory doesn't exist"); } InstallDirectoryHelper.Initialize(gameDir); } catch (Exception e) { MessageBox.Show($"Error opening game directory: {args[0]}\n\n{e}", "Invalid arguments", MessageBoxButtons.OK, MessageBoxIcon.Error); Console.WriteLine(e); return; } if (SelfUpdater.CheckForUpdatesAndShowDialog().Result == true) { return; } var updateSources = GetUpdateSources(args.Skip(1).ToArray()); if (updateSources == null || !updateSources.Any()) { return; } var window = ModUpdateProgressDialog.CreateUpdateDialog(updateSources, silentInstallGuids); window.Icon = Icon.ExtractAssociatedIcon(typeof(Program).Assembly.Location); Application.Run(window); } }
private void toolStripButtonOpenModsDir_Click(object sender, EventArgs e) { try { Process.Start(InstallDirectoryHelper.GetModsPath().FullName); } catch (SystemException ex) { MessageBox.Show(ex.Message, "Failed to start application", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private static DefaultAssemblyResolver GetResolver(FileInfo location) { var resolver = new DefaultAssemblyResolver(); if (location.Directory != null) { var coreDir = Path.Combine(InstallDirectoryHelper.GetPluginPath(), "core"); if (Directory.Exists(coreDir)) { resolver.AddSearchDirectory(coreDir); } } return(resolver); }
private void PopulateStartMenu() { var toAdd = new List <ToolStripItem>(); var pluginPath = InstallDirectoryHelper.GetPluginPath(); var allExes = InstallDirectoryHelper.KoikatuDirectory.GetFiles("*.exe", SearchOption.AllDirectories); var filteredExes = allExes.Where(x => !x.Name.Equals("bepinex.patcher.exe", StringComparison.OrdinalIgnoreCase) && !x.FullName.StartsWith(pluginPath, StringComparison.OrdinalIgnoreCase)); foreach (var file in filteredExes.OrderBy(x => x.Name)) { var item = new ToolStripMenuItem(file.Name); item.AutoToolTip = false; item.ToolTipText = file.FullName; item.Click += (o, args) => { ProcessTools.SafeStartProcess(file.FullName); }; toAdd.Add(item); } this.SafeInvoke(() => startTheGameToolStripMenuItem.DropDownItems.AddRange(toAdd.ToArray())); }
private void PopulateStartMenu() { var toAdd = new List <ToolStripItem>(); var pluginPath = InstallDirectoryHelper.GetPluginPath(); var allExes = InstallDirectoryHelper.KoikatuDirectory.GetFiles("*.exe", SearchOption.AllDirectories); var filteredExes = allExes.Where(x => !x.Name.Equals("bepinex.patcher.exe", StringComparison.OrdinalIgnoreCase) && !x.FullName.StartsWith(pluginPath, StringComparison.OrdinalIgnoreCase)); var first = true; foreach (var folder in filteredExes.GroupBy(x => x.DirectoryName, StringComparer.OrdinalIgnoreCase).OrderBy(x => x.Key, StringComparer.OrdinalIgnoreCase)) { if (!first) { toAdd.Add(new ToolStripSeparator()); } first = false; foreach (var file in folder.OrderBy(x => x.Name, StringComparer.OrdinalIgnoreCase)) { // Trim .exe but leave other extensions var trimmedName = file.Name.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) ? file.Name.Substring(0, file.Name.Length - 4) : file.Name; var item = new ToolStripMenuItem(trimmedName); item.AutoToolTip = false; item.ToolTipText = file.FullName; item.Click += (o, args) => { ProcessTools.SafeStartProcess(file.FullName); }; try { item.Image = Icon.ExtractAssociatedIcon(file.FullName)?.ToBitmap(); } catch { item.Image = null; } toAdd.Add(item); } } this.SafeInvoke(() => { foreach (var item in toAdd) { startTheGameToolStripMenuItem.DropDownItems.Add(item); } }); }
public void ReloadList() { CancelListReload(); objectListView1.ClearObjects(); _cancellationTokenSource = new CancellationTokenSource(); var token = _cancellationTokenSource.Token; var observable = SideloaderModLoader.TryReadSideloaderMods(InstallDirectoryHelper.GetModsPath().FullName, token); observable .Buffer(TimeSpan.FromSeconds(3)) .ObserveOn(this) .Subscribe(list => objectListView1.AddObjects((ICollection)list), () => { objectListView1.FastAutoResizeColumns(); MainWindow.SetStatusText("Done loading zipmods"); }, token); }
private void SetupTabs() { // Try to load saved state first, if that fails load defaults try { if (!string.IsNullOrWhiteSpace(Settings.Default.DockState)) { using (var s = new MemoryStream(Encoding.Unicode.GetBytes(Settings.Default.DockState))) { dockPanel.LoadFromXml(s, DeserializeTab); return; } } } catch (Exception ex) { Console.WriteLine("Failed to read opened tabs from config: " + ex.ToStringDemystified()); foreach (var content in dockPanel.Contents) { content.DockHandler.Close(); } dockPanel.ResumeLayout(true, true); } OpenOrGetCardWindow(InstallDirectoryHelper.GetMaleCardDir()); OpenOrGetCardWindow(InstallDirectoryHelper.GetFemaleCardDir()); GetOrCreateWindow <SideloaderModsWindow>(); GetOrCreateWindow <PluginsWindow>(); dockPanel.DockRightPortion = 400; var propertiesToolWindow = GetOrCreateWindow <PropertiesToolWindow>(); propertiesToolWindow.DockState = DockState.DockRight; var logWindow = GetOrCreateWindow <LogViewer>(); logWindow.DockState = DockState.DockBottomAutoHide; }
private ModUpdateProgressDialog() { InitializeComponent(); switch (InstallDirectoryHelper.GetGameType()) { case GameType.PlayHome: case GameType.AiShoujoSteam: case GameType.AiShoujo: case GameType.HoneySelect2: pictureBox1.Image = Resources.aichika; break; case GameType.Koikatsu: case GameType.KoikatsuSteam: case GameType.EmotionCreators: pictureBox1.Image = Resources.chikajump; break; case GameType.Unknown: break; } }
private static DirectoryInfo GetKoikatuDirectory() { var path = Settings.Default.GamePath; if (!InstallDirectoryHelper.IsValidGamePath(path)) { try { path = Registry.CurrentUser.OpenSubKey(@"Software\Illusion\Koikatu\koikatu") ?.GetValue("INSTALLDIR") as string; } catch (SystemException) { } if (!InstallDirectoryHelper.IsValidGamePath(path)) { MessageBox.Show( "Koikatu is either not registered properly or its install directory is missing or inaccessible.\n\nYou will have to select game directory manually.", "Failed to find Koikatu install directory", MessageBoxButtons.OK, MessageBoxIcon.Error); path = ShowInstallDirectoryDialog(path); } if (string.IsNullOrEmpty(path) || !InstallDirectoryHelper.IsValidGamePath(path)) { MessageBox.Show( "Koikatu is either not registered properly or its install directory is missing or inaccessible.", "Failed to get Koikatu install directory", MessageBoxButtons.OK, MessageBoxIcon.Error); Environment.Exit(1); } Settings.Default.GamePath = path; } CheckInstallPathPermissions(path); return(new DirectoryInfo(path)); }
private async Task <bool> UpdateSingleItem(IGrouping <string, Tuple <UpdateInfo, UpdateItem> > task) { var firstItem = task.First().Item2; var itemSize = firstItem.GetDownloadSize(); var lastTimestamp = DateTime.UtcNow; var lastDownloadedKBytes = 0l; var progress = new Progress <double>(thisPercent => { var timeNow = DateTime.UtcNow; var secondsSinceLastUpdate = (timeNow - lastTimestamp).TotalSeconds; if (secondsSinceLastUpdate < 1 && thisPercent < 100) { return; } //This item: 70% done (1MB / 20MB) //Overall: 50% done (111MB / 1221MB) //Speed: 1234KB/s (average 1111KB/s) var downloadedKBytes = (long)(itemSize.GetRawSize() * (thisPercent / 100d)); var downloadedSize = FileSize.FromKilobytes(downloadedKBytes); var totalDownloadedSize = _completedSize + downloadedSize; var totalPercent = ((double)totalDownloadedSize.GetRawSize() / (double)_overallSize.GetRawSize()) * 100d; var speed = (downloadedKBytes - lastDownloadedKBytes) / secondsSinceLastUpdate; if (double.IsNaN(speed)) { speed = 0; } lastDownloadedKBytes = downloadedKBytes; lastTimestamp = timeNow; labelPercent.Text = $@"This item: {thisPercent:F1}% done ({downloadedSize} / {itemSize}) Overall: {totalPercent:F1}% done ({totalDownloadedSize} / {_overallSize}) Speed: {speed:F1}KB/s"; progressBar1.Value = Math.Min((int)(totalPercent * 10), progressBar1.Maximum); }); SetStatus($"Updating {firstItem.TargetPath.Name}"); SetStatus($"Updating {InstallDirectoryHelper.GetRelativePath(firstItem.TargetPath)}", false, true); var sourcesToAttempt = task.Where(x => !_badUpdateSources.Contains(x.Item1)).OrderBy(x => GetPing(x.Item1)).ToList(); if (sourcesToAttempt.Count == 0) { Console.WriteLine("There are no working sources to download from. Check the log for reasons why the sources failed."); _failedItems.Add(task); return(false); } Exception ex = null; foreach (var source in sourcesToAttempt) { try { // Needed because ZipUpdater doesn't support progress if (source.Item2.RemoteFile is ZipUpdater.ArchiveItem) { labelPercent.Text = $"Extracting... Overall progress: {_completedSize} / {_overallSize}."; } await RetryHelper.RetryOnExceptionAsync(() => source.Item2.Update(progress, _cancelToken.Token), 3, TimeSpan.FromSeconds(3), _cancelToken.Token); _completedSize += source.Item2.GetDownloadSize(); ex = null; break; } catch (OperationCanceledException) { throw; } catch (Exception e) { Console.WriteLine($"Marking source {source.Item1.Source.Origin} as broken because of exception: {e.ToStringDemystified()}"); ex = e; _badUpdateSources.Add(source.Item1); } } // Check if all sources failed if (ex != null) { Console.WriteLine("There are no working sources to download from. Check the log for reasons why the sources failed."); _failedItems.Add(task); _failedExceptions.Add(ex); return(false); } return(true); }
private static DirectoryInfo GetGameDirectory() { var path = Settings.Default.GamePath; if (!InstallDirectoryHelper.IsValidGamePath(path)) { for (var dir = new DirectoryInfo(Program.ProgramLocation); dir.Exists && dir.Parent != null; dir = dir.Parent) { if (InstallDirectoryHelper.IsValidGamePath(dir.FullName)) { path = dir.FullName; break; } } if (!InstallDirectoryHelper.IsValidGamePath(path)) { MessageBox.Show( "Your game's install directory could not be detected or is inaccessible.\n\nYou will have to select the game directory manually.", "Failed to find game install directory", MessageBoxButtons.OK, MessageBoxIcon.Error); if (string.IsNullOrWhiteSpace(path)) { // Get a plausible initial path try { path = Registry.CurrentUser.OpenSubKey(@"Software\Illusion\Koikatu\koikatu") ?.GetValue("INSTALLDIR") as string; } catch (SystemException) { } } path = ShowInstallDirectoryDialog(path); } if (!InstallDirectoryHelper.IsValidGamePath(path)) { MessageBox.Show( "Your game is either not registered properly or its install directory is missing or inaccessible.", "Failed to find game install directory", MessageBoxButtons.OK, MessageBoxIcon.Error); Environment.Exit(1); } Settings.Default.GamePath = path; if (path.Length > 100) { MessageBox.Show( "Your game path is very long and is likely to cause issues with running the game and/or KK Manager.\n\nPlease consider moving your game to a simpler directory like \"D:\\Games\\Koikatsu\" to avoid potential issues. ", "Game directory warning", MessageBoxButtons.OK); } else if (path.Any(x => x > 127)) { MessageBox.Show( "Your game path contains special characters that might cause issues with running the game.\n\nPlease consider moving your game to a simpler directory like \"D:\\Games\\Koikatsu\" to avoid potential issues. ", "Game directory warning", MessageBoxButtons.OK); } } CheckInstallPathPermissions(path); return(new DirectoryInfo(path)); }
private void openMaleCardFolderToolStripMenuItem_Click(object sender, EventArgs e) { OpenOrGetCardWindow(InstallDirectoryHelper.GetMaleCardDir()); }