├── .gitignore ├── LICENSE ├── README.md ├── TelltaleModLauncher.sln ├── TelltaleModLauncher ├── App.config ├── App.xaml ├── App.xaml.cs ├── AppSettings.cs ├── Files │ ├── AppSettingsFile.cs │ ├── GameVersionSettings.cs │ └── Mod.cs ├── GameVersion.cs ├── IconExtractor.dll ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── ModManager.cs ├── ModManager_ViewMod.xaml ├── ModManager_ViewMod.xaml.cs ├── ModManager_ViewMod_ViewText.xaml ├── ModManager_ViewMod_ViewText.xaml.cs ├── Mod_ResdescEdit.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── SetupWizard_Window.xaml ├── SetupWizard_Window.xaml.cs ├── TelltaleModLauncher.csproj ├── Utillities │ ├── IOManagement.cs │ └── MessageBoxes.cs ├── icon.ico └── packages.config ├── changes.txt └── screenshots ├── mod-install-tut ├── 1-download.png ├── 1_1archive.png ├── 1_2archive.png ├── 2-open.png ├── 3-locateandadd.png └── 4-done.png ├── shot1.png └── shot2.png /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Telltale Modding Group 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Telltale Mod Launcher 2 | 3 | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/Telltale-Modding-Group/TelltaleModLauncher)](https://github.com/Telltale-Modding-Group/TelltaleModLauncher/releases) 4 | [![Github All Releases](https://img.shields.io/github/downloads/Telltale-Modding-Group/TelltaleModLauncher/total.svg)](https://github.com/Telltale-Modding-Group/TelltaleModLauncher/releases) 5 | 6 | # [DOWNLOAD HERE](https://github.com/Telltale-Modding-Group/TelltaleModLauncher/releases)! 7 | 8 | **Releases are now being put out! You can get them [HERE](https://github.com/Telltale-Modding-Group/TelltaleModLauncher/releases)!** 9 | **If you need help or have questions about the application, click [HERE](https://github.com/Telltale-Modding-Group/TelltaleModLauncher/wiki/%5BHelp%5D-Application-Setup)!** 10 | **If your looking for Mods to get, supported mods can be found [HERE](https://github.com/Telltale-Modding-Group/TelltaleModLauncher/wiki/Supported-Mods)!** **[Discord Server](https://discord.gg/rn8HvqZjZZ)** 11 | 12 | ## DISCLAIMER 13 | ***NOTE: This project is a work in progress. Some features have not been implemented just yet and there could be issues/bugs that you might encounter. If you do please follow [this](https://github.com/Telltale-Modding-Group/TelltaleModLauncher/wiki/%5BHelp%5D---Reporting-an-Issue-or-Bug) to submit an issue.*** 14 | 15 | ***NOTE (3/16/21): Creator functionality is being stripped and moved to the [Telltale Script Editor](https://github.com/Telltale-Modding-Group/Telltale-Script-Editor) as of the next release V0.7.0 which will be coming soon [(biggest update yet)](https://github.com/Telltale-Modding-Group/TelltaleModLauncher/blob/main/changes.txt).*** 16 | 17 | ***NOTE (9/6/21): Apologies for the very very late update. I cannot predict when V0.7.0 will finally come but in the meantime I've updated the launcher to 0.6.5 which is mostly a quality-of-life update which makes the setup of the Launcher alot more simpler and less confusing (despite making a tutorial that is linked on this page that guides you how to set it up properly...)*** 18 | 19 | ## Supported Games 20 | The launcher currently supports the following games. 21 | - **The Walking Dead Definitive Edition** 22 | 23 | NOTE: The installer has not been tested with any other Telltale game besides 'The Walking Dead Definitive Edition' though future support is planned. 24 | 25 | ## About 26 | This launcher is designed to make installing and managing mods for Telltale Games much easier through a very user friendly interface. 27 | 28 | **If you wish to make mods, we have the following tools avaliable.** 29 | - **[Texture Mods](https://github.com/Telltale-Modding-Group/DDS-D3DTX-Converter)** **[(Tutorial)](https://github.com/Telltale-Modding-Group/DDS-D3DTX-Converter/wiki/%5BTutorial%5D--How-to-make-a-Texture-Mod-(Part-1))** 30 | - **[Scripting Mods](https://github.com/Telltale-Modding-Group/Telltale-Script-Editor)** 31 | 32 | Additional info can be found and asked in our **[Discord Server](https://discord.gg/rn8HvqZjZZ)**. 33 | 34 | ![Screenshot 1](screenshots/shot1.png) 35 | -------------------------------------------------------------------------------- /TelltaleModLauncher.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30320.27 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TelltaleModLauncher", "TelltaleModLauncher\TelltaleModLauncher.csproj", "{863D1CA8-665D-471B-850D-1926A7CB9227}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {863D1CA8-665D-471B-850D-1926A7CB9227}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {863D1CA8-665D-471B-850D-1926A7CB9227}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {863D1CA8-665D-471B-850D-1926A7CB9227}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {863D1CA8-665D-471B-850D-1926A7CB9227}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {6D15BB1E-53C0-4605-8315-AAA9CD858512} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /TelltaleModLauncher/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /TelltaleModLauncher/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /TelltaleModLauncher/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace TelltaleModLauncher 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /TelltaleModLauncher/AppSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Threading; 7 | using System.Diagnostics; 8 | using System.IO; 9 | using System.Windows.Forms; 10 | using Newtonsoft; 11 | using Newtonsoft.Json; 12 | using Newtonsoft.Json.Linq; 13 | using Newtonsoft.Json.Serialization; 14 | using TelltaleModLauncher.Utillities; 15 | using TelltaleModLauncher.Files; 16 | 17 | namespace TelltaleModLauncher 18 | { 19 | /// 20 | /// Main class pertaining to the application settings. 21 | /// 22 | public class AppSettings 23 | { 24 | //public 25 | public string appVersionString = "v0.7.0"; 26 | 27 | public AppSettingsFile appSettingsFile; 28 | public List GameVersionSettings { get; set; } 29 | public GameVersionSettings current_GameVersionSettings; 30 | 31 | //private 32 | private static string systemDocumentsPath = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); 33 | private static string configFile_filename = "TelltaleModLauncher_Config.json"; 34 | private static string configFile_directory_location = systemDocumentsPath + "/TelltaleModLauncher/"; 35 | private static string configFile_file_location = configFile_directory_location + configFile_filename; 36 | private static string launcherHelpLink = "https://github.com/Telltale-Modding-Group/TelltaleModLauncher/wiki/%5BHelp%5D"; 37 | private static string launcherHelpSetupLink = "https://github.com/Telltale-Modding-Group/TelltaleModLauncher/wiki/%5BHelp%5D-Application-Setup"; 38 | 39 | /// 40 | /// Application Settings Class, creates an AppSettings object. This is called on application startup. 41 | /// If there is an existing config file, it will parse the data from it. 42 | /// If there is not an existing config file, or a TelltaleModLauncher directory, create a new one. 43 | /// 44 | public AppSettings() 45 | { 46 | if (File.Exists(configFile_file_location)) 47 | { 48 | ReadConfigFile(); 49 | } 50 | else 51 | { 52 | appSettingsFile = new AppSettingsFile(); 53 | New_GameVersionSettingsList(); 54 | 55 | if (!Directory.Exists(configFile_directory_location)) 56 | IOManagement.CreateDirectory(configFile_directory_location); 57 | 58 | WriteToFile(); 59 | } 60 | } 61 | 62 | /// 63 | /// Launches the exe that is found in the current selected game version exe location. 64 | /// 65 | public void LaunchGame() 66 | { 67 | ProcessStartInfo processStartInfo = new ProcessStartInfo(); 68 | processStartInfo.FileName = current_GameVersionSettings.Game_LocationExe; 69 | processStartInfo.WorkingDirectory = current_GameVersionSettings.Game_Location; 70 | 71 | Process.Start(processStartInfo); 72 | } 73 | 74 | /// 75 | /// Changes the current game version to the desired game version. 76 | /// 77 | /// 78 | public void ChangeGameVersion(GameVersion newVersion) 79 | { 80 | foreach(GameVersionSettings gameVersionSetting in GameVersionSettings) 81 | { 82 | if(newVersion.Equals(gameVersionSetting.Game_Version)) 83 | { 84 | current_GameVersionSettings = gameVersionSetting; 85 | return; 86 | } 87 | } 88 | } 89 | 90 | /// 91 | /// Creates a new game version settings list. 92 | /// 93 | private void New_GameVersionSettingsList() 94 | { 95 | GameVersionSettings = new List(); 96 | 97 | var enumListString = Enum.GetNames(typeof(GameVersion)); 98 | 99 | for (int i = 0; i < enumListString.Length; i++) 100 | { 101 | GameVersionSettings new_gameVersionSettings = new GameVersionSettings(); 102 | new_gameVersionSettings.Game_Version = (GameVersion)Enum.Parse(typeof(GameVersion), enumListString[i]); 103 | 104 | GameVersionSettings.Add(new_gameVersionSettings); 105 | } 106 | } 107 | 108 | /// 109 | /// Reads and parses the data from the app config file. 110 | /// 111 | public void ReadConfigFile() 112 | { 113 | appSettingsFile = new AppSettingsFile(); 114 | GameVersionSettings = new List(); 115 | 116 | //read the data from the config file 117 | string jsonText = File.ReadAllText(configFile_file_location); 118 | 119 | //parse the data into a json array 120 | JArray array; 121 | 122 | try 123 | { 124 | array = JArray.Parse(jsonText); 125 | } 126 | catch(Exception e) 127 | { 128 | MessageBox.Show(e.ToString(), e.Message, MessageBoxButtons.OK, MessageBoxIcon.Error); 129 | return; 130 | } 131 | 132 | JObject AppSettingsFile_fromJson = array[0] as JObject; 133 | JArray GameVersionSettings_fromJson = array[1] as JArray; 134 | 135 | //loop through each property to get the data 136 | foreach (JProperty property in AppSettingsFile_fromJson.Properties()) 137 | { 138 | string name = property.Name; 139 | 140 | if (name.Equals(nameof(appSettingsFile.Default_Game_Version))) 141 | appSettingsFile.Default_Game_Version = (GameVersion)(int)property.Value; 142 | 143 | if (name.Equals(nameof(appSettingsFile.UI_LightMode))) 144 | appSettingsFile.UI_LightMode = (bool)property.Value; 145 | 146 | if (name.Equals(nameof(appSettingsFile.UI_WindowDefocusing))) 147 | appSettingsFile.UI_WindowDefocusing = (bool)property.Value; 148 | } 149 | 150 | //loop through each property to get the data 151 | foreach (JObject obj in GameVersionSettings_fromJson.Children()) 152 | { 153 | GameVersionSettings new_gameVersionSettings = new GameVersionSettings(); 154 | 155 | //loop through each property to get the data 156 | foreach (JProperty property in obj.Properties()) 157 | { 158 | string name = property.Name; 159 | 160 | if (name.Equals(nameof(current_GameVersionSettings.Game_Location))) 161 | new_gameVersionSettings.Game_Location = (string)property.Value; 162 | 163 | if (name.Equals(nameof(current_GameVersionSettings.Game_LocationExe))) 164 | new_gameVersionSettings.Game_LocationExe = (string)property.Value; 165 | 166 | if (name.Equals(nameof(current_GameVersionSettings.Game_Version))) 167 | new_gameVersionSettings.Game_Version = (GameVersion)(int)property.Value; 168 | } 169 | 170 | GameVersionSettings.Add(new_gameVersionSettings); 171 | } 172 | 173 | foreach(GameVersionSettings version in GameVersionSettings) 174 | { 175 | if (appSettingsFile.Default_Game_Version.Equals(version.Game_Version)) 176 | current_GameVersionSettings = version; 177 | } 178 | } 179 | 180 | /// 181 | /// Writes existing values of the App Settings objects into the config file. 182 | /// 183 | public void WriteToFile() 184 | { 185 | if(File.Exists(configFile_file_location)) 186 | IOManagement.DeleteFile(configFile_file_location); 187 | 188 | //open a stream writer to create the text file and write to it 189 | using (StreamWriter file = File.CreateText(configFile_file_location)) 190 | { 191 | //get our json seralizer 192 | JsonSerializer serializer = new JsonSerializer(); 193 | 194 | List jsonObjects = new List(); 195 | jsonObjects.Add(appSettingsFile); 196 | jsonObjects.Add(GameVersionSettings); 197 | 198 | //seralize the data and write it to the configruation file 199 | serializer.Formatting = Formatting.Indented; 200 | serializer.Serialize(file, jsonObjects); 201 | } 202 | } 203 | 204 | /// 205 | /// Updates the changes to the app config file by replacing it and writing a new one. (there is a better way of doing it, but this works fine) 206 | /// 207 | public void UpdateChangesToFile() 208 | { 209 | IOManagement.DeleteFile(configFile_file_location); 210 | WriteToFile(); 211 | } 212 | 213 | /// 214 | /// Checks the current selected game version values if the following values are assigned/exist. 215 | /// Game_LocationExe, Game_Location, and Game_Location_Mods 216 | /// returns false if one or all of these values aren't assigned/exist 217 | /// 218 | /// 219 | public bool IsGameSetupAndValid(bool showMessageBoxes = false) 220 | { 221 | if (current_GameVersionSettings == null) 222 | return true; 223 | 224 | if (File.Exists(current_GameVersionSettings.Game_LocationExe) == false) 225 | { 226 | if (showMessageBoxes) 227 | MessageBoxes.Error("The game executable location does not exist!", "Error"); 228 | 229 | return false; 230 | } 231 | 232 | if (Directory.Exists(current_GameVersionSettings.Game_Location) == false) 233 | { 234 | if (showMessageBoxes) 235 | MessageBoxes.Error("The directory of the game does not exist!", "Error"); 236 | 237 | return false; 238 | } 239 | 240 | if (Directory.Exists(current_GameVersionSettings.Game_Location_Mods) == false) 241 | { 242 | if (showMessageBoxes) 243 | MessageBoxes.Error("The directory of the game archives/pack folder does not exist!", "Error"); 244 | 245 | return false; 246 | } 247 | 248 | return true; 249 | } 250 | 251 | /// 252 | /// Opens up the default web explorer and directs the user to the launcher help page 253 | /// 254 | public void Open_LauncherHelp() 255 | { 256 | var processStartInfo = new ProcessStartInfo 257 | { 258 | FileName = launcherHelpLink, 259 | UseShellExecute = true 260 | }; 261 | 262 | Process.Start(processStartInfo); 263 | } 264 | 265 | /// 266 | /// Opens up the default web explorer and directs the user to the launcher help page 267 | /// 268 | public void Open_LauncherHelpSetup() 269 | { 270 | var processStartInfo = new ProcessStartInfo 271 | { 272 | FileName = launcherHelpSetupLink, 273 | UseShellExecute = true 274 | }; 275 | 276 | Process.Start(processStartInfo); 277 | } 278 | 279 | //---------------- GETTERS ---------------- 280 | public string Get_Current_GameVersionSettings_LibTelltaleGameID() 281 | { 282 | if (current_GameVersionSettings == null) 283 | return ""; 284 | 285 | return current_GameVersionSettings.Game_LibTelltale_GameID; 286 | } 287 | 288 | public string Get_Current_GameVersionSettings_GameDirectory() 289 | { 290 | if (current_GameVersionSettings == null) 291 | return ""; 292 | 293 | return current_GameVersionSettings.Game_Location; 294 | } 295 | 296 | public string Get_Current_GameVersionSettings_GameExeLocation() 297 | { 298 | if (current_GameVersionSettings == null) 299 | return ""; 300 | 301 | return current_GameVersionSettings.Game_LocationExe; 302 | } 303 | 304 | public string Get_Current_GameVersionSettings_ModsLocation() 305 | { 306 | if (current_GameVersionSettings == null) 307 | return ""; 308 | 309 | return current_GameVersionSettings.Game_Location_Mods; 310 | } 311 | 312 | public GameVersion Get_Current_GameVersionName() 313 | { 314 | if (current_GameVersionSettings == null) 315 | return GameVersion.Other; 316 | 317 | return current_GameVersionSettings.Game_Version; 318 | } 319 | 320 | public bool Get_AppSettings_LightMode() 321 | { 322 | return appSettingsFile.UI_LightMode; 323 | } 324 | 325 | public bool Get_AppSettings_DefocusEffect() 326 | { 327 | return appSettingsFile.UI_WindowDefocusing; 328 | } 329 | 330 | public string Get_App_ConfigDirectory() 331 | { 332 | return configFile_directory_location; 333 | } 334 | //---------------- GETTERS END ---------------- 335 | //---------------- MODIFIERS ---------------- 336 | public void Set_Current_AppSettings_DefaultGameVersion(GameVersion version) 337 | { 338 | appSettingsFile.Default_Game_Version = version; 339 | } 340 | 341 | public void Set_Current_AppSettings_UI_LightMode(bool state) 342 | { 343 | appSettingsFile.UI_LightMode = state; 344 | } 345 | 346 | public void Set_Current_AppSettings_UI_DefocusEffect(bool state) 347 | { 348 | appSettingsFile.UI_WindowDefocusing = state; 349 | } 350 | 351 | public void Set_Current_GameVersionSettings(int selectedIndex) 352 | { 353 | current_GameVersionSettings = GameVersionSettings[selectedIndex]; 354 | } 355 | 356 | public void Set_Current_GameVersionSettings_GameExeLocation() 357 | { 358 | string newFilePath = ""; 359 | 360 | IOManagement.GetFilePath(ref newFilePath, "Exe Files (.exe)|*.exe", "Select the Game Executable File"); 361 | 362 | if (File.Exists(newFilePath)) 363 | { 364 | current_GameVersionSettings.Game_Location = Path.GetDirectoryName(newFilePath); 365 | current_GameVersionSettings.Game_LocationExe = newFilePath; 366 | } 367 | } 368 | //---------------- MODIFIERS END ---------------- 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /TelltaleModLauncher/Files/AppSettingsFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TelltaleModLauncher.Files 8 | { 9 | public class AppSettingsFile 10 | { 11 | public GameVersion Default_Game_Version { get; set; } 12 | public bool UI_LightMode { get; set; } = false; 13 | public bool UI_WindowDefocusing { get; set; } = true; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /TelltaleModLauncher/Files/GameVersionSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | 8 | namespace TelltaleModLauncher.Files 9 | { 10 | public class GameVersionSettings 11 | { 12 | //the version of said game 13 | public GameVersion Game_Version { get; set; } 14 | 15 | //the directory of the game 16 | public string Game_Location { get; set; } = "Undefined"; 17 | 18 | //the location of the game executable 19 | public string Game_LocationExe { get; set; } = "Undefined"; 20 | 21 | //the ttarch enum value for the game 22 | public string Game_LibTelltale_GameID 23 | { 24 | get 25 | { 26 | return GameVersion_Functions.Get_GameID_FromVersion(Game_Version); 27 | } 28 | } 29 | 30 | //the location of the game mods folder (where the archives of the game are, either in /Archives or /Packs) 31 | public string Game_Location_Mods 32 | { 33 | get 34 | { 35 | if (Directory.Exists(Game_Location + "/Archives/")) 36 | return Game_Location + "/Archives/"; 37 | else if (Directory.Exists(Game_Location + "/Packs/")) 38 | return Game_Location + "/Packs/"; 39 | else if (Directory.Exists(Game_Location + "/Pack/")) 40 | return Game_Location + "/Pack/"; 41 | else 42 | return ""; 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /TelltaleModLauncher/Files/Mod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TelltaleModLauncher.Files 8 | { 9 | public class Mod 10 | { 11 | /// 12 | /// Mod Json Format Version 13 | /// 14 | public string ModJsonFormatVersion { get; } = "1.0"; 15 | 16 | /// 17 | /// The display name of the mod. 18 | /// 19 | public string ModDisplayName { get; set; } 20 | 21 | /// 22 | /// The version number string of the mod. 23 | /// 24 | public string ModVersion { get; set; } 25 | 26 | /// 27 | /// The author of the mod. 28 | /// 29 | public string ModAuthor { get; set; } 30 | 31 | /// 32 | /// The game version the mod is compatible with. 33 | /// 34 | public string ModCompatibility { get; set; } 35 | 36 | /// 37 | /// The list of filename.extension's assoicated with the mod. 38 | /// 39 | public List ModFiles { get; set; } 40 | 41 | /// 42 | /// The list of filenames.extension's that are associated with the mod to be placed in the game directory. 43 | /// 44 | public List ModFilesGameDirectory { get; set; } 45 | 46 | /// 47 | /// The file path of the mod info json file. 48 | /// 49 | public string ModInfoJson_FilePath { get; set; } 50 | 51 | /// 52 | /// Sets the resource priority for the mod archives 53 | /// 54 | public int ModResourcePriority { get; set; } 55 | 56 | /// 57 | /// Creates a blank mod object, must be filled 58 | /// 59 | public Mod() 60 | { 61 | 62 | } 63 | 64 | /// 65 | /// Creates a mod object with the given data to reference the actual mod data on the disk. 66 | /// 67 | /// 68 | /// 69 | /// 70 | /// 71 | public Mod (string ModDisplayName, string ModVersion, string ModAuthor, List ModFiles, string ModCompatibility) 72 | { 73 | this.ModAuthor = ModAuthor; 74 | this.ModDisplayName = ModDisplayName; 75 | this.ModVersion = ModVersion; 76 | this.ModFiles = ModFiles; 77 | this.ModCompatibility = ModCompatibility; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /TelltaleModLauncher/GameVersion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace TelltaleModLauncher 8 | { 9 | /// 10 | /// The supported Game Versions. 11 | /// Add supported game versions in here 12 | /// NOTE: this is only a name identifier, it needs to be supported by the code too! 13 | /// 14 | public enum GameVersion 15 | { 16 | The_Walking_Dead_Definitive_Series = 0, 17 | The_Walking_Dead_Season_Four = 1, 18 | The_Walking_Dead_Season_Three = 2, 19 | The_Walking_Dead_Michonne = 3, 20 | The_Walking_Dead_Season_Two = 4, 21 | The_Walking_Dead_Season_One = 5, 22 | Game_Of_Thrones = 6, 23 | The_Wolf_Among_Us = 7, 24 | Marvels_Gaurdians_Of_The_Galaxy = 8, 25 | Batman_The_Telltale_Series = 9, 26 | Batman_The_Enemy_Within = 10, 27 | Tales_from_The_Borderlands = 11, 28 | Telltale_Texas_Holdem = 12, 29 | Bone_Out_from_Boneville = 13, 30 | Bone_The_Great_Cow_Race = 14, 31 | CSI_3_Dimensions_of_Murder = 15, 32 | CSI_Deadly_Intent = 16, 33 | CSI_Fatal_Conspiracy = 17, 34 | CSI_Hard_Evidence = 18, 35 | Jurassic_Park_The_Game = 19, 36 | Law_and_Order_Legacies = 20, 37 | Minecraft_Story_Mode_Season_One = 21, 38 | Minecraft_Story_Mode_Season_Two = 22, 39 | Poker_Night_at_The_Inventory = 23, 40 | Poker_Night_2 = 24, 41 | Sam_and_Max_Season_One_101 = 25, 42 | Sam_and_Max_Season_One_102 = 26, 43 | Sam_and_Max_Season_One_103 = 27, 44 | Sam_and_Max_Season_One_104 = 28, 45 | Sam_and_Max_Season_One_105 = 29, 46 | Sam_and_Max_Season_One_106 = 30, 47 | Sam_and_Max_Season_Two_201 = 31, 48 | Sam_and_Max_Season_Two_202 = 32, 49 | Sam_and_Max_Season_Two_203 = 33, 50 | Sam_and_Max_Season_Two_204 = 34, 51 | Sam_and_Max_Season_Two_205 = 35, 52 | Sam_and_Max_Season_Three_301 = 36, 53 | Sam_and_Max_Season_Three_302 = 37, 54 | Sam_and_Max_Season_Three_303 = 38, 55 | Sam_and_Max_Season_Three_304 = 39, 56 | Sam_and_Max_Season_Three_305 = 40, 57 | Sam_and_Max_Save_The_World_Remastered = 41, 58 | Hector_Badge_Of_Carnage_101 = 42, 59 | Hector_Badge_Of_Carnage_102 = 43, 60 | Hector_Badge_Of_Carnage_103 = 44, 61 | Puzzle_Agent_101 = 45, 62 | Puzzle_Agent_102 = 46, 63 | Back_To_The_Future_101 = 47, 64 | Back_To_The_Future_102 = 48, 65 | Back_To_The_Future_103 = 49, 66 | Back_To_The_Future_104 = 50, 67 | Back_To_The_Future_105 = 51, 68 | Strong_Bad_Cool_Game_for_Attractive_People_101 = 52, 69 | Strong_Bad_Cool_Game_for_Attractive_People_102 = 53, 70 | Strong_Bad_Cool_Game_for_Attractive_People_103 = 54, 71 | Strong_Bad_Cool_Game_for_Attractive_People_104 = 55, 72 | Strong_Bad_Cool_Game_for_Attractive_People_105 = 56, 73 | Tales_of_Monkey_Island_101 = 57, 74 | Tales_of_Monkey_Island_102 = 58, 75 | Tales_of_Monkey_Island_103 = 59, 76 | Tales_of_Monkey_Island_104 = 60, 77 | Tales_of_Monkey_Island_105 = 61, 78 | Wallace_And_Gromits_Grand_Adventures_101 = 62, 79 | Wallace_And_Gromits_Grand_Adventures_102 = 63, 80 | Wallace_And_Gromits_Grand_Adventures_103 = 64, 81 | Wallace_And_Gromits_Grand_Adventures_104 = 65, 82 | Other = 66 83 | }; 84 | 85 | public class GameVersion_Functions 86 | { 87 | public static List Get_Versions_StringList(bool replaceUnderscoreWithSpaces = false) 88 | { 89 | if (replaceUnderscoreWithSpaces) 90 | { 91 | List enumNames = new List(Enum.GetNames(typeof(GameVersion))); 92 | List changed_enumNames = new List(); 93 | 94 | foreach (string enumName in enumNames) 95 | { 96 | changed_enumNames.Add(enumName.Replace("_", " ")); 97 | } 98 | 99 | return changed_enumNames; 100 | } 101 | else 102 | return new List(Enum.GetNames(typeof(GameVersion))); 103 | } 104 | 105 | public static GameVersion Get_Versions_ParseStringValue(string value) 106 | { 107 | return (GameVersion)Enum.Parse(typeof(GameVersion), value); 108 | } 109 | 110 | public static string Get_Versions_StringValue(GameVersion value) 111 | { 112 | return Enum.GetName(typeof(GameVersion), value); 113 | } 114 | 115 | public static int Get_Versions_IntValue(GameVersion value) 116 | { 117 | return (int)value; 118 | } 119 | 120 | public static GameVersion Get_Versions_ParseIntValue(int value) 121 | { 122 | return (GameVersion)value; 123 | } 124 | 125 | public static string Get_GameID_FromVersion(GameVersion version) 126 | { 127 | switch (version) 128 | { 129 | case GameVersion.Back_To_The_Future_101: 130 | return "bttf101"; 131 | case GameVersion.Back_To_The_Future_102: 132 | return "bttf102"; 133 | case GameVersion.Back_To_The_Future_103: 134 | return "bttf103"; 135 | case GameVersion.Back_To_The_Future_104: 136 | return "bttf104"; 137 | case GameVersion.Back_To_The_Future_105: 138 | return "bttf105"; 139 | case GameVersion.Batman_The_Telltale_Series: 140 | return "batman"; 141 | case GameVersion.Batman_The_Enemy_Within: 142 | return "batman2"; 143 | case GameVersion.Bone_Out_from_Boneville: 144 | return "boneville"; 145 | case GameVersion.Bone_The_Great_Cow_Race: 146 | return "cowrace"; 147 | case GameVersion.CSI_3_Dimensions_of_Murder: 148 | return "csi3dimensions"; 149 | case GameVersion.CSI_Deadly_Intent: 150 | return "csideadly"; 151 | case GameVersion.CSI_Fatal_Conspiracy: 152 | return "csifatal"; 153 | case GameVersion.CSI_Hard_Evidence: 154 | return "csihard"; 155 | case GameVersion.Game_Of_Thrones: 156 | return "thrones"; 157 | case GameVersion.Hector_Badge_Of_Carnage_101: 158 | return "hector101"; 159 | case GameVersion.Hector_Badge_Of_Carnage_102: 160 | return "hector102"; 161 | case GameVersion.Hector_Badge_Of_Carnage_103: 162 | return "hector103"; 163 | case GameVersion.Jurassic_Park_The_Game: 164 | return "jurrassicpark"; 165 | case GameVersion.Law_and_Order_Legacies: 166 | return "lawandorder"; 167 | case GameVersion.Marvels_Gaurdians_Of_The_Galaxy: 168 | return "marvel"; 169 | case GameVersion.Minecraft_Story_Mode_Season_One: 170 | return "mcsm"; 171 | case GameVersion.Minecraft_Story_Mode_Season_Two: 172 | return "mc2"; 173 | case GameVersion.Poker_Night_at_The_Inventory: 174 | return "celebritypoker"; 175 | case GameVersion.Poker_Night_2: 176 | return "celebritypoker2"; 177 | case GameVersion.Puzzle_Agent_101: 178 | return "grickle101"; 179 | case GameVersion.Puzzle_Agent_102: 180 | return "grickle102"; 181 | case GameVersion.Sam_and_Max_Save_The_World_Remastered: 182 | return "sammaxremaster"; 183 | case GameVersion.Sam_and_Max_Season_One_101: 184 | return "sammax101"; 185 | case GameVersion.Sam_and_Max_Season_One_102: 186 | return "sammax102"; 187 | case GameVersion.Sam_and_Max_Season_One_103: 188 | return "sammax103"; 189 | case GameVersion.Sam_and_Max_Season_One_104: 190 | return "sammax104"; 191 | case GameVersion.Sam_and_Max_Season_One_105: 192 | return "sammax105"; 193 | case GameVersion.Sam_and_Max_Season_One_106: 194 | return "sammax106"; 195 | case GameVersion.Sam_and_Max_Season_Three_301: 196 | return "sammax301"; 197 | case GameVersion.Sam_and_Max_Season_Three_302: 198 | return "sammax302"; 199 | case GameVersion.Sam_and_Max_Season_Three_303: 200 | return "sammax303"; 201 | case GameVersion.Sam_and_Max_Season_Three_304: 202 | return "sammax304"; 203 | case GameVersion.Sam_and_Max_Season_Three_305: 204 | return "sammax305"; 205 | case GameVersion.Sam_and_Max_Season_Two_201: 206 | return "sammax201"; 207 | case GameVersion.Sam_and_Max_Season_Two_202: 208 | return "sammax202"; 209 | case GameVersion.Sam_and_Max_Season_Two_203: 210 | return "sammax203"; 211 | case GameVersion.Sam_and_Max_Season_Two_204: 212 | return "sammax204"; 213 | case GameVersion.Sam_and_Max_Season_Two_205: 214 | return "sammax205"; 215 | case GameVersion.Strong_Bad_Cool_Game_for_Attractive_People_101: 216 | return "sbcg4ap101"; 217 | case GameVersion.Strong_Bad_Cool_Game_for_Attractive_People_102: 218 | return "sbcg4ap102"; 219 | case GameVersion.Strong_Bad_Cool_Game_for_Attractive_People_103: 220 | return "sbcg4ap103"; 221 | case GameVersion.Strong_Bad_Cool_Game_for_Attractive_People_104: 222 | return "sbcg4ap104"; 223 | case GameVersion.Strong_Bad_Cool_Game_for_Attractive_People_105: 224 | return "sbcg4ap105"; 225 | case GameVersion.Tales_from_The_Borderlands: 226 | return "borderlands"; 227 | case GameVersion.Tales_of_Monkey_Island_101: 228 | return "monkeyisland101"; 229 | case GameVersion.Tales_of_Monkey_Island_102: 230 | return "monkeyisland102"; 231 | case GameVersion.Tales_of_Monkey_Island_103: 232 | return "monkeyisland103"; 233 | case GameVersion.Tales_of_Monkey_Island_104: 234 | return "monkeyisland104"; 235 | case GameVersion.Tales_of_Monkey_Island_105: 236 | return "monkeyisland105"; 237 | case GameVersion.Telltale_Texas_Holdem: 238 | return "texasholdem"; 239 | case GameVersion.The_Walking_Dead_Season_One: 240 | return "twd1"; 241 | case GameVersion.The_Walking_Dead_Definitive_Series: 242 | return "wdc"; 243 | case GameVersion.The_Walking_Dead_Michonne: 244 | return "michonne"; 245 | case GameVersion.The_Walking_Dead_Season_Four: 246 | return "wd4"; 247 | case GameVersion.The_Walking_Dead_Season_Three: 248 | return "wd3"; 249 | case GameVersion.The_Walking_Dead_Season_Two: 250 | return "wd2"; 251 | case GameVersion.The_Wolf_Among_Us: 252 | return "fables"; 253 | case GameVersion.Wallace_And_Gromits_Grand_Adventures_101: 254 | return "wag101"; 255 | case GameVersion.Wallace_And_Gromits_Grand_Adventures_102: 256 | return "wag102"; 257 | case GameVersion.Wallace_And_Gromits_Grand_Adventures_103: 258 | return "wag103"; 259 | case GameVersion.Wallace_And_Gromits_Grand_Adventures_104: 260 | return "wag104"; 261 | default: 262 | return ""; 263 | } 264 | } 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /TelltaleModLauncher/IconExtractor.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Telltale-Modding-Group/TelltaleModLauncher/7aecde7dd45cc15b05fc69160848f4228efe55b7/TelltaleModLauncher/IconExtractor.dll -------------------------------------------------------------------------------- /TelltaleModLauncher/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | The Walking Dead Definitive Series 56 | Mods: 0 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /TelltaleModLauncher/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | using System.Drawing; 16 | using ControlzEx.Theming; 17 | using TelltaleModLauncher.Utillities; 18 | using TelltaleModLauncher.Files; 19 | using TsudaKageyu; 20 | 21 | namespace TelltaleModLauncher 22 | { 23 | /// 24 | /// Main UI Interaction logic for MainWindow.xaml 25 | /// 26 | public partial class MainWindow 27 | { 28 | //main script objects 29 | private AppSettings appSettings; 30 | private ModManager modManager; 31 | 32 | //xaml windows 33 | private ModManager_ViewMod modManager_ViewMod; 34 | private SetupWizard_Window setupWizard_Window; 35 | private ModManager_ViewMod_ViewText modManager_ViewMod_ViewText; 36 | //recomendation: singleton pattern for managing window instances 37 | 38 | //IMPORTANT: xaml calls UpdateUI() too soon causing errors due to incomplete initalization. 39 | //This 'nullifies' UpdateUI() until InitalizeApplication() is done. 40 | private bool startingUp = true; 41 | 42 | //the bitmap image object for the big launch button 43 | private BitmapImage bitmapimage; 44 | 45 | /// 46 | /// XAML Main Window Initalization 47 | /// 48 | public MainWindow() 49 | { 50 | //xaml initalization 51 | InitializeComponent(); 52 | 53 | //application initalization 54 | InitalizeApplication(); 55 | 56 | //update the ui 57 | UpdateUI(); 58 | 59 | //update our app settings UI with the values from the config file 60 | ui_settings_darkmode_toggle.IsOn = appSettings.appSettingsFile.UI_LightMode; 61 | ui_settings_defocus_toggle.IsOn = appSettings.appSettingsFile.UI_WindowDefocusing; 62 | ui_launcher_gameversion_combobox.SelectedIndex = (int)appSettings.appSettingsFile.Default_Game_Version; 63 | } 64 | 65 | /// 66 | /// Initalizes the main script objects and windows 67 | /// 68 | private void InitalizeApplication() 69 | { 70 | //initalize our objects 71 | appSettings = new AppSettings(); 72 | modManager = new ModManager(appSettings, this); 73 | 74 | //get the mods from the current game version folder 75 | modManager.GetModsFromFolder(); 76 | 77 | //create our window objects 78 | modManager_ViewMod_ViewText = new ModManager_ViewMod_ViewText(); 79 | modManager_ViewMod = new ModManager_ViewMod(modManager_ViewMod_ViewText, appSettings); 80 | setupWizard_Window = new SetupWizard_Window(appSettings, this, modManager); 81 | 82 | //we finished starting up now, so lets set this to false 83 | startingUp = false; 84 | 85 | //check if the currently selected game that was selected is valid, if it isn't then pop open the setup wizzard 86 | if (appSettings.IsGameSetupAndValid() == false) 87 | InitalizeSetupWizard(); 88 | } 89 | 90 | /// 91 | /// Initalizes the setup wizard and hides the main window 92 | /// 93 | private void InitalizeSetupWizard() 94 | { 95 | //hide our main launcher window 96 | this.Hide(); 97 | 98 | //show our setup wizard menu 99 | setupWizard_Window.ShowDialog(); 100 | } 101 | 102 | /// 103 | /// Gets the file icon of an .exe 104 | /// 105 | /// 106 | /// 107 | private ImageSource GetFileIcon(string fileLocation) 108 | { 109 | //extract icon 110 | IconExtractor iconExtractor = new IconExtractor(fileLocation); 111 | 112 | //get main icon 113 | Icon icon = iconExtractor.GetIcon(0); 114 | 115 | //split the icon (as there are multiple sizes embeded) 116 | Icon[] splitIcons = IconUtil.Split(icon); 117 | 118 | //dispose of the original icon object since we no longer need it 119 | icon.Dispose(); 120 | 121 | //the highest quality icon, will be assigned later 122 | Icon iconHQ; 123 | 124 | //pixel width, will be changed through iterations and compared 125 | int width = 0; 126 | 127 | //the index of the highest quality one we find in the list 128 | int hqIndex = 0; 129 | 130 | //run a loop through the icon list to get highest quality icon 131 | for(int i = 0; i < splitIcons.Length; i++) 132 | { 133 | //if the pixel width is bigger than our width variable then assign it 134 | if (splitIcons[i].Width > width) 135 | { 136 | //assign the pixel width (used for comparison later) 137 | width = splitIcons[i].Width; 138 | 139 | //get the index of the element 140 | hqIndex = i; 141 | } 142 | } 143 | 144 | //if the loop finds the one with the highest quality, then use it using the hq index 145 | iconHQ = splitIcons[hqIndex]; 146 | 147 | //convert the icon to a bitmap 148 | Bitmap bitmap = IconUtil.ToBitmap(iconHQ); 149 | 150 | //create a temporary path for it 151 | string tempPath = appSettings.Get_App_ConfigDirectory() + "tempIconPreview.bmp"; 152 | 153 | //if there is already a file of the same name, get rid of it 154 | if (System.IO.File.Exists(tempPath)) 155 | IOManagement.DeleteFile(tempPath); 156 | 157 | //save the bitmap to the temp path we defined 158 | bitmap.Save(tempPath); 159 | 160 | //clear the original object if it isn't already 161 | if (bitmapimage != null) 162 | bitmapimage = null; 163 | 164 | //initallize our bitmap image object with a new one (not the same as the bitmap we defined prior) 165 | bitmapimage = new BitmapImage(); 166 | bitmapimage.BeginInit(); //initalize the image 167 | bitmapimage.UriSource = new Uri(tempPath, UriKind.Absolute); //set the path 168 | bitmapimage.CacheOption = BitmapCacheOption.OnLoad; //cache the image since we only need it once 169 | bitmapimage.EndInit(); //end the initalization 170 | 171 | //return the final image 172 | return bitmapimage; 173 | } 174 | 175 | /// 176 | /// Updates the UI to reflect the new values from the scripts. 177 | /// 178 | public void UpdateUI() 179 | { 180 | //if the app is starting up, don't continue (otherwise we get issues that you don't want) 181 | if (startingUp) 182 | return; 183 | 184 | bool ifModSelected = ui_modmanager_modlist_listview.SelectedIndex != -1 && ui_modmanager_modlist_listview.SelectedItem != null; 185 | bool ifModsExist = ui_modmanager_modlist_listview.Items.Count != 0; 186 | bool ifCanLaunchGame = ui_launcher_gameversion_combobox.SelectedIndex != -1 && appSettings.IsGameSetupAndValid(); 187 | 188 | //launcher stuff 189 | string gameExePath = appSettings.Get_Current_GameVersionSettings_GameExeLocation(); 190 | ui_launcher_gameversion_combobox.ItemsSource = GameVersion_Functions.Get_Versions_StringList(true); 191 | ui_launcher_launchgame_tile_gameModsAmount_textBlock.Text = string.Format("Mods: {0}", modManager.mods.Count); 192 | ui_launcher_launchgame_tile.IsEnabled = ifCanLaunchGame; 193 | ui_window_appversion_label.Content = appSettings.appVersionString; 194 | 195 | if(ui_launcher_gameversion_combobox.SelectedItem != null) 196 | ui_launcher_launchgame_tile_gameTitle_textBlock.Text = ui_launcher_gameversion_combobox.SelectedItem.ToString(); 197 | 198 | ui_launcher_launchgame_tile_exeIcon_image.Source = null; 199 | 200 | if(System.IO.File.Exists(gameExePath)) 201 | ui_launcher_launchgame_tile_exeIcon_image.Source = GetFileIcon(gameExePath); 202 | 203 | //mod manager stuff 204 | ui_modmanager_addmod_button.IsEnabled = ifCanLaunchGame; 205 | ui_modmanager_removemod_button.IsEnabled = ifModSelected; 206 | ui_modmanager_viewmod_button.IsEnabled = ifModSelected; 207 | ui_modmanager_openmodfolder_button.IsEnabled = ifCanLaunchGame; 208 | ui_modmanager_purgemod_button.IsEnabled = ifModsExist; 209 | ui_modmanager_refreshmodfolder_button.IsEnabled = ifCanLaunchGame; 210 | ui_modmanager_modlist_listview.IsEnabled = ifCanLaunchGame; 211 | ui_modmanager_modlist_listview.ItemsSource = modManager.mods; 212 | ui_modmanager_modlist_listview.Items.Refresh(); 213 | ui_modmanager_modlist_listview_contextmenu_add.IsEnabled = ui_modmanager_addmod_button.IsEnabled; 214 | ui_modmanager_modlist_listview_contextmenu_remove.IsEnabled = ui_modmanager_removemod_button.IsEnabled; 215 | ui_modmanager_modlist_listview_contextmenu_openmodfolder.IsEnabled = ui_modmanager_openmodfolder_button.IsEnabled; 216 | ui_modmanager_modlist_listview_contextmenu_refreshmods.IsEnabled = ui_modmanager_refreshmodfolder_button.IsEnabled; 217 | ui_modmanager_modlist_listview_contextmenu_view.IsEnabled = ui_modmanager_viewmod_button.IsEnabled; 218 | ui_modmanager_gameversion_label.Content = appSettings.Get_Current_GameVersionName(); 219 | ui_modmanager_gameversion_label.Content = string.Format("Game: {0}", appSettings.Get_Current_GameVersionName().ToString().Replace("_", " ")); 220 | 221 | //settings stuff 222 | ui_settings_gameversion_label.Content = string.Format("Current Game: {0}", appSettings.Get_Current_GameVersionName().ToString().Replace("_", " ")); 223 | ui_settings_gameversion_combobox.ItemsSource = GameVersion_Functions.Get_Versions_StringList(true); 224 | ui_settings_gameversion_combobox.SelectedIndex = (int)appSettings.appSettingsFile.Default_Game_Version; 225 | ui_settings_gamedirectoryexe_textbox.Text = appSettings.Get_Current_GameVersionSettings_GameExeLocation(); 226 | } 227 | 228 | /// 229 | /// Blurs and darkens the current window (if defocus is enabled) 230 | /// 231 | private void UI_Effect_DeFocusWindow() 232 | { 233 | //if the effect isn't on, don't continue 234 | if (appSettings.Get_AppSettings_DefocusEffect() == false) 235 | return; 236 | 237 | //create our blur effect 238 | System.Windows.Media.Effects.BlurEffect blurEffect = new System.Windows.Media.Effects.BlurEffect(); 239 | blurEffect.Radius = 10; 240 | 241 | //set the blur effect and our opacity to darken the window 242 | this.Effect = blurEffect; 243 | this.Opacity = 0.75; 244 | } 245 | 246 | /// 247 | /// Clears the effects applied to the window (if defocus is enabled) 248 | /// 249 | private void UI_Effect_ClearEffects() 250 | { 251 | //if the effect isn't on, don't continue 252 | if (appSettings.Get_AppSettings_DefocusEffect() == false) 253 | return; 254 | 255 | //remove the effect and set the opacity back 256 | this.Effect = null; 257 | this.Opacity = 1; 258 | } 259 | 260 | //---------------- MAIN APPLICATION ACTIONS ---------------- 261 | /// 262 | /// Adds a mod to the game 263 | /// 264 | private void Action_AddMod() 265 | { 266 | //(if enabled) defocus the main window 267 | UI_Effect_DeFocusWindow(); 268 | 269 | //call the main function in the mod manager for adding a mod 270 | modManager.AddMod(); 271 | 272 | //(if enabled) clear focus effects when we finish/cancled adding a mod 273 | UI_Effect_ClearEffects(); 274 | 275 | //update the UI to reflect any new changes 276 | UpdateUI(); 277 | } 278 | 279 | private void Action_RemoveMod() 280 | { 281 | //call the main removal function in the mod manager for removing a mod 282 | modManager.RemoveMod(ui_modmanager_modlist_listview.SelectedIndex); 283 | 284 | //update the UI to reflect any new changes 285 | UpdateUI(); 286 | } 287 | 288 | private void Action_PurgeMod() 289 | { 290 | //(if enabled) defocus the main window 291 | UI_Effect_DeFocusWindow(); 292 | 293 | //call the main function to remove all mods in a mod folder 294 | modManager.PurgeMods(); 295 | 296 | //(if enabled) clear focus effects when we finish/canceled purging mods 297 | UI_Effect_ClearEffects(); 298 | 299 | //update the UI to reflect any new changes 300 | UpdateUI(); 301 | } 302 | 303 | private void Action_ViewMod() 304 | { 305 | //(if enabled) defocus the main window 306 | UI_Effect_DeFocusWindow(); 307 | 308 | //get the currently selected mod in the list view 309 | Mod selectedMod = modManager.mods[ui_modmanager_modlist_listview.SelectedIndex]; 310 | 311 | //set the mod in our viewmod window to what we selected and open it 312 | modManager_ViewMod.SetMod(selectedMod); 313 | modManager_ViewMod.ShowDialog(); 314 | 315 | //(if enabled) clear focus effects when we finish/canceled viewing a mod 316 | UI_Effect_ClearEffects(); 317 | 318 | //update the UI to reflect any new changes 319 | UpdateUI(); 320 | } 321 | 322 | private void Action_SetCurrentGameExePath() 323 | { 324 | //(if enabled) defocus the main window 325 | UI_Effect_DeFocusWindow(); 326 | 327 | //open a window and tell the user to set the game exe location, then update those changes to the file 328 | appSettings.Set_Current_GameVersionSettings_GameExeLocation(); 329 | appSettings.UpdateChangesToFile(); 330 | 331 | //(if enabled) clear focus effects when we finish/canceled setting a path for the game 332 | UI_Effect_ClearEffects(); 333 | 334 | //update the UI to reflect any new changes 335 | UpdateUI(); 336 | } 337 | 338 | private void Action_OpenCurrentGameModsFolder() 339 | { 340 | //call the main function in the mod manager for opening the mod folder in explorer 341 | modManager.OpenModFolder(); 342 | 343 | //update the UI to reflect any new changes 344 | UpdateUI(); 345 | } 346 | 347 | private void Action_GetModsFromCurrentGameModsFolder() 348 | { 349 | //call the main function in the mod manager for getting the mods in the folder of the currently selected game 350 | modManager.GetModsFromFolder(); 351 | 352 | //update the UI to reflect any new changes 353 | UpdateUI(); 354 | } 355 | 356 | //---------------- XAML FUNCTIONS ---------------- 357 | private void ui_modmanager_addmod_button_Click(object sender, RoutedEventArgs e) 358 | { 359 | Action_AddMod(); 360 | } 361 | 362 | private void ui_modmanager_removemod_button_Click(object sender, RoutedEventArgs e) 363 | { 364 | Action_RemoveMod(); 365 | } 366 | 367 | private void ui_modmanager_purgemod_button_Click(object sender, RoutedEventArgs e) 368 | { 369 | Action_PurgeMod(); 370 | } 371 | 372 | private void ui_modmanager_modlist_listview_SelectionChanged(object sender, SelectionChangedEventArgs e) 373 | { 374 | //update the UI to reflect any new changes 375 | UpdateUI(); 376 | } 377 | 378 | private void ui_modmanager_viewmod_button_Click(object sender, RoutedEventArgs e) 379 | { 380 | Action_ViewMod(); 381 | } 382 | 383 | private void ui_modmanager_modlist_listview_contextmenu_view_click(object sender, RoutedEventArgs e) 384 | { 385 | Action_ViewMod(); 386 | } 387 | 388 | private void ui_modmanager_modlist_listview_contextmenu_remove_click(object sender, RoutedEventArgs e) 389 | { 390 | Action_RemoveMod(); 391 | } 392 | 393 | private void ui_modmanager_modlist_listview_MouseDoubleClick(object sender, MouseButtonEventArgs e) 394 | { 395 | Action_ViewMod(); 396 | } 397 | 398 | private void ui_settings_gamedirectoryexeBrowse_button_Click(object sender, RoutedEventArgs e) 399 | { 400 | Action_SetCurrentGameExePath(); 401 | } 402 | 403 | private void ui_launcher_launchgame_tile_Click(object sender, RoutedEventArgs e) 404 | { 405 | appSettings.LaunchGame(); 406 | } 407 | 408 | private void ui_modmanager_openmodfolder_button_Click(object sender, RoutedEventArgs e) 409 | { 410 | Action_OpenCurrentGameModsFolder(); 411 | } 412 | 413 | private void ui_window_help_button_Click(object sender, RoutedEventArgs e) 414 | { 415 | appSettings.Open_LauncherHelp(); 416 | } 417 | 418 | private void ui_modmanager_modlist_listview_contextmenu_add_click(object sender, RoutedEventArgs e) 419 | { 420 | Action_AddMod(); 421 | } 422 | private void ui_modmanager_modlist_listview_contextmenu_openmodfolder_click(object sender, RoutedEventArgs e) 423 | { 424 | Action_OpenCurrentGameModsFolder(); 425 | } 426 | 427 | private void ui_modmanager_refreshmodfolder_button_Click(object sender, RoutedEventArgs e) 428 | { 429 | Action_GetModsFromCurrentGameModsFolder(); 430 | } 431 | 432 | private void ui_modmanager_modlist_listview_contextmenu_refreshmods_click(object sender, RoutedEventArgs e) 433 | { 434 | Action_GetModsFromCurrentGameModsFolder(); 435 | } 436 | 437 | private void ui_settings_gamedirectoryexe_textbox_MouseDoubleClick(object sender, MouseButtonEventArgs e) 438 | { 439 | Action_SetCurrentGameExePath(); 440 | } 441 | 442 | private void ui_launcher_gameversion_combobox_SelectionChanged(object sender, SelectionChangedEventArgs e) 443 | { 444 | //get the currently selected game version enum value from the launcher tab 445 | GameVersion selectedGameVersion = (GameVersion)ui_launcher_gameversion_combobox.SelectedIndex; 446 | 447 | //tell the app to switch to this version 448 | appSettings.ChangeGameVersion(selectedGameVersion); 449 | 450 | //tell the manager we changed game versions 451 | modManager.ChangedGameVersion(); 452 | 453 | //update the UI to reflect any new changes 454 | UpdateUI(); 455 | } 456 | 457 | private void ui_settings_defocus_toggle_Toggled(object sender, RoutedEventArgs e) 458 | { 459 | //set the value of the defocus toggle to that of the UI element in the settings tab 460 | appSettings.Set_Current_AppSettings_UI_DefocusEffect(ui_settings_defocus_toggle.IsOn); 461 | 462 | //update changes to file automatically 463 | appSettings.UpdateChangesToFile(); 464 | 465 | //update the UI to reflect any new changes 466 | UpdateUI(); 467 | } 468 | 469 | private void ui_settings_gameversion_combobox_SelectionChanged(object sender, SelectionChangedEventArgs e) 470 | { 471 | //get the currently selected game version from the settings tab, to set our DEFAULT game version for when the launcher starts up again 472 | GameVersion selectedGameVersion = (GameVersion)ui_settings_gameversion_combobox.SelectedIndex; 473 | 474 | //tell the app we switched the default game version 475 | appSettings.Set_Current_AppSettings_DefaultGameVersion(selectedGameVersion); 476 | 477 | //update those changes to the file 478 | appSettings.UpdateChangesToFile(); 479 | 480 | //update the UI to reflect any new changes 481 | UpdateUI(); 482 | } 483 | 484 | private void ui_settings_darkmode_toggle_Toggled(object sender, RoutedEventArgs e) 485 | { 486 | //get the UI theme based on what is toggled 487 | string darkmodeTheme = ui_settings_darkmode_toggle.IsOn ? "Light.Blue" : "Dark.Blue"; 488 | 489 | //set the theme of all of our windows to what we toggled 490 | ThemeManager.Current.ChangeTheme(this, darkmodeTheme); 491 | modManager_ViewMod.UI_ChangeTheme(darkmodeTheme); 492 | setupWizard_Window.UI_ChangeTheme(darkmodeTheme); 493 | 494 | //update the value in the app config file 495 | appSettings.Set_Current_AppSettings_UI_LightMode(ui_settings_darkmode_toggle.IsOn); 496 | 497 | //update the changes to file 498 | appSettings.UpdateChangesToFile(); 499 | 500 | //update the UI to reflect any new changes 501 | UpdateUI(); 502 | } 503 | 504 | private void MetroWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) 505 | { 506 | //shut down the app (cause for whatever reason it still runs in the background) 507 | Application.Current.Shutdown(); 508 | } 509 | //---------------- XAML FUNCTIONS END ---------------- 510 | } 511 | } 512 | -------------------------------------------------------------------------------- /TelltaleModLauncher/ModManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using System.Diagnostics; 7 | using System.Threading; 8 | using System.IO; 9 | using System.IO.Compression; 10 | using System.Threading.Tasks; 11 | using Newtonsoft; 12 | using Newtonsoft.Json; 13 | using Newtonsoft.Json.Linq; 14 | using Newtonsoft.Json.Serialization; 15 | using TelltaleModLauncher.Utillities; 16 | using TelltaleModLauncher.Files; 17 | 18 | namespace TelltaleModLauncher 19 | { 20 | /// 21 | /// The main class for the mod manager functionality. 22 | /// 23 | public class ModManager 24 | { 25 | //public variables 26 | public List mods; 27 | 28 | //private variables 29 | private AppSettings appSettings; 30 | private MainWindow mainWindow; 31 | private string modZipFilePath; 32 | 33 | private FileSystemWatcher fileSystemWatcher; 34 | 35 | /// 36 | /// Initalizes a new Mod Manager object. The following fields must be given. 37 | /// 38 | /// 39 | /// 40 | public ModManager(AppSettings appSettings, MainWindow mainWindow) 41 | { 42 | this.appSettings = appSettings; 43 | this.mainWindow = mainWindow; 44 | 45 | mods = new List(); 46 | 47 | //Initalize_FileSystemWatcher(); 48 | } 49 | 50 | //------------------------- MAIN ACTIONS ------------------------- 51 | //------------------------- MAIN ACTIONS ------------------------- 52 | //------------------------- MAIN ACTIONS ------------------------- 53 | 54 | /// 55 | /// Adds a mod to the mod manager. 56 | /// Will prompt the user with a file browser to select a mod file (.zip) 57 | /// 58 | public void AddMod() 59 | { 60 | //create a temporary string to contain the path 61 | string filePath = ""; 62 | 63 | //prompt the user with a file browser dialog 64 | IOManagement.GetFilePath(ref filePath, "ZIP files|*.zip", "Select a Mod File"); 65 | 66 | //if the string is not empty (meaning the user has chosen their path) read the zip file for a modinfo.json 67 | if (String.IsNullOrEmpty(filePath) == false) 68 | ReadModZipFile(filePath); 69 | } 70 | 71 | /// 72 | /// Removes a mod from the mod manager. 73 | /// Will prompt the user if they want to remove the file. 74 | /// If yes, it will remove the files associated with the mod on the disk, and remove it from the mod manager. 75 | /// 76 | /// 77 | public void RemoveMod(int selectedIndex, bool ignorePrompt = false) 78 | { 79 | //obtain the given mod at the selected index 80 | Mod selectedMod = mods[selectedIndex]; 81 | 82 | if (ignorePrompt) //ignores the confirmation prompt and removes the mod object, mod contents, and json file 83 | { 84 | RemoveModFiles(selectedMod); //remove the files associated with the mod 85 | IOManagement.DeleteFile(selectedMod.ModInfoJson_FilePath); //remove the modinfo.json file 86 | mods.Remove(selectedMod); //remove the mod from the list in memory 87 | } 88 | else 89 | { 90 | //description for the confirmation prompt 91 | string promptDescription = string.Format("Are you sure you want to remove '{0}'?", selectedMod.ModDisplayName); 92 | 93 | //prompt the user about removing the mod 94 | if (MessageBoxes.Info_Confirm(promptDescription, "Remove Mod")) 95 | { 96 | RemoveModFiles(selectedMod); //remove the files associated with the mod 97 | IOManagement.DeleteFile(selectedMod.ModInfoJson_FilePath); //remove the modinfo.json file 98 | mods.Remove(selectedMod); //remove the mod from the list in memory 99 | } 100 | } 101 | } 102 | 103 | /// 104 | /// Removes all mods from the mod manager. 105 | /// Will prompt the user if they wish to proceed. 106 | /// If yes, it will remove all mods from the manager and the files associated with each from the disk. 107 | /// 108 | public void PurgeMods() 109 | { 110 | //prompt the user upfront if they wish to remove all of the mods in the directory 111 | if (MessageBoxes.Warning_Confirm("Are you sure you want to purge the mod directory? This will remove all the mod files currently installed. This action can't be reverted.", "Purge Mods")) 112 | { 113 | //get the game mods location of the current game version 114 | string dir = appSettings.Get_Current_GameVersionSettings_ModsLocation(); 115 | 116 | //loop through the mod list first and remove the files in relation to each mod 117 | foreach (Mod mod in mods) 118 | { 119 | foreach (string modfile in mod.ModFiles) 120 | { 121 | string modfile_pathOnDisk = Path.Combine(appSettings.Get_Current_GameVersionSettings_ModsLocation(), modfile); 122 | IOManagement.DeleteFile(modfile_pathOnDisk); 123 | } 124 | } 125 | 126 | //loop through the mods directory again to get the .json files, and remove them 127 | foreach (string modJsonFile in IOManagement.GetFilesPathsByExtension(dir, ".json")) 128 | { 129 | IOManagement.DeleteFile(modJsonFile); 130 | } 131 | 132 | //clear the mods list 133 | mods.Clear(); 134 | } 135 | } 136 | 137 | /// 138 | /// Opens the Game Mods folder with Windows Explorer. 139 | /// 140 | public void OpenModFolder() 141 | { 142 | //create a windows explorer processinfo to be exectued 143 | ProcessStartInfo processStartInfo = new ProcessStartInfo(); 144 | processStartInfo.FileName = appSettings.Get_Current_GameVersionSettings_ModsLocation(); 145 | processStartInfo.UseShellExecute = true; 146 | processStartInfo.Verb = "open"; 147 | 148 | //start the process 149 | Process.Start(processStartInfo); 150 | } 151 | 152 | //------------------------- MAIN ACTIONS END ------------------------- 153 | //------------------------- MAIN ACTIONS END ------------------------- 154 | //------------------------- MAIN ACTIONS END ------------------------- 155 | 156 | /// 157 | /// Initalizes the file system watcher object to watch the current game mods folder. 158 | /// TODO: STILL NEEDS WORK 159 | /// 160 | public void Initalize_FileSystemWatcher() 161 | { 162 | //get our values ready, look for .json files only 163 | string fileSystemWatcher_filter = "*.json"; 164 | 165 | //if our app settings object is null, don't continue 166 | if (appSettings == null) 167 | return; 168 | 169 | //get the mod location of the current selected game 170 | string fileSystemWatcher_location = appSettings.Get_Current_GameVersionSettings_ModsLocation(); 171 | 172 | //if our given directory location does not exist, don't continue 173 | if(!Directory.Exists(fileSystemWatcher_location)) 174 | return; 175 | 176 | //if we already have a watcher, dispose of it 177 | if(fileSystemWatcher != null) 178 | fileSystemWatcher.Dispose(); 179 | 180 | //initalize our file system watcher object 181 | fileSystemWatcher = new FileSystemWatcher(fileSystemWatcher_location, fileSystemWatcher_filter); 182 | fileSystemWatcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.Security; 183 | 184 | //add our events 185 | fileSystemWatcher.Changed += FileSystemWatcher_Changed; 186 | fileSystemWatcher.Created += FileSystemWatcher_Created; 187 | fileSystemWatcher.Deleted += FileSystemWatcher_Deleted; 188 | fileSystemWatcher.Renamed += FileSystemWatcher_Renamed; 189 | 190 | //initalize the file system watcher object 191 | fileSystemWatcher.EnableRaisingEvents = true; 192 | fileSystemWatcher.IncludeSubdirectories = false; 193 | } 194 | 195 | // TODO: STILL NEEDS WORK 196 | private void FileSystemWatcher_Renamed(object sender, RenamedEventArgs e) 197 | { 198 | GetModsFromFolder(); 199 | } 200 | 201 | // TODO: STILL NEEDS WORK 202 | private void FileSystemWatcher_Deleted(object sender, FileSystemEventArgs e) 203 | { 204 | GetModsFromFolder(); 205 | } 206 | 207 | // TODO: STILL NEEDS WORK 208 | private void FileSystemWatcher_Created(object sender, FileSystemEventArgs e) 209 | { 210 | GetModsFromFolder(); 211 | } 212 | 213 | // TODO: STILL NEEDS WORK 214 | private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e) 215 | { 216 | GetModsFromFolder(); 217 | } 218 | 219 | /// 220 | /// Remove the mod files assoicated with the given mod on the disk. 221 | /// 222 | /// 223 | public void RemoveModFiles(Mod mod) 224 | { 225 | //loop through each of the mod files detailed in the mods .json file 226 | foreach (string modfile in mod.ModFiles) 227 | { 228 | string modfile_pathOnDisk = Path.Combine(appSettings.Get_Current_GameVersionSettings_ModsLocation(), modfile); 229 | 230 | if(File.Exists(modfile_pathOnDisk)) 231 | IOManagement.DeleteFile(modfile_pathOnDisk); 232 | } 233 | } 234 | 235 | /// 236 | /// Call this function when the game version is changed on the launcher, clears the list and checks the mod folder of the game version for mods 237 | /// 238 | public void ChangedGameVersion() 239 | { 240 | //check if the current selected game version has a mods location 241 | if(Directory.Exists(appSettings.Get_Current_GameVersionSettings_ModsLocation()) == false) 242 | { 243 | //clear the list 244 | mods.Clear(); 245 | } 246 | else 247 | { 248 | mods.Clear(); 249 | Initalize_FileSystemWatcher(); 250 | GetModsFromFolder(); 251 | } 252 | } 253 | 254 | /// 255 | /// Reads the Game Mod Folder for any existing mods by looking for a modinfo.json file. 256 | /// Will fill the mods list on the mod manager if there are any found. 257 | /// 258 | public void GetModsFromFolder() 259 | { 260 | //if the game mods directory exists 261 | if (Directory.Exists(appSettings.Get_Current_GameVersionSettings_ModsLocation())) 262 | { 263 | //clear the list 264 | mods.Clear(); 265 | 266 | //get all of the modinfo.json files found in the folder 267 | List modJsonFilesPath = IOManagement.GetFilesPathsByExtension(appSettings.Get_Current_GameVersionSettings_ModsLocation(), ".json"); 268 | 269 | //go through the json files list and read each one to get the data 270 | foreach (string jsonFilePath in modJsonFilesPath) 271 | { 272 | Json_ReadModFile_New(jsonFilePath, true, false); 273 | } 274 | 275 | //temp list for any bad mods found 276 | List badMods = new List(); 277 | 278 | //loop through the existing mod list and check if each mod has its assoicated files 279 | foreach (Mod mod in mods) 280 | { 281 | //if the given mod does not pass the check, then its missing files! so add it to the list 282 | if (CheckIfModFilesExist(mod) == false) 283 | { 284 | badMods.Add(mod); 285 | } 286 | } 287 | 288 | //loop through the list of the bad mods that have been found and remove each one. 289 | //NOTE: FUTURE REFERENCE, Give the user a prompt that notifies them. For now we will handle removing the bad mod automatically. 290 | foreach (Mod badMod in badMods) 291 | { 292 | RemoveMod(mods.IndexOf(badMod), true); 293 | } 294 | } 295 | 296 | System.Windows.Application.Current.Dispatcher.Invoke(new Action(() => 297 | { 298 | //update the UI on the main window 299 | mainWindow.UpdateUI(); 300 | })); 301 | } 302 | 303 | /// 304 | /// Extracts the mod file zip contents to the Game Mods directory. 305 | /// 306 | public void ExtractModZipFileContents_ToDirectory(Mod mod) 307 | { 308 | //extract entire zip file's contents to the mods folder 309 | using (ZipArchive archive = ZipFile.OpenRead(modZipFilePath)) 310 | { 311 | foreach (ZipArchiveEntry entry in archive.Entries) 312 | { 313 | //check if the given entry has an extension, i.e. check if it is a file and not a folder (we want to extract the contents, not the folder) 314 | if (Path.HasExtension(entry.FullName)) 315 | { 316 | // Gets the full path to ensure that relative segments are removed. 317 | string modFile_extractedFromArchive = Path.GetFullPath(Path.Combine(appSettings.Get_Current_GameVersionSettings_ModsLocation(), entry.Name)); 318 | 319 | //checks the extension for a .json file, if one is found then it sets it for the mod 320 | if (entry.FullName.EndsWith(".json", StringComparison.OrdinalIgnoreCase)) 321 | mod.ModInfoJson_FilePath = modFile_extractedFromArchive; 322 | 323 | // Ordinal match is safest, case-sensitive volumes can be mounted within volumes that are case-insensitive. 324 | if (modFile_extractedFromArchive.StartsWith(appSettings.Get_Current_GameVersionSettings_ModsLocation(), StringComparison.Ordinal)) 325 | { 326 | //if there is an existing modfile that shares the same path/extension and everything, remove it 327 | //NOTE: in the future, want to prompt the user about replacing mod files 328 | if (File.Exists(modFile_extractedFromArchive)) 329 | IOManagement.DeleteFile(modFile_extractedFromArchive); 330 | 331 | foreach (string gameDirFile in mod.ModFilesGameDirectory) 332 | { 333 | if (gameDirFile.Equals(entry.Name)) 334 | { 335 | 336 | } 337 | } 338 | 339 | //extract the given entry to the game mods directory 340 | entry.ExtractToFile(modFile_extractedFromArchive); 341 | } 342 | } 343 | } 344 | } 345 | } 346 | 347 | /// 348 | /// Check if the given mod files exist. If the files are missing for the mod, it prompts the user if they wish to remove the mod. 349 | /// returns false is there are missing mod files. 350 | /// returns true is there are no missing mod files. 351 | /// 352 | /// 353 | /// 354 | public bool CheckIfModFilesExist(Mod mod) 355 | { 356 | //initalize a temporary list for the missing mod file paths 357 | List missingModFiles = new List(); 358 | 359 | //loop through the modfiles list in the mod for any missing files 360 | foreach (string modfile in mod.ModFiles) 361 | { 362 | string modfile_pathOnDisk = Path.Combine(appSettings.Get_Current_GameVersionSettings_ModsLocation(), modfile); 363 | 364 | //if the modfile does not exist on the disk, add it to the missing files list. 365 | if (!File.Exists(modfile_pathOnDisk)) 366 | { 367 | missingModFiles.Add(modfile); 368 | } 369 | } 370 | 371 | if (missingModFiles.Count != 0) 372 | return false; 373 | else 374 | return true; 375 | } 376 | 377 | /// 378 | /// Checks the given mod's contents with all the other mod's contents found in the main mods list. 379 | /// 380 | /// 381 | public void CheckModContents_WithExistingMods(Mod newMod, bool addMod = false) 382 | { 383 | List conflictingMods = new List(); //temp list for the conflicting mods 384 | List conflictingModNames = new List(); //temp list for the conflicting mods names (for the ui prompt) 385 | List conflictingModFiles = new List(); //temp list for the conflicting mods files (for the ui prompt) 386 | 387 | //loop through the mod list 388 | foreach (Mod mod in mods) 389 | { 390 | //create a boolean that states whether or not the given mod has conflicts 391 | bool hasConflictingFiles = false; 392 | 393 | //loop through the mod files for the current mod in the loop 394 | foreach(string file in mod.ModFiles) 395 | { 396 | //loop through each 'newModFile' and check each one with the given mod 'file' 397 | foreach(string newModFile in newMod.ModFiles) 398 | { 399 | if(file.Equals(newModFile)) 400 | { 401 | hasConflictingFiles = true; 402 | conflictingModFiles.Add(file); 403 | } 404 | } 405 | } 406 | 407 | //if there are conflicting files, add the current mod and its name to the list 408 | if(hasConflictingFiles) 409 | { 410 | conflictingMods.Add(mod); 411 | conflictingModNames.Add(mod.ModDisplayName); 412 | } 413 | } 414 | 415 | //if there are conflicting mods 416 | if(conflictingMods.Count != 0) 417 | { 418 | //for prompt ui 419 | string conflictingModsMessage = string.Join(", ", conflictingModNames); 420 | string conflictingModFilesMessage = string.Join(", ", conflictingModFiles); 421 | string finalMessage = string.Format("{0} has conflicts with the following mods! {1}. They share the following files! {2}. Do you want to remove the conflicting mods?", newMod.ModDisplayName, conflictingModsMessage, conflictingModFilesMessage); 422 | 423 | //notify the user about the conflicts, if they take action (press yes) it will remove the conflicting mods from the list, and removes the respective files and .json files 424 | if (MessageBoxes.Error_Confirm(finalMessage, "Mod Conflicts!")) 425 | { 426 | foreach(Mod mod in conflictingMods) 427 | { 428 | RemoveModFiles(mod); 429 | IOManagement.DeleteFile(mod.ModInfoJson_FilePath); 430 | mods.Remove(mod); 431 | } 432 | } 433 | 434 | return; 435 | } 436 | 437 | //if everything passes, add the mod (if the boolean on the function call has been set) 438 | if(addMod) 439 | { 440 | ExtractModZipFileContents_ToDirectory(newMod); 441 | mods.Add(newMod); 442 | } 443 | } 444 | 445 | /// 446 | /// Adds a mod with a bunch of validation checks. 447 | /// If a validation check fails, it will not add the mod. 448 | /// 449 | /// 450 | public void ValidateAndAddMod(Mod newMod) 451 | { 452 | //if there are no mods in the list, go ahead and install it 453 | if (mods.Count < 1) 454 | { 455 | mods.Add(newMod); 456 | ExtractModZipFileContents_ToDirectory(newMod); 457 | 458 | return; //dont continue 459 | } 460 | 461 | //if there are mods, then loop through each one to check their properties 462 | foreach (Mod mod in mods) 463 | { 464 | //if mod shares the name 465 | if (mod.ModDisplayName.Equals(newMod.ModDisplayName)) 466 | { 467 | if (mod.ModVersion.Equals(newMod.ModVersion)) //if the mod is the same version and has the same name, this mod is a duplicate! stop! 468 | { 469 | string message = string.Format("You already have '{0}' version '{1}' installed!. Do you wish to replace it anyway?", mod.ModDisplayName, mod.ModVersion, newMod.ModVersion); 470 | 471 | if (MessageBoxes.Info_Confirm(message, "Replace Mod")) 472 | { 473 | ReplaceMod(mod, newMod); 474 | } 475 | 476 | return; 477 | } 478 | else //if the mod has the same name but is a different version, then prompt the user if they want to replace it with the given version. 479 | { 480 | string message = string.Format("You have '{0}' installed with version '{1}'. Do you wish to replace it with this version {2}?", mod.ModDisplayName, mod.ModVersion, newMod.ModVersion); 481 | 482 | if (MessageBoxes.Info_Confirm(message, "Replace Mod")) 483 | { 484 | ReplaceMod(mod, newMod); 485 | } 486 | 487 | return; 488 | } 489 | } 490 | 491 | //now check the mod's compatiblity 492 | GameVersion parsedModCompatiblity; 493 | 494 | try 495 | { 496 | //attempt to parse the mods game version string as a game version enum 497 | parsedModCompatiblity = GameVersion_Functions.Get_Versions_ParseStringValue(newMod.ModCompatibility); 498 | } 499 | catch(Exception e) 500 | { 501 | //the parsing failed, show the exception 502 | MessageBoxes.Error(e.Message, e.ToString()); 503 | return; //dont continue 504 | } 505 | 506 | //if the parse is sucessful, now check if it matches the current game version we have selected 507 | if(parsedModCompatiblity.Equals(appSettings.Get_Current_GameVersionName()) == false) 508 | { 509 | //for ui 510 | string current_gameVersionString = Enum.GetName(typeof(GameVersion), appSettings.Get_Current_GameVersionName()); 511 | string mod_gameVersionString = Enum.GetName(typeof(GameVersion), parsedModCompatiblity); 512 | string message = string.Format("'{0}' is incompatible with your current game version '{1}'. The mod was built for the following game version '{2}'.", mod.ModDisplayName, current_gameVersionString, mod_gameVersionString); 513 | 514 | //notify the user 515 | //NOTE: Future addition - add an option for the user to convert the mod version, but warn them that this may not work. 516 | MessageBoxes.Error(message, "Incompatible Game Version!"); 517 | 518 | return;//dont continue 519 | } 520 | } 521 | 522 | //if all checks pass, do a final check to check the contents of the mod with the existing ones 523 | CheckModContents_WithExistingMods(newMod, true); 524 | } 525 | 526 | /// 527 | /// Reads a mod zip file. 528 | /// Extracts the modinfo.json file 529 | /// 530 | /// 531 | public void ReadModZipFile(string newModZipFilePath) 532 | { 533 | modZipFilePath = newModZipFilePath; 534 | modZipFilePath = Path.GetFullPath(modZipFilePath); 535 | string modZipFile_ParentDirectory = Path.GetDirectoryName(modZipFilePath); 536 | string modJson_extractedFromArchive = ""; 537 | 538 | // Ensures that the last character on the extraction path is the directory separator char. 539 | if (!modZipFile_ParentDirectory.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) 540 | modZipFile_ParentDirectory += Path.DirectorySeparatorChar; 541 | 542 | using (ZipArchive archive = ZipFile.OpenRead(modZipFilePath)) 543 | { 544 | foreach (ZipArchiveEntry entry in archive.Entries) 545 | { 546 | if (entry.FullName.EndsWith(".json", StringComparison.OrdinalIgnoreCase)) 547 | { 548 | // Gets the full path to ensure that relative segments are removed. 549 | modJson_extractedFromArchive = Path.GetFullPath(Path.Combine(modZipFile_ParentDirectory, entry.Name)); 550 | 551 | if(File.Exists(modJson_extractedFromArchive)) 552 | IOManagement.DeleteFile(modJson_extractedFromArchive); 553 | 554 | // Ordinal match is safest, case-sensitive volumes can be mounted within volumes that are case-insensitive. 555 | if (modJson_extractedFromArchive.StartsWith(modZipFile_ParentDirectory, StringComparison.Ordinal)) 556 | entry.ExtractToFile(modJson_extractedFromArchive); 557 | } 558 | } 559 | } 560 | 561 | //after extraction, read the json file 562 | Json_ReadModFile(modJson_extractedFromArchive); 563 | } 564 | 565 | /// 566 | /// Writes a brand new modinfo.json file 567 | /// 568 | /// 569 | /// 570 | public void Json_WriteModFile(string modFileLocation, Mod mod) 571 | { 572 | //open a stream writer to create the text file and write to it 573 | using (StreamWriter file = File.CreateText(modFileLocation)) 574 | { 575 | //get our json seralizer 576 | JsonSerializer serializer = new JsonSerializer(); 577 | 578 | //seralize the data and write it to the configruation file 579 | serializer.Formatting = Formatting.Indented; 580 | serializer.Serialize(file, mod); 581 | } 582 | } 583 | 584 | /// 585 | /// Replaces an existing mod with a new mod. 586 | /// Also replaces the files associated with the existing mod with the new one. 587 | /// 588 | /// 589 | /// 590 | private void ReplaceMod(Mod orignalMod, Mod newMod) 591 | { 592 | RemoveModFiles(orignalMod); 593 | IOManagement.DeleteFile(orignalMod.ModInfoJson_FilePath); 594 | mods.Remove(orignalMod); 595 | 596 | ExtractModZipFileContents_ToDirectory(newMod); 597 | mods.Add(newMod); 598 | } 599 | 600 | /// 601 | /// Reads the data from the modinfo.json file and returns a mod object. 602 | /// 603 | /// 604 | /// 605 | public Mod GetJsonData(string modJsonFile) 606 | { 607 | //create a new mod object 608 | Mod newMod = new Mod(); 609 | 610 | //check if the json does not exist 611 | if(!File.Exists(modJsonFile)) 612 | { 613 | string message = "This mod zip file is not setup like a mod launcher file! Please refer to the help section to see how a mod zip file should be setup."; 614 | 615 | MessageBoxes.Error(message, "Can't Add Mod!"); 616 | 617 | return null; 618 | } 619 | 620 | //read the data from the config file 621 | string jsonText = File.ReadAllText(modJsonFile); 622 | 623 | //parse the data into a json array 624 | JObject obj = JObject.Parse(jsonText); 625 | 626 | //loop through each property to get the data 627 | foreach (JProperty property in obj.Properties()) 628 | { 629 | //get the name of the property from the json object 630 | string name = property.Name; 631 | 632 | if (name.Equals(nameof(Mod.ModAuthor))) 633 | newMod.ModAuthor = (string)property.Value; 634 | 635 | if (name.Equals(nameof(Mod.ModCompatibility))) 636 | newMod.ModCompatibility = (string)property.Value; 637 | 638 | if (name.Equals(nameof(Mod.ModDisplayName))) 639 | newMod.ModDisplayName = (string)property.Value; 640 | 641 | if (name.Equals(nameof(Mod.ModVersion))) 642 | newMod.ModVersion = (string)property.Value; 643 | 644 | //if the property is a mod files array, parse the given files to a list 645 | if (name.Equals(nameof(Mod.ModFiles))) 646 | { 647 | JArray fileArray = (JArray)obj[nameof(Mod.ModFiles)]; 648 | List parsedModFiles = new List(); 649 | 650 | foreach (JValue file in fileArray) 651 | { 652 | parsedModFiles.Add((string)file.Value); 653 | } 654 | 655 | newMod.ModFiles = parsedModFiles; 656 | } 657 | 658 | //if the property is a mod files array, parse the given files to a list 659 | if (name.Equals(nameof(Mod.ModFilesGameDirectory))) 660 | { 661 | JArray fileArray = (JArray)obj[nameof(Mod.ModFilesGameDirectory)]; 662 | List parsedModFilesGameDirectory = new List(); 663 | 664 | foreach (JValue file in fileArray) 665 | { 666 | parsedModFilesGameDirectory.Add((string)file.Value); 667 | } 668 | 669 | newMod.ModFiles = parsedModFilesGameDirectory; 670 | } 671 | } 672 | 673 | newMod.ModInfoJson_FilePath = modJsonFile; 674 | 675 | return newMod; 676 | } 677 | 678 | /// 679 | /// Reads a modinfo.json file and parses the data into a new mod object. 680 | /// After sucessfully getting the data, it will execute ValidateAndAddMod() 681 | /// 682 | /// 683 | public void Json_ReadModFile(string modJsonFile, bool bypassValidation = false, bool deleteJson = true) 684 | { 685 | //create a new mod object 686 | Mod newMod = GetJsonData(modJsonFile); 687 | 688 | //if the new mod is null, do not continue! 689 | if(newMod == null) 690 | return; 691 | 692 | if (deleteJson) 693 | { 694 | //delete the modJsonFile since we don't need it anymore 695 | IOManagement.DeleteFile(modJsonFile); 696 | } 697 | 698 | //bypass the validation stage and just add the mod anyway 699 | //(for when this function is called to gather mods from the mod folder on startup) 700 | if (bypassValidation) 701 | { 702 | mods.Add(newMod); 703 | 704 | if(CheckIfModFilesExist(newMod) == false) 705 | ExtractModZipFileContents_ToDirectory(newMod); 706 | } 707 | else 708 | { 709 | //otherwise, validate the mod. if its sucessful it will be added 710 | ValidateAndAddMod(newMod); 711 | } 712 | } 713 | 714 | /// 715 | /// Reads a modinfo.json file and parses the data into a new mod object. 716 | /// After sucessfully getting the data, it will execute ValidateAndAddMod() 717 | /// 718 | /// 719 | public void Json_ReadModFile_New(string modJsonFile, bool bypassValidation = false, bool deleteJson = true) 720 | { 721 | //create a new mod object 722 | Mod newMod = GetJsonData(modJsonFile); 723 | 724 | //if the new mod is null, do not continue! 725 | if (newMod == null) 726 | return; 727 | 728 | newMod.ModInfoJson_FilePath = modJsonFile; 729 | 730 | if (deleteJson) 731 | { 732 | //delete the modJsonFile since we don't need it anymore 733 | IOManagement.DeleteFile(modJsonFile); 734 | } 735 | 736 | //bypass the validation stage and just add the mod anyway 737 | //(for when this function is called to gather mods from the mod folder on startup) 738 | if (bypassValidation) 739 | { 740 | mods.Add(newMod); 741 | 742 | if (CheckIfModFilesExist(newMod) == false) 743 | ExtractModZipFileContents_ToDirectory(newMod); 744 | } 745 | else 746 | { 747 | //otherwise, validate the mod. if its sucessful it will be added 748 | ValidateAndAddMod(newMod); 749 | } 750 | } 751 | } 752 | } 753 | -------------------------------------------------------------------------------- /TelltaleModLauncher/ModManager_ViewMod.xaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 43 | 44 | -------------------------------------------------------------------------------- /TelltaleModLauncher/ModManager_ViewMod.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | using ControlzEx.Theming; 15 | using System.IO; 16 | 17 | using TelltaleModLauncher.Files; 18 | 19 | namespace TelltaleModLauncher 20 | { 21 | /// 22 | /// Interaction logic for ModManager_ViewMod.xaml 23 | /// 24 | public partial class ModManager_ViewMod 25 | { 26 | //mod object, this will need to be set with SetMod() to display the mod values. 27 | private Mod mod; 28 | 29 | private AppSettings appSettings; 30 | private ModManager_ViewMod_ViewText modManager_ViewMod_ViewText; 31 | 32 | /// 33 | /// Opens a 'ViewMod' window to view a mod. 34 | /// 35 | public ModManager_ViewMod(ModManager_ViewMod_ViewText modManager_ViewMod_ViewText, AppSettings appSettings) 36 | { 37 | //xaml initalization 38 | InitializeComponent(); 39 | 40 | this.modManager_ViewMod_ViewText = modManager_ViewMod_ViewText; 41 | this.appSettings = appSettings; 42 | 43 | //create a temporary mod object with some default values 44 | mod = new Mod("Mod Name", "0", "Mod Author", new List(), "None"); 45 | } 46 | 47 | /// 48 | /// Sets the mod object so the values can be obtained and shown to the user. 49 | /// 50 | /// 51 | public void SetMod(Mod mod) 52 | { 53 | this.mod = mod; 54 | UpdateUI(); 55 | } 56 | 57 | /// 58 | /// Updates the UI Elements of the XAML window to reflect the mod values 59 | /// 60 | private void UpdateUI() 61 | { 62 | ui_displayauthor_label.Content = string.Format("Author: {0}", mod.ModAuthor); 63 | ui_displaycompatibility_label.Content = string.Format("Compatibility: {0}", mod.ModCompatibility.Replace("_", " ")); 64 | ui_displayname_label.Content = string.Format("Name: {0}", mod.ModDisplayName); 65 | ui_displayversion_label.Content = string.Format("Version: {0}", mod.ModVersion); 66 | ui_modpriority_textbox.Text = mod.ModResourcePriority.ToString(); 67 | 68 | ui_displayfiles_listview.ItemsSource = mod.ModFiles; 69 | } 70 | 71 | private void UI_Effect_DeFocusWindow() 72 | { 73 | if (appSettings.Get_AppSettings_DefocusEffect() == false) 74 | return; 75 | 76 | System.Windows.Media.Effects.BlurEffect blurEffect = new System.Windows.Media.Effects.BlurEffect(); 77 | blurEffect.Radius = 10; 78 | 79 | this.Effect = blurEffect; 80 | this.Opacity = 0.75; 81 | } 82 | 83 | private void UI_Effect_ClearEffects() 84 | { 85 | if (appSettings.Get_AppSettings_DefocusEffect() == false) 86 | return; 87 | 88 | this.Effect = null; 89 | this.Opacity = 1; 90 | } 91 | 92 | private void ViewMod_Closing(object sender, System.ComponentModel.CancelEventArgs e) 93 | { 94 | if(modManager_ViewMod_ViewText != null) 95 | modManager_ViewMod_ViewText.Close(); 96 | 97 | //hide the window on closing instead of creating a new window object every time 98 | e.Cancel = true; 99 | this.Hide(); 100 | } 101 | 102 | /// 103 | /// Changes the theme of the window. 104 | /// 105 | /// 106 | public void UI_ChangeTheme(string theme) 107 | { 108 | ThemeManager.Current.ChangeTheme(this, theme); 109 | } 110 | 111 | private void ui_displayfiles_listview_MouseDoubleClick(object sender, MouseButtonEventArgs e) 112 | { 113 | if (ui_displayfiles_listview.SelectedItem == null) 114 | return; 115 | 116 | string modDirectory = appSettings.Get_Current_GameVersionSettings_ModsLocation(); 117 | string selectedModFilePath = (string)ui_displayfiles_listview.SelectedItem; 118 | string finalPath = System.IO.Path.Combine(modDirectory, selectedModFilePath); 119 | 120 | UI_Effect_DeFocusWindow(); 121 | 122 | if (modManager_ViewMod_ViewText.CheckPreviewValidity(finalPath)) 123 | { 124 | modManager_ViewMod_ViewText.OpenWindow(finalPath, mod.ModDisplayName); 125 | //modManager_ViewMod_ViewText.ShowDialog(); 126 | } 127 | 128 | UI_Effect_ClearEffects(); 129 | } 130 | 131 | private void ui_displayfiles_viewfilecontents_click(object sender, RoutedEventArgs e) 132 | { 133 | if (ui_displayfiles_listview.SelectedItem == null) 134 | return; 135 | 136 | string modDirectory = appSettings.Get_Current_GameVersionSettings_ModsLocation(); 137 | string selectedModFilePath = (string)ui_displayfiles_listview.SelectedItem; 138 | string finalPath = System.IO.Path.Combine(modDirectory, selectedModFilePath); 139 | 140 | UI_Effect_DeFocusWindow(); 141 | 142 | if (modManager_ViewMod_ViewText.CheckPreviewValidity(finalPath)) 143 | { 144 | modManager_ViewMod_ViewText.OpenWindow(finalPath, mod.ModDisplayName); 145 | //modManager_ViewMod_ViewText.ShowDialog(); 146 | } 147 | 148 | UI_Effect_ClearEffects(); 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /TelltaleModLauncher/ModManager_ViewMod_ViewText.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /TelltaleModLauncher/ModManager_ViewMod_ViewText.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | using System.IO; 15 | using TelltaleModLauncher.Utillities; 16 | 17 | namespace TelltaleModLauncher 18 | { 19 | /// 20 | /// Interaction logic for ModManager_ViewMod_ViewText.xaml 21 | /// 22 | public partial class ModManager_ViewMod_ViewText 23 | { 24 | public string modDisplayName; 25 | public string filePath; 26 | public string fileContents; 27 | 28 | public ModManager_ViewMod_ViewText() 29 | { 30 | InitializeComponent(); 31 | 32 | fileContents = "Empty"; 33 | } 34 | 35 | public void OpenWindow(string filePath, string modDisplayName) 36 | { 37 | this.filePath = filePath; 38 | this.modDisplayName = modDisplayName; 39 | this.Show(); 40 | this.Activate(); 41 | 42 | LoadInContents(); 43 | 44 | UpdateUI(); 45 | } 46 | 47 | public bool CheckPreviewValidity(string newFilePath) 48 | { 49 | if (File.Exists(newFilePath) == false) 50 | { 51 | string message = string.Format("'{0}' does not exist!", newFilePath); 52 | 53 | MessageBoxes.Error(message, "Can't Read File"); 54 | 55 | return false; 56 | } 57 | 58 | string fileExt = System.IO.Path.GetExtension(newFilePath); 59 | 60 | if (fileExt.Equals(".txt") == false) 61 | { 62 | string message = string.Format("File Type '{0}' is not supported for previewing!", fileExt); 63 | 64 | MessageBoxes.Error(message, "Can't Read File"); 65 | 66 | return false; 67 | } 68 | 69 | return true; 70 | } 71 | 72 | public void LoadInContents() 73 | { 74 | if(File.Exists(filePath)) 75 | { 76 | try // read the contents in a try catch as double protection incase the .txt contents are actually unsupported. 77 | { 78 | fileContents = File.ReadAllText(filePath); 79 | } 80 | catch(Exception e) 81 | { 82 | MessageBoxes.Error(e.ToString(), e.Message); 83 | } 84 | } 85 | } 86 | 87 | public void UpdateUI() 88 | { 89 | string fileName = System.IO.Path.GetFileName(filePath); 90 | string final_fileName = string.Format("{0}/{1}", modDisplayName, fileName); 91 | 92 | ui_viewtext_filename_label.Content = final_fileName; 93 | ui_viewtext_filecontents_textbox.Text = fileContents; 94 | } 95 | 96 | private void ViewText_Closing(object sender, System.ComponentModel.CancelEventArgs e) 97 | { 98 | //hide the window on closing instead of creating a new window object every time 99 | e.Cancel = true; 100 | this.Hide(); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /TelltaleModLauncher/Mod_ResdescEdit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | using System.IO.Compression; 8 | using System.Diagnostics; 9 | using System.Windows.Forms; 10 | using LibTelltale; 11 | 12 | namespace TelltaleModLauncher 13 | { 14 | public class Mod_ResdescEdit 15 | { 16 | private AppSettings appSettings; 17 | 18 | public Mod_ResdescEdit(AppSettings appSettings) 19 | { 20 | this.appSettings = appSettings; 21 | } 22 | 23 | /// 24 | /// Encrypts a given file using libtelltale 25 | /// 26 | /// 27 | /// 28 | private void EncryptFile(string fileLocation) 29 | { 30 | //read the file into a byte array 31 | byte[] file_bytes = File.ReadAllBytes(fileLocation); 32 | 33 | //check if the file has a lenc extension 34 | bool isLenc = Path.GetExtension(fileLocation).Equals(".lenc"); 35 | 36 | //get the game ID to encrypt the file with the proper encryption key that matches the current selected game 37 | string gameID = appSettings.current_GameVersionSettings.Game_LibTelltale_GameID; 38 | 39 | //use libtelltale and encrypt the file 40 | MemoryHelper.Bytes bytes = Config.EncryptResourceDescription(file_bytes, gameID, false, isLenc); 41 | 42 | //overwrite the original resource description file with the encrypted bytes 43 | File.WriteAllBytes(fileLocation, bytes.bytes); 44 | 45 | //free the memory since we have no use for it 46 | MemoryHelper.FreeReadBytes(bytes); 47 | } 48 | 49 | /// 50 | /// Decrypts a given file using libtelltale 51 | /// 52 | /// 53 | /// 54 | private void DecryptFile(string fileLocation) 55 | { 56 | //read the file into a byte array 57 | byte[] file_bytes = File.ReadAllBytes(fileLocation); 58 | 59 | //get the game ID to decrypt the file with the proper encryption key that matches the current selected game 60 | string gameID = appSettings.current_GameVersionSettings.Game_LibTelltale_GameID; 61 | 62 | //use libtelltale and decrypt the file 63 | MemoryHelper.Bytes bytes = Config.DecryptResourceDescription(file_bytes, gameID, false); 64 | 65 | //overwrite the original resource description file with the decrypted bytes 66 | File.WriteAllBytes(fileLocation, bytes.bytes); 67 | 68 | //free the memory since we have no use for it 69 | MemoryHelper.FreeReadBytes(bytes); 70 | } 71 | 72 | public void Parse_File(string file) 73 | { 74 | List file_lines = new List(File.ReadAllLines(file)); 75 | 76 | string archivePriority_name = "set.priority"; 77 | string archiveGamePriority_name = "set.gameDataPriority"; 78 | 79 | int archivePriority_value = 0; 80 | int archiveGamePriority_value = 0; 81 | 82 | foreach(string line in file_lines) 83 | { 84 | string archivePriority_file = line.Remove(archivePriority_name.Length - 1, Math.Abs(line.Length - archivePriority_name.Length)); 85 | string archiveGamePriority_file = line.Remove(archiveGamePriority_name.Length - 1, Math.Abs(line.Length - archiveGamePriority_name.Length)); 86 | 87 | if (archivePriority_file.Equals(archivePriority_name)) 88 | { 89 | string a = line.Remove(0, archivePriority_file.Length); 90 | string noSpaces = a.Replace(" ", ""); 91 | string noEquals = noSpaces.Replace("=", ""); 92 | 93 | archivePriority_value = int.Parse(noEquals); 94 | } 95 | 96 | if (archiveGamePriority_file.Equals(archivePriority_name)) 97 | { 98 | string a = line.Remove(0, archiveGamePriority_file.Length); 99 | string noSpaces = a.Replace(" ", ""); 100 | string noEquals = noSpaces.Replace("=", ""); 101 | 102 | archiveGamePriority_value = int.Parse(noEquals); 103 | } 104 | } 105 | } 106 | 107 | public void Edit_File(string file, int archivePriority_value, int archiveGamePriority_value) 108 | { 109 | List file_lines = new List(File.ReadAllLines(file)); 110 | 111 | string archivePriority_name = "set.priority"; 112 | string archiveGamePriority_name = "set.gameDataPriority"; 113 | 114 | int index = 0; 115 | 116 | foreach (string line in file_lines) 117 | { 118 | string archivePriority_file = line.Remove(archivePriority_name.Length - 1, Math.Abs(line.Length - archivePriority_name.Length)); 119 | string archiveGamePriority_file = line.Remove(archiveGamePriority_name.Length - 1, Math.Abs(line.Length - archiveGamePriority_name.Length)); 120 | 121 | if (archivePriority_file.Equals(archivePriority_name)) 122 | { 123 | string a = line.Remove(0, archivePriority_file.Length); 124 | string noSpaces = a.Replace(" ", ""); 125 | string noEquals = noSpaces.Replace("=", ""); 126 | 127 | file_lines[index] = string.Format("{0} = {1}", archivePriority_name, archivePriority_value.ToString()); 128 | } 129 | 130 | if (archiveGamePriority_file.Equals(archivePriority_name)) 131 | { 132 | string a = line.Remove(0, archiveGamePriority_file.Length); 133 | string noSpaces = a.Replace(" ", ""); 134 | string noEquals = noSpaces.Replace("=", ""); 135 | 136 | file_lines[index] = string.Format("{0} = {1}", archiveGamePriority_name, archiveGamePriority_value.ToString()); 137 | } 138 | 139 | index++; 140 | } 141 | 142 | File.WriteAllLines(file, file_lines); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /TelltaleModLauncher/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("TelltaleModLauncher")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("TelltaleModLauncher")] 15 | [assembly: AssemblyCopyright("Copyright © 2020")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /TelltaleModLauncher/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace TelltaleModLauncher.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TelltaleModLauncher.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /TelltaleModLauncher/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /TelltaleModLauncher/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace TelltaleModLauncher.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /TelltaleModLauncher/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /TelltaleModLauncher/SetupWizard_Window.xaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 53 | 54 | 55 | 56 | 57 | 58 | Done 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /TelltaleModLauncher/SetupWizard_Window.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Shapes; 14 | using ControlzEx.Theming; 15 | using TelltaleModLauncher.Utillities; 16 | 17 | namespace TelltaleModLauncher 18 | { 19 | /// 20 | /// Interaction logic for SetupWizard.xaml 21 | /// 22 | public partial class SetupWizard_Window 23 | { 24 | //main objects passed down from MainWindow 25 | private AppSettings appSettings; 26 | private MainWindow mainWindow; 27 | private ModManager modManager; 28 | 29 | /// 30 | /// Initalizes the setup wizzard window. 31 | /// 32 | /// 33 | /// 34 | /// 35 | public SetupWizard_Window(AppSettings appSettings, MainWindow mainWindow, ModManager modManager) 36 | { 37 | InitializeComponent(); 38 | 39 | this.appSettings = appSettings; 40 | this.mainWindow = mainWindow; 41 | this.modManager = modManager; 42 | 43 | UpdateUI(); 44 | } 45 | 46 | /// 47 | /// Updates the UI elements to reflect the new data from the objects. 48 | /// 49 | public void UpdateUI() 50 | { 51 | string darkmodeTheme = appSettings.Get_AppSettings_LightMode() ? "Light.Blue" : "Dark.Blue"; 52 | ThemeManager.Current.ChangeTheme(this, darkmodeTheme); 53 | 54 | ui_window_appversion_label.Content = appSettings.appVersionString; 55 | ui_gamesetup_gameversion_combobox.ItemsSource = GameVersion_Functions.Get_Versions_StringList(true); 56 | ui_gamesetup_gamedirectoryexe_textbox.Text = appSettings.Get_Current_GameVersionSettings_GameExeLocation(); 57 | } 58 | 59 | /// 60 | /// Changes the theme of the window. 61 | /// 62 | /// 63 | public void UI_ChangeTheme(string theme) 64 | { 65 | ThemeManager.Current.ChangeTheme(this, theme); 66 | } 67 | 68 | //---------------- XAML FUNCTIONS ---------------- 69 | 70 | private void ui_gamesetup_gameversion_combobox_SelectionChanged(object sender, SelectionChangedEventArgs e) 71 | { 72 | GameVersion selectedGameVersion = (GameVersion)ui_gamesetup_gameversion_combobox.SelectedIndex; 73 | 74 | appSettings.ChangeGameVersion(selectedGameVersion); 75 | 76 | UpdateUI(); 77 | } 78 | 79 | private void ui_gamesetup_ttarchexePathNumber_combobox_SelectionChanged(object sender, SelectionChangedEventArgs e) 80 | { 81 | UpdateUI(); 82 | } 83 | 84 | private void ui_gamesetup_gamedirectoryexeBrowse_button_Click(object sender, RoutedEventArgs e) 85 | { 86 | appSettings.Set_Current_GameVersionSettings_GameExeLocation(); 87 | 88 | UpdateUI(); 89 | } 90 | 91 | private void ui_window_help_button_Click(object sender, RoutedEventArgs e) 92 | { 93 | appSettings.Open_LauncherHelpSetup(); 94 | 95 | UpdateUI(); 96 | } 97 | 98 | private void ui_gamesetup_done_Click(object sender, RoutedEventArgs e) 99 | { 100 | GameVersion selectedGameVersion = GameVersion_Functions.Get_Versions_ParseIntValue(ui_gamesetup_gameversion_combobox.SelectedIndex); 101 | appSettings.ChangeGameVersion(selectedGameVersion); 102 | 103 | modManager.ChangedGameVersion(); 104 | 105 | if(appSettings.IsGameSetupAndValid(true) == false) 106 | return; 107 | 108 | appSettings.UpdateChangesToFile(); 109 | 110 | this.Hide(); 111 | mainWindow.Show(); 112 | mainWindow.Activate(); 113 | } 114 | 115 | //---------------- XAML FUNCTIONS END ---------------- 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /TelltaleModLauncher/TelltaleModLauncher.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {863D1CA8-665D-471B-850D-1926A7CB9227} 8 | WinExe 9 | TelltaleModLauncher 10 | TelltaleModLauncher 11 | v4.7.2 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | true 16 | true 17 | A:\Work\MODDING\Github\Launcher\TelltaleModLauncher\builds\ 18 | true 19 | Disk 20 | false 21 | Foreground 22 | 7 23 | Days 24 | false 25 | false 26 | true 27 | true 28 | 0 29 | 1.0.0.%2a 30 | false 31 | false 32 | true 33 | 34 | 35 | AnyCPU 36 | true 37 | full 38 | false 39 | bin\Debug\ 40 | DEBUG;TRACE 41 | prompt 42 | 4 43 | true 44 | 45 | 46 | AnyCPU 47 | pdbonly 48 | true 49 | bin\Release\ 50 | TRACE 51 | prompt 52 | 4 53 | true 54 | 55 | 56 | icon.ico 57 | 58 | 59 | TelltaleModLauncher.App 60 | 61 | 62 | 63 | ..\packages\ControlzEx.4.4.0\lib\net462\ControlzEx.dll 64 | 65 | 66 | .\IconExtractor.dll 67 | 68 | 69 | ..\packages\MahApps.Metro.2.3.4\lib\net47\MahApps.Metro.dll 70 | 71 | 72 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.dll 73 | 74 | 75 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.BootstrapIcons.dll 76 | 77 | 78 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.BoxIcons.dll 79 | 80 | 81 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.Codicons.dll 82 | 83 | 84 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.Core.dll 85 | 86 | 87 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.Entypo.dll 88 | 89 | 90 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.EvaIcons.dll 91 | 92 | 93 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.FeatherIcons.dll 94 | 95 | 96 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.FileIcons.dll 97 | 98 | 99 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.Fontaudio.dll 100 | 101 | 102 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.FontAwesome.dll 103 | 104 | 105 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.ForkAwesome.dll 106 | 107 | 108 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.Ionicons.dll 109 | 110 | 111 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.JamIcons.dll 112 | 113 | 114 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.Material.dll 115 | 116 | 117 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.MaterialDesign.dll 118 | 119 | 120 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.MaterialLight.dll 121 | 122 | 123 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.Microns.dll 124 | 125 | 126 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.Modern.dll 127 | 128 | 129 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.Octicons.dll 130 | 131 | 132 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.PicolIcons.dll 133 | 134 | 135 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.PixelartIcons.dll 136 | 137 | 138 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.RadixIcons.dll 139 | 140 | 141 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.RemixIcon.dll 142 | 143 | 144 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.RPGAwesome.dll 145 | 146 | 147 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.SimpleIcons.dll 148 | 149 | 150 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.Typicons.dll 151 | 152 | 153 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.Unicons.dll 154 | 155 | 156 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.VaadinIcons.dll 157 | 158 | 159 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.WeatherIcons.dll 160 | 161 | 162 | ..\packages\MahApps.Metro.IconPacks.4.8.0\lib\net47\MahApps.Metro.IconPacks.Zondicons.dll 163 | 164 | 165 | ..\packages\Microsoft.Xaml.Behaviors.Wpf.1.1.19\lib\net45\Microsoft.Xaml.Behaviors.dll 166 | 167 | 168 | ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll 169 | 170 | 171 | ..\packages\Ookii.Dialogs.Wpf.1.2.0\lib\net45\Ookii.Dialogs.Wpf.dll 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 4.0 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | MSBuild:Compile 201 | Designer 202 | 203 | 204 | ModManager_ViewMod_ViewText.xaml 205 | 206 | 207 | 208 | SetupWizard_Window.xaml 209 | 210 | 211 | 212 | MSBuild:Compile 213 | Designer 214 | 215 | 216 | App.xaml 217 | Code 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | MainWindow.xaml 226 | Code 227 | 228 | 229 | Designer 230 | MSBuild:Compile 231 | 232 | 233 | Designer 234 | MSBuild:Compile 235 | 236 | 237 | Designer 238 | MSBuild:Compile 239 | 240 | 241 | 242 | 243 | 244 | 245 | ModManager_ViewMod.xaml 246 | 247 | 248 | Code 249 | 250 | 251 | True 252 | True 253 | Resources.resx 254 | 255 | 256 | True 257 | Settings.settings 258 | True 259 | 260 | 261 | ResXFileCodeGenerator 262 | Resources.Designer.cs 263 | 264 | 265 | 266 | SettingsSingleFileGenerator 267 | Settings.Designer.cs 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | False 276 | Microsoft .NET Framework 4.7.2 %28x86 and x64%29 277 | true 278 | 279 | 280 | False 281 | .NET Framework 3.5 SP1 282 | false 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | ; Move all assemblies and related files to lib folder 291 | ROBOCOPY "$(TargetDir) " "$(TargetDir)lib\ " /XF *.exe *.config *.manifest /XD lib logs data /E /IS /MOVE 292 | move /Y "$(TargetDir)lib\LibTelltale.dll" "$(TargetDir)" 293 | if %25errorlevel%25 leq 4 exit 0 else exit %25errorlevel%25 294 | 295 | -------------------------------------------------------------------------------- /TelltaleModLauncher/Utillities/IOManagement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | using System.Windows.Forms; 8 | using Ookii.Dialogs.Wpf; 9 | 10 | namespace TelltaleModLauncher.Utillities 11 | { 12 | /// 13 | /// This class contains common System.IO functions but 'enhanced' with safety checks, warnings, and error messages. 14 | /// It also contains other additional custom System.IO functions 15 | /// We recomend you use this class's functions in-place of the traditional System.IO functions 16 | /// 17 | public class IOManagement 18 | { 19 | /// 20 | /// Duplicate/Copy a file, this will output the copied file path 21 | /// 22 | /// 23 | /// 24 | /// 25 | public static void DuplicateFile(string originalFilePath, out string copiedFilePath, string copiedSuffix = "_duplicated") 26 | { 27 | copiedFilePath = "null"; 28 | 29 | //check if the file exists as a safety measure, if not then stop 30 | if (File.Exists(originalFilePath) == false) 31 | { 32 | //get our message 33 | string message = ""; 34 | 35 | if (string.IsNullOrEmpty(originalFilePath) || string.IsNullOrWhiteSpace(originalFilePath)) 36 | message = "No given file to duplicate!"; 37 | else 38 | message = originalFilePath + " - given file does not exist! Can't duplicate this file!"; 39 | 40 | //notify the user that this action is not possible 41 | MessageBoxes.Error(message, "ERROR"); 42 | 43 | //dont continue 44 | return; 45 | } 46 | 47 | //build the new file path string from the original 48 | string originalFileExtension = Path.GetExtension(originalFilePath); 49 | string originalFilename = Path.GetFileNameWithoutExtension(originalFilePath); 50 | string originalPath = Path.GetDirectoryName(originalFilePath); 51 | string newFileName = originalFilename + copiedSuffix + originalFileExtension; 52 | copiedFilePath = originalPath + "/" + newFileName; 53 | 54 | try 55 | { 56 | //duplicate the file 57 | File.Copy(originalFilePath, copiedFilePath); 58 | } 59 | catch (Exception e) 60 | { 61 | //we have an exception 62 | string message = string.Format("Can't Copy the file! Exception: {0}. Exception Message: {1}", e, e.Message); 63 | 64 | //notify the user that this action is not possible 65 | MessageBoxes.Error(message, "ERROR"); 66 | } 67 | } 68 | 69 | /// 70 | /// Duplicate/Copy a file to a specified directory 71 | /// 72 | /// 73 | /// 74 | /// 75 | public static void DuplicateFileToDirectory(string originalFilePath, string outputDirectory, bool sameNameAsOriginal = true) 76 | { 77 | string duplicatedFilePath = ""; 78 | string newFileName = ""; 79 | 80 | DuplicateFile(originalFilePath, out duplicatedFilePath); 81 | 82 | if (sameNameAsOriginal) 83 | { 84 | newFileName = Path.GetFileName(originalFilePath); 85 | } 86 | else 87 | { 88 | newFileName = Path.GetFileName(duplicatedFilePath); 89 | } 90 | 91 | string newOutputPath = Path.Combine(outputDirectory, newFileName); 92 | 93 | MoveFile(duplicatedFilePath, newOutputPath); 94 | } 95 | 96 | /// 97 | /// Duplicate/Copy a file and replace it with the original file 98 | /// 99 | /// 100 | /// 101 | public static void ReplaceFile(string originalFilePath, string newFilePath) 102 | { 103 | string duplicatedArchive = ""; 104 | 105 | DuplicateFile(newFilePath, out duplicatedArchive); 106 | DeleteFile(originalFilePath); 107 | MoveFile(duplicatedArchive, originalFilePath); 108 | } 109 | 110 | /// 111 | /// Move a given file to a new location. 112 | /// This can also be used to re-name files. 113 | /// Note: the new file path must contain the filename and extension. 114 | /// Example: originalFilePath = "OldPath/File.txt" newFilePath = "NewPath/File.txt" 115 | /// 116 | /// 117 | /// 118 | /// 119 | public static void MoveFile(string originalFilePath, string newFilePath, bool giveWarning = false) 120 | { 121 | //check if the file exists as a safety measure, if not then stop 122 | if (File.Exists(originalFilePath) == false) 123 | { 124 | //get our message 125 | string message = ""; 126 | 127 | if (string.IsNullOrEmpty(originalFilePath) || string.IsNullOrWhiteSpace(originalFilePath)) 128 | message = "No given file to move!"; 129 | else 130 | message = originalFilePath + " - given file does not exist! Can't move this file!"; 131 | 132 | //notify the user that this action is not possible 133 | MessageBoxes.Error(message, "ERROR"); 134 | 135 | //dont continue with the rest of the function 136 | return; 137 | } 138 | 139 | if (giveWarning) 140 | { 141 | //get our message 142 | string message = "Are you sure you want to move the following file? " + originalFilePath; 143 | 144 | if (MessageBoxes.Warning_Confirm(message, "Warning") == false) 145 | { 146 | //dont continue with the rest of the function 147 | return; 148 | } 149 | } 150 | 151 | try 152 | { 153 | //move the file 154 | File.Move(originalFilePath, newFilePath); 155 | } 156 | catch (Exception e) 157 | { 158 | //we have an IO exception 159 | string message = string.Format("Can't Move the file! Exception: {0}. Exception Message: {1}", e, e.Message); 160 | 161 | //notify the user that this action is not possible 162 | MessageBoxes.Error(message, "ERROR"); 163 | } 164 | } 165 | 166 | /// 167 | /// Create a given directory 168 | /// 169 | /// 170 | /// 171 | public static void CreateDirectory(string newDirectoryPath, bool giveWarning = false) 172 | { 173 | //check if the directory exists as a safety measure, if not then stop 174 | if (string.IsNullOrEmpty(newDirectoryPath) || string.IsNullOrWhiteSpace(newDirectoryPath)) 175 | { 176 | //get our message 177 | string message = "No given directory path to create!"; 178 | 179 | //notify the user that this action is not possible 180 | MessageBoxes.Error(message, "ERROR"); 181 | 182 | //dont continue with the rest of the function 183 | return; 184 | } 185 | 186 | if (giveWarning) 187 | { 188 | //get our message 189 | string message = "Are you sure you want to create the following directory? " + newDirectoryPath; 190 | 191 | //warn the user about the action 192 | if (MessageBoxes.Warning_Confirm(message, "Warning") == false) 193 | { 194 | //dont continue with the rest of the function 195 | return; 196 | } 197 | } 198 | 199 | try 200 | { 201 | //delete the file 202 | Directory.CreateDirectory(newDirectoryPath); 203 | } 204 | catch (Exception e) 205 | { 206 | //we have an IO exception 207 | string message = string.Format("Can't create the directory! Exception: {0}. Exception Message: {1}", e, e.Message); 208 | 209 | //notify the user that this action is not possible 210 | MessageBoxes.Error(message, "ERROR"); 211 | } 212 | } 213 | 214 | /// 215 | /// Move a given directory. 216 | /// 217 | /// 218 | /// 219 | /// 220 | public static void MoveDirectory(string oldDirectoryPath, string newDirectoryPath, bool giveWarning = false) 221 | { 222 | //check if the irectory exists as a safety measure, if not then stop 223 | if (Directory.Exists(oldDirectoryPath) == false) 224 | { 225 | //get our message 226 | string message = ""; 227 | 228 | if (string.IsNullOrEmpty(oldDirectoryPath) || string.IsNullOrWhiteSpace(oldDirectoryPath)) 229 | message = "No given directory path to move!"; 230 | else 231 | message = oldDirectoryPath + " - given create does not exist! Can't delete this directory!"; 232 | 233 | //notify the user that this action is not possible 234 | MessageBoxes.Error(message, "ERROR"); 235 | 236 | //dont continue with the rest of the function 237 | return; 238 | } 239 | 240 | if (giveWarning) 241 | { 242 | //get our message 243 | string message = "Are you sure you want to move the following directory? " + newDirectoryPath; 244 | 245 | //warn the user about the action 246 | if (MessageBoxes.Warning_Confirm(message, "Warning") == false) 247 | { 248 | //dont continue with the rest of the function 249 | return; 250 | } 251 | } 252 | 253 | try 254 | { 255 | //delete the file 256 | Directory.Move(oldDirectoryPath, newDirectoryPath); 257 | } 258 | catch (Exception e) 259 | { 260 | //we have an IO exception 261 | string message = string.Format("Can't move the directory! Exception: {0}. Exception Message: {1}", e, e.Message); 262 | 263 | //notify the user that this action is not possible 264 | MessageBoxes.Error(message, "ERROR"); 265 | } 266 | } 267 | 268 | /// 269 | /// Delete a given directory 270 | /// 271 | /// 272 | /// 273 | public static void DeleteDirectory(string originalDirectoryPath, bool giveWarning = false, bool recursiveDelete = false) 274 | { 275 | //check if the file exists as a safety measure, if not then stop 276 | if (Directory.Exists(originalDirectoryPath) == false) 277 | { 278 | //get our message 279 | string message = ""; 280 | 281 | if (string.IsNullOrEmpty(originalDirectoryPath) || string.IsNullOrWhiteSpace(originalDirectoryPath)) 282 | message = "No given file to delete!"; 283 | else 284 | message = originalDirectoryPath + " - given directory does not exist! Can't delete this directory!"; 285 | 286 | //notify the user that this action is not possible 287 | MessageBoxes.Error(message, "ERROR"); 288 | 289 | //dont continue with the rest of the function 290 | return; 291 | } 292 | 293 | if (giveWarning) 294 | { 295 | //get our message 296 | string message = "Are you sure you want to delete the following directory? " + originalDirectoryPath; 297 | 298 | //warn the user about the action 299 | if (MessageBoxes.Warning_Confirm(message, "Warning") == false) 300 | { 301 | //dont continue with the rest of the function 302 | return; 303 | } 304 | } 305 | 306 | try 307 | { 308 | //delete the file 309 | Directory.Delete(originalDirectoryPath, recursiveDelete); 310 | } 311 | catch (Exception e) 312 | { 313 | //we have an IO exception 314 | string message = string.Format("Can't Delete the directory! Exception: {0}. Exception Message: {1}", e, e.Message); 315 | 316 | //notify the user that this action is not possible 317 | MessageBoxes.Error(message, "ERROR"); 318 | } 319 | } 320 | 321 | /// 322 | /// Deletes all subdirectory/contents in directory 323 | /// 324 | /// 325 | /// 326 | /// 327 | public static void DeleteDirectoryContents(string directoryPath, bool giveWarning = false, bool recursiveDelete = false) 328 | { 329 | //check if the file exists as a safety measure, if not then stop 330 | if (Directory.Exists(directoryPath) == false) 331 | { 332 | //get our message 333 | string message = ""; 334 | 335 | if (string.IsNullOrEmpty(directoryPath) || string.IsNullOrWhiteSpace(directoryPath)) 336 | message = "No given file to delete!"; 337 | else 338 | message = directoryPath + " - given directory does not exist! Can't delete this directory!"; 339 | 340 | //notify the user that this action is not possible 341 | MessageBoxes.Error(message, "ERROR"); 342 | 343 | //dont continue with the rest of the function 344 | return; 345 | } 346 | 347 | if (giveWarning) 348 | { 349 | //get our message 350 | string message = "Are you sure you want to delete the contents in the following directory? " + directoryPath; 351 | 352 | //warn the user about the action 353 | if (MessageBoxes.Warning_Confirm(message, "Warning") == false) 354 | { 355 | //dont continue with the rest of the function 356 | return; 357 | } 358 | } 359 | 360 | try 361 | { 362 | //delete the directory 363 | foreach (string subDirectory in Directory.GetDirectories(directoryPath)) 364 | { 365 | Directory.Delete(subDirectory, recursiveDelete); 366 | } 367 | } 368 | catch (Exception e) 369 | { 370 | //we have an IO exception 371 | string message = string.Format("Can't delete the directory contents! Exception: {0}. Exception Message: {1}", e, e.Message); 372 | 373 | //notify the user that this action is not possible 374 | MessageBoxes.Error(message, "ERROR"); 375 | } 376 | } 377 | 378 | /// 379 | /// Delete a given file. 380 | /// 381 | /// 382 | /// 383 | public static void DeleteFile(string originalFilePath, bool giveWarning = false) 384 | { 385 | //check if the file exists as a safety measure, if not then stop 386 | if (File.Exists(originalFilePath) == false) 387 | { 388 | //get our message 389 | string message = ""; 390 | 391 | if (string.IsNullOrEmpty(originalFilePath) || string.IsNullOrWhiteSpace(originalFilePath)) 392 | message = "No given file to delete!"; 393 | else 394 | message = originalFilePath + " - given file does not exist! Can't delete this file!"; 395 | 396 | //notify the user that this action is not possible 397 | MessageBoxes.Error(message, "ERROR"); 398 | 399 | //dont continue with the rest of the function 400 | return; 401 | } 402 | 403 | if (giveWarning) 404 | { 405 | //get our message 406 | string message = "Are you sure you want to delete the following file? " + originalFilePath; 407 | 408 | //warn the user about the action 409 | if (MessageBoxes.Warning_Confirm(message, "Warning") == false) 410 | { 411 | //dont continue with the rest of the function 412 | return; 413 | } 414 | } 415 | 416 | try 417 | { 418 | //delete the file 419 | File.Delete(originalFilePath); 420 | } 421 | catch (Exception e) 422 | { 423 | //we have an IO exception 424 | string message = string.Format("Can't Delete the file! Exception: {0}. Exception Message: {1}", e, e.Message); 425 | 426 | //notify the user that this action is not possible 427 | MessageBoxes.Error(message, "ERROR"); 428 | } 429 | } 430 | 431 | /// 432 | /// Get the number of files in a directory by a specified file extension. 433 | /// 434 | /// 435 | /// 436 | /// 437 | public static int GetNumberOfFilesByExtension(string givenDirectory, string fileExtension) 438 | { 439 | //the return value 440 | int numberOfFiles = 0; 441 | 442 | //lets get our file list 443 | List filesInDirectory = new List(Directory.GetFiles(givenDirectory)); 444 | 445 | //loop through the list 446 | foreach (string file in filesInDirectory) 447 | { 448 | //increment our variable whenever we see what we are looking for 449 | if (Path.GetExtension(file).Equals(fileExtension)) 450 | { 451 | numberOfFiles++; 452 | } 453 | } 454 | 455 | return numberOfFiles; 456 | } 457 | 458 | /// 459 | /// Get the file paths in a given directory by a specified file extension. (include the period on the extension, like .txt) 460 | /// 461 | /// 462 | /// 463 | /// 464 | public static List GetFilesPathsByExtension(string givenDirectory, string fileExtension) 465 | { 466 | //the list we will be returning 467 | List filesPaths = new List(); 468 | 469 | //prepare our file list (only assigns it when there are files in the directory) 470 | List filesInDirectory = new List(); 471 | 472 | if (string.IsNullOrEmpty(givenDirectory) == false || string.IsNullOrWhiteSpace(givenDirectory) == false) 473 | filesInDirectory = new List(Directory.GetFiles(givenDirectory)); 474 | 475 | //loop through the list 476 | foreach (string file in filesInDirectory) 477 | { 478 | //add to the list whenever we see what we are looking for 479 | if (Path.GetExtension(file).Equals(fileExtension)) 480 | { 481 | filesPaths.Add(file); 482 | } 483 | } 484 | 485 | return filesPaths; 486 | } 487 | 488 | /// 489 | /// Delete the files in a given directory. 490 | /// 491 | /// 492 | /// 493 | /// 494 | /// 495 | public static void DeleteFilesInDirectory(string directory, bool warning = false, string promptDescription = "", string promptTitle = "") 496 | { 497 | if(warning) 498 | { 499 | if (MessageBoxes.Warning_Confirm(promptDescription, promptTitle) == false) 500 | return; 501 | } 502 | 503 | foreach (string filePath in Directory.GetFiles(directory)) 504 | { 505 | DeleteFile(filePath); 506 | } 507 | } 508 | 509 | /// 510 | /// Delete the sub directories in a given directory. 511 | /// 512 | /// 513 | /// 514 | /// 515 | /// 516 | public static void DeleteDirectoriesInDirectory(string mainDir, bool warning = false, string promptDescription = "", string promptTitle = "") 517 | { 518 | if (warning) 519 | { 520 | if (MessageBoxes.Warning_Confirm(promptDescription, promptTitle) == false) 521 | return; 522 | } 523 | 524 | foreach (string directory in Directory.GetDirectories(mainDir)) 525 | { 526 | DeleteDirectory(directory); 527 | } 528 | } 529 | 530 | //------------------------------ PROMPTS ------------------------------ 531 | //------------------------------ PROMPTS ------------------------------ 532 | //------------------------------ PROMPTS ------------------------------ 533 | 534 | /// 535 | /// Opens a FolderBrowserDialog for the user to select a folder path. 536 | /// 537 | /// 538 | /// 539 | public static void GetFolderPath(ref string newFolderPath, string dialogTitle = "Select a Folder Path") 540 | { 541 | //open a folder dialog 542 | VistaFolderBrowserDialog folderBrowserDialog = new VistaFolderBrowserDialog(); 543 | folderBrowserDialog.Description = dialogTitle; 544 | 545 | //open the dialog and cache the result 546 | var result = folderBrowserDialog.ShowDialog(); 547 | 548 | //if the user selected a path, return that string. 549 | if (result.HasValue && result.Value == true && !string.IsNullOrWhiteSpace(folderBrowserDialog.SelectedPath)) 550 | { 551 | newFolderPath = folderBrowserDialog.SelectedPath; 552 | } 553 | } 554 | 555 | /// 556 | /// Opens a FileBrowserDialog for the user to select a file path. 557 | /// 558 | /// 559 | /// 560 | public static void GetFilePath(ref string newFilePath, string dialogTitle = "Select a File Path") 561 | { 562 | //open a file dialog 563 | using (OpenFileDialog openFileDialog = new OpenFileDialog()) 564 | { 565 | //set our file dialog options here 566 | openFileDialog.Multiselect = false; 567 | openFileDialog.Title = dialogTitle; 568 | 569 | //open the dialog and cache the result 570 | DialogResult result = openFileDialog.ShowDialog(); 571 | 572 | //if the user selects a file, return that string. 573 | if (result == System.Windows.Forms.DialogResult.OK && !string.IsNullOrWhiteSpace(openFileDialog.FileName)) 574 | { 575 | newFilePath = openFileDialog.FileName; 576 | } 577 | } 578 | } 579 | 580 | /// 581 | /// Opens a FileBrowserDialog for the user to select a file path with a specified file extension. 582 | /// 583 | /// 584 | /// 585 | /// 586 | public static void GetFilePath(ref string newFilePath, string extensionFilter, string dialogTitle = "Select a File Path") 587 | { 588 | //open a file dialog 589 | using (OpenFileDialog openFileDialog = new OpenFileDialog()) 590 | { 591 | //set our file dialog options here 592 | openFileDialog.Multiselect = false; 593 | openFileDialog.RestoreDirectory = true; 594 | openFileDialog.Title = dialogTitle; 595 | openFileDialog.Filter = extensionFilter; 596 | 597 | //open the dialog and cache the result 598 | DialogResult result = openFileDialog.ShowDialog(); 599 | 600 | //if the user selects a file, return that string. 601 | if (result == System.Windows.Forms.DialogResult.OK && !string.IsNullOrWhiteSpace(openFileDialog.FileName)) 602 | { 603 | newFilePath = openFileDialog.FileName; 604 | } 605 | } 606 | } 607 | } 608 | } 609 | -------------------------------------------------------------------------------- /TelltaleModLauncher/Utillities/MessageBoxes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | 8 | namespace TelltaleModLauncher.Utillities 9 | { 10 | public class MessageBoxes 11 | { 12 | /// 13 | /// Shows a message box with a information icon and an OK button. 14 | /// 15 | /// 16 | /// 17 | public static void Info(string message, string caption) 18 | { 19 | MessageBox.Show(message, caption, MessageBoxButton.OK, MessageBoxImage.Information); 20 | } 21 | 22 | /// 23 | /// Shows a message box with a error icon and an OK button. 24 | /// 25 | /// 26 | /// 27 | public static void Error(string message, string caption) 28 | { 29 | MessageBox.Show(message, caption, MessageBoxButton.OK, MessageBoxImage.Error); 30 | } 31 | 32 | /// 33 | /// Shows a message box with a warning icon and an OK button. 34 | /// 35 | /// 36 | /// 37 | public static void Warning(string message, string caption) 38 | { 39 | MessageBox.Show(message, caption, MessageBoxButton.OK, MessageBoxImage.Warning); 40 | } 41 | 42 | /// 43 | /// Shows a message box with a information icon and an YesNo button. Yes = True, No = False 44 | /// 45 | /// 46 | /// 47 | /// 48 | public static bool Info_Confirm(string message, string caption) 49 | { 50 | MessageBoxResult result = MessageBox.Show(message, caption, MessageBoxButton.YesNo, MessageBoxImage.Information); 51 | 52 | return result == MessageBoxResult.Yes ? true : false; 53 | } 54 | 55 | /// 56 | /// Shows a message box with a error icon and an YesNo button. Yes = True, No = False 57 | /// 58 | /// 59 | /// 60 | /// 61 | public static bool Error_Confirm(string message, string caption) 62 | { 63 | MessageBoxResult result = MessageBox.Show(message, caption, MessageBoxButton.YesNo, MessageBoxImage.Error); 64 | 65 | return result == MessageBoxResult.Yes ? true : false; 66 | } 67 | 68 | /// 69 | /// Shows a message box with a warning icon and an YesNo button. Yes = True, No = False 70 | /// 71 | /// 72 | /// 73 | /// 74 | public static bool Warning_Confirm(string message, string caption) 75 | { 76 | MessageBoxResult result = MessageBox.Show(message, caption, MessageBoxButton.YesNo, MessageBoxImage.Warning); 77 | 78 | return result == MessageBoxResult.Yes ? true : false; 79 | } 80 | 81 | /// 82 | /// Shows a message box with a information icon and an YesNoCancel button. 0 = Yes, No = 1, Cancel = 2 83 | /// 84 | /// 85 | /// 86 | /// 87 | public static int Info_ConfirmOrCancel(string message, string caption) 88 | { 89 | MessageBoxResult result = MessageBox.Show(message, caption, MessageBoxButton.YesNoCancel, MessageBoxImage.Information); 90 | 91 | switch (result) 92 | { 93 | case MessageBoxResult.Yes: 94 | return 0; 95 | case MessageBoxResult.No: 96 | return 1; 97 | default: 98 | return 2; 99 | } 100 | } 101 | 102 | /// 103 | /// Shows a message box with a warning icon and an YesNoCancel button. 0 = Yes, No = 1, Cancel = 2 104 | /// 105 | /// 106 | /// 107 | /// 108 | public static int Warning_ConfirmOrCancel(string message, string caption) 109 | { 110 | MessageBoxResult result = MessageBox.Show(message, caption, MessageBoxButton.YesNoCancel, MessageBoxImage.Warning); 111 | 112 | switch (result) 113 | { 114 | case MessageBoxResult.Yes: 115 | return 0; 116 | case MessageBoxResult.No: 117 | return 1; 118 | default: 119 | return 2; 120 | } 121 | } 122 | 123 | /// 124 | /// Shows a message box with a error icon and an YesNoCancel button. 0 = Yes, No = 1, Cancel = 2 125 | /// 126 | /// 127 | /// 128 | /// 129 | public static int Error_ConfirmOrCancel(string message, string caption) 130 | { 131 | MessageBoxResult result = MessageBox.Show(message, caption, MessageBoxButton.YesNoCancel, MessageBoxImage.Error); 132 | 133 | switch (result) 134 | { 135 | case MessageBoxResult.Yes: 136 | return 0; 137 | case MessageBoxResult.No: 138 | return 1; 139 | default: 140 | return 2; 141 | } 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /TelltaleModLauncher/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Telltale-Modding-Group/TelltaleModLauncher/7aecde7dd45cc15b05fc69160848f4228efe55b7/TelltaleModLauncher/icon.ico -------------------------------------------------------------------------------- /TelltaleModLauncher/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /changes.txt: -------------------------------------------------------------------------------- 1 | v0.5.0 (1st release) 2 | - First Release 3 | 4 | v0.6.0 (2nd release) 5 | - [Added] "Add Mod" and Open Mod Folder" to the context menu for the Mod List on the 'Mod Manager' menu as additional functions for convenience. 6 | - [Added] feature for reading .txt files in a mod archive and viewing the contents of that .txt file. 7 | - [Added] application version number on the application bar 8 | - [Updated] Help URL 9 | 10 | v0.6.5 (3rd release) 11 | - [Removed] Creator Tab since it's no longer needed. The functionality and tools for creating mods will be moved seperately to the Telltale Script Editor and other related tools. 12 | - [Removed] Game Mods Folder field during setup since it isn't necessary for the user to define, the launcher now automatically finds the correct folder for the game. (causes less confusion during setup, makes things easier for the user) 13 | - [Removed] Lua Compiler dependency since it's not needed 14 | - [Removed] Lua Decompiler depedency since it's not needed 15 | - [Removed] Removed the dependencies tab and it's options since it's not needed, and other depedencies are handled internally. No setup needed for the user. 16 | 17 | v0.7.0 (W.I.P) 18 | - [Added] Support for most other Telltale Games (not all have been tested) 19 | - [Added] Launch Game Exe Icon preview 20 | - [Added] Window Defocusing effect when opening other windows in the app (helps with useability, can be toggled off) 21 | - [Added] Double click to browse for fields that display a file path 22 | - [Added] Tooltips to every interactable element (mouse over and it tells you about said element) 23 | - [Added] Mod list refresh button, it's also automated as well in the background. 24 | - [Added] Mod refresh to the context menu 25 | - [Added] Mods (if supported) can now place files in the game directory automatically (useful since some mods will have .ini config files) 26 | - [Added] Mod priorities are now displayed and visible, mod priorities can also be set and modified 27 | - [Changed] Mods are now sorted by priority 28 | - [Changed] Can still add/replace a mod even if it has both the same name and version (will give you a prompt instead of not allowing you to do it) 29 | - [Removed] ttarchexe depedency, which has now been replaced by LibTelltale (By Lucas Saragosa). 30 | - [Fix] Fixed issue when the launcher would crash when opening mod files that were not properly structured. (i.e. if you downloaded the source code zip of a project rather than the actual mod zip). Now it warns the user and displays an error 31 | - [Fix] Fixed issue when the launcher would crash on startup due to the file system watcher for mod refreshing 32 | -------------------------------------------------------------------------------- /screenshots/mod-install-tut/1-download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Telltale-Modding-Group/TelltaleModLauncher/7aecde7dd45cc15b05fc69160848f4228efe55b7/screenshots/mod-install-tut/1-download.png -------------------------------------------------------------------------------- /screenshots/mod-install-tut/1_1archive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Telltale-Modding-Group/TelltaleModLauncher/7aecde7dd45cc15b05fc69160848f4228efe55b7/screenshots/mod-install-tut/1_1archive.png -------------------------------------------------------------------------------- /screenshots/mod-install-tut/1_2archive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Telltale-Modding-Group/TelltaleModLauncher/7aecde7dd45cc15b05fc69160848f4228efe55b7/screenshots/mod-install-tut/1_2archive.png -------------------------------------------------------------------------------- /screenshots/mod-install-tut/2-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Telltale-Modding-Group/TelltaleModLauncher/7aecde7dd45cc15b05fc69160848f4228efe55b7/screenshots/mod-install-tut/2-open.png -------------------------------------------------------------------------------- /screenshots/mod-install-tut/3-locateandadd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Telltale-Modding-Group/TelltaleModLauncher/7aecde7dd45cc15b05fc69160848f4228efe55b7/screenshots/mod-install-tut/3-locateandadd.png -------------------------------------------------------------------------------- /screenshots/mod-install-tut/4-done.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Telltale-Modding-Group/TelltaleModLauncher/7aecde7dd45cc15b05fc69160848f4228efe55b7/screenshots/mod-install-tut/4-done.png -------------------------------------------------------------------------------- /screenshots/shot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Telltale-Modding-Group/TelltaleModLauncher/7aecde7dd45cc15b05fc69160848f4228efe55b7/screenshots/shot1.png -------------------------------------------------------------------------------- /screenshots/shot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Telltale-Modding-Group/TelltaleModLauncher/7aecde7dd45cc15b05fc69160848f4228efe55b7/screenshots/shot2.png --------------------------------------------------------------------------------