diff --git a/CHANGELOG.txt b/CHANGELOG.txt index be044da..fc4c49d 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -10,9 +10,13 @@ Changed: Enlarged the custom games list. Changed: Upgraded to Visual Studio 2017 from 2012. Hopefully shouldn't change anything. Changed: Dependencies will now appear only above the patches that depend on them. Changed: Required thcrap directories will now be created automatically if they do not exist. +Changed: Repository descriptor json files will now be saved upon visiting the patch menu. +Changed: Patch descriptor json files will now be updated whenever they're fetched from the repositories. +Changed: The patch list will no longer lose focus on every repository check. Fixed: The tray icon's Main Games menu not working (no idea when that broke). Fixed: thcrap's encoding for patches not using UTF-8. Fixed: Error if patch directory does not exist. +Fixed: Error when games.js does not exist. 1.0-pre3 (13/08/2019) Added: Selected patches list to show the order of installed patches. diff --git a/README.md b/README.md index 2efcf88..3d17140 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,27 @@ # Touhou-Launcher -This is basically a rewrite of the Touhou Launcher created by Widdiful.\ +A rewrite of the Touhou Launcher created by Widdiful and an alternative to the thcrap configurator.\ I tried making it more user friendly and added options wherever it was needed. -If you don't know what that is, it's a program you can use and set up to launch any Touhou game (and even others if you're using the custom games tab) from the UI or the tray icon. It supports Neko Project II for PC-98 games, game exe files (the game itself, custom.exe or vpatch.exe) and thcrap.\ +The Touhou Launcher a program you can use and set up to launch any Touhou game (and even others if you're using the custom games tab) from the UI or the tray icon. It supports Neko Project II for PC-98 games, game exe files (the game itself, custom.exe or vpatch.exe), and thcrap.\ +In addition, it supports the addition and removal of patches from the thcrap patch repository using a checkbox and list format, with dependencies being added automatically.\ There is also a "Replays" tab you can use to either navigate popular Touhou replay websites (Don't, actually. The .NET web browser is worse than Internet Explorer 8) or enter your own links to let the launcher automatically download and put them in the correct folder.\ Finally, each game has a background picture that you can change to whatever you want. # Features Dynamic tray icon menu for custom games.\ -Proper thcrap support.\ +Proper thcrap support, including patch and game profile configuration. (The offline version ships without the configurator.)\ No auto-updater. I know some of you probably hate things like that.\ Customizability for how the games launch.\ Russian language support (Thanks Lensrub).\ Work-in-progress Japanese language support.\ Custom language support for testing purposes if you're interested in translating it.\ -Almost all of the features from the original.\ -\ +Almost all of the features from the original Touhou Launcher. + +# How To Use +First of all, fill in Neko Project II/thcrap_loader's paths in the settings tab.\ +You can then fill in the games' paths by right-clicking on their buttons.\ +If you're not using the offline build, you can choose the "Custom" option from the thcrap dropdown menu on a game's configuration screen to configure patches for that game. + This is a nonprofit project developed independently by a fan.\ Touhou belongs to Team Shanghai Alice.\ \ diff --git a/Touhou Launcher/thcrap.cs b/Touhou Launcher/thcrap.cs index d98d3dc..78784b0 100644 --- a/Touhou Launcher/thcrap.cs +++ b/Touhou Launcher/thcrap.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; @@ -100,7 +100,8 @@ private void thcrap_Load(object sender, EventArgs e) addRepo(File.ReadAllText(localRepo.FullName), true); } searchRepo(MainForm.curCfg.StartingRepo); - games = JsonConvert.DeserializeObject>(File.ReadAllText(MainForm.curCfg.crapDir + "\\config\\games.js")); + if (File.Exists(MainForm.curCfg.crapDir + "\\config\\games.js")) + games = JsonConvert.DeserializeObject>(File.ReadAllText(MainForm.curCfg.crapDir + "\\config\\games.js")); for (int i = 0; i < 3; i += 2) { if (MainForm.curCfg.gameCFG[cfgForm.game].GameDir[i] != "" && !games.ContainsValue(MainForm.curCfg.gameCFG[cfgForm.game].GameDir[i].Replace("\\", "/"))) @@ -124,9 +125,8 @@ private void onJsonGet(object sender, DownloadStringCompletedEventArgs e) { if (e.Error == null && !e.Cancelled) { - string json = e.Result; string[] args = (string[])e.UserState; - addRepo(json); + addRepo(e.Result); if (!bool.Parse(args[1])) { searchRepo(args[0].Substring(0, args[0].LastIndexOf('/', args[0].LastIndexOf('/') - 1) + 1)); @@ -156,6 +156,9 @@ private void addRepo(string repojs, bool offline = false) try { repoData data = JsonConvert.DeserializeObject(repojs); + FileInfo jsPath = new FileInfo(MainForm.curCfg.crapDir + "\\repos\\" + data.id + "\\repo.js"); + jsPath.Directory.Create(); + File.WriteAllText(jsPath.FullName, repojs); if (!repoList.Items.ContainsKey(data.id) || (bool)repoList.Items[data.id].Tag == true) { foreach (string neighbor in data.neighbors) @@ -175,7 +178,7 @@ private void addRepo(string repojs, bool offline = false) ListViewItem title = repoList.Items[data.id]; title.Tag = offline; } - repoList_SelectedIndexChanged(this, new EventArgs()); + repoList_SelectedIndexChanged(repoList.Items[data.id], new EventArgs()); } } catch (Exception ex) @@ -190,11 +193,8 @@ private void onPatchGet(object sender, DownloadStringCompletedEventArgs e) { patchData patch = JsonConvert.DeserializeObject(e.Result); FileInfo jsPath = new FileInfo(MainForm.curCfg.crapDir + "\\repos\\" + (string)e.UserState + "\\" + patch.id + "\\patch.js"); - if (!jsPath.Exists) - { jsPath.Directory.Create(); File.WriteAllText(jsPath.FullName, e.Result); - } foreach (string dependency in patch.dependencies) { string[] dependencySet = dependency.Split('/'); @@ -211,19 +211,17 @@ private void onPatchGet(object sender, DownloadStringCompletedEventArgs e) } else repository = dependencySet[0]; - addPatch(repository, dependencySet[dependencySet.Length - 1], (string)e.UserState + "/" + patch.id + "/"); + addPatch(repository, dependencySet[dependencySet.Length - 1], patchStates.IndexOf((string)e.UserState + "/" + patch.id + "/")); } } } - private void addPatch(string repo, string patch, string dependent = "") + private void addPatch(string repo, string patch, int dependent = -1) { if (!patchStates.Contains(repo + "/" + patch + "/")) { - int depIndex = patchStates.IndexOf(dependent); - depIndex = depIndex == -1 || dependent == "" ? patchStates.Count : depIndex; - patchStates.Insert(depIndex, repo + "/" + patch + "/"); - repoList_SelectedIndexChanged(this, new EventArgs()); + patchStates.Insert(dependent == -1 ? patchStates.Count : dependent, repo + "/" + patch + "/"); + repoList_SelectedIndexChanged(repoList.Items[repo], new EventArgs()); } WebClient wc = new WebClient(); wc.Encoding = Encoding.UTF8; @@ -250,6 +248,8 @@ private void thcrap_Closing(object sender, FormClosingEventArgs e) private void repoList_SelectedIndexChanged(object sender, EventArgs e) { + if (sender == repoList || repoList.SelectedItems.Contains((ListViewItem)sender) || repoList.SelectedIndices.Contains(0)) + { patchList.Items.Clear(); if (repoList.SelectedItems.Count > 0) { @@ -276,6 +276,7 @@ private void repoList_SelectedIndexChanged(object sender, EventArgs e) patchList.ItemChecked += patchList_ItemChecked; } } + } private void patchList_ItemChecked(object sender, ItemCheckedEventArgs e) { @@ -284,7 +285,7 @@ private void patchList_ItemChecked(object sender, ItemCheckedEventArgs e) { addPatch(repoList.SelectedItems[0].SubItems[1].Text, e.Item.Text); } - else if (patchStates.Contains(id)) //I have no idea what this is + else { patchStates.Remove(id); if (repoList.SelectedIndices[0] == 0)