├── ModdingTools ├── steam_appid.txt ├── hueh.ico ├── Resources │ ├── ok.png │ ├── cook.png │ ├── dye.png │ ├── hat.png │ ├── play.png │ ├── save.png │ ├── about.png │ ├── badge.png │ ├── close.png │ ├── compile.png │ ├── console.png │ ├── delete.png │ ├── delete1.png │ ├── folder.png │ ├── generic.png │ ├── heeh_1b.png │ ├── heeh_2.png │ ├── heeh_3.png │ ├── loading.gif │ ├── msg.app.png │ ├── msg.exc.png │ ├── noimage.png │ ├── refresh.png │ ├── remix.png │ ├── steam.png │ ├── steam1.png │ ├── sticker.png │ ├── tools.png │ ├── weapon.png │ ├── compile4.gif │ ├── compncook.png │ ├── console1.png │ ├── deathwish.png │ ├── icon_004.png │ ├── icon_043.png │ ├── icon_044.png │ ├── icon_073.png │ ├── icon_164.png │ ├── minimize.png │ ├── msg.error.png │ ├── msg.info.png │ ├── msg.warn.png │ ├── uploaded.png │ ├── loading_text.png │ ├── msg.question.png │ ├── noimage_wide.png │ ├── settings-icon.png │ └── editorcrashedhueh4.png ├── steam_api64.dll ├── Steamworks.NET.dll ├── Logging │ ├── ILogger.cs │ ├── Handlers │ │ ├── DebuggerLogger.cs │ │ └── CommandLineLogger.cs │ └── Logger.cs ├── BuildData.cs ├── Engine │ ├── APNG │ │ ├── Chunks │ │ │ ├── IDATChunk.cs │ │ │ ├── IENDChunk.cs │ │ │ ├── OtherChunk.cs │ │ │ ├── acTLChunk.cs │ │ │ ├── IHDRChunk.cs │ │ │ ├── fdATChunk.cs │ │ │ ├── fcTLChunk.cs │ │ │ └── Chunk.cs │ │ ├── Helper.cs │ │ ├── Frame.cs │ │ └── CrcHelper.cs │ ├── EditorProcessStateWatchdog.cs │ ├── UpdateChecker.cs │ ├── Meme.cs │ ├── NamedPipe.cs │ ├── SteamWorkshopStorage.cs │ ├── ScriptWatcher.cs │ ├── UModelFacade.cs │ └── GameFinder.cs ├── Steam │ ├── AbstractModUploader.AbstractMethods.cs │ ├── AbstractModUploader.HelperMethods.cs │ ├── AbstractModUploader.cs │ └── SteamApiCallback.cs ├── GUI │ ├── ThemeConstants.cs │ ├── GUIWorker.cs │ ├── CategorySpacer.cs │ ├── ProcessRunner.cs │ ├── ArgEditorItem.cs │ ├── ARItem.cs │ ├── GUIProcessRunner.cs │ ├── BorderPanel.cs │ ├── ConfigList.cs │ ├── HuehProgressBar.cs │ ├── ARList.cs │ ├── GUIWorker.Designer.cs │ ├── ConfigItem.cs │ └── ContentBrowser.cs ├── packages.config ├── Headless │ ├── ConsoleProcessRunner.cs │ └── CommandLineOptions.cs ├── Windows │ ├── ChangelogWindow.cs │ ├── AboutWindow.cs │ ├── Tools │ │ ├── Benchmark.cs │ │ └── Benchmark.Designer.cs │ ├── ArgEditor.cs │ ├── ConfigWindow.cs │ ├── Validators │ │ └── ModdingValidators.cs │ ├── MapChooser.cs │ ├── WorkshopLocker.cs │ ├── ArrayInputWindow.cs │ └── ArgEditor.Designer.cs ├── Properties │ ├── AssemblyInfo.cs │ └── Settings.settings ├── app.config └── Modding │ └── ModDirectorySource.cs ├── Create-Release-Files.bat ├── ModdingTools.Cli ├── app.config ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── ModdingTools.Cli.csproj ├── ModdingTools.Updater ├── app.config ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ └── Resources.Designer.cs ├── ModdingTools.Updater.csproj ├── CUFormEx.cs ├── Program.cs ├── MainWindow.cs └── OMMHelper.cs ├── HeadlessModeCheatsheet.md ├── Create-Release-Files.ps1 ├── README.md ├── OpenModManager.sln ├── .gitattributes └── .gitignore /ModdingTools/steam_appid.txt: -------------------------------------------------------------------------------- 1 | 734880 -------------------------------------------------------------------------------- /ModdingTools/hueh.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/hueh.ico -------------------------------------------------------------------------------- /ModdingTools/Resources/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/ok.png -------------------------------------------------------------------------------- /ModdingTools/steam_api64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/steam_api64.dll -------------------------------------------------------------------------------- /ModdingTools/Resources/cook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/cook.png -------------------------------------------------------------------------------- /ModdingTools/Resources/dye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/dye.png -------------------------------------------------------------------------------- /ModdingTools/Resources/hat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/hat.png -------------------------------------------------------------------------------- /ModdingTools/Resources/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/play.png -------------------------------------------------------------------------------- /ModdingTools/Resources/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/save.png -------------------------------------------------------------------------------- /ModdingTools/Steamworks.NET.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Steamworks.NET.dll -------------------------------------------------------------------------------- /ModdingTools/Resources/about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/about.png -------------------------------------------------------------------------------- /ModdingTools/Resources/badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/badge.png -------------------------------------------------------------------------------- /ModdingTools/Resources/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/close.png -------------------------------------------------------------------------------- /ModdingTools/Resources/compile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/compile.png -------------------------------------------------------------------------------- /ModdingTools/Resources/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/console.png -------------------------------------------------------------------------------- /ModdingTools/Resources/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/delete.png -------------------------------------------------------------------------------- /ModdingTools/Resources/delete1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/delete1.png -------------------------------------------------------------------------------- /ModdingTools/Resources/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/folder.png -------------------------------------------------------------------------------- /ModdingTools/Resources/generic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/generic.png -------------------------------------------------------------------------------- /ModdingTools/Resources/heeh_1b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/heeh_1b.png -------------------------------------------------------------------------------- /ModdingTools/Resources/heeh_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/heeh_2.png -------------------------------------------------------------------------------- /ModdingTools/Resources/heeh_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/heeh_3.png -------------------------------------------------------------------------------- /ModdingTools/Resources/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/loading.gif -------------------------------------------------------------------------------- /ModdingTools/Resources/msg.app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/msg.app.png -------------------------------------------------------------------------------- /ModdingTools/Resources/msg.exc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/msg.exc.png -------------------------------------------------------------------------------- /ModdingTools/Resources/noimage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/noimage.png -------------------------------------------------------------------------------- /ModdingTools/Resources/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/refresh.png -------------------------------------------------------------------------------- /ModdingTools/Resources/remix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/remix.png -------------------------------------------------------------------------------- /ModdingTools/Resources/steam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/steam.png -------------------------------------------------------------------------------- /ModdingTools/Resources/steam1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/steam1.png -------------------------------------------------------------------------------- /ModdingTools/Resources/sticker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/sticker.png -------------------------------------------------------------------------------- /ModdingTools/Resources/tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/tools.png -------------------------------------------------------------------------------- /ModdingTools/Resources/weapon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/weapon.png -------------------------------------------------------------------------------- /Create-Release-Files.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | Powershell.exe -executionpolicy remotesigned -File Create-Release-Files.ps1 3 | pause -------------------------------------------------------------------------------- /ModdingTools/Resources/compile4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/compile4.gif -------------------------------------------------------------------------------- /ModdingTools/Resources/compncook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/compncook.png -------------------------------------------------------------------------------- /ModdingTools/Resources/console1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/console1.png -------------------------------------------------------------------------------- /ModdingTools/Resources/deathwish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/deathwish.png -------------------------------------------------------------------------------- /ModdingTools/Resources/icon_004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/icon_004.png -------------------------------------------------------------------------------- /ModdingTools/Resources/icon_043.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/icon_043.png -------------------------------------------------------------------------------- /ModdingTools/Resources/icon_044.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/icon_044.png -------------------------------------------------------------------------------- /ModdingTools/Resources/icon_073.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/icon_073.png -------------------------------------------------------------------------------- /ModdingTools/Resources/icon_164.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/icon_164.png -------------------------------------------------------------------------------- /ModdingTools/Resources/minimize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/minimize.png -------------------------------------------------------------------------------- /ModdingTools/Resources/msg.error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/msg.error.png -------------------------------------------------------------------------------- /ModdingTools/Resources/msg.info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/msg.info.png -------------------------------------------------------------------------------- /ModdingTools/Resources/msg.warn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/msg.warn.png -------------------------------------------------------------------------------- /ModdingTools/Resources/uploaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/uploaded.png -------------------------------------------------------------------------------- /ModdingTools/Resources/loading_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/loading_text.png -------------------------------------------------------------------------------- /ModdingTools/Resources/msg.question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/msg.question.png -------------------------------------------------------------------------------- /ModdingTools/Resources/noimage_wide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/noimage_wide.png -------------------------------------------------------------------------------- /ModdingTools/Resources/settings-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/settings-icon.png -------------------------------------------------------------------------------- /ModdingTools/Resources/editorcrashedhueh4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu8/OpenModManager/HEAD/ModdingTools/Resources/editorcrashedhueh4.png -------------------------------------------------------------------------------- /ModdingTools.Cli/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ModdingTools.Updater/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ModdingTools.Updater/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ModdingTools/Logging/ILogger.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Shared; 2 | 3 | namespace ModdingTools.Logging 4 | { 5 | interface ILogger 6 | { 7 | void Init(); 8 | void Append(string text, string sender, LogLevel level); 9 | void Unregister(); 10 | LogLevel VerbosityLevel(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ModdingTools.Cli/Program.cs: -------------------------------------------------------------------------------- 1 | using ModdingTools.Headless; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace ModdingTools.Cli 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | ProgramHeadless.MainHeadless(args); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ModdingTools/BuildData.cs: -------------------------------------------------------------------------------- 1 | namespace ModdingTools 2 | { 3 | class BuildData 4 | { 5 | public const string UpdateUrl = "https://hat.ovh/omm_version.txt"; 6 | public const string ReleasesPage = "https://github.com/mcu8/OpenModManager/releases/latest"; 7 | public const string ChangeLogUrl = "https://hat.ovh/omm_changelog.php"; 8 | public const long CurrentVersion = 159; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ModdingTools/Engine/APNG/Chunks/IDATChunk.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace LibAPNG 4 | { 5 | public class IDATChunk : Chunk 6 | { 7 | public IDATChunk(byte[] bytes) 8 | : base(bytes) 9 | { 10 | } 11 | 12 | public IDATChunk(MemoryStream ms) 13 | : base(ms) 14 | { 15 | } 16 | 17 | public IDATChunk(Chunk chunk) 18 | : base(chunk) 19 | { 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /ModdingTools/Engine/APNG/Chunks/IENDChunk.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace LibAPNG 4 | { 5 | public class IENDChunk : Chunk 6 | { 7 | public IENDChunk(byte[] bytes) 8 | : base(bytes) 9 | { 10 | } 11 | 12 | public IENDChunk(MemoryStream ms) 13 | : base(ms) 14 | { 15 | } 16 | 17 | public IENDChunk(Chunk chunk) 18 | : base(chunk) 19 | { 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /ModdingTools/Steam/AbstractModUploader.AbstractMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Web.UI; 6 | using System.Windows.Forms; 7 | 8 | namespace ModdingTools.Steam 9 | { 10 | public abstract partial class AbstractModUploader 11 | { 12 | protected abstract void SetStatusText(string text); 13 | protected abstract void SetProgress(int value); 14 | protected abstract void SetState(); 15 | protected abstract Form GetParentForm(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ModdingTools/Engine/APNG/Chunks/OtherChunk.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace LibAPNG 4 | { 5 | public class OtherChunk : Chunk 6 | { 7 | public OtherChunk(byte[] bytes) 8 | : base(bytes) 9 | { 10 | } 11 | 12 | public OtherChunk(MemoryStream ms) 13 | : base(ms) 14 | { 15 | } 16 | 17 | public OtherChunk(Chunk chunk) 18 | : base(chunk) 19 | { 20 | } 21 | 22 | protected override void ParseData(MemoryStream ms) 23 | { 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /ModdingTools/GUI/ThemeConstants.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | 3 | namespace ModdingTools.GUI 4 | { 5 | public class ThemeConstants 6 | { 7 | public static readonly Color BackgroundColor = Color.FromArgb(36, 36, 36); 8 | public static readonly Color ForegroundColor = Color.White; 9 | public static readonly Color BorderColor = Color.FromArgb(64, 64, 128); 10 | public static readonly Color TitleBarBackground = Color.Black; 11 | public static readonly Color TitleBarForeground = Color.White; 12 | public static readonly Color TileUnselected = Color.FromArgb(64, 64, 64); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ModdingTools/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /HeadlessModeCheatsheet.md: -------------------------------------------------------------------------------- 1 | # Cook mod 2 | ``` 3 | ModdingTools.Cli.exe --cookmod --mod=mod_folder_name_here 4 | ``` 5 | 6 | Example: `ModdingTools.Cli.exe --cookmod --mod=mcu8_maps_SpaceshipEx` 7 | 8 | # Compile mod 9 | ``` 10 | ModdingTools.Cli.exe --compilemod --mod=mod_folder_name_here 11 | ``` 12 | 13 | Example: `ModdingTools.Cli.exe --compilemod --mod=mcu8_maps_SpaceshipEx` 14 | 15 | # Mod list 16 | ``` 17 | ModdingTools.Cli.exe --modlist 18 | ``` 19 | 20 | # Launch editor 21 | ``` 22 | ModdingTools.Cli.exe --editor 23 | ``` 24 | 25 | # Test map 26 | ``` 27 | ModdingTools.Cli.exe --testmap=map_name_here 28 | ``` 29 | Example: `ModdingTools.Cli.exe --testmap=hatintimeentry` -------------------------------------------------------------------------------- /ModdingTools/Logging/Handlers/DebuggerLogger.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Shared; 2 | using System.Diagnostics; 3 | 4 | namespace ModdingTools.Logging.Handlers 5 | { 6 | public class DebuggerLogger : ILogger 7 | { 8 | 9 | public void Append(string text, string sender, LogLevel level) 10 | { 11 | string tag = "[" + Logger.GetLoggerDate() + "][" + Logger.GetLevelText(level) + "][" + sender + "]"; 12 | Debug.WriteLine(tag + text); 13 | } 14 | 15 | public void Init() 16 | { 17 | } 18 | 19 | public void Unregister() 20 | { 21 | } 22 | 23 | public LogLevel VerbosityLevel() 24 | { 25 | return LogLevel.Verbose; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ModdingTools/Engine/APNG/Chunks/acTLChunk.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace LibAPNG 4 | { 5 | public class acTLChunk : Chunk 6 | { 7 | public acTLChunk(byte[] bytes) 8 | : base(bytes) 9 | { 10 | } 11 | 12 | public acTLChunk(MemoryStream ms) 13 | : base(ms) 14 | { 15 | } 16 | 17 | public acTLChunk(Chunk chunk) 18 | : base(chunk) 19 | { 20 | } 21 | 22 | public uint NumFrames { get; private set; } 23 | 24 | public uint NumPlays { get; private set; } 25 | 26 | protected override void ParseData(MemoryStream ms) 27 | { 28 | NumFrames = Helper.ConvertEndian(ms.ReadUInt32()); 29 | NumPlays = Helper.ConvertEndian(ms.ReadUInt32()); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /ModdingTools/Headless/ConsoleProcessRunner.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Shared; 2 | using ModdingTools.Engine; 3 | using ModdingTools.Logging; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace ModdingTools.Headless 10 | { 11 | public class ConsoleProcessRunner : AbstractProcessRunner 12 | { 13 | public override void FinishAppRun() 14 | { 15 | } 16 | 17 | public override void Log(string msg, LogLevel level) 18 | { 19 | Logger.Log(level, msg); 20 | } 21 | 22 | public override void PostAppRun() 23 | { 24 | } 25 | 26 | public override void PreAppRun(bool cleanConsole, string taskName) 27 | { 28 | Logger.PrintBoxed($"Starting task: {taskName}...", ConsoleColor.White); 29 | } 30 | 31 | public override void PreRunWithoutWait() 32 | { 33 | } 34 | 35 | public override void SetText(string value) 36 | { 37 | Console.Title = value??""; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ModdingTools.Updater/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 ModdingTools.Updater.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ModdingTools/Headless/CommandLineOptions.cs: -------------------------------------------------------------------------------- 1 | using CommandLine; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace ModdingTools.Headless 8 | { 9 | class CommandLineOptions 10 | { 11 | [Option(Group = "task", HelpText = "Compile scripts")] 12 | public bool CompileMod { get; set; } 13 | 14 | [Option(Group = "task", HelpText = "Cook mod")] 15 | public bool CookMod { get; set; } 16 | 17 | [Option(Group = "task", HelpText = "Print mod list")] 18 | public bool ModList { get; set; } 19 | 20 | [Option(Group = "task", HelpText = "Launch editor")] 21 | public bool Editor { get; set; } 22 | 23 | [Option("testmap", HelpText = "Test map", Group = "task")] 24 | public string TestMap { get; set; } 25 | 26 | [Option("testmapall", HelpText = "Test map (all mods)", Group = "task")] 27 | public string TestMapAll { get; set; } 28 | 29 | [Option("mod", HelpText = "Mod folder name")] 30 | public string ModName { get; set; } 31 | 32 | [Option("nologo", HelpText = "Hide banner", Default = false)] 33 | public bool NoLogo { get; set; } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ModdingTools/Engine/EditorProcessStateWatchdog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Windows.Forms; 8 | 9 | namespace ModdingTools.Engine 10 | { 11 | internal class EditorProcessStateWatchdog 12 | { 13 | public bool IsEditorRunning { get; private set; } 14 | 15 | public event EventHandler EditorStateChanged; 16 | 17 | public EditorProcessStateWatchdog() { 18 | var th = new Thread(ThreadWorker); 19 | th.IsBackground = true; 20 | th.Start(); 21 | } 22 | 23 | private void ThreadWorker() 24 | { 25 | while (true) 26 | { 27 | try 28 | { 29 | var x = Process.GetProcessesByName("HatinTimeEditor"); 30 | var isRunning = x != null && x.Length > 0; 31 | if (isRunning != IsEditorRunning) 32 | { 33 | IsEditorRunning = isRunning; 34 | // trigger state change 35 | EditorStateChanged?.Invoke(this, EventArgs.Empty); 36 | } 37 | } 38 | catch (Exception) { } // nah 39 | Thread.Sleep(5000); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ModdingTools/Engine/APNG/Chunks/IHDRChunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace LibAPNG 5 | { 6 | public class IHDRChunk : Chunk 7 | { 8 | public IHDRChunk(byte[] chunkBytes) 9 | : base(chunkBytes) 10 | { 11 | } 12 | 13 | public IHDRChunk(MemoryStream ms) 14 | : base(ms) 15 | { 16 | } 17 | 18 | public IHDRChunk(Chunk chunk) 19 | : base(chunk) 20 | { 21 | } 22 | 23 | public int Width { get; private set; } 24 | 25 | public int Height { get; private set; } 26 | 27 | public byte BitDepth { get; private set; } 28 | 29 | public byte ColorType { get; private set; } 30 | 31 | public byte CompressionMethod { get; private set; } 32 | 33 | public byte FilterMethod { get; private set; } 34 | 35 | public byte InterlaceMethod { get; private set; } 36 | 37 | protected override void ParseData(MemoryStream ms) 38 | { 39 | Width = Helper.ConvertEndian(ms.ReadInt32()); 40 | Height = Helper.ConvertEndian(ms.ReadInt32()); 41 | BitDepth = Convert.ToByte(ms.ReadByte()); 42 | ColorType = Convert.ToByte(ms.ReadByte()); 43 | CompressionMethod = Convert.ToByte(ms.ReadByte()); 44 | FilterMethod = Convert.ToByte(ms.ReadByte()); 45 | InterlaceMethod = Convert.ToByte(ms.ReadByte()); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /ModdingTools/Windows/ChangelogWindow.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Windows; 2 | using ModdingTools.Engine; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Data; 7 | using System.Diagnostics; 8 | using System.Drawing; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Windows.Forms; 12 | 13 | namespace ModdingTools.Windows 14 | { 15 | public partial class ChangelogWindow : CUWindow 16 | { 17 | public ChangelogWindow(bool changelogOnly = false) 18 | { 19 | InitializeComponent(); 20 | webBrowser1.ScriptErrorsSuppressed = true; 21 | webBrowser1.DocumentText = ""; 22 | webBrowser1.Navigate(BuildData.ChangeLogUrl + "?ver=" + BuildData.CurrentVersion); 23 | if (changelogOnly) 24 | { 25 | this.IsResizable = true; 26 | this.IsCloseButtonEnabled = true; 27 | this.ControlBoxVisible = true; 28 | tableLayoutPanel1.Visible = false; 29 | label2.Visible = false; 30 | webBrowser1.Dock = DockStyle.Fill; 31 | this.Text = "CHANGELOG"; 32 | } 33 | } 34 | 35 | private void cuButton1_Click(object sender, EventArgs e) 36 | { 37 | this.DialogResult = DialogResult.Yes; 38 | } 39 | 40 | private void cuButton2_Click_1(object sender, EventArgs e) 41 | { 42 | this.DialogResult = DialogResult.No; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ModdingTools/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("OpenModManager")] 9 | [assembly: AssemblyDescription("Funni modding tool for A Hat in Time")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("m_cu8/m_cube")] 12 | [assembly: AssemblyProduct("OpenModManager")] 13 | [assembly: AssemblyCopyright("https://github.com/mcu8/OpenModManager")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("0569be64-ba84-4c53-9296-ee830f5a002f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ModdingTools.Updater/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("OpenModManager Updater")] 9 | [assembly: AssemblyDescription("Updater for OpenModManager")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("m_cu8/m_cube")] 12 | [assembly: AssemblyProduct("OpenModManager")] 13 | [assembly: AssemblyCopyright("https://github.com/mcu8/OpenModManager")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("25aaae0c-404d-4877-af19-f6245eb17f0e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /ModdingTools.Cli/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("OpenModManager (Console Interface)")] 9 | [assembly: AssemblyDescription("Funni modding tool for A Hat in Time")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("m_cu8/m_cube")] 12 | [assembly: AssemblyProduct("OpenModManager")] 13 | [assembly: AssemblyCopyright("https://github.com/mcu8/OpenModManager")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("0569be64-ba84-4c53-9296-ee830f5a002f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Create-Release-Files.ps1: -------------------------------------------------------------------------------- 1 | Clear-Host 2 | 3 | $scriptpath = $MyInvocation.MyCommand.Path 4 | $dir = Split-Path $scriptpath 5 | Write-host "My directory is $dir" 6 | 7 | $devenv = "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.com" 8 | 9 | $outputDir = Join-Path -Path $dir -Child "Release" 10 | $tmpDir = Join-Path -Path $outputDir -Child ".tmp" 11 | 12 | Remove-Item -Path $outputDir\*.* -Force -Recurse 13 | New-Item -Path $tmpDir -ItemType Directory -ErrorAction Ignore 14 | Remove-Item -Path $tmpDir\* -Force -Recurse 15 | 16 | $ommFiles = Join-Path -Path $dir -Child "ModdingTools.Cli\bin\Debug" 17 | $ommUpdaterFiles = Join-Path -Path $dir -Child "ModdingTools.Updater\bin\Debug" 18 | 19 | Remove-Item -Force $ommFiles\* 20 | Remove-Item -Force $ommUpdaterFiles\* 21 | 22 | $csproj = Join-Path -Path $dir -Child "OpenModManager.sln" 23 | & $devenv "$csproj" /build Debug 24 | 25 | Write-Host $ommFiles 26 | Copy-Item -Path $ommFiles\* -Recurse -Destination $tmpDir 27 | 28 | Write-Host $ommUpdaterFiles 29 | Copy-Item -Path $ommUpdaterFiles\* -Recurse -Destination $tmpDir 30 | 31 | Move-Item -Path $tmpDir\ModdingTools.Updater.exe -Destination $tmpDir\ModdingTools.Updater.New.exe 32 | Move-Item -Path $tmpDir\ModdingTools.Updater.pdb -Destination $tmpDir\ModdingTools.Updater.New.pdb 33 | 34 | Compress-Archive -Path $tmpDir\* -DestinationPath $outputDir\OpenModManager-bin.zip 35 | Remove-Item -Path $tmpDir -Recurse -Force 36 | 37 | $sha256 = Get-FileHash $outputDir\OpenModManager-bin.zip -Algorithm SHA256 | Select-Object -ExpandProperty Hash 38 | [IO.File]::WriteAllText("$outputDir\OpenModManager-bin.zip.sha256", ("$sha256".ToLower() + " OpenModManager-bin.zip") -join "`n") 39 | -------------------------------------------------------------------------------- /ModdingTools/Engine/APNG/Chunks/fdATChunk.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace LibAPNG 4 | { 5 | internal class fdATChunk : Chunk 6 | { 7 | public fdATChunk(byte[] bytes) 8 | : base(bytes) 9 | { 10 | } 11 | 12 | public fdATChunk(MemoryStream ms) 13 | : base(ms) 14 | { 15 | } 16 | 17 | public fdATChunk(Chunk chunk) 18 | : base(chunk) 19 | { 20 | } 21 | 22 | public uint SequenceNumber { get; private set; } 23 | 24 | public byte[] FrameData { get; private set; } 25 | 26 | protected override void ParseData(MemoryStream ms) 27 | { 28 | SequenceNumber = Helper.ConvertEndian(ms.ReadUInt32()); 29 | FrameData = ms.ReadBytes((int)Length - 4); 30 | } 31 | 32 | public IDATChunk ToIDATChunk() 33 | { 34 | uint newCrc; 35 | using (var msCrc = new MemoryStream()) 36 | { 37 | msCrc.WriteBytes(new[] {(byte)'I', (byte)'D', (byte)'A', (byte)'T'}); 38 | msCrc.WriteBytes(FrameData); 39 | 40 | newCrc = CrcHelper.Calculate(msCrc.ToArray()); 41 | } 42 | 43 | using (var ms = new MemoryStream()) 44 | { 45 | ms.WriteUInt32(Helper.ConvertEndian(Length - 4)); 46 | ms.WriteBytes(new[] {(byte)'I', (byte)'D', (byte)'A', (byte)'T'}); 47 | ms.WriteBytes(FrameData); 48 | ms.WriteUInt32(Helper.ConvertEndian(newCrc)); 49 | ms.Position = 0; 50 | 51 | return new IDATChunk(ms); 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /ModdingTools/Windows/AboutWindow.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Windows; 2 | using ModdingTools.Engine; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Data; 7 | using System.Diagnostics; 8 | using System.Drawing; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Windows.Forms; 12 | 13 | namespace ModdingTools.Windows 14 | { 15 | public partial class AboutWindow : CUWindow 16 | { 17 | public AboutWindow() 18 | { 19 | InitializeComponent(); 20 | label3.Text = $"App build number: {BuildData.CurrentVersion}"; 21 | } 22 | 23 | private void cuButton2_Click(object sender, EventArgs e) 24 | { 25 | Utils.StartInDefaultBrowser("https://hat.ovh"); 26 | } 27 | 28 | private void cuButton3_Click(object sender, EventArgs e) 29 | { 30 | Utils.StartInDefaultBrowser("https://github.com/mcu8/OpenModManager"); 31 | } 32 | 33 | private void cuButton1_Click(object sender, EventArgs e) 34 | { 35 | this.Close(); 36 | } 37 | 38 | private void cuButton4_Click(object sender, EventArgs e) 39 | { 40 | Utils.StartInDefaultBrowser("https://bsky.app/profile/m-cu.be"); 41 | } 42 | 43 | private void cuButton5_Click(object sender, EventArgs e) 44 | { 45 | Process.Start("steam://openurl/https://steamcommunity.com/id/m_cu8/myworkshopfiles/?appid=253230"); 46 | } 47 | 48 | private void cuButton6_Click(object sender, EventArgs e) 49 | { 50 | new ChangelogWindow(true).ShowDialog(this); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ModdingTools/Engine/UpdateChecker.cs: -------------------------------------------------------------------------------- 1 | using ModdingTools.Settings; 2 | using System; 3 | using System.Diagnostics; 4 | using System.Net; 5 | using System.Threading.Tasks; 6 | 7 | namespace ModdingTools.Engine 8 | { 9 | 10 | public class UpdateChecker 11 | { 12 | static readonly bool TestMode = false; 13 | 14 | private Action OnUpdateAvaiable; 15 | private string UpdateUrl; 16 | private long BuildNumber; 17 | 18 | public UpdateChecker(long buildNumber, string updateUrl, Action onUpdateAvaiable) 19 | { 20 | BuildNumber = buildNumber; 21 | UpdateUrl = updateUrl; 22 | OnUpdateAvaiable = onUpdateAvaiable; 23 | } 24 | 25 | public void CheckForUpdatesAsync() 26 | { 27 | if (!OMMSettings.Instance.UpdateCheck) 28 | { 29 | Debug.WriteLine("Updates disabled"); 30 | return; 31 | } 32 | Task.Factory.StartNew(() => 33 | { 34 | try 35 | { 36 | using (var wc = new WebClient()) 37 | { 38 | var remoteVersion = long.Parse(wc.DownloadString(UpdateUrl).Trim()); 39 | if (remoteVersion > BuildNumber || TestMode) 40 | { 41 | OnUpdateAvaiable?.Invoke(); 42 | } 43 | } 44 | } 45 | catch (Exception e) 46 | { 47 | Debug.WriteLine("!!" + e.Message); 48 | Debug.WriteLine("!!" + e.StackTrace); 49 | } 50 | }); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ModdingTools/Engine/Meme.cs: -------------------------------------------------------------------------------- 1 | using ModdingTools.Settings; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Media; 8 | using System.Text; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace ModdingTools.Engine 13 | { 14 | // Don't ask... 15 | class Meme 16 | { 17 | static SoundPlayer pl; 18 | static bool IsPlaying = false; 19 | 20 | public static void PlayElevatorMusic() 21 | { 22 | if (IsPlaying) return; // prevent the ear-rape 23 | if (!OMMSettings.Instance.Memes) return; 24 | var ph = Path.Combine(Program.GetAppRoot(), @"lol.wav"); 25 | if (!File.Exists(ph)) return; 26 | Debug.WriteLine("MemeStart()"); 27 | IsPlaying = false; 28 | Task.Factory.StartNew(() => 29 | { 30 | if (pl != null) 31 | { 32 | pl.Stop(); 33 | pl.Dispose(); 34 | pl = null; 35 | } 36 | 37 | pl = new SoundPlayer(ph); 38 | pl.PlayLooping(); // loop the music 39 | IsPlaying = true; 40 | while (IsPlaying) 41 | { 42 | Thread.Sleep(100); 43 | } 44 | pl.Stop(); 45 | IsPlaying = false; 46 | }); 47 | } 48 | 49 | public static void StopElevatorMusic() 50 | { 51 | if (!OMMSettings.Instance.Memes) return; 52 | Debug.WriteLine("MemeStop()"); 53 | IsPlaying = false; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ModdingTools/GUI/GUIWorker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Data; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using ModdingTools.Windows; 10 | 11 | namespace ModdingTools.GUI 12 | { 13 | public partial class GUIWorker : UserControl 14 | { 15 | public GUIWorker() 16 | { 17 | this.DoubleBuffered = true; 18 | InitializeComponent(); 19 | } 20 | 21 | public void SetStatus(string text) 22 | { 23 | SetStatus(text, Color.Empty); 24 | } 25 | 26 | public void SetProgress(int value, string text = null) 27 | { 28 | if (text == null) text = $"{value}%"; 29 | huehProgressBar1.Value = value; 30 | huehProgressBar1.Text = text; 31 | } 32 | 33 | public void SetStatus(string text, Color color) 34 | { 35 | if (this.InvokeRequired) 36 | { 37 | this.Invoke(new MethodInvoker(() => SetStatus(text, color))); 38 | return; 39 | } 40 | 41 | SetTextOrHideOnNull(color, text); 42 | } 43 | 44 | public void SetTextOrHideOnNull(string text = null) 45 | { 46 | SetTextOrHideOnNull(Color.Empty, text); 47 | } 48 | 49 | public void SetTextOrHideOnNull(Color color, string text = null) 50 | { 51 | if (text == null) 52 | { 53 | MainWindow.Instance.SetCard(MainWindow.CardControllerTabs.Mods); 54 | MainWindow.Instance.ToggleSearchBar(true); 55 | } 56 | else 57 | { 58 | cuGradientTextBox1.Insert(text, color); 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /ModdingTools/Windows/Tools/Benchmark.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Windows; 2 | using ModdingTools.GUI; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Data; 7 | using System.Diagnostics; 8 | using System.Drawing; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | using System.Windows.Forms; 14 | 15 | namespace ModdingTools.Windows.Tools 16 | { 17 | public partial class Benchmark : CUWindow 18 | { 19 | public Benchmark() 20 | { 21 | InitializeComponent(); 22 | } 23 | 24 | bool closing = false; 25 | 26 | Stopwatch sw = new Stopwatch(); 27 | public void Start() 28 | { 29 | sw.Start(); 30 | 31 | Task.Factory.StartNew(() => 32 | { 33 | while(sw.IsRunning) 34 | { 35 | if (closing) return; 36 | try 37 | { 38 | this.Invoke(new MethodInvoker(() => 39 | { 40 | label1.Text = sw.Elapsed.ToString(@"hh\:mm\:ss\.fff"); 41 | })); 42 | } 43 | catch (Exception) 44 | { 45 | break; 46 | } 47 | Thread.Sleep(10); 48 | } 49 | this.Invoke(new MethodInvoker(() => 50 | { 51 | label1.ForeColor = Color.Green; 52 | })); 53 | }); 54 | } 55 | 56 | public void Stop() 57 | { 58 | sw.Stop(); 59 | } 60 | 61 | private void Benchmark_FormClosing(object sender, FormClosingEventArgs e) 62 | { 63 | closing = true; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ModdingTools/GUI/CategorySpacer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Data; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using ModdingTools.Engine; 10 | 11 | namespace ModdingTools.GUI 12 | { 13 | public partial class CategorySpacer : UserControl 14 | { 15 | 16 | public delegate void OnToggle(CategorySpacer sender, bool state); 17 | public OnToggle Toggle = null; 18 | 19 | public delegate void OnHeaderClick(CategorySpacer sender); 20 | public OnHeaderClick HeaderClick = null; 21 | 22 | public CategorySpacer(string title, string subtitle) 23 | { 24 | InitializeComponent(); 25 | this.panel1.BackColor = ThemeConstants.BorderColor; 26 | this.label2.Text = title; 27 | this.label1.Text = subtitle; 28 | } 29 | 30 | public bool SelectionMode { get; set; } 31 | 32 | private bool _ToggleState; 33 | public bool ToggleState 34 | { 35 | get 36 | { 37 | return _ToggleState; 38 | } 39 | set 40 | { 41 | _ToggleState = value; 42 | CUButtonBorderless1.Image = (value) ? Properties.Resources.icon_044 : Properties.Resources.icon_043; 43 | Toggle?.Invoke(this, value); 44 | } 45 | } 46 | 47 | private void CUButtonBorderless1_Click(object sender, EventArgs e) 48 | { 49 | ToggleState = !ToggleState; 50 | } 51 | 52 | private void label1_Click(object sender, EventArgs e) 53 | { 54 | Utils.OpenInExplorer(label1.Text); 55 | } 56 | 57 | private void label2_Click(object sender, EventArgs e) 58 | { 59 | HeaderClick?.Invoke(this); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Open Mod Manager 2 | **For *A Hat in Time*** 3 | 4 | ![Screenshot](https://hat.ovh/omm.png) 5 | 6 | --- 7 | 8 | ### What is this? Flying boat? 9 | 10 | Nope — it's the **Mod Manager**, fully rewritten from scratch with new features: 11 | 12 | - Resizable window 13 | - Embedded console 14 | - "Mafia Punch™" button (for killing the editor when it stops responding) 15 | - Batch-building multiple mods at once 16 | - Fully dark-themed interface 17 | - Improved Asset Replacements editor 18 | - Mod configuration editor 19 | - Clipbook generator (from GIFs) 20 | - Asset exporter (supports `SoundNodeWave` and `Texture2D`) 21 | - Custom workshop uploader with advanced features 22 | - Search bar 23 | - Script watcher (automatically compiles scripts when modified — disabled by default) 24 | - Mod list context menu 25 | - Customizable command line arguments 26 | - Headless mode 27 | - VS Code integration 28 | - ...and more! 29 | 30 | You can find a ready-to-run version on the [Releases](https://github.com/mcu8/OpenModManager/releases/latest) page. 31 | 32 | --- 33 | 34 | ### Now with Steam Workshop Upload Support! 35 | 36 | Supports mod uploading via the **Steamworks API** (no more `Int32` issue)! 37 | ⚠️ Works only with the **Steam version** of the game and **64-bit operating systems** (since the game is 64-bit anyway). 38 | 🛠 Requires [.NET Framework v4.8](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48). 39 | 40 | --- 41 | 42 | ### Installation 43 | 44 | 1. Download the latest release from the [Releases](https://github.com/mcu8/OpenModManager/releases/latest) page. 45 | 2. Extract it to any folder. 46 | 3. Run the `ModdingTools.exe` executable. 47 | 48 | --- 49 | 50 | ### Building from Source 51 | 52 | 1. Clone the repository. 53 | 2. Open the solution in **Visual Studio 2022** or newer. 54 | 55 | --- 56 | 57 | ### Disclaimer 58 | 59 | This is an unofficial tool and is not affiliated with **Gears for Breakfast**. 60 | -------------------------------------------------------------------------------- /ModdingTools/GUI/ProcessRunner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using System.Diagnostics; 4 | using System.Runtime.InteropServices; 5 | using System.Threading.Tasks; 6 | using static ModdingTools.Engine.ProcessFactory; 7 | using System.Collections.Generic; 8 | using ModdingTools.Engine; 9 | using ModdingTools.Windows; 10 | using System.Text.RegularExpressions; 11 | using System.IO; 12 | using System.Threading; 13 | using System.Windows.Input; 14 | using System.Drawing; 15 | using CUFramework.Shared; 16 | using CUFramework.Controls; 17 | 18 | namespace ModdingTools.GUI 19 | { 20 | public partial class ProcessRunner : UserControl 21 | { 22 | public GUIProcessRunner Runner { get; private set; } 23 | 24 | public ProcessRunner() 25 | { 26 | InitializeComponent(); 27 | Runner = new GUIProcessRunner(this); 28 | 29 | SetText(null); 30 | mButton3.Visible = false; 31 | } 32 | 33 | public void SetText(string value) 34 | { 35 | if (this.InvokeRequired) 36 | { 37 | this.Invoke(new MethodInvoker(() => SetText(value))); 38 | } 39 | else 40 | { 41 | if (MainWindow.Instance != null) 42 | { 43 | MainWindow.Instance.GuiWorker.SetStatus(value); 44 | } 45 | 46 | if (value == null) Text = ""; 47 | else Text = value; 48 | } 49 | } 50 | 51 | public void Log(string msg, LogLevel level) 52 | { 53 | if (level >= LogLevel.Info) 54 | { 55 | MainWindow.Instance.GuiWorker.SetStatus(msg, CUConsoleControl.GetLevelColor(level)); 56 | } 57 | consoleControl1.Log(msg, level); 58 | } 59 | 60 | private void mButton3_Click(object sender, EventArgs e) 61 | { 62 | Runner.KillAllWorkers(); 63 | } 64 | 65 | private void mButton1_Click(object sender, EventArgs e) 66 | { 67 | consoleControl1.Clear(); 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /ModdingTools/Logging/Handlers/CommandLineLogger.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Shared; 2 | using System; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace ModdingTools.Logging.Handlers 7 | { 8 | public class CommandLineLogger : ILogger 9 | { 10 | public void Init() 11 | { 12 | try 13 | { 14 | Console.Title = "OMM"; 15 | } catch (IOException) 16 | { 17 | // just ignore for now 18 | } 19 | } 20 | 21 | public static void PrintBanner() 22 | { 23 | Logger.PrintBoxed(Properties.Resources.Banner + "\n\n" + "[Command Line mode]\nApp build number: " + BuildData.CurrentVersion, ConsoleColor.Yellow); 24 | 25 | Console.WriteLine(""); 26 | Console.WriteLine(""); 27 | } 28 | 29 | public void Append(string text, string sender, LogLevel level) 30 | { 31 | string tag = "[" + Logger.GetLoggerDate() + " " + Logger.GetLevelText(level) + "] "; 32 | 33 | switch (level) 34 | { 35 | case LogLevel.Success: 36 | Console.ForegroundColor = ConsoleColor.Green; 37 | break; 38 | case LogLevel.Error: 39 | Console.ForegroundColor = ConsoleColor.Red; 40 | break; 41 | case LogLevel.Warn: 42 | Console.ForegroundColor = ConsoleColor.Yellow; 43 | break; 44 | case LogLevel.Info: 45 | Console.ForegroundColor = ConsoleColor.White; 46 | break; 47 | case LogLevel.Verbose: 48 | Console.ForegroundColor = ConsoleColor.Gray; 49 | break; 50 | } 51 | 52 | Console.WriteLine(tag + text); 53 | Console.ResetColor(); 54 | } 55 | 56 | public void Unregister() 57 | { 58 | } 59 | 60 | public LogLevel VerbosityLevel() 61 | { 62 | return LogLevel.Info; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ModdingTools/GUI/ArgEditorItem.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Dialogs.Validators; 2 | using ModdingTools.Settings; 3 | using ModdingTools.Windows; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.ComponentModel; 7 | using System.Data; 8 | using System.Drawing; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Windows.Forms; 12 | using System.Windows.Input; 13 | 14 | namespace ModdingTools.GUI 15 | { 16 | public partial class ArgEditorItem : UserControl 17 | { 18 | private OMMSettings.ArgsDefaultsKeys MyKey; 19 | public ArgEditorItem(OMMSettings.ArgsDefaultsKeys key) 20 | { 21 | MyKey = key; 22 | InitializeComponent(); 23 | RefreshData(); 24 | } 25 | 26 | private void RefreshData() 27 | { 28 | label5.Text = OMMSettings.Instance.GetArgumentsFor(MyKey); 29 | label6.Text = OMMSettings.Instance.GetLocalizedArgKeyName(MyKey); 30 | if (label5.Text != OMMSettings.ArgsDefaults[MyKey]) 31 | { 32 | this.label6.Image = global::ModdingTools.Properties.Resources.delete; 33 | } 34 | else 35 | { 36 | this.label6.Image = global::ModdingTools.Properties.Resources.ok; 37 | } 38 | } 39 | 40 | public ArgEditorItem() 41 | { 42 | InitializeComponent(); 43 | } 44 | 45 | private void mButtonBorderless1_Click(object sender, EventArgs e) 46 | { 47 | OMMSettings.Instance.ResetArguments(MyKey); 48 | OMMSettings.Instance.Save(); 49 | RefreshData(); 50 | } 51 | 52 | private void label5_Click(object sender, EventArgs e) 53 | { 54 | var iw = CUInputWindow.Ask(this, $"Editing arguments for action: {MyKey}", "", new NonEmptyValidator(), label5.Text, true); 55 | if (iw != null && iw != label5.Text) 56 | { 57 | OMMSettings.Instance.ChangeArgument(MyKey, iw); 58 | OMMSettings.Instance.Save(); 59 | RefreshData(); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ModdingTools/Steam/AbstractModUploader.HelperMethods.cs: -------------------------------------------------------------------------------- 1 | using Steamworks; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace ModdingTools.Steam 8 | { 9 | public abstract partial class AbstractModUploader 10 | { 11 | private static string TranslateStatus(EItemUpdateStatus s) 12 | { 13 | switch (s) 14 | { 15 | case EItemUpdateStatus.k_EItemUpdateStatusInvalid: 16 | return "..."; 17 | case EItemUpdateStatus.k_EItemUpdateStatusCommittingChanges: 18 | return "Committing changes..."; 19 | case EItemUpdateStatus.k_EItemUpdateStatusPreparingConfig: 20 | return "Preparing config..."; 21 | case EItemUpdateStatus.k_EItemUpdateStatusPreparingContent: 22 | return "Preparing content..."; 23 | case EItemUpdateStatus.k_EItemUpdateStatusUploadingContent: 24 | return "Uploading content..."; 25 | case EItemUpdateStatus.k_EItemUpdateStatusUploadingPreviewFile: 26 | return "Uploading preview file..."; 27 | default: 28 | return s.ToString(); 29 | } 30 | } 31 | private static string BytesToString(ulong byteCount) 32 | { 33 | try 34 | { 35 | string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; //Longs run out around EB 36 | if (byteCount == 0) 37 | return "0" + suf[0]; 38 | long bytes = Math.Abs((long)byteCount); 39 | int place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024))); 40 | double num = Math.Round(bytes / Math.Pow(1024, place), 1); 41 | return (Math.Sign((long)byteCount) * num).ToString() + suf[place]; 42 | } 43 | catch (Exception e) 44 | { 45 | // normally, that shouldn't happen... but nah 46 | return byteCount + "B"; 47 | } 48 | } 49 | 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ModdingTools/GUI/ARItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Data; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using ModdingTools.Windows; 10 | using ModdingTools.Windows.Validators; 11 | 12 | namespace ModdingTools.GUI 13 | { 14 | public partial class ARItem : UserControl 15 | { 16 | public ARItem(string target, string replacement) 17 | { 18 | InitializeComponent(); 19 | label4.Text = target; 20 | label3.Text = replacement; 21 | } 22 | 23 | public string Target => label4.Text; 24 | public string Replacement => label3.Text; 25 | 26 | private void CUButtonBorderless1_Click(object sender, EventArgs e) 27 | { 28 | if (this.Parent is FlowLayoutPanel) 29 | { 30 | CallUpdateEvent(); 31 | this.Parent.Controls.Remove(this); 32 | } 33 | } 34 | 35 | private void label4_Click(object sender, EventArgs e) 36 | { 37 | var a = CUInputWindow.Ask(this, "AR Editor", "Please, enter the original asset name", new ARValidator(), label4.Text); 38 | if (a != null) 39 | { 40 | if (label4.Text != a) 41 | { 42 | label4.Text = a; 43 | CallUpdateEvent(); 44 | } 45 | } 46 | } 47 | 48 | private void label3_Click(object sender, EventArgs e) 49 | { 50 | var a = CUInputWindow.Ask(this, "AR Editor", "Please, enter the replacement asset name", new ARValidator(), label3.Text); 51 | if (a != null) 52 | { 53 | if (label3.Text != a) 54 | { 55 | label3.Text = a; 56 | CallUpdateEvent(); 57 | } 58 | } 59 | } 60 | 61 | private void CallUpdateEvent() 62 | { 63 | if (this.Parent.Parent is ARList) 64 | ((ARList)this.Parent.Parent).CallOnUpdateEvent(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ModdingTools/Engine/APNG/Helper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LibAPNG 4 | { 5 | internal class Helper 6 | { 7 | /// 8 | /// Convert big-endian to little-endian or reserve 9 | /// 10 | internal static byte[] ConvertEndian(byte[] i) 11 | { 12 | if (i.Length % 2 != 0) 13 | throw new Exception("byte array length must multiply of 2"); 14 | 15 | Array.Reverse(i); 16 | 17 | return i; 18 | } 19 | 20 | /// 21 | /// Convert big-endian to little-endian or reserve 22 | /// 23 | internal static int ConvertEndian(int i) 24 | { 25 | return BitConverter.ToInt32(ConvertEndian(BitConverter.GetBytes(i)), 0); 26 | } 27 | 28 | /// 29 | /// Convert big-endian to little-endian or reserve 30 | /// 31 | internal static uint ConvertEndian(uint i) 32 | { 33 | return BitConverter.ToUInt32(ConvertEndian(BitConverter.GetBytes(i)), 0); 34 | } 35 | 36 | /// 37 | /// Convert big-endian to little-endian or reserve 38 | /// 39 | internal static Int16 ConvertEndian(Int16 i) 40 | { 41 | return BitConverter.ToInt16(ConvertEndian(BitConverter.GetBytes(i)), 0); 42 | } 43 | 44 | /// 45 | /// Convert big-endian to little-endian or reserve 46 | /// 47 | internal static UInt16 ConvertEndian(UInt16 i) 48 | { 49 | return BitConverter.ToUInt16(ConvertEndian(BitConverter.GetBytes(i)), 0); 50 | } 51 | 52 | /// 53 | /// Compare two byte array 54 | /// 55 | public static bool IsBytesEqual(byte[] byte1, byte[] byte2) 56 | { 57 | if (byte1.Length != byte2.Length) 58 | return false; 59 | 60 | for (int i = 0; i < byte1.Length; i++) 61 | { 62 | if (byte1[i] != byte2[i]) 63 | return false; 64 | } 65 | return true; 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /ModdingTools/GUI/GUIProcessRunner.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Shared; 2 | using ModdingTools.Engine; 3 | using ModdingTools.Windows; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Web.UI; 9 | using System.Windows.Forms; 10 | 11 | namespace ModdingTools.GUI 12 | { 13 | public class GUIProcessRunner : AbstractProcessRunner 14 | { 15 | ProcessRunner Parent; 16 | public GUIProcessRunner(ProcessRunner parent) 17 | { 18 | this.Parent = parent; 19 | } 20 | 21 | public override void FinishAppRun() 22 | { 23 | Parent.Invoke(new MethodInvoker(() => 24 | { 25 | MainWindow.Instance.ToggleConsole(false); 26 | })); 27 | } 28 | 29 | public override void Log(string msg, LogLevel level) 30 | { 31 | Parent.Log(msg, level); 32 | } 33 | 34 | public override void PostAppRun() 35 | { 36 | if (runningProcesses.Count == 0) 37 | Parent.Invoke(new MethodInvoker(() => 38 | { 39 | Parent.mButton3.Visible = false; 40 | })); 41 | } 42 | 43 | public override void PreAppRun(bool cleanConsole, string taskName) 44 | { 45 | Parent.Invoke(new MethodInvoker(() => 46 | { 47 | if (cleanConsole) Parent.consoleControl1.Clear(); 48 | Parent.consoleControl1.Log(taskName, LogLevel.Verbose); 49 | MainWindow.Instance.CallWorker(); 50 | Parent.mButton3.Visible = true; 51 | })); 52 | } 53 | 54 | public override void PreRunWithoutWait() 55 | { 56 | Parent.Invoke(new MethodInvoker(() => 57 | { 58 | Program.Benchmark = new Windows.Tools.Benchmark(); 59 | Program.Benchmark.StartPosition = FormStartPosition.CenterScreen; 60 | Program.Benchmark.TopMost = true; 61 | Program.Benchmark.Show(); 62 | })); 63 | } 64 | 65 | public override void SetText(string value) 66 | { 67 | Parent.SetText(value); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /ModdingTools/Windows/ArgEditor.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Windows; 2 | using ModdingTools.GUI; 3 | using ModdingTools.Settings; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.ComponentModel; 7 | using System.Data; 8 | using System.Drawing; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Windows.Forms; 12 | using static ModdingTools.Settings.OMMSettings; 13 | 14 | namespace ModdingTools.Windows 15 | { 16 | public partial class ArgEditor : CUWindow 17 | { 18 | private static int BarOffset = 30; 19 | 20 | public ArgEditor() 21 | { 22 | InitializeComponent(); 23 | Init(); 24 | UpdateWidths(); 25 | } 26 | 27 | public void Init() 28 | { 29 | this.flowLayoutPanel1.SuspendLayout(); 30 | 31 | this.flowLayoutPanel1.Controls.Clear(); 32 | foreach (ArgsDefaultsKeys item in Enum.GetValues(typeof(OMMSettings.ArgsDefaultsKeys))) 33 | { 34 | var e = new ArgEditorItem(item); 35 | e.Padding = new Padding(0); 36 | e.Width = flowLayoutPanel1.ClientSize.Width - BarOffset; 37 | this.flowLayoutPanel1.Controls.Add(e); 38 | } 39 | this.flowLayoutPanel1.ResumeLayout(); 40 | } 41 | 42 | private void UpdateWidths(bool useHack = true) 43 | { 44 | flowLayoutPanel1.SuspendLayout(); 45 | foreach (var a in flowLayoutPanel1.Controls) 46 | { 47 | if (a is ArgEditorItem) 48 | { 49 | ((Control)a).Width = flowLayoutPanel1.ClientSize.Width - BarOffset; 50 | } 51 | } 52 | flowLayoutPanel1.ResumeLayout(); 53 | 54 | if (useHack) 55 | { 56 | this.flowLayoutPanel1.Width -= 1; 57 | this.flowLayoutPanel1.Width += 1; // little hack to force-update the layout 58 | } 59 | } 60 | 61 | private void flowLayoutPanel1_SizeChanged(object sender, EventArgs e) 62 | { 63 | 64 | } 65 | 66 | private void ArgEditor_SizeChanged(object sender, EventArgs e) 67 | { 68 | UpdateWidths(false); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ModdingTools/Steam/AbstractModUploader.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Dialogs; 2 | using ModdingTools.Engine; 3 | using ModdingTools.Modding; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Windows.Forms; 10 | 11 | namespace ModdingTools.Steam 12 | { 13 | // time to rewrite that mess... 14 | 15 | // Remember: you can use only one isntance of uploader at once!!! 16 | public abstract partial class AbstractModUploader 17 | { 18 | public bool IsUploaderRunning { get; protected set; } = false; 19 | 20 | // return true if success, otherwise false 21 | public bool UpdateOrUploadMod(ModObject mod, string changelog, string[] tags, bool keepUnCooked, bool keepScripts, int visibility, string description) 22 | { 23 | if (IsUploaderRunning) 24 | { 25 | GetParentForm().Invoke(new MethodInvoker(() => { 26 | CUMessageBox.Show(GetParentForm(), "Only one uploader instance can run at once!"); 27 | })); 28 | return false; 29 | } 30 | } 31 | 32 | private void PrepareUploadFolder(ModObject mod, bool keepScripts, bool keepUncookedContent) 33 | { 34 | var tmpDir = Path.Combine(Program.GetAppRoot(), "uploader_tmp"); 35 | if (Directory.Exists(tmpDir)) 36 | Directory.Delete(tmpDir, true); 37 | Directory.CreateDirectory(tmpDir); 38 | 39 | Utils.DirectoryCopy(mod.RootPath, tmpDir, true); 40 | 41 | if (!keepScripts) 42 | { 43 | if (Directory.Exists(Path.Combine(tmpDir, "CompiledScripts"))) 44 | Directory.Delete(Path.Combine(tmpDir, "CompiledScripts"), true); 45 | if (Directory.Exists(Path.Combine(tmpDir, "Classes"))) 46 | Directory.Delete(Path.Combine(tmpDir, "Classes"), true); 47 | } 48 | 49 | if (!keepUncookedContent) 50 | { 51 | if (Directory.Exists(Path.Combine(tmpDir, "Maps"))) 52 | Directory.Delete(Path.Combine(tmpDir, "Maps"), true); 53 | if (Directory.Exists(Path.Combine(tmpDir, "Content"))) 54 | Directory.Delete(Path.Combine(tmpDir, "Content"), true); 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /OpenModManager.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.33122.133 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModdingTools", "ModdingTools\ModdingTools.csproj", "{0569BE64-BA84-4C53-9296-EE830F5A002F}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModdingTools.Cli", "ModdingTools.Cli\ModdingTools.Cli.csproj", "{23733746-7020-4E5B-958F-E3AA34E9E60F}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModdingTools.Updater", "ModdingTools.Updater\ModdingTools.Updater.csproj", "{25AAAE0C-404D-4877-AF19-F6245EB17F0E}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E8DC7A4E-EEAB-4932-8AE6-3281C6BC6A69}" 13 | ProjectSection(SolutionItems) = preProject 14 | Create-Release-Files.bat = Create-Release-Files.bat 15 | Create-Release-Files.ps1 = Create-Release-Files.ps1 16 | EndProjectSection 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {0569BE64-BA84-4C53-9296-EE830F5A002F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {0569BE64-BA84-4C53-9296-EE830F5A002F}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {0569BE64-BA84-4C53-9296-EE830F5A002F}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {0569BE64-BA84-4C53-9296-EE830F5A002F}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {23733746-7020-4E5B-958F-E3AA34E9E60F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {23733746-7020-4E5B-958F-E3AA34E9E60F}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {23733746-7020-4E5B-958F-E3AA34E9E60F}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {23733746-7020-4E5B-958F-E3AA34E9E60F}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {25AAAE0C-404D-4877-AF19-F6245EB17F0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {25AAAE0C-404D-4877-AF19-F6245EB17F0E}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {25AAAE0C-404D-4877-AF19-F6245EB17F0E}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {25AAAE0C-404D-4877-AF19-F6245EB17F0E}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {323CAB77-0883-4EDD-BC2C-6F905872FD93} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /ModdingTools/GUI/BorderPanel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Windows.Forms; 7 | 8 | namespace ModdingTools.GUI 9 | { 10 | class BorderPanel : Panel 11 | { 12 | public BorderPanel() { 13 | 14 | this.Resize += (o, e) => 15 | { 16 | this.Invalidate(); 17 | }; 18 | this.BackColor = ThemeConstants.BackgroundColor; 19 | this.ForeColor = ThemeConstants.ForegroundColor; 20 | this.Padding = new Padding(0,0,0,0); 21 | 22 | this.Paint += BaseWindow_Paint; 23 | this.BorderStyle = BorderStyle.None; 24 | } 25 | 26 | public static void EatControl(Control c) 27 | { 28 | var f = new BorderPanel(); 29 | var parentC = c.Parent; 30 | var loc = c.Location; 31 | var size = c.Size; 32 | var index = c.TabIndex; 33 | var dock = c.Dock; 34 | var anchor = c.Anchor; 35 | 36 | c.Width -= 5; 37 | c.Height -= 4; 38 | 39 | if (c is TextBox) 40 | { 41 | ((TextBox)c).BorderStyle = BorderStyle.None; 42 | } 43 | 44 | c.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom; 45 | c.Location = new Point(2, 2); 46 | 47 | parentC.Controls.Remove(c); 48 | f.BorderStyle = BorderStyle.None; 49 | f.Location = loc; 50 | f.Size = size; 51 | f.TabIndex = index; 52 | f.Dock = dock; 53 | f.Anchor = anchor; 54 | f.Controls.Add(c); 55 | 56 | parentC.Controls.Add(f); 57 | } 58 | 59 | private void BaseWindow_Paint(object sender, PaintEventArgs e) 60 | { 61 | DrawBorder(e); 62 | } 63 | 64 | private int _border = 2; 65 | public int BorderThickness 66 | { 67 | get => _border; 68 | set 69 | { 70 | _border = value; 71 | Refresh(); 72 | } 73 | } 74 | 75 | public void DrawBorder(PaintEventArgs e) 76 | { 77 | var pen = new Pen(ThemeConstants.BorderColor); 78 | pen.Width = _border; 79 | 80 | var rect = new Rectangle(new Point(0, 0), new Size(this.Width - 2, this.Height - 2)); 81 | e.Graphics.DrawRectangle(pen, rect); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /ModdingTools/Steam/SteamApiCallback.cs: -------------------------------------------------------------------------------- 1 | using Steamworks; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | 9 | // let's rewrite that shit... 10 | namespace ModdingTools.Steam.SteamApiCallback 11 | { 12 | public class SteamCallbackEventArgs : EventArgs 13 | { 14 | public T CallbackResult { get; set; } 15 | public bool IOFailed { get; protected set; } 16 | 17 | public SteamCallbackEventArgs(T CallbackResult, bool IOFailed) 18 | { 19 | this.IOFailed = IOFailed; 20 | this.CallbackResult = CallbackResult; 21 | } 22 | } 23 | 24 | public abstract class SteamCallback 25 | { 26 | protected static CallResult CallResult; 27 | 28 | // it's static, cuz we only can run one callback at once... 29 | protected static bool IsRunning = false; 30 | 31 | public event EventHandler> OnCallbackFinished; 32 | 33 | public SteamCallback() 34 | { 35 | CallResult = CallResult.Create(OnItemCreated); 36 | } 37 | 38 | protected abstract SteamAPICall_t CreateCall(); 39 | 40 | public void Run() 41 | { 42 | if (IsRunning) 43 | { 44 | throw new Exception("Another callback is already running!"); 45 | } 46 | IsRunning = true; 47 | CallResult.Set(CreateCall()); 48 | SteamAPI.RunCallbacks(); 49 | } 50 | 51 | public Task RunAsync() 52 | { 53 | return Task.Factory.StartNew(() => Run()); 54 | } 55 | 56 | protected void OnCallFinished() 57 | { 58 | IsRunning = false; 59 | } 60 | 61 | protected void OnItemCreated(T callBack, bool bIOFailure) 62 | { 63 | OnCallFinished(); 64 | OnCallbackFinished?.Invoke(this, new SteamCallbackEventArgs(callBack, bIOFailure)); 65 | } 66 | } 67 | 68 | public class SteamCreateItemCallback : SteamCallback 69 | { 70 | private AppId_t AppId; 71 | private EWorkshopFileType EWorkshopFileType; 72 | 73 | public SteamCreateItemCallback(uint appId, EWorkshopFileType eWorkshopFileType = EWorkshopFileType.k_EWorkshopFileTypeCommunity) 74 | { 75 | AppId = new AppId_t(appId); 76 | EWorkshopFileType = eWorkshopFileType; 77 | } 78 | 79 | protected override SteamAPICall_t CreateCall() 80 | { 81 | return SteamUGC.CreateItem(AppId, EWorkshopFileType); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /ModdingTools/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | False 7 | 8 | 9 | False 10 | 11 | 12 | False 13 | 14 | 15 | True 16 | 17 | 18 | True 19 | 20 | 21 | False 22 | 23 | 24 | 25 | 26 | 27 | 0 28 | 29 | 30 | 8192 31 | 32 | 33 | False 34 | 35 | 36 | False 37 | 38 | 39 | False 40 | 41 | 42 | 0 43 | 44 | 45 | 46 | 47 | 48 | False 49 | 50 | 51 | False 52 | 53 | 54 | False 55 | 56 | 57 | -------------------------------------------------------------------------------- /ModdingTools/Engine/NamedPipe.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32.SafeHandles; 2 | using System; 3 | using System.Diagnostics; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace ModdingTools.Engine 7 | { 8 | // adapted from UnrealFrontend, for handling cooking&compiling output 9 | public class NamedPipe : IDisposable 10 | { 11 | [StructLayout(LayoutKind.Sequential)] 12 | public class Overlapped 13 | { 14 | } 15 | 16 | public const int INVALID_HANDLE_VALUE = -1; 17 | 18 | public const uint PIPE_ACCESS_INBOUND = 1u; 19 | 20 | public const uint PIPE_TYPE_BYTE = 0u; 21 | 22 | public const uint PIPE_READMODE_BYTE = 0u; 23 | 24 | private const uint BUFFER_SIZE = 1024u; 25 | 26 | private SafePipeHandle PipeHandle; 27 | 28 | [DllImport("kernel32", SetLastError = true)] 29 | public static extern SafePipeHandle CreateNamedPipe(string lpName, uint dwOpenMode, uint dwPipeMode, uint nMaxInstances, uint nOutBufferSize, uint nInBufferSize, uint nDefaultTimeOut, IntPtr pipeSecurityDescriptor); 30 | 31 | [DllImport("kernel32", SetLastError = true)] 32 | public static extern bool ConnectNamedPipe(SafePipeHandle hHandle, Overlapped lpOverlapped); 33 | 34 | [DllImport("kernel32", SetLastError = true)] 35 | public static extern bool DisconnectNamedPipe(SafePipeHandle hHandle); 36 | 37 | [DllImport("kernel32", SetLastError = true)] 38 | public static extern bool ReadFile(SafePipeHandle hHandle, byte[] lpBuffer, uint nNumberOfBytesToRead, byte[] lpNumberOfBytesRead, uint lpOverlapped); 39 | 40 | public void Disconnect() 41 | { 42 | DisconnectNamedPipe(PipeHandle); 43 | } 44 | 45 | public void Dispose() 46 | { 47 | Dispose(disposing: true); 48 | GC.SuppressFinalize(this); 49 | } 50 | 51 | protected virtual void Dispose(bool disposing) 52 | { 53 | if (disposing) 54 | { 55 | PipeHandle.Dispose(); 56 | } 57 | } 58 | 59 | public bool Connect(Process ClientProcess) 60 | { 61 | try 62 | { 63 | string lpName = "\\\\.\\pipe\\" + ClientProcess.Id + "cout"; 64 | PipeHandle = CreateNamedPipe(lpName, 1u, 0u, 1u, 1024u, 1024u, 1000u, IntPtr.Zero); 65 | if (PipeHandle.IsInvalid) 66 | { 67 | return false; 68 | } 69 | ConnectNamedPipe(PipeHandle, null); 70 | } 71 | catch (Exception) 72 | { 73 | return false; 74 | } 75 | return true; 76 | } 77 | 78 | public string Read() 79 | { 80 | byte[] array = new byte[1025]; 81 | byte[] array2 = new byte[4]; 82 | string text = ""; 83 | ReadFile(PipeHandle, array, 1024u, array2, 0u); 84 | int num = array2[0] + (array2[1] << 8) + (array2[2] << 16) + (array2[3] << 24); 85 | for (int i = 0; i < num; i += 2) 86 | { 87 | int num2 = array[i] + (array[i + 1] << 8); 88 | text += (char)num2; 89 | } 90 | return text; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /ModdingTools.Cli/ModdingTools.Cli.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {23733746-7020-4E5B-958F-E3AA34E9E60F} 8 | Exe 9 | ModdingTools.Cli 10 | ModdingTools.Cli 11 | v4.8 12 | 512 13 | true 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | {0569be64-ba84-4c53-9296-ee830f5a002f} 53 | ModdingTools 54 | False 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /ModdingTools/Engine/APNG/Chunks/fcTLChunk.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace LibAPNG 4 | { 5 | public enum DisposeOps 6 | { 7 | APNGDisposeOpNone = 0, 8 | APNGDisposeOpBackground = 1, 9 | APNGDisposeOpPrevious = 2, 10 | } 11 | 12 | public enum BlendOps 13 | { 14 | APNGBlendOpSource = 0, 15 | APNGBlendOpOver = 1, 16 | } 17 | 18 | public class fcTLChunk : Chunk 19 | { 20 | public fcTLChunk(byte[] bytes) 21 | : base(bytes) 22 | { 23 | } 24 | 25 | public fcTLChunk(MemoryStream ms) 26 | : base(ms) 27 | { 28 | } 29 | 30 | public fcTLChunk(Chunk chunk) 31 | : base(chunk) 32 | { 33 | } 34 | 35 | /// 36 | /// Sequence number of the animation chunk, starting from 0 37 | /// 38 | public uint SequenceNumber { get; private set; } 39 | 40 | /// 41 | /// Width of the following frame 42 | /// 43 | public uint Width { get; private set; } 44 | 45 | /// 46 | /// Height of the following frame 47 | /// 48 | public uint Height { get; private set; } 49 | 50 | /// 51 | /// X position at which to render the following frame 52 | /// 53 | public uint XOffset { get; private set; } 54 | 55 | /// 56 | /// Y position at which to render the following frame 57 | /// 58 | public uint YOffset { get; private set; } 59 | 60 | /// 61 | /// Frame delay fraction numerator 62 | /// 63 | public ushort DelayNum { get; private set; } 64 | 65 | /// 66 | /// Frame delay fraction denominator 67 | /// 68 | public ushort DelayDen { get; private set; } 69 | 70 | /// 71 | /// Type of frame area disposal to be done after rendering this frame 72 | /// 73 | public DisposeOps DisposeOp { get; private set; } 74 | 75 | /// 76 | /// Type of frame area rendering for this frame 77 | /// 78 | public BlendOps BlendOp { get; private set; } 79 | 80 | protected override void ParseData(MemoryStream ms) 81 | { 82 | SequenceNumber = Helper.ConvertEndian(ms.ReadUInt32()); 83 | Width = Helper.ConvertEndian(ms.ReadUInt32()); 84 | Height = Helper.ConvertEndian(ms.ReadUInt32()); 85 | XOffset = Helper.ConvertEndian(ms.ReadUInt32()); 86 | YOffset = Helper.ConvertEndian(ms.ReadUInt32()); 87 | DelayNum = Helper.ConvertEndian(ms.ReadUInt16()); 88 | DelayDen = Helper.ConvertEndian(ms.ReadUInt16()); 89 | DisposeOp = (DisposeOps)ms.ReadByte(); 90 | BlendOp = (BlendOps)ms.ReadByte(); 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /ModdingTools/Engine/APNG/Frame.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | 4 | namespace LibAPNG 5 | { 6 | /// 7 | /// Describe a single frame. 8 | /// 9 | public class Frame 10 | { 11 | public static byte[] Signature = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; 12 | 13 | private List idatChunks = new List(); 14 | private List otherChunks = new List(); 15 | 16 | /// 17 | /// Gets or Sets the acTL chunk 18 | /// 19 | public IHDRChunk IHDRChunk { get; set; } 20 | 21 | /// 22 | /// Gets or Sets the fcTL chunk 23 | /// 24 | public fcTLChunk fcTLChunk { get; set; } 25 | 26 | /// 27 | /// Gets or Sets the IEND chunk 28 | /// 29 | public IENDChunk IENDChunk { get; set; } 30 | 31 | /// 32 | /// Gets or Sets the other chunks 33 | /// 34 | public List OtherChunks 35 | { 36 | get { return otherChunks; } 37 | set { otherChunks = value; } 38 | } 39 | 40 | /// 41 | /// Gets or Sets the IDAT chunks 42 | /// 43 | public List IDATChunks 44 | { 45 | get { return idatChunks; } 46 | set { idatChunks = value; } 47 | } 48 | 49 | /// 50 | /// Add an Chunk to end end of existing list. 51 | /// 52 | public void AddOtherChunk(OtherChunk chunk) 53 | { 54 | otherChunks.Add(chunk); 55 | } 56 | 57 | /// 58 | /// Add an IDAT Chunk to end end of existing list. 59 | /// 60 | public void AddIDATChunk(IDATChunk chunk) 61 | { 62 | idatChunks.Add(chunk); 63 | } 64 | 65 | /// 66 | /// Gets the frame as PNG FileStream. 67 | /// 68 | public MemoryStream GetStream() 69 | { 70 | var ihdrChunk = new IHDRChunk(IHDRChunk); 71 | if (fcTLChunk != null) 72 | { 73 | // Fix frame size with fcTL data. 74 | ihdrChunk.ModifyChunkData(0, Helper.ConvertEndian(fcTLChunk.Width)); 75 | ihdrChunk.ModifyChunkData(4, Helper.ConvertEndian(fcTLChunk.Height)); 76 | } 77 | 78 | // Write image data 79 | var ms = new MemoryStream(); 80 | 81 | ms.WriteBytes(Signature); 82 | ms.WriteBytes(ihdrChunk.RawData); 83 | otherChunks.ForEach(o => ms.WriteBytes(o.RawData)); 84 | idatChunks.ForEach(i => ms.WriteBytes(i.RawData)); 85 | ms.WriteBytes(IENDChunk.RawData); 86 | 87 | ms.Flush(); 88 | ms.Position = 0; 89 | return ms; 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /ModdingTools/GUI/ConfigList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Data; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using ModdingTools.Windows; 10 | using ModdingTools.Modding; 11 | 12 | namespace ModdingTools.GUI 13 | { 14 | public partial class ConfigList : UserControl 15 | { 16 | private static int BarOffset = 10; 17 | private ModObject ModObj; 18 | 19 | public ConfigList() 20 | { 21 | InitializeComponent(); 22 | } 23 | 24 | public void Fill(ModObject o) 25 | { 26 | ModObj = o; 27 | 28 | this.flowLayoutPanel1.SuspendLayout(); 29 | 30 | this.flowLayoutPanel1.Controls.Clear(); 31 | foreach (var item in o.Config) 32 | { 33 | var e = new ConfigItem(item, o); 34 | e.Padding = new Padding(0); 35 | e.Width = flowLayoutPanel1.ClientSize.Width - BarOffset; 36 | this.flowLayoutPanel1.Controls.Add(e); 37 | } 38 | this.flowLayoutPanel1.ResumeLayout(); 39 | 40 | UpdateWidths(); 41 | } 42 | 43 | public void Append(ModObject.ModConfigItem conf, ModObject o) 44 | { 45 | this.flowLayoutPanel1.SuspendLayout(); 46 | 47 | var e = new ConfigItem(conf, o); 48 | e.Padding = new Padding(0); 49 | e.Width = flowLayoutPanel1.ClientSize.Width - BarOffset; 50 | this.flowLayoutPanel1.Controls.Add(e); 51 | 52 | this.flowLayoutPanel1.ResumeLayout(); 53 | 54 | UpdateWidths(); 55 | } 56 | 57 | private void UpdateWidths(bool useHack = true) 58 | { 59 | flowLayoutPanel1.SuspendLayout(); 60 | foreach (var a in flowLayoutPanel1.Controls) 61 | { 62 | if (a is ConfigItem) 63 | { 64 | ((Control)a).Width = flowLayoutPanel1.ClientSize.Width - BarOffset; 65 | } 66 | } 67 | flowLayoutPanel1.ResumeLayout(); 68 | 69 | if (useHack) 70 | { 71 | this.flowLayoutPanel1.Width -= 1; 72 | this.flowLayoutPanel1.Width += 1; // little hack to force-update the layout 73 | } 74 | } 75 | 76 | private void mButtonBorderless1_Click(object sender, EventArgs e) 77 | { 78 | var cfg = new ModObject.ModConfigItem(); 79 | ModObj.Config.Add(cfg); 80 | Append(cfg, ModObj); 81 | CallOnUpdateEvent(); 82 | } 83 | 84 | private void flowLayoutPanel1_SizeChanged(object sender, EventArgs e) 85 | { 86 | UpdateWidths(false); 87 | } 88 | 89 | public event EventHandler OnUpdate; 90 | public virtual void CallOnUpdateEvent() 91 | { 92 | OnUpdate?.Invoke(this, new EventArgs()); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /ModdingTools.Updater/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 ModdingTools.Updater.Properties { 12 | using System; 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", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ModdingTools.Updater.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ModdingTools/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | False 13 | 14 | 15 | False 16 | 17 | 18 | False 19 | 20 | 21 | True 22 | 23 | 24 | True 25 | 26 | 27 | False 28 | 29 | 30 | 31 | 32 | 33 | 0 34 | 35 | 36 | 8192 37 | 38 | 39 | False 40 | 41 | 42 | False 43 | 44 | 45 | False 46 | 47 | 48 | 0 49 | 50 | 51 | 52 | 53 | 54 | False 55 | 56 | 57 | False 58 | 59 | 60 | False 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /ModdingTools/Engine/SteamWorkshopStorage.cs: -------------------------------------------------------------------------------- 1 | using ModdingTools.Modding; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace ModdingTools.Engine 9 | { 10 | public class SteamWorkshopStorage 11 | { 12 | Dictionary SteamWorkshopData; 13 | private string FileName; 14 | 15 | public SteamWorkshopStorage(string fileName) 16 | { 17 | SteamWorkshopData = new Dictionary(StringComparer.InvariantCultureIgnoreCase); 18 | this.FileName = fileName; 19 | Reload(); 20 | } 21 | 22 | public long GetIdForMod(ModObject mod) 23 | { 24 | var dirname = mod.GetDirectoryName(); 25 | if (SteamWorkshopData.ContainsKey(dirname)) 26 | return SteamWorkshopData[dirname]; 27 | return 0; 28 | } 29 | 30 | public void SetIdForMod(ModObject mod, long value) 31 | { 32 | var dirname = mod.GetDirectoryName(); 33 | if (SteamWorkshopData.ContainsKey(dirname)) 34 | SteamWorkshopData[dirname] = value; 35 | else 36 | SteamWorkshopData.Add(dirname, value); 37 | Save(); 38 | } 39 | 40 | // New parser for the SteamWorkshop.ini file, maybe that will avoid parser mistakes... hopefully :huehpain: 41 | private void Reload() 42 | { 43 | SteamWorkshopData.Clear(); 44 | 45 | if (!File.Exists(FileName)) return; // just do nothing if it doesn't exists 46 | 47 | var data = File.ReadAllLines(FileName); 48 | 49 | var nextLineShouldHaveValue = false; 50 | var cachedPrevLineName = ""; 51 | foreach (var line in data) 52 | { 53 | var sanitized = line.Trim(); 54 | if (sanitized.StartsWith("#") || sanitized.StartsWith("//") || string.IsNullOrEmpty(sanitized)) continue; // skip comments and empty lines 55 | 56 | if (sanitized.StartsWith("[") && sanitized.EndsWith("]")) 57 | { 58 | cachedPrevLineName = sanitized.TrimStart('[').TrimEnd(']'); 59 | nextLineShouldHaveValue = true; 60 | } 61 | else if (nextLineShouldHaveValue && sanitized.Split('=')[0].Trim().StartsWith("WorkshopId")) 62 | { 63 | SteamWorkshopData.Add(cachedPrevLineName, long.Parse(sanitized.Split('=')[1].Trim())); 64 | nextLineShouldHaveValue = false; 65 | cachedPrevLineName = ""; 66 | } 67 | } 68 | } 69 | 70 | public void Save() 71 | { 72 | var b = new StringBuilder(); 73 | foreach (var e in SteamWorkshopData) 74 | { 75 | if (e.Value <= 0) continue; // skip empty values 76 | b.AppendLine($"[{e.Key}]"); 77 | b.AppendLine($"WorkshopId={e.Value}"); 78 | b.AppendLine(""); 79 | } 80 | File.WriteAllText(FileName, b.ToString()); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /ModdingTools/GUI/HuehProgressBar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Drawing.Drawing2D; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows.Forms; 9 | 10 | namespace ModdingTools.GUI 11 | { 12 | public class HuehProgressBar : System.Windows.Forms.Control 13 | { 14 | Timer Timer; 15 | Image i1, i2, i3; 16 | const float scale = 0.4f; 17 | 18 | private int _oldValue = -1; 19 | private string _oldText = null; 20 | public int Value { get; set; } = 0; 21 | public new string Text { get; set; } = "..."; 22 | public HuehProgressBar() 23 | { 24 | this.DoubleBuffered = true; 25 | 26 | i1 = ResizeImage(Properties.Resources.heeh_1b, scale); 27 | i2 = ResizeImage(Properties.Resources.heeh_2, scale); 28 | i3 = ResizeImage(Properties.Resources.heeh_3, scale); 29 | 30 | this.Paint += Form1_Paint; 31 | 32 | this.Timer = new Timer(); 33 | Timer.Interval = 10; 34 | Timer.Tick += Timer_Tick; 35 | Timer.Start(); 36 | } 37 | 38 | public static Image ResizeImage(Image image, float sc) 39 | { 40 | var new_width = image.Width * sc; 41 | var new_height = image.Height * sc; 42 | Bitmap new_image = new Bitmap((int)new_width, (int)new_height); 43 | Graphics g = Graphics.FromImage((Image)new_image); 44 | g.InterpolationMode = InterpolationMode.High; 45 | g.DrawImage(image, 0, 0, new_width, new_height); 46 | return new_image; 47 | } 48 | 49 | private void Form1_Paint(object sender, PaintEventArgs e) 50 | { 51 | var startPos = this.Height - i3.Height * 1; 52 | var clipOff = 20; 53 | 54 | var drawBrush = new SolidBrush(this.ForeColor); 55 | var drawFont = new Font(this.Font.FontFamily, this.Font.Size, this.Font.Style, this.Font.Unit); 56 | var drawFormat = new StringFormat(); 57 | drawFormat.Alignment = StringAlignment.Far; 58 | 59 | int posX = this.Width - (int)(i1.Width * 1.2f); //this.Width / 2 - i3.Width / 2; 60 | 61 | float progress = (this.Height - i3.Height - i1.Height) * (Math.Min((float)Value, 100f) / 100f); 62 | e.Graphics.SmoothingMode = SmoothingMode.None; 63 | e.Graphics.DrawImage(i2, new Rectangle(posX, startPos - (int)progress, i3.Width, (int)progress + clipOff)); 64 | e.Graphics.DrawImage(i3, posX, startPos); 65 | 66 | var y = startPos - (i1.Height) - progress + clipOff; 67 | e.Graphics.DrawImage(i1, posX, y); 68 | 69 | e.Graphics.DrawString(Text, drawFont, drawBrush, posX - clipOff, y + clipOff / 2, drawFormat); 70 | drawFont.Dispose(); 71 | } 72 | 73 | private void Timer_Tick(object sender, EventArgs e) 74 | { 75 | if (_oldText != Text || _oldValue != Value) 76 | { 77 | _oldText = Text; 78 | _oldValue = Value; 79 | this.Refresh(); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /ModdingTools/Windows/Tools/Benchmark.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ModdingTools.Windows.Tools 2 | { 3 | partial class Benchmark 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Benchmark)); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.SuspendLayout(); 34 | // 35 | // label1 36 | // 37 | this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 27.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 38 | this.label1.Location = new System.Drawing.Point(4, 44); 39 | this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); 40 | this.label1.Name = "label1"; 41 | this.label1.Size = new System.Drawing.Size(393, 127); 42 | this.label1.TabIndex = 1; 43 | this.label1.Text = "00:00:00"; 44 | this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 45 | // 46 | // Benchmark 47 | // 48 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; 49 | this.ClientSize = new System.Drawing.Size(400, 181); 50 | this.Controls.Add(this.label1); 51 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 52 | this.IsMaximizeButtonEnabled = false; 53 | this.IsMinimizeButtonEnabled = false; 54 | this.IsResizable = false; 55 | this.Location = new System.Drawing.Point(0, 0); 56 | this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); 57 | this.MaximumSize = new System.Drawing.Size(2560, 1268); 58 | this.MinimumSize = new System.Drawing.Size(400, 123); 59 | this.Name = "Benchmark"; 60 | this.Padding = new System.Windows.Forms.Padding(3, 2, 3, 2); 61 | this.Text = "EDITOR TAS SPEEDRUN ANY%"; 62 | this.TitlebarColor = System.Drawing.Color.Black; 63 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Benchmark_FormClosing); 64 | this.Controls.SetChildIndex(this.label1, 0); 65 | this.ResumeLayout(false); 66 | 67 | } 68 | 69 | #endregion 70 | 71 | private System.Windows.Forms.Label label1; 72 | } 73 | } -------------------------------------------------------------------------------- /ModdingTools/Modding/ModDirectorySource.cs: -------------------------------------------------------------------------------- 1 | using ModdingTools.Logging; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace ModdingTools.Modding 10 | { 11 | public class ModDirectorySource 12 | { 13 | public string Root { get; private set; } 14 | public string Name { get; private set; } 15 | 16 | public bool IsReadOnly { get; private set; } 17 | public bool Enabled { get; set; } 18 | public bool AutoLoad { get; set; } 19 | 20 | public ModObject FindModByScriptPath(string scriptPath) 21 | { 22 | var path = Path.GetFullPath(scriptPath).ToLower(); 23 | var mods = GetMods(); 24 | Logger.Log(CUFramework.Shared.LogLevel.Verbose, path); 25 | foreach (var mod in mods) 26 | { 27 | var x = Path.GetFullPath(mod.GetClassesDir()).ToLower(); 28 | Logger.Log(CUFramework.Shared.LogLevel.Verbose, x); 29 | 30 | // idk I'm skeptical about this method... but for testing it should be enough 31 | if (path.StartsWith(x)) 32 | return mod; 33 | } 34 | return null; 35 | } 36 | 37 | public ModObject[] GetMods(string modName = null) 38 | { 39 | List mods = new List(); 40 | if (!AutoLoad) 41 | return mods.ToArray(); 42 | 43 | if (!Directory.Exists(Root)) 44 | return mods.ToArray(); 45 | 46 | var paths = Directory.GetDirectories(Root); 47 | foreach (var path in paths) 48 | { 49 | if (modName != null) 50 | { 51 | if (!modName.Equals(Path.GetFileName(path), StringComparison.InvariantCultureIgnoreCase)) 52 | { 53 | continue; 54 | } 55 | } 56 | 57 | var modIniPath = Path.Combine(path, "modinfo.ini"); 58 | if (File.Exists(modIniPath)) 59 | { 60 | try 61 | { 62 | var mod = new ModObject(path, this); 63 | mods.Add(mod); 64 | } 65 | catch (Exception ex) 66 | { 67 | CUFramework.Dialogs.CUMessageBox.Show($"Mod parser failed while reading mod {path}!\n" + ex.Message + "\n" + ex.ToString()); 68 | Debug.WriteLine(":sealnyon: Oopsie woopsie!\n" + ex.Message + "\n" + ex.ToString()); 69 | } 70 | } 71 | } 72 | return mods.ToArray(); 73 | } 74 | 75 | public ModDirectorySource(string name, string path, bool autoLoad, bool defaultEnabled = true, bool isReadOnly = false) 76 | { 77 | this.Name = name; 78 | this.Root = path; 79 | this.AutoLoad = autoLoad; 80 | 81 | if (!Directory.Exists(path) && !isReadOnly) 82 | { 83 | Directory.CreateDirectory(path); 84 | } 85 | 86 | this.Enabled = defaultEnabled; 87 | this.IsReadOnly = isReadOnly; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /ModdingTools/Engine/APNG/Chunks/Chunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace LibAPNG 6 | { 7 | public class Chunk 8 | { 9 | internal Chunk() 10 | { 11 | Length = 0; 12 | ChunkType = String.Empty; 13 | ChunkData = null; 14 | Crc = 0; 15 | } 16 | 17 | internal Chunk(byte[] bytes) 18 | { 19 | var ms = new MemoryStream(bytes); 20 | Length = Helper.ConvertEndian(ms.ReadUInt32()); 21 | ChunkType = Encoding.ASCII.GetString(ms.ReadBytes(4)); 22 | ChunkData = ms.ReadBytes((int)Length); 23 | Crc = Helper.ConvertEndian(ms.ReadUInt32()); 24 | 25 | if (ms.Position != ms.Length) 26 | throw new Exception("Chunk length not correct."); 27 | if (Length != ChunkData.Length) 28 | throw new Exception("Chunk data length not correct."); 29 | 30 | ParseData(new MemoryStream(ChunkData)); 31 | } 32 | 33 | internal Chunk(MemoryStream ms) 34 | { 35 | Length = Helper.ConvertEndian(ms.ReadUInt32()); 36 | ChunkType = Encoding.ASCII.GetString(ms.ReadBytes(4)); 37 | ChunkData = ms.ReadBytes((int)Length); 38 | Crc = Helper.ConvertEndian(ms.ReadUInt32()); 39 | 40 | ParseData(new MemoryStream(ChunkData)); 41 | } 42 | 43 | internal Chunk(Chunk chunk) 44 | { 45 | Length = chunk.Length; 46 | ChunkType = chunk.ChunkType; 47 | ChunkData = chunk.ChunkData; 48 | Crc = chunk.Crc; 49 | 50 | ParseData(new MemoryStream(ChunkData)); 51 | } 52 | 53 | public uint Length { get; set; } 54 | 55 | public string ChunkType { get; set; } 56 | 57 | public byte[] ChunkData { get; set; } 58 | 59 | public uint Crc { get; set; } 60 | 61 | /// 62 | /// Get raw data of the chunk 63 | /// 64 | public byte[] RawData 65 | { 66 | get 67 | { 68 | var ms = new MemoryStream(); 69 | ms.WriteUInt32(Helper.ConvertEndian(Length)); 70 | ms.WriteBytes(Encoding.ASCII.GetBytes(ChunkType)); 71 | ms.WriteBytes(ChunkData); 72 | ms.WriteUInt32(Helper.ConvertEndian(Crc)); 73 | 74 | return ms.ToArray(); 75 | } 76 | } 77 | 78 | /// 79 | /// Modify the ChunkData part. 80 | /// 81 | public void ModifyChunkData(int postion, byte[] newData) 82 | { 83 | Array.Copy(newData, 0, ChunkData, postion, newData.Length); 84 | 85 | using (var msCrc = new MemoryStream()) 86 | { 87 | msCrc.WriteBytes(Encoding.ASCII.GetBytes(ChunkType)); 88 | msCrc.WriteBytes(ChunkData); 89 | 90 | Crc = CrcHelper.Calculate(msCrc.ToArray()); 91 | } 92 | } 93 | 94 | /// 95 | /// Modify the ChunkData part. 96 | /// 97 | public void ModifyChunkData(int postion, uint newData) 98 | { 99 | ModifyChunkData(postion, BitConverter.GetBytes(newData)); 100 | } 101 | 102 | protected virtual void ParseData(MemoryStream ms) 103 | { 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /ModdingTools/Windows/ConfigWindow.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Dialogs; 2 | using CUFramework.Windows; 3 | using ModdingTools.Engine; 4 | using ModdingTools.GUI; 5 | using ModdingTools.Settings; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.ComponentModel; 9 | using System.Data; 10 | using System.Diagnostics; 11 | using System.Drawing; 12 | using System.IO; 13 | using System.Linq; 14 | using System.Text; 15 | using System.Windows.Forms; 16 | 17 | namespace ModdingTools.Windows 18 | { 19 | public partial class ConfigWindow : CUWindow 20 | { 21 | public ConfigWindow() 22 | { 23 | InitializeComponent(); 24 | if (!DesignMode) 25 | { 26 | LoadSettings(); 27 | } 28 | } 29 | 30 | private void LoadSettings() 31 | { 32 | checkBox1.Checked = !OMMSettings.Instance.AutoScanDownloadedMods; 33 | checkBox2.Checked = OMMSettings.Instance.Memes; 34 | checkBox4.Checked = OMMSettings.Instance.MultilangCook; 35 | checkBox3.Checked = OMMSettings.Instance.RmShaderOnCook; 36 | checkBox5.Checked = OMMSettings.Instance.UpdateCheck; 37 | checkBox6.Checked = OMMSettings.Instance.FastCook; 38 | checkBox7.Checked = OMMSettings.Instance.VSCIntegration; 39 | checkBox8.Checked = OMMSettings.Instance.KillGameBeforeCooking; 40 | checkBox9.Checked = OMMSettings.Instance.KillEditorBeforeCooking; 41 | checkBox10.Checked = OMMSettings.Instance.MafiaPunchGameToo; 42 | checkBox11.Checked = OMMSettings.Instance.AlwaysloadedWorkaround; 43 | } 44 | 45 | private void SaveSettings() 46 | { 47 | OMMSettings.Instance.AutoScanDownloadedMods = !checkBox1.Checked; 48 | OMMSettings.Instance.Memes = checkBox2.Checked; 49 | OMMSettings.Instance.MultilangCook = checkBox4.Checked; 50 | OMMSettings.Instance.RmShaderOnCook = checkBox3.Checked; 51 | OMMSettings.Instance.UpdateCheck = checkBox5.Checked; 52 | OMMSettings.Instance.FastCook = checkBox6.Checked; 53 | OMMSettings.Instance.VSCIntegration = checkBox7.Checked; 54 | OMMSettings.Instance.KillGameBeforeCooking = checkBox8.Checked; 55 | OMMSettings.Instance.KillEditorBeforeCooking = checkBox9.Checked; 56 | OMMSettings.Instance.MafiaPunchGameToo = checkBox10.Checked; 57 | OMMSettings.Instance.AlwaysloadedWorkaround = checkBox11.Checked; 58 | OMMSettings.Instance.Save(); 59 | } 60 | 61 | private void mButton3_Click(object sender, EventArgs e) 62 | { 63 | this.Close(); 64 | } 65 | 66 | private void mButton2_Click(object sender, EventArgs e) 67 | { 68 | if (checkBox11.Checked && checkBox6.Checked) 69 | { 70 | CUMessageBox.Show("Fast script cooking and alwaysloaded workaround cannot be enabled at the same time!"); 71 | return; 72 | } 73 | 74 | SaveSettings(); 75 | this.Close(); 76 | } 77 | 78 | private void label1_Click(object sender, EventArgs e) 79 | { 80 | Utils.StartInDefaultBrowser("https://marketplace.visualstudio.com/items?itemName=EliotVU.uc"); 81 | } 82 | 83 | private void cuButton1_Click(object sender, EventArgs e) 84 | { 85 | Utils.KillUpdater(); 86 | Process.Start(Path.Combine(Program.GetAppRoot(), "ModdingTools.Updater.exe")); 87 | Program.CloseApp(0); 88 | } 89 | 90 | private void cuButton2_Click(object sender, EventArgs e) 91 | { 92 | var conf = new ArgEditor(); 93 | conf.StartPosition = FormStartPosition.CenterParent; 94 | conf.ShowDialog(); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /ModdingTools/Windows/Validators/ModdingValidators.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Dialogs.Validators; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Text.RegularExpressions; 8 | 9 | namespace ModdingTools.Windows.Validators 10 | { 11 | public class ModNameValidator : IValidator 12 | { 13 | public string Validate(string inputText) 14 | { 15 | if (inputText.Length < 3) 16 | { 17 | return "Mod name should have at least 3 characters"; 18 | } 19 | 20 | if (!Regex.IsMatch(inputText, @"^[a-zA-Z0-9_]+$")) 21 | { 22 | return "Invalid characters in mod folder name - you can only use numbers and letters and _"; 23 | } 24 | 25 | if (inputText.ToLower().Trim() == "newmod" || inputText.ToLower().Trim() == "mymod") 26 | { 27 | return "Seriously? Give it some more unique name..."; 28 | } 29 | 30 | string modName = inputText; 31 | string modsRoot = Path.Combine(Program.ProcFactory.GetGamePath(), @"HatinTimeGame\Mods"); 32 | string modPath = Path.Combine(modsRoot, modName); 33 | string modInfoPath = Path.Combine(modPath, "modinfo.ini"); 34 | 35 | if (File.Exists(modInfoPath)) 36 | { 37 | return "There's already a mod with name \"" + modName + "\". Please delete it or set it up."; 38 | } 39 | 40 | return null; 41 | } 42 | } 43 | 44 | public class ARValidator : IValidator 45 | { 46 | public string Validate(string inputText) 47 | { 48 | 49 | if (!Regex.IsMatch(inputText, @"[A-Za-z0-9]{1,255}\'[A-Za-z0-9\.\-_]{1,255}\'$")) 50 | { 51 | return "Invalid asset name!\nIt should look something like this: StaticMesh'MyPackage.MyMesh'"; 52 | } 53 | return null; 54 | } 55 | } 56 | 57 | public class WildcardValidator : IValidator 58 | { 59 | public string Validate(string inputText) 60 | { 61 | var e = inputText.Trim().Replace("/", "\\"); 62 | if (e.StartsWith("\\") || e.StartsWith(".\\")) 63 | return "Use only relative file paths here!"; 64 | 65 | if (e.Contains("..")) 66 | return "No, you can't use .. here..."; 67 | 68 | if (e.Contains("<") || e.Contains(">") || e.Contains("]") || e.Contains("|") || e.Contains("?") || e.Contains("\"") || e.Contains(":")) 69 | return "No, you can't use []|?<>\": characters here..."; 70 | 71 | if (e.EndsWith("\\")) 72 | return "Don't add \\ character at the end... If you want to exclude directory contents, type 'DirectoryName\\*' instead!"; 73 | 74 | var exploded = e.Split('\\'); 75 | if (exploded.Length > 1) 76 | { 77 | for (var x = 0; x != exploded.Length - 2; x++) 78 | if (exploded[x].Contains("*")) 79 | return "No, you can't use wildcards in the top directory names!"; 80 | } 81 | 82 | return null; 83 | } 84 | } 85 | 86 | public class SplitListValidator : IValidator 87 | { 88 | char SplitChar; 89 | public SplitListValidator(char splitChar) 90 | { 91 | this.SplitChar = splitChar; 92 | } 93 | 94 | public string Validate(string inputText) 95 | { 96 | if (inputText.Contains(SplitChar)) 97 | { 98 | return $"Item shouldn't contain the '{SplitChar}' character."; 99 | } 100 | return null; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /ModdingTools/Engine/ScriptWatcher.cs: -------------------------------------------------------------------------------- 1 | using ModdingTools.Modding; 2 | using ModdingTools.Windows; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Threading.Tasks; 7 | 8 | namespace ModdingTools.Engine 9 | { 10 | class ScriptWatcherManager 11 | { 12 | private static Dictionary WatcherProcesses = new Dictionary(); 13 | public static void AttachWatcher(ModObject o) 14 | { 15 | if (WatcherProcesses.ContainsKey(o.GetDirectoryName())) 16 | { 17 | return; 18 | } 19 | WatcherProcesses.Add(o.GetDirectoryName(), new ScriptWatcher(o)); 20 | } 21 | 22 | public static void DetachWatcher(ModObject o) 23 | { 24 | if (WatcherProcesses.ContainsKey(o.GetDirectoryName())) 25 | { 26 | WatcherProcesses[o.GetDirectoryName()].Dispose(); 27 | WatcherProcesses.Remove(o.GetDirectoryName()); 28 | } 29 | } 30 | 31 | public static bool IsWatcherAttached(ModObject o) 32 | { 33 | return WatcherProcesses.ContainsKey(o.GetDirectoryName()); 34 | } 35 | } 36 | 37 | class ScriptWatcher : IDisposable 38 | { 39 | FileSystemWatcher watcher; 40 | readonly ModObject Mod; 41 | 42 | public ScriptWatcher(ModObject mod) 43 | { 44 | this.Mod = mod; 45 | var path = mod.RootPath; 46 | 47 | // Create a new FileSystemWatcher and set its properties. 48 | watcher = new FileSystemWatcher(); 49 | watcher.Path = Path.Combine(path, "Classes"); 50 | 51 | /* Watch for changes in LastAccess and LastWrite times, and 52 | the renaming of files or directories. */ 53 | watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite 54 | | NotifyFilters.FileName | NotifyFilters.DirectoryName; 55 | 56 | // Only watch script files. 57 | watcher.Filter = "*.uc"; 58 | 59 | // Add event handlers. 60 | watcher.Changed += new FileSystemEventHandler(OnChanged); 61 | watcher.Renamed += new RenamedEventHandler(OnRenamed); 62 | 63 | watcher.EnableRaisingEvents = true; 64 | } 65 | 66 | 67 | 68 | // Define the event handlers. 69 | 70 | long lastMillis; 71 | private void OnChanged(object source, FileSystemEventArgs e) 72 | { 73 | if (Utils.GetUnixTimestamp(DateTime.Now) - lastMillis > 1000) 74 | { 75 | lastMillis = Utils.GetUnixTimestamp(DateTime.Now); 76 | } 77 | else 78 | { 79 | return; 80 | } 81 | 82 | try 83 | { 84 | watcher.EnableRaisingEvents = false; 85 | if (e.ChangeType == WatcherChangeTypes.Changed) 86 | { 87 | var ph = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(e.FullPath))); 88 | Mod.UnCookMod(); 89 | Task.Factory.StartNew(() => 90 | { 91 | MainWindow.Instance.Runner.KillAllWorkers(); 92 | Mod.CompileScripts(MainWindow.Instance.Runner, true); 93 | }); 94 | } 95 | 96 | } 97 | finally 98 | { 99 | watcher.EnableRaisingEvents = true; 100 | } 101 | } 102 | 103 | private void OnRenamed(object source, RenamedEventArgs e) 104 | { 105 | } 106 | 107 | public void Dispose() 108 | { 109 | watcher.Dispose(); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /ModdingTools/Windows/MapChooser.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Windows; 2 | using ModdingTools.Modding; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Data; 7 | using System.Drawing; 8 | using System.IO; 9 | using System.Linq; 10 | using System.Runtime.InteropServices; 11 | using System.Text; 12 | using System.Windows.Forms; 13 | using static ModdingTools.Windows.ModProperties; 14 | using static System.Windows.Forms.VisualStyles.VisualStyleElement; 15 | 16 | namespace ModdingTools.Windows 17 | { 18 | public partial class MapChooser : CUWindow 19 | { 20 | [DllImport("user32.dll")] 21 | static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); 22 | 23 | static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); 24 | const UInt32 SWP_NOSIZE = 0x0001; 25 | const UInt32 SWP_NOMOVE = 0x0002; 26 | const UInt32 SWP_SHOWWINDOW = 0x0040; 27 | 28 | private ModObject Mod; 29 | public MapChooser(ModObject o) 30 | { 31 | InitializeComponent(); 32 | Mod = o; 33 | 34 | this.HandleCreated += MapChooser_HandleCreated; 35 | 36 | string lastMap = ""; 37 | try 38 | { 39 | var flagFile = Path.Combine(Mod.RootPath, ".lastMap"); 40 | if (File.Exists(flagFile)) 41 | lastMap = File.ReadAllText(flagFile); 42 | } 43 | catch (Exception) 44 | { 45 | } 46 | 47 | comboBox1.Items.Add(new MapItem("hub_spaceship", "Spaceship", true)); 48 | comboBox1.Items.Add(new MapItem("mafia_town", "Mafia Town", true)); 49 | comboBox1.Items.Add(new MapItem("hatintimeentry", "HatInTimeEntry", true)); 50 | comboBox1.Items.Add(new MapItem("??menu", "Main Menu", true)); 51 | 52 | var maps = Mod.GetCookedMaps(); 53 | if (maps != null) 54 | foreach (var a in maps) 55 | { 56 | comboBox1.Items.Add(new MapItem(a, null, true)); 57 | if (a.Equals(Mod.IntroductionMap, StringComparison.InvariantCultureIgnoreCase)) 58 | { 59 | comboBox1.SelectedIndex = comboBox1.Items.Count - 1; 60 | } 61 | } 62 | if (comboBox1.SelectedIndex < 0) 63 | { 64 | comboBox1.SelectedIndex = 0; 65 | } 66 | 67 | if (string.IsNullOrEmpty(lastMap)) return; 68 | 69 | foreach(var x in comboBox1.Items) 70 | { 71 | var item = (MapItem)x; 72 | if (item.Name.Equals(lastMap, StringComparison.InvariantCultureIgnoreCase)) 73 | { 74 | comboBox1.SelectedItem = x; 75 | break; 76 | } 77 | } 78 | } 79 | 80 | private void MapChooser_HandleCreated(object sender, EventArgs e) 81 | { 82 | SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); 83 | } 84 | 85 | public string GetSelectedMap() 86 | { 87 | return ((MapItem)comboBox1.SelectedItem).Name; 88 | } 89 | 90 | private void mButton9_Click(object sender, EventArgs e) 91 | { 92 | var item = (MapItem)comboBox1.SelectedItem; 93 | try 94 | { 95 | File.WriteAllText(Path.Combine(Mod.RootPath, ".lastMap"), item.Name); 96 | } 97 | catch (Exception) { } 98 | this.DialogResult = DialogResult.OK; 99 | } 100 | 101 | private void cuButton1_Click(object sender, EventArgs e) 102 | { 103 | this.DialogResult = DialogResult.Cancel; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /ModdingTools/Engine/UModelFacade.cs: -------------------------------------------------------------------------------- 1 | using ModdingTools.Engine.TGA; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Drawing; 6 | using System.Drawing.Imaging; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | 11 | namespace ModdingTools.Engine 12 | { 13 | public class UModelFacade 14 | { 15 | 16 | public UModelFacade() 17 | { 18 | if (!File.Exists(GetUModelEXE())) 19 | { 20 | throw new Exception("Please, place the umodel.exe and SDL2.dll into the program root directory and try again!\nYou can download it from https://www.gildor.org/en/projects/umodel"); 21 | } 22 | } 23 | 24 | 25 | public enum ExportType 26 | { 27 | SoundNodeWave, Texture2D, StaticMesh, AnimSet, Font 28 | } 29 | 30 | private string GetUModelEXE() 31 | { 32 | return Path.Combine(Program.GetAppRoot(), "umodel.exe"); 33 | } 34 | 35 | private string GetTMPDir() 36 | { 37 | return Path.Combine(Program.GetAppRoot(), "ExporterTMP"); 38 | } 39 | 40 | public static string GetExtensionForType(ExportType exportType, bool forcePng = false) 41 | { 42 | string extension = null; 43 | switch (exportType) 44 | { 45 | case ExportType.SoundNodeWave: 46 | extension = ".ogg"; 47 | break; 48 | case ExportType.Texture2D: 49 | extension = forcePng ? ".png" : ".tga"; 50 | break; 51 | } 52 | return extension; 53 | } 54 | 55 | public bool Run(string args) 56 | { 57 | Debug.WriteLine("CmdArgs >> " + args); 58 | var p = new Process(); 59 | p.StartInfo.FileName = GetUModelEXE(); 60 | p.StartInfo.Arguments = args; 61 | p.StartInfo.UseShellExecute = false; 62 | p.StartInfo.CreateNoWindow = true; 63 | p.Start(); 64 | 65 | p.WaitForExit(); 66 | 67 | return p.ExitCode == 0; 68 | } 69 | 70 | public bool Export(string root, string package, string assetName, string group, ExportType exportType, string destination, bool forceTgaToPng = false) 71 | { 72 | var tmpDir = GetTMPDir(); 73 | if (Directory.Exists(tmpDir)) 74 | { 75 | Directory.Delete(tmpDir, true); 76 | } 77 | Directory.CreateDirectory(tmpDir); 78 | 79 | // .\umodel.exe -game=ue3 -path="C:\Program Files (x86)\Steam\steamapps\common\HatinTime\HatinTimeGame\EditorCookedPC" -export HatinTime_Music_Metro4 Act_4_Pink_Paw_Station -sounds -out=".\test" 80 | var res = Run($"-game=ue3 -path=\"{root}\" -3rdparty -groups -export {package} {assetName}{(exportType == ExportType.SoundNodeWave ? " -sounds" : " " + exportType.ToString())} -out=\"{tmpDir}\""); 81 | if (!res) 82 | { 83 | return false; 84 | } 85 | 86 | var extension = GetExtensionForType(exportType); 87 | 88 | var path = Path.Combine(tmpDir, package, group.Replace('.', Path.DirectorySeparatorChar), assetName + extension); 89 | Debug.WriteLine("ExceptedPath: " + path); 90 | 91 | if (File.Exists(path)) 92 | { 93 | if (File.Exists(destination)) 94 | { 95 | File.Delete(destination); 96 | } 97 | 98 | if (forceTgaToPng && exportType == ExportType.Texture2D) 99 | { 100 | using (var b = new TargaImage(path)) 101 | { 102 | b.Image.Save(destination, ImageFormat.Png); 103 | } 104 | } 105 | else 106 | { 107 | File.Move(path, destination); 108 | } 109 | return true; 110 | } 111 | 112 | return false; 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /ModdingTools/GUI/ARList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Data; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using ModdingTools.Windows; 10 | using ModdingTools.Windows.Validators; 11 | using CUFramework.Dialogs; 12 | 13 | namespace ModdingTools.GUI 14 | { 15 | public partial class ARList : UserControl 16 | { 17 | private static int BarOffset = 10; 18 | 19 | public ARList() 20 | { 21 | InitializeComponent(); 22 | } 23 | 24 | public void Fill(Dictionary dictonary) 25 | { 26 | this.flowLayoutPanel1.SuspendLayout(); 27 | 28 | this.flowLayoutPanel1.Controls.Clear(); 29 | foreach (var item in dictonary) 30 | { 31 | var e = new ARItem(item.Key, item.Value); 32 | e.Padding = new Padding(0); 33 | e.Width = flowLayoutPanel1.ClientSize.Width - BarOffset; 34 | this.flowLayoutPanel1.Controls.Add(e); 35 | } 36 | this.flowLayoutPanel1.ResumeLayout(); 37 | 38 | UpdateWidths(); 39 | } 40 | 41 | public void Append(string key, string val) 42 | { 43 | this.flowLayoutPanel1.SuspendLayout(); 44 | 45 | var e = new ARItem(key, val); 46 | e.Padding = new Padding(0); 47 | e.Width = flowLayoutPanel1.ClientSize.Width - BarOffset; 48 | this.flowLayoutPanel1.Controls.Add(e); 49 | 50 | this.flowLayoutPanel1.ResumeLayout(); 51 | 52 | UpdateWidths(); 53 | } 54 | 55 | private void UpdateWidths(bool useHack = true) 56 | { 57 | flowLayoutPanel1.SuspendLayout(); 58 | foreach (var a in flowLayoutPanel1.Controls) 59 | { 60 | if (a is ARItem) 61 | { 62 | ((Control)a).Width = flowLayoutPanel1.ClientSize.Width - BarOffset; 63 | } 64 | } 65 | flowLayoutPanel1.ResumeLayout(); 66 | 67 | if (useHack) 68 | { 69 | this.flowLayoutPanel1.Width -= 1; 70 | this.flowLayoutPanel1.Width += 1; // little hack to force-update the layout 71 | } 72 | } 73 | 74 | public Dictionary Collect() 75 | { 76 | var d = new Dictionary(); 77 | foreach (var a in flowLayoutPanel1.Controls) 78 | { 79 | if (a is ARItem) 80 | { 81 | var item = (ARItem)a; 82 | d.Add(item.Target, item.Replacement); 83 | } 84 | } 85 | return d; 86 | } 87 | 88 | private void CUButtonBorderless1_Click(object sender, EventArgs e) 89 | { 90 | string source = CUInputWindow.Ask(this, "Asset Replacement: from", "Enter the asset name which you want to replace", new ARValidator()); 91 | if (source != null) 92 | { 93 | if (Collect().Where(item => item.Key.ToLowerInvariant() == source.ToLowerInvariant()).Count() > 0) 94 | { 95 | CUMessageBox.Show("ARList already contains item with key: " + source, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); 96 | return; 97 | } 98 | 99 | string target = CUInputWindow.Ask(this, "Asset Replacement: to", $"Replacement: {source}{Environment.NewLine}Enter the target asset name", new ARValidator()); 100 | if (target != null) 101 | { 102 | Append(source, target); 103 | CallOnUpdateEvent(); 104 | } 105 | } 106 | } 107 | 108 | private void flowLayoutPanel1_SizeChanged(object sender, EventArgs e) 109 | { 110 | UpdateWidths(false); 111 | } 112 | 113 | public event EventHandler OnUpdate; 114 | public virtual void CallOnUpdateEvent() 115 | { 116 | OnUpdate?.Invoke(this, new EventArgs()); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /ModdingTools/Windows/WorkshopLocker.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Dialogs; 2 | using CUFramework.Windows; 3 | using ModdingTools.Engine; 4 | using System; 5 | using System.Drawing; 6 | using System.IO; 7 | using System.Security.AccessControl; 8 | using System.Security.Principal; 9 | 10 | namespace ModdingTools.Windows 11 | { 12 | public partial class WorkshopLocker : CUWindow 13 | { 14 | public WorkshopLocker() 15 | { 16 | InitializeComponent(); 17 | UpdateState(); 18 | } 19 | 20 | private void UpdateState() 21 | { 22 | var wsDir = GameFinder.GetWorkshopDir(); 23 | if (!Directory.Exists(wsDir)) 24 | Directory.CreateDirectory(wsDir); 25 | DirectoryInfo dInfo = new DirectoryInfo(wsDir); 26 | try 27 | { 28 | var testFile = Path.Combine(wsDir, ".test"); 29 | File.WriteAllText(testFile, "test"); 30 | File.Delete(testFile); 31 | label1.Text = "UNLOCKED"; 32 | label1.ForeColor = Color.Green; 33 | } 34 | catch (UnauthorizedAccessException) 35 | { 36 | label1.Text = "LOCKED"; 37 | label1.ForeColor = Color.Red; 38 | } 39 | } 40 | 41 | 42 | public void ChangeLockState(string path, bool unlocked) 43 | { 44 | try 45 | { 46 | RemoveOldProtection(path); 47 | var x = path + ".disabled"; 48 | if (unlocked && Directory.Exists(x)) 49 | { 50 | ApplyProtection(path, false); 51 | Directory.Delete(path, false); 52 | Directory.Move(x, path); 53 | } 54 | else if (!unlocked && !Directory.Exists(x)) 55 | { 56 | Directory.Move(path, x); 57 | Directory.CreateDirectory(path); 58 | ApplyProtection(path, true); 59 | } 60 | } 61 | catch (Exception e) 62 | { 63 | CUMessageBox.Show(e.Message); 64 | } 65 | UpdateState(); 66 | } 67 | 68 | public void RemoveOldProtection(string path) 69 | { 70 | // for compatibilty with old algo 71 | DirectoryInfo dInfo = new DirectoryInfo(path); 72 | DirectorySecurity dSecurity = dInfo.GetAccessControl(); 73 | var rule = new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), 74 | FileSystemRights.Write | FileSystemRights.ReadAndExecute | FileSystemRights.ListDirectory, InheritanceFlags.None, 75 | PropagationFlags.NoPropagateInherit, AccessControlType.Deny); 76 | dSecurity.RemoveAccessRule(rule); 77 | dInfo.SetAccessControl(dSecurity); 78 | } 79 | 80 | 81 | public void ApplyProtection(string path, bool v) 82 | { 83 | DirectoryInfo dInfo = new DirectoryInfo(path); 84 | DirectorySecurity dSecurity = dInfo.GetAccessControl(); 85 | var rule = new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), 86 | FileSystemRights.Write, InheritanceFlags.None, 87 | PropagationFlags.NoPropagateInherit, AccessControlType.Deny); 88 | if(v) 89 | { 90 | dSecurity.AddAccessRule(rule); 91 | } 92 | else 93 | { 94 | dSecurity.RemoveAccessRule(rule); 95 | } 96 | dInfo.SetAccessControl(dSecurity); 97 | } 98 | 99 | private void mButton2_Click(object sender, EventArgs e) 100 | { 101 | var wsDir = GameFinder.GetWorkshopDir(); 102 | if (!Directory.Exists(wsDir)) 103 | Directory.CreateDirectory(wsDir); 104 | 105 | ChangeLockState(wsDir, false); 106 | } 107 | 108 | private void cuButton1_Click(object sender, EventArgs e) 109 | { 110 | var wsDir = GameFinder.GetWorkshopDir(); 111 | if (!Directory.Exists(wsDir)) 112 | Directory.CreateDirectory(wsDir); 113 | 114 | ChangeLockState(wsDir, true); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /ModdingTools.Updater/ModdingTools.Updater.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {25AAAE0C-404D-4877-AF19-F6245EB17F0E} 8 | WinExe 9 | ModdingTools.Updater 10 | ModdingTools.Updater 11 | v4.8 12 | 512 13 | true 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Form 53 | 54 | 55 | Form 56 | 57 | 58 | MainWindow.cs 59 | 60 | 61 | 62 | 63 | 64 | MainWindow.cs 65 | 66 | 67 | ResXFileCodeGenerator 68 | Resources.Designer.cs 69 | Designer 70 | 71 | 72 | True 73 | Resources.resx 74 | True 75 | 76 | 77 | 78 | SettingsSingleFileGenerator 79 | Settings.Designer.cs 80 | 81 | 82 | True 83 | Settings.settings 84 | True 85 | 86 | 87 | 88 | 89 | {50A7E9B0-70EF-11D1-B75A-00A0C90564FE} 90 | 1 91 | 0 92 | 0 93 | tlbimp 94 | False 95 | True 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /ModdingTools/Windows/ArrayInputWindow.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Dialogs; 2 | using CUFramework.Dialogs.Validators; 3 | using CUFramework.Windows; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.ComponentModel; 7 | using System.Data; 8 | using System.Drawing; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Windows.Forms; 12 | 13 | namespace ModdingTools.Windows 14 | { 15 | public partial class ArrayInputWindow : CUWindow 16 | { 17 | public bool AllowDuplicates { get; set; } 18 | 19 | public IValidator Validator; 20 | 21 | public ArrayInputWindow(IValidator validator = null) 22 | { 23 | InitializeComponent(); 24 | this.Validator = validator; 25 | } 26 | 27 | public static List Ask(string title, string desc, string[] defaultItems, IValidator validator) 28 | { 29 | var a = new ArrayInputWindow(validator); 30 | a.label1.Text = desc; 31 | a.Text = title; 32 | if (defaultItems != null) 33 | a.listBox1.Items.AddRange(defaultItems); 34 | var result = a.ShowDialog(); 35 | if (result == DialogResult.OK) 36 | { 37 | var res = new List(); 38 | foreach (var i in a.listBox1.Items) 39 | res.Add((string)i); 40 | return res; 41 | } 42 | return null; 43 | } 44 | 45 | private void cuButton2_Click(object sender, EventArgs e) 46 | { 47 | this.DialogResult = DialogResult.Cancel; 48 | } 49 | 50 | private void cuButton1_Click(object sender, EventArgs e) 51 | { 52 | this.DialogResult = DialogResult.OK; 53 | } 54 | 55 | private void cuButton3_Click(object sender, EventArgs e) 56 | { 57 | if (listBox1.Items.Contains(cuTextBox1.Text) && !AllowDuplicates) 58 | { 59 | CUMessageBox.Show("The list already contains an element with this name!"); 60 | return; 61 | } 62 | var result = Validator != null ? Validator.Validate(cuTextBox1.Text) : ""; 63 | if (string.IsNullOrEmpty(result)) 64 | { 65 | listBox1.Items.Add(cuTextBox1.Text); 66 | cuTextBox1.Text = ""; 67 | } 68 | else 69 | { 70 | CUMessageBox.Show(result); 71 | } 72 | } 73 | 74 | private void cuButton5_Click(object sender, EventArgs e) 75 | { 76 | MoveItem(-1); 77 | } 78 | 79 | // https://stackoverflow.com/questions/4796109/how-to-move-item-in-listbox-up-and-down 80 | public void MoveItem(int direction) 81 | { 82 | // Checking selected item 83 | if (listBox1.SelectedItem == null || listBox1.SelectedIndex < 0) 84 | return; // No selected item - nothing to do 85 | 86 | // Calculate new index using move direction 87 | int newIndex = listBox1.SelectedIndex + direction; 88 | 89 | // Checking bounds of the range 90 | if (newIndex < 0 || newIndex >= listBox1.Items.Count) 91 | return; // Index out of range - nothing to do 92 | 93 | object selected = listBox1.SelectedItem; 94 | 95 | // Removing removable element 96 | listBox1.Items.Remove(selected); 97 | // Insert it in new position 98 | listBox1.Items.Insert(newIndex, selected); 99 | // Restore selection 100 | listBox1.SetSelected(newIndex, true); 101 | } 102 | 103 | private void cuButton6_Click(object sender, EventArgs e) 104 | { 105 | MoveItem(1); 106 | } 107 | 108 | private void cuButton4_Click(object sender, EventArgs e) 109 | { 110 | while (listBox1.SelectedItems.Count > 0) 111 | listBox1.Items.Remove(listBox1.SelectedItem); 112 | } 113 | 114 | private void cuTextBox1_KeyDown(object sender, KeyEventArgs e) 115 | { 116 | if (e.KeyCode == Keys.Enter) 117 | { 118 | cuButton3_Click(sender, e); 119 | e.Handled = true; 120 | e.SuppressKeyPress = true; 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /ModdingTools.Updater/CUFormEx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | using System.Windows.Forms; 7 | 8 | namespace ModdingTools.Updater 9 | { 10 | public class CUFormEx : Form 11 | { 12 | [DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")] 13 | private static extern IntPtr CreateRoundRectRgn 14 | ( 15 | int nLeftRect, // x-coordinate of upper-left corner 16 | int nTopRect, // y-coordinate of upper-left corner 17 | int nRightRect, // x-coordinate of lower-right corner 18 | int nBottomRect, // y-coordinate of lower-right corner 19 | int nWidthEllipse, // height of ellipse 20 | int nHeightEllipse // width of ellipse 21 | ); 22 | 23 | [DllImport("dwmapi.dll")] 24 | public static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset); 25 | 26 | [DllImport("dwmapi.dll")] 27 | public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize); 28 | 29 | [DllImport("dwmapi.dll")] 30 | public static extern int DwmIsCompositionEnabled(ref int pfEnabled); 31 | 32 | private bool m_aeroEnabled; // variables for box shadow 33 | private const int CS_DROPSHADOW = 0x00020000; 34 | private const int WM_NCPAINT = 0x0085; 35 | private const int WM_ACTIVATEAPP = 0x001C; 36 | 37 | public struct MARGINS // struct for box shadow 38 | { 39 | public int leftWidth; 40 | public int rightWidth; 41 | public int topHeight; 42 | public int bottomHeight; 43 | } 44 | 45 | private const int WM_NCHITTEST = 0x84; // variables for dragging the form 46 | private const int HTCLIENT = 0x1; 47 | private const int HTCAPTION = 0x2; 48 | 49 | protected override void WndProc(ref Message m) 50 | { 51 | switch (m.Msg) 52 | { 53 | case WM_NCPAINT: // box shadow 54 | if (m_aeroEnabled) 55 | { 56 | var v = 2; 57 | DwmSetWindowAttribute(this.Handle, 2, ref v, 4); 58 | MARGINS margins = new MARGINS() 59 | { 60 | bottomHeight = 1, 61 | leftWidth = 1, 62 | rightWidth = 1, 63 | topHeight = 1 64 | }; 65 | DwmExtendFrameIntoClientArea(this.Handle, ref margins); 66 | 67 | } 68 | break; 69 | default: 70 | break; 71 | } 72 | base.WndProc(ref m); 73 | 74 | if (m.Msg == WM_NCHITTEST && (int)m.Result == HTCLIENT) // drag the form 75 | m.Result = (IntPtr)HTCAPTION; 76 | 77 | } 78 | 79 | public CUFormEx() 80 | { 81 | this.MouseDown += HandleDrag; 82 | } 83 | 84 | protected override CreateParams CreateParams 85 | { 86 | get 87 | { 88 | m_aeroEnabled = CheckAeroEnabled(); 89 | 90 | CreateParams cp = base.CreateParams; 91 | if (!m_aeroEnabled) 92 | cp.ClassStyle |= CS_DROPSHADOW; 93 | 94 | return cp; 95 | } 96 | } 97 | 98 | private bool CheckAeroEnabled() 99 | { 100 | if (Environment.OSVersion.Version.Major >= 6) 101 | { 102 | int enabled = 0; 103 | DwmIsCompositionEnabled(ref enabled); 104 | return (enabled == 1) ? true : false; 105 | } 106 | return false; 107 | } 108 | 109 | [DllImport("user32.dll")] 110 | public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam); 111 | [DllImport("user32.dll")] 112 | public static extern bool ReleaseCapture(); 113 | protected void HandleDrag(object sender, MouseEventArgs e) 114 | { 115 | bool flag = e.Button == MouseButtons.Left; 116 | if (flag) 117 | { 118 | ReleaseCapture(); 119 | SendMessage(base.Handle, 161, 2, 0); 120 | } 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /ModdingTools/Engine/APNG/CrcHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace LibAPNG 5 | { 6 | internal class CrcHelper 7 | { 8 | #region Consts 9 | 10 | private static readonly UInt32[] CrcTable = 11 | { 12 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 13 | 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 14 | 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 15 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 16 | 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 17 | 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 18 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 19 | 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 20 | 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 21 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 22 | 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 23 | 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 24 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 25 | 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 26 | 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 27 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 28 | 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 29 | 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 30 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 31 | 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 32 | 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 33 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 34 | 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 35 | 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 36 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 37 | 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 38 | 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 39 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 40 | 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 41 | 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 42 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 43 | 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 44 | 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 45 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 46 | 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 47 | 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 48 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 49 | 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 50 | 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 51 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 52 | 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 53 | 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 54 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 55 | 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 56 | 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 57 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 58 | 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 59 | 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 60 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 61 | 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 62 | 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 63 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 64 | 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 65 | 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 66 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 67 | 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 68 | 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 69 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 70 | 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 71 | 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 72 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 73 | 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 74 | 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 75 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 76 | }; 77 | 78 | #endregion Consts 79 | 80 | public static uint Calculate(byte[] what) 81 | { 82 | UInt32 crc = what.Aggregate( 83 | 0xffffffff, 84 | (current, t) => (current >> 8) ^ CrcTable[(current & 0xff) ^ t]); 85 | crc ^= 0xffffffff; 86 | 87 | return crc; 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /ModdingTools.Updater/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows.Forms; 9 | 10 | namespace ModdingTools.Updater 11 | { 12 | internal static class Program 13 | { 14 | /// 15 | /// The main entry point for the application. 16 | /// 17 | [STAThread] 18 | static void Main() 19 | { 20 | var args = Environment.GetCommandLineArgs(); 21 | if (Process.GetCurrentProcess().ProcessName.Equals("ModdingTools.Updater", StringComparison.InvariantCultureIgnoreCase)) 22 | { 23 | AttachBugTracker(); 24 | 25 | // Enable TLS 1.2 & 1.1 because .Net Framework 4.0 doesn't have it enabled by default 26 | System.Net.ServicePointManager.SecurityProtocol = (System.Net.SecurityProtocolType)(768 | 3072); 27 | 28 | Application.EnableVisualStyles(); 29 | Application.SetCompatibleTextRenderingDefault(false); 30 | Application.Run(new MainWindow()); 31 | } 32 | else 33 | { 34 | Process.Start(Path.Combine(GetAppRoot(), "ModdingTools.exe")); 35 | Environment.Exit(0); 36 | } 37 | } 38 | 39 | public static string GetAppRoot() 40 | { 41 | return Path.GetDirectoryName(Application.ExecutablePath); 42 | } 43 | 44 | private static void AttachBugTracker() 45 | { 46 | if (!Debugger.IsAttached) 47 | { 48 | // Add the event handler for handling UI thread exceptions to the event. 49 | Application.ThreadException += (sender, e) 50 | => FatalExceptionObject(e); 51 | 52 | // Set the unhandled exception mode to force all Windows Forms errors to go through our handler. 53 | Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); 54 | 55 | // Add the event handler for handling non-UI thread exceptions to the event. 56 | AppDomain.CurrentDomain.UnhandledException += (sender, e) 57 | => FatalExceptionObject(e.ExceptionObject); 58 | 59 | // This AppDomain-wide event provides a mechanism to prevent exception escalation policy (which, by default, terminates the process) from triggering. 60 | // Each handler is passed a UnobservedTaskExceptionEventArgs instance, which may be used to examine the exception and to mark it as observed. 61 | TaskScheduler.UnobservedTaskException += (sender, e) 62 | => FatalExceptionObject(e); 63 | } 64 | } 65 | 66 | static bool isReported = false; 67 | static int threads; 68 | public static void FatalExceptionObject(object exc) 69 | { 70 | if (!Debugger.IsAttached) 71 | { 72 | if (isReported) 73 | { 74 | CloseApp(1); 75 | } 76 | 77 | var e = exc as Exception; 78 | if (e == null) 79 | { 80 | e = new NotSupportedException( 81 | "Unhandled exception doesn't derive from System.Exception: " 82 | + exc.ToString() 83 | ); 84 | } 85 | 86 | threads = Process.GetCurrentProcess().Threads.Count; 87 | 88 | var x = new StringBuilder(); 89 | x.AppendLine("Failed to launch OMM Updater: "); 90 | x.AppendLine(e.Message); 91 | x.AppendLine(e.StackTrace); 92 | if (e.InnerException != null) 93 | { 94 | x.AppendLine("---[inner exception]---"); 95 | x.AppendLine(e.InnerException.Message); 96 | x.AppendLine(e.InnerException.StackTrace); 97 | } 98 | x.AppendLine(""); 99 | x.AppendLine("Threads: " + threads); 100 | 101 | MessageBox.Show(x.ToString()); 102 | isReported = true; 103 | CloseApp(1); 104 | } 105 | } 106 | 107 | public static void CloseApp(int i) 108 | { 109 | Debug.WriteLine("Closing application..."); 110 | if (!Debugger.IsAttached) 111 | { 112 | Application.Exit(); 113 | } 114 | else 115 | { 116 | Environment.Exit(i); 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /ModdingTools/Windows/ArgEditor.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ModdingTools.Windows 2 | { 3 | partial class ArgEditor 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ArgEditor)); 32 | this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); 33 | this.label3 = new System.Windows.Forms.Label(); 34 | this.SuspendLayout(); 35 | // 36 | // flowLayoutPanel1 37 | // 38 | this.flowLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 39 | | System.Windows.Forms.AnchorStyles.Left) 40 | | System.Windows.Forms.AnchorStyles.Right))); 41 | this.flowLayoutPanel1.AutoScroll = true; 42 | this.flowLayoutPanel1.Location = new System.Drawing.Point(2, 89); 43 | this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); 44 | this.flowLayoutPanel1.Name = "flowLayoutPanel1"; 45 | this.flowLayoutPanel1.Size = new System.Drawing.Size(910, 416); 46 | this.flowLayoutPanel1.TabIndex = 1; 47 | this.flowLayoutPanel1.SizeChanged += new System.EventHandler(this.flowLayoutPanel1_SizeChanged); 48 | // 49 | // label3 50 | // 51 | this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 52 | | System.Windows.Forms.AnchorStyles.Right))); 53 | this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(238))); 54 | this.label3.ForeColor = System.Drawing.Color.Yellow; 55 | this.label3.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; 56 | this.label3.Location = new System.Drawing.Point(6, 36); 57 | this.label3.Name = "label3"; 58 | this.label3.Size = new System.Drawing.Size(902, 43); 59 | this.label3.TabIndex = 27; 60 | this.label3.Text = "Only use if you know what you are doing!\r\nModifying these options may mess some t" + 61 | "hings up, but you can restore the default settings at any time!"; 62 | this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 63 | // 64 | // ArgEditor 65 | // 66 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; 67 | this.ClientSize = new System.Drawing.Size(915, 507); 68 | this.Controls.Add(this.label3); 69 | this.Controls.Add(this.flowLayoutPanel1); 70 | this.DoubleBuffered = true; 71 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 72 | this.IsMaximizeButtonEnabled = false; 73 | this.IsMinimizeButtonEnabled = false; 74 | this.Location = new System.Drawing.Point(0, 0); 75 | this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); 76 | this.MaximizeBox = false; 77 | this.MaximumSize = new System.Drawing.Size(1920, 1029); 78 | this.MinimizeBox = false; 79 | this.MinimumSize = new System.Drawing.Size(915, 507); 80 | this.Name = "ArgEditor"; 81 | this.Text = "ARGUMENT EDITOR"; 82 | this.SizeChanged += new System.EventHandler(this.ArgEditor_SizeChanged); 83 | this.Controls.SetChildIndex(this.flowLayoutPanel1, 0); 84 | this.Controls.SetChildIndex(this.label3, 0); 85 | this.ResumeLayout(false); 86 | 87 | } 88 | 89 | #endregion 90 | 91 | private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; 92 | private System.Windows.Forms.Label label3; 93 | } 94 | } -------------------------------------------------------------------------------- /ModdingTools/GUI/GUIWorker.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace ModdingTools.GUI 2 | { 3 | partial class GUIWorker 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.label4 = new System.Windows.Forms.Label(); 32 | this.cuGradientTextBox1 = new CUFramework.Controls.CUGradientTextBox(); 33 | this.huehProgressBar1 = new ModdingTools.GUI.HuehProgressBar(); 34 | this.SuspendLayout(); 35 | // 36 | // label4 37 | // 38 | this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 39 | | System.Windows.Forms.AnchorStyles.Right))); 40 | this.label4.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(16)))), ((int)(((byte)(16)))), ((int)(((byte)(16))))); 41 | this.label4.Cursor = System.Windows.Forms.Cursors.Arrow; 42 | this.label4.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); 43 | this.label4.ForeColor = System.Drawing.Color.White; 44 | this.label4.Location = new System.Drawing.Point(0, 376); 45 | this.label4.Name = "label4"; 46 | this.label4.Padding = new System.Windows.Forms.Padding(5); 47 | this.label4.Size = new System.Drawing.Size(660, 31); 48 | this.label4.TabIndex = 9; 49 | this.label4.Text = "Please wait..."; 50 | this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 51 | // 52 | // cuGradientTextBox1 53 | // 54 | this.cuGradientTextBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 55 | | System.Windows.Forms.AnchorStyles.Left) 56 | | System.Windows.Forms.AnchorStyles.Right))); 57 | this.cuGradientTextBox1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(42)))), ((int)(((byte)(42)))), ((int)(((byte)(42))))); 58 | this.cuGradientTextBox1.Font = new System.Drawing.Font("Consolas", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238))); 59 | this.cuGradientTextBox1.Location = new System.Drawing.Point(3, -2); 60 | this.cuGradientTextBox1.Name = "cuGradientTextBox1"; 61 | this.cuGradientTextBox1.Size = new System.Drawing.Size(402, 375); 62 | this.cuGradientTextBox1.TabIndex = 10; 63 | this.cuGradientTextBox1.Text = "cuGradientTextBox1"; 64 | this.cuGradientTextBox1.TextAlign = CUFramework.Controls.CUGradientTextBox.ETextAlign.Left; 65 | // 66 | // huehProgressBar1 67 | // 68 | this.huehProgressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 69 | | System.Windows.Forms.AnchorStyles.Right))); 70 | this.huehProgressBar1.ForeColor = System.Drawing.Color.White; 71 | this.huehProgressBar1.Location = new System.Drawing.Point(412, 32); 72 | this.huehProgressBar1.Name = "huehProgressBar1"; 73 | this.huehProgressBar1.Size = new System.Drawing.Size(246, 365); 74 | this.huehProgressBar1.TabIndex = 11; 75 | this.huehProgressBar1.Value = 0; 76 | // 77 | // GUIWorker 78 | // 79 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; 80 | this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(42)))), ((int)(((byte)(42)))), ((int)(((byte)(42))))); 81 | this.Controls.Add(this.label4); 82 | this.Controls.Add(this.huehProgressBar1); 83 | this.Controls.Add(this.cuGradientTextBox1); 84 | this.Name = "GUIWorker"; 85 | this.Size = new System.Drawing.Size(660, 407); 86 | this.ResumeLayout(false); 87 | 88 | } 89 | 90 | #endregion 91 | private System.Windows.Forms.Label label4; 92 | private CUFramework.Controls.CUGradientTextBox cuGradientTextBox1; 93 | private HuehProgressBar huehProgressBar1; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /ModdingTools.Updater/MainWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Net; 6 | using System.Threading.Tasks; 7 | using System.Windows.Forms; 8 | 9 | namespace ModdingTools.Updater 10 | { 11 | public partial class MainWindow : CUFormEx 12 | { 13 | private int CurrentProgress = -1; 14 | private string CurrentStatus; 15 | private bool DownloadCompleted; 16 | private bool IsCancelling = false; 17 | private bool IsLocked = false; 18 | 19 | public MainWindow() 20 | { 21 | InitializeComponent(); 22 | this.StartPosition = FormStartPosition.CenterScreen; 23 | this.Shown += MainWindow_Shown; 24 | label2.MouseDown += HandleDrag; 25 | timer1.Tick += Timer1_Tick; 26 | } 27 | 28 | private void Timer1_Tick(object sender, EventArgs e) 29 | { 30 | label2.Text = CurrentStatus; 31 | button1.Enabled = !IsLocked; 32 | if (CurrentProgress >= 0) 33 | { 34 | progressBar1.Value = CurrentProgress; 35 | progressBar1.Style = ProgressBarStyle.Blocks; 36 | } 37 | else progressBar1.Style = ProgressBarStyle.Marquee; 38 | } 39 | 40 | private void MainWindow_Shown(object sender, EventArgs e) 41 | { 42 | Task.Factory.StartNew(() => 43 | { 44 | if (!Debugger.IsAttached) 45 | { 46 | try 47 | { 48 | RunUpdaterTasks(); 49 | } 50 | catch (Exception ex) 51 | { 52 | Program.FatalExceptionObject(ex); 53 | } 54 | } 55 | else 56 | { 57 | RunUpdaterTasks(); 58 | } 59 | }); 60 | } 61 | 62 | public void RunUpdaterTasks() 63 | { 64 | CurrentStatus = "Killing OMM instances..."; 65 | OMMHelper.KillOMM(); 66 | 67 | CurrentStatus = "Downloading update data..."; 68 | var data = OMMHelper.GetUpdateData(); 69 | 70 | if (IsCancelling) 71 | { 72 | Program.CloseApp(-1); 73 | return; 74 | } 75 | 76 | var appRoot = Program.GetAppRoot(); 77 | var updateZipPath = Path.Combine(appRoot, "update.zip"); 78 | 79 | CurrentStatus = "Downloading update package..."; 80 | using(var wc = new WebClient()) 81 | { 82 | wc.Headers.Add("User-agent", "OpenModManager.Updater/1.0"); 83 | if (File.Exists(updateZipPath)) File.Delete(updateZipPath); 84 | wc.DownloadProgressChanged += Wc_DownloadProgressChanged; 85 | DownloadCompleted = false; 86 | wc.DownloadFileAsync(new Uri(data.URL), updateZipPath); 87 | wc.DownloadFileCompleted += Wc_DownloadFileCompleted; 88 | 89 | while (!DownloadCompleted) 90 | { 91 | if (IsCancelling) 92 | wc.CancelAsync(); 93 | 94 | } 95 | 96 | if (IsCancelling) 97 | { 98 | if (File.Exists(updateZipPath)) 99 | File.Delete(updateZipPath); 100 | Program.CloseApp(-1); 101 | return; 102 | } 103 | 104 | CurrentProgress = -1; 105 | IsLocked = true; 106 | CurrentStatus = "Verifying downloaded package..."; 107 | if (data.Verify(updateZipPath)) 108 | { 109 | CurrentStatus = "Extracting downloaded package..."; 110 | OMMHelper.ExtractZIP(updateZipPath, appRoot); 111 | CurrentStatus = "OK!"; 112 | CurrentProgress = 100; 113 | File.Delete(updateZipPath); 114 | System.Diagnostics.Process.Start(Path.Combine(appRoot, "ModdingTools.exe")); 115 | Program.CloseApp(0); 116 | } 117 | else 118 | { 119 | throw new Exception("Checksum verify failed!"); 120 | } 121 | } 122 | } 123 | 124 | private void Wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) 125 | { 126 | DownloadCompleted = true; 127 | } 128 | 129 | private void Wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) 130 | { 131 | CurrentProgress = e.ProgressPercentage; 132 | CurrentStatus = $"Downloading update package... [{e.BytesReceived}/{e.TotalBytesToReceive}]"; 133 | } 134 | 135 | private void button1_Click(object sender, EventArgs e) 136 | { 137 | if (!IsLocked) 138 | IsCancelling = true; 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /ModdingTools.Updater/OMMHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.IO.Packaging; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Security.Cryptography; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Windows.Forms; 12 | 13 | namespace ModdingTools.Updater 14 | { 15 | public class OMMHelper 16 | { 17 | public struct DownloadData 18 | { 19 | public string URL; 20 | public string SHA256; 21 | 22 | public bool IsValid() 23 | { 24 | return !string.IsNullOrWhiteSpace(URL) 25 | && URL.StartsWith("https://") 26 | && !string.IsNullOrWhiteSpace(SHA256) 27 | && SHA256.Length == 64; 28 | } 29 | 30 | public bool Verify(string filePath) 31 | { 32 | using (var sha = System.Security.Cryptography.SHA256.Create()) 33 | { 34 | using (FileStream fileStream = File.OpenRead(filePath)) 35 | { 36 | var hash = BitConverter.ToString(sha.ComputeHash(fileStream)).Replace("-", string.Empty); 37 | return hash.Equals(SHA256, StringComparison.InvariantCultureIgnoreCase); 38 | } 39 | } 40 | } 41 | 42 | public override string ToString() 43 | { 44 | return $"URL: {URL}\nSHA256: {SHA256}\nIsValid: {IsValid()}"; 45 | } 46 | } 47 | 48 | public static DownloadData GetUpdateData() 49 | { 50 | // Well, I should parse this json file by using Newtonsoft.JSON... 51 | // ...but I don't want to add any extra dependencies just for that one file lol 52 | var baseUrl = "https://api.github.com/repos/mcu8/OpenModManager/releases/latest"; 53 | string jsonData; 54 | using(var wc = new WebClient()) 55 | { 56 | wc.Headers.Add("User-agent", "OpenModManager.Updater/1.0"); 57 | jsonData = wc.DownloadString(baseUrl); 58 | } 59 | 60 | // get "browser_download_url" tag... the harder way :p 61 | if (string.IsNullOrEmpty(jsonData)) 62 | throw new Exception("Unable to find download URL... [1]"); 63 | 64 | var data = new DownloadData(); 65 | 66 | var x = jsonData.Split(new string[] { "\"browser_download_url\":\"" }, StringSplitOptions.None); 67 | if (x.Length > 1) 68 | { 69 | foreach (var e in x) 70 | { 71 | var result = e.Split('"')[0]; 72 | if (result.StartsWith("https://") && result.EndsWith("-bin.zip")) 73 | data.URL = result; 74 | else if (result.StartsWith("https://") && result.EndsWith("-bin.zip.sha256")) 75 | { 76 | using (var wc = new WebClient()) 77 | { 78 | wc.Headers.Add("User-agent", "OpenModManager.Updater/1.0"); 79 | data.SHA256 = wc.DownloadString(result).Split(' ')[0]; 80 | } 81 | } 82 | 83 | if (data.IsValid()) return data; 84 | } 85 | } 86 | else 87 | { 88 | throw new Exception("Unable to find download URL... [3]"); 89 | } 90 | 91 | // well, probably an error 92 | throw new Exception("Unable to find download URL... [2]"); 93 | } 94 | 95 | public static void KillOMM() 96 | { 97 | KillProcessByImageName("ModdingTools", false); 98 | KillProcessByImageName("ModdingTools.Cli", false); 99 | } 100 | 101 | public static void KillProcessByImageName(string name, bool async) 102 | { 103 | if (async) 104 | { 105 | Task.Factory.StartNew(() => 106 | { 107 | foreach (var x in Process.GetProcessesByName(name)) 108 | x.Kill(); 109 | }); 110 | } 111 | else 112 | { 113 | foreach (var x in Process.GetProcessesByName(name)) 114 | x.Kill(); 115 | } 116 | } 117 | 118 | public static void ExtractZIP(string zipFilePath, string targetFolderPath) 119 | { 120 | var zip = GetShell32Folder(zipFilePath).Items(); 121 | GetShell32Folder(targetFolderPath).CopyHere(zip, 16 | 4 | 8); 122 | } 123 | 124 | private static Shell32.Folder GetShell32Folder(string folderPath) 125 | { 126 | Type shellAppType = Type.GetTypeFromProgID("Shell.Application"); 127 | Object shell = Activator.CreateInstance(shellAppType); 128 | return (Shell32.Folder)shellAppType.InvokeMember("NameSpace", 129 | System.Reflection.BindingFlags.InvokeMethod, null, shell, new object[] { folderPath }); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /ModdingTools/Engine/GameFinder.cs: -------------------------------------------------------------------------------- 1 | 2 | //#define STEAM_NO_REGISTRY_TEST 3 | 4 | using Microsoft.Win32; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | 11 | namespace ModdingTools.Engine 12 | { 13 | 14 | public class GameFinder 15 | { 16 | public const string AppID = "253230"; 17 | 18 | #if STEAM_NO_REGISTRY_TEST 19 | public static string GetSteamDir() 20 | { 21 | return null; 22 | } 23 | #else 24 | public static string GetSteamDir() 25 | { 26 | try 27 | { 28 | var key = @"HKEY_LOCAL_MACHINE\SOFTWARE\Valve\Steam"; 29 | if (Environment.Is64BitOperatingSystem) 30 | { 31 | key = @"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Valve\Steam"; 32 | } 33 | return (string)Registry.GetValue(key, "InstallPath", null); 34 | } 35 | catch 36 | { 37 | // if it somehow fails... we don't care lol 38 | return null; 39 | } 40 | } 41 | #endif 42 | 43 | public static string GetWorkshopDir() 44 | { 45 | var steamDir = GetSteamDir(); 46 | if (steamDir == null || !Directory.Exists(steamDir)) 47 | { 48 | // fallback to more cheap dir detection... probably using Proton or bad Steam install? 49 | 50 | // the funny 51 | var baseDir = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(FindGameDir())))); 52 | return Path.Combine(baseDir, @"workshop\content", AppID); 53 | } 54 | return Path.Combine(steamDir, @"steamapps\workshop\content", AppID); 55 | } 56 | 57 | public static string GetModsDir() 58 | { 59 | return Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(FindGameDir())), "HatInTimeGame", "Mods"); 60 | } 61 | 62 | public static string GetSrcDir() 63 | { 64 | return Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(FindGameDir())), "Development", "Src"); 65 | } 66 | 67 | public static string GetCookedPcDir() 68 | { 69 | return Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(FindGameDir())), "HatInTimeGame", "CookedPC"); 70 | } 71 | 72 | public static string GetEditorCookedPcDir() 73 | { 74 | return Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(FindGameDir())), "HatInTimeGame", "EditorCookedPC"); 75 | } 76 | 77 | // Cache that, cuz we changing the working dir - must be absolute! 78 | private static string CachedGameDir = null; 79 | public static string FindGameDir() 80 | { 81 | if (CachedGameDir != null) 82 | return CachedGameDir; 83 | 84 | if (File.Exists("GameDirPath.dat")) 85 | { 86 | try 87 | { 88 | var testPath = File.ReadAllText("GameDirPath.dat"); 89 | var gamePath = Path.Combine(testPath, "HatinTimeGame.exe"); 90 | var editorPath = Path.Combine(testPath, "HatinTimeEditor.exe"); 91 | 92 | if (File.Exists(gamePath) && File.Exists(editorPath)) 93 | { 94 | CachedGameDir = Path.GetFullPath(testPath); 95 | return testPath; 96 | } 97 | else 98 | { 99 | File.Delete("GameDirPath.dat"); 100 | } 101 | } 102 | catch (Exception) 103 | { 104 | File.Delete("GameDirPath.dat"); 105 | } 106 | } 107 | 108 | var strSteamInstallPath = GetSteamDir(); 109 | 110 | if (strSteamInstallPath != null && Directory.Exists(strSteamInstallPath)) 111 | { 112 | var libPathes = new List(); 113 | libPathes.Add(strSteamInstallPath); 114 | 115 | var libFile = File.ReadAllLines(Path.Combine(strSteamInstallPath, "steamapps\\libraryfolders.vdf")); 116 | int i = 0; 117 | foreach (var line in libFile) 118 | { 119 | if (i >= 4) 120 | { 121 | var d = line.Trim().Split('"'); 122 | if (d.Count() == 5) 123 | { 124 | libPathes.Add(d[3].Replace(@"\\", @"\")); 125 | } 126 | } 127 | i++; 128 | } 129 | 130 | foreach (var lib in libPathes) 131 | { 132 | var testPath = Path.Combine(lib, "steamapps\\common\\HatinTime\\Binaries\\Win64"); 133 | var gamePath = Path.Combine(testPath, "HatinTimeGame.exe"); 134 | var editorPath = Path.Combine(testPath, "HatinTimeEditor.exe"); 135 | 136 | if (File.Exists(gamePath) && File.Exists(editorPath)) 137 | { 138 | CachedGameDir = Path.GetFullPath(testPath); 139 | return testPath; 140 | } 141 | } 142 | } 143 | return null; 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /ModdingTools/GUI/ConfigItem.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Dialogs.Validators; 2 | using ModdingTools.Modding; 3 | using ModdingTools.Windows; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.ComponentModel; 7 | using System.Data; 8 | using System.Drawing; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Windows.Forms; 12 | using static ModdingTools.Modding.ModObject; 13 | 14 | namespace ModdingTools.GUI 15 | { 16 | public partial class ConfigItem : UserControl 17 | { 18 | ModObject.ModConfigItem Conf; 19 | ModObject Obj; 20 | 21 | public ConfigItem(ModObject.ModConfigItem item, ModObject ob) 22 | { 23 | InitializeComponent(); 24 | Conf = item; 25 | Obj = ob; 26 | 27 | label4.Text = Conf.PropertyName; 28 | label3.Text = Conf.Description.Replace("[br]", Environment.NewLine); 29 | label5.Text = Conf.Name; 30 | 31 | RepopulateOptionsDict(true); 32 | } 33 | 34 | private void mButtonBorderless1_Click(object sender, EventArgs e) 35 | { 36 | CallUpdateEvent(); 37 | if (this.Parent is FlowLayoutPanel) 38 | { 39 | this.Parent.Controls.Remove(this); 40 | } 41 | Obj.Config.Remove(Conf); 42 | } 43 | 44 | private void CallUpdateEvent() 45 | { 46 | if (this.Parent.Parent is ConfigList) 47 | ((ConfigList)this.Parent.Parent).CallOnUpdateEvent(); 48 | } 49 | 50 | private void label4_Click(object sender, EventArgs e) 51 | { 52 | var a = CUInputWindow.Ask(this, "Config Editor", "Please, enter config property name (var config int )", new NonEmptyValidator(), label4.Text); 53 | if (a != null) 54 | { 55 | label4.Text = a; 56 | Conf.PropertyName = a; 57 | CallUpdateEvent(); 58 | } 59 | } 60 | 61 | private void label3_Click(object sender, EventArgs e) 62 | { 63 | var a = CUInputWindow.Ask(this, "Config Editor", "Please, enter the description", new NonEmptyValidator(), label3.Text, true); 64 | if (a != null) 65 | { 66 | label3.Text = a; 67 | Conf.Description = a.Replace(Environment.NewLine, "[br]"); 68 | CallUpdateEvent(); 69 | } 70 | } 71 | 72 | private void ConfigItem_Load(object sender, EventArgs e) 73 | { 74 | 75 | } 76 | 77 | private void label5_Click(object sender, EventArgs e) 78 | { 79 | var a = CUInputWindow.Ask(this, "Config Editor", "Please, enter config display name", new NonEmptyValidator(), label5.Text); 80 | if (a != null) 81 | { 82 | label5.Text = a; 83 | Conf.Name = a; 84 | CallUpdateEvent(); 85 | } 86 | } 87 | 88 | private void RepopulateOptionsDict(bool firstRun = false) 89 | { 90 | int i = 0; 91 | if (!firstRun) 92 | { 93 | Conf.Options.Clear(); 94 | foreach (var _item in listBox1.Items) 95 | { 96 | var item = (ModConfigItem_Indexed)_item; 97 | Conf.Options.Add(i, item); 98 | i++; 99 | } 100 | } 101 | else 102 | { 103 | foreach (var conf in Conf.Options) 104 | { 105 | listBox1.Items.Add(conf.Value); 106 | } 107 | listBox1.Update(); 108 | } 109 | } 110 | 111 | private void mButtonBorderless3_Click(object sender, EventArgs e) 112 | { 113 | var a = CUInputWindow.Ask(this, "Config Editor", "Please, enter a new value name", new NonEmptyValidator()); 114 | if (a != null) 115 | { 116 | listBox1.Items.Add(new ModConfigItem_Indexed(FindLowestAvailableConfigId(), a)); 117 | RepopulateOptionsDict(); 118 | CallUpdateEvent(); 119 | } 120 | } 121 | 122 | private int FindLowestAvailableConfigId() 123 | { 124 | int i = 0; 125 | while (true) 126 | { 127 | bool found = false; 128 | foreach (var _item in listBox1.Items) 129 | { 130 | var item = (ModConfigItem_Indexed)_item; 131 | if (item.Id == i) 132 | { 133 | found = true; 134 | break; 135 | } 136 | } 137 | if (found) 138 | { 139 | i++; 140 | continue; 141 | } 142 | return i; 143 | } 144 | } 145 | 146 | private void mButtonBorderless2_Click(object sender, EventArgs e) 147 | { 148 | listBox1.Items.Remove(listBox1.SelectedItem); 149 | RepopulateOptionsDict(); 150 | CallUpdateEvent(); 151 | } 152 | 153 | private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) 154 | { 155 | /*if (Conf.DefaultIndex != comboBox1.SelectedIndex) 156 | CallUpdateEvent(); 157 | 158 | Conf.DefaultIndex = comboBox1.SelectedIndex;*/ 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /ModdingTools/GUI/ContentBrowser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Data; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using System.IO; 10 | using ModdingTools.Modding; 11 | using ModdingTools.Engine; 12 | using System.Diagnostics; 13 | 14 | namespace ModdingTools.GUI 15 | { 16 | public partial class ContentBrowser : UserControl 17 | { 18 | public bool HasContentError { get; private set; } 19 | 20 | Dictionary Adict = new Dictionary 21 | { 22 | { ".upk", "Only Asset Packages (.upk) are allowed in the Content folder." }, 23 | { ".umap", "Only Unreal Maps (.umap) are allowed in the Maps folder." }, 24 | { ".int", "Only Localization Files (.int) are allowed in the Localization folder." } 25 | }; 26 | 27 | Dictionary BDict = new Dictionary 28 | { 29 | { ".upk", "This is an Asset Package (.upk) which goes in the Content folder." }, 30 | { ".umap", "This is an Unreal Map (.umap) which goes in the Maps folder." }, 31 | { ".int", "This is a Localization File (.int) which goes in the Localization folder." } 32 | }; 33 | 34 | public ContentBrowser() 35 | { 36 | InitializeComponent(); 37 | } 38 | 39 | private struct ContentTreeViewInfo 40 | { 41 | public string Filename; 42 | 43 | public string ErrorMessage; 44 | 45 | public ContentTreeViewInfo(string InFilename, string InErrorMessage) 46 | { 47 | Filename = InFilename; 48 | ErrorMessage = InErrorMessage; 49 | } 50 | } 51 | 52 | public void LoadMod(ModObject mod) 53 | { 54 | HasContentError = false; 55 | AssetNameLabel.Text = "(none selected)"; 56 | AssetDescriptionLabel.Text = ""; 57 | 58 | ContentTreeView.Nodes.Clear(); 59 | IterateContent(ContentTreeView.Nodes, mod, mod.GetContentDir(), ".upk", true); 60 | IterateContent(ContentTreeView.Nodes, mod, mod.GetMapsDir(), ".umap", true); 61 | IterateContent(ContentTreeView.Nodes, mod, mod.GetLocsDir(), ".int", true); 62 | ContentTreeView.ExpandAll(); 63 | } 64 | 65 | private void IterateContent(TreeNodeCollection root, ModObject mod, string currPath, string acceptExt, bool isBase = false) 66 | { 67 | if (!Directory.Exists(currPath)) 68 | return; 69 | 70 | if (isBase) 71 | { 72 | var node = root.Add("folder", Path.GetFileName(currPath), "folder", "folder"); 73 | IterateContent(node.Nodes, mod, currPath, acceptExt); 74 | return; 75 | } 76 | foreach (string path in Directory.GetFiles(currPath, "*.*")) 77 | { 78 | Debug.WriteLine(GameFinder.GetCookedPcDir()); 79 | var exts = acceptExt.Split('|'); 80 | var extension = Path.GetExtension(path); 81 | var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path); 82 | if (!exts.Contains(acceptExt)) 83 | { 84 | var treeNode = root.Add("", Path.GetFileName(path), "error", "error"); 85 | var text = "This asset does not belong here."; 86 | foreach (var a in Adict) 87 | { 88 | if (exts.Contains(a.Key)) text += Environment.NewLine + a.Value; 89 | } 90 | 91 | foreach (var b in BDict) 92 | { 93 | if (extension == b.Key) text += Environment.NewLine + b.Value; 94 | } 95 | 96 | treeNode.Tag = new ContentTreeViewInfo(Path.GetFileName(path), text); 97 | HasContentError = true; 98 | } 99 | else if (fileNameWithoutExtension.ToLower() == mod.GetDirectoryName().ToLower() && !exts.Contains(".int") && !exts.Contains(".umap")) 100 | { 101 | var treeNode = root.Add("", Path.GetFileName(path), "error", "error"); 102 | treeNode.Tag = new ContentTreeViewInfo(Path.GetFileName(path), "Packages can't have the same name as your mod folder.\nAdd a _Content suffix or something. Example:\n" + fileNameWithoutExtension + "_Content" + extension); 103 | HasContentError = true; 104 | } 105 | else if (Utils.FileExists(GameFinder.GetCookedPcDir(), Path.GetFileName(path))) 106 | { 107 | var treeNode = root.Add("", Path.GetFileName(path), "error", "error"); 108 | treeNode.Tag = new ContentTreeViewInfo(Path.GetFileName(path), "There's an asset with an identical name in CookedPC.\nPlease give your asset another name.\n(btw don't put your own stuff in CookedPC. Keep it to the mods folder.)"); 109 | HasContentError = true; 110 | } 111 | else 112 | { 113 | var ext = exts.Contains(".int") ? "localization" : "package"; 114 | var treeNode = root.Add("", Path.GetFileName(path), ext, ext); 115 | treeNode.Tag = new ContentTreeViewInfo(Path.GetFileName(path), ""); 116 | } 117 | } 118 | foreach (var file in Directory.GetDirectories(currPath)) 119 | { 120 | var node = root.Add("", Path.GetFileName(file), "folder", "folder"); 121 | IterateContent(node.Nodes, mod, file, acceptExt); 122 | } 123 | } 124 | 125 | private void ContentTreeView_AfterSelect(object sender, TreeViewEventArgs e) 126 | { 127 | if (ContentTreeView.SelectedNode.Tag == null) 128 | { 129 | AssetNameLabel.Text = "(none selected)"; 130 | return; 131 | } 132 | ContentTreeViewInfo contentTreeViewInfo = (ContentTreeViewInfo)ContentTreeView.SelectedNode.Tag; 133 | AssetNameLabel.Text = contentTreeViewInfo.Filename; 134 | AssetDescriptionLabel.Text = contentTreeViewInfo.ErrorMessage; 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /ModdingTools/Logging/Logger.cs: -------------------------------------------------------------------------------- 1 | using CUFramework.Shared; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Data; 5 | using System.Diagnostics; 6 | using System.Linq; 7 | using System.Windows.Forms.VisualStyles; 8 | 9 | namespace ModdingTools.Logging 10 | { 11 | static class Logger 12 | { 13 | private static Dictionary HANDLER_REGISTRY { get; set; } 14 | 15 | private static bool IsInitialized = false; 16 | public static void InitializeLogger() 17 | { 18 | HANDLER_REGISTRY = new Dictionary(); 19 | 20 | if (Debugger.IsAttached) 21 | RegisterOutputHandler("DebuggerLogger", new Logging.Handlers.DebuggerLogger()); 22 | 23 | RegisterOutputHandler("CommandLineLogger", new Logging.Handlers.CommandLineLogger()); 24 | 25 | IsInitialized = true; 26 | } 27 | 28 | public static void RegisterOutputHandler(string name, ILogger handler) 29 | { 30 | if (!HANDLER_REGISTRY.ContainsKey(name)) 31 | { 32 | HANDLER_REGISTRY.Add(name, handler); 33 | HANDLER_REGISTRY[name].Init(); 34 | } 35 | } 36 | 37 | public static void UnregisterOutputHandler(string name) 38 | { 39 | if (HANDLER_REGISTRY.ContainsKey(name)) 40 | { 41 | HANDLER_REGISTRY[name].Unregister(); 42 | HANDLER_REGISTRY.Remove(name); 43 | } 44 | } 45 | 46 | public static string GetLoggerDate() 47 | { 48 | System.DateTime regDate = System.DateTime.Now; 49 | return regDate.ToString("HH:mm:ss"); 50 | } 51 | 52 | public static string GetLevelText(LogLevel level) 53 | { 54 | return level.ToString(); 55 | } 56 | 57 | public static void Log(LogLevel Level, string Message, string Sender = "") 58 | { 59 | if (!IsInitialized) InitializeLogger(); 60 | if ((Message != null)) 61 | { 62 | if (Message.Contains("\n")) 63 | { 64 | foreach (string msg in Message.Split('\n')) 65 | { 66 | SendToHandlers(msg, Sender, Level); 67 | } 68 | } 69 | else 70 | { 71 | SendToHandlers(Message, Sender, Level); 72 | } 73 | } 74 | } 75 | 76 | public static void PrintBoxed(string text, ConsoleColor color) 77 | { 78 | 79 | Console.ResetColor(); 80 | string[] lines = text.Split('\n'); 81 | 82 | for (int i = 0; i != lines.Length; i++) 83 | { 84 | lines[i] = lines[i].Replace("\n", String.Empty); 85 | lines[i] = lines[i].Replace("\r", String.Empty); 86 | lines[i] = lines[i].Replace("\t", String.Empty); 87 | } 88 | 89 | int total = (lines.Length <= 1 ? text.Length : lines.Max(a => a.Length)) + 6; 90 | 91 | string x = ""; 92 | string y = ""; 93 | for (int i = 0; i != total; i++) 94 | { 95 | x += "█"; 96 | } 97 | for (int i = 0; i != total - 2; i++) 98 | { 99 | y += " "; 100 | } 101 | 102 | for (int i = 0; i < lines.Length; i++) 103 | { 104 | while (lines[i].Length < total - 6) 105 | { 106 | lines[i] += " "; 107 | } 108 | } 109 | 110 | Console.WriteLine(""); 111 | Console.WriteLine(""); 112 | Console.Write(" "); 113 | Console.ForegroundColor = color; 114 | Console.Write(x); 115 | Console.WriteLine(""); 116 | Console.ResetColor(); 117 | Console.Write(" "); 118 | Console.ForegroundColor = color; 119 | Console.Write("█"); 120 | Console.ResetColor(); 121 | Console.Write(y); 122 | Console.ForegroundColor = color; 123 | Console.Write("█"); 124 | 125 | foreach (var line in lines) 126 | { 127 | Console.WriteLine(""); 128 | Console.ResetColor(); 129 | Console.Write(" "); 130 | Console.ForegroundColor = color; 131 | Console.Write("█"); 132 | Console.ResetColor(); 133 | Console.Write(" " + line + " "); 134 | Console.ForegroundColor = color; 135 | Console.Write("█"); 136 | Console.ResetColor(); 137 | } 138 | 139 | Console.WriteLine(""); 140 | 141 | Console.Write(" "); 142 | Console.ForegroundColor = color; 143 | Console.Write("█"); 144 | Console.ResetColor(); 145 | Console.Write(y); 146 | Console.ForegroundColor = color; 147 | Console.WriteLine("█"); 148 | Console.ResetColor(); 149 | Console.Write(" "); 150 | Console.ForegroundColor = color; 151 | Console.Write(x); 152 | Console.ResetColor(); 153 | Console.WriteLine(""); 154 | } 155 | 156 | private static void SendToHandlers(string text, string sender, LogLevel level) 157 | { 158 | foreach (var entity in new List(HANDLER_REGISTRY.Values)) 159 | { 160 | if (level < entity.VerbosityLevel()) continue; 161 | entity.Append(text, sender, level); 162 | } 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc 262 | 263 | # Ignore ModManager executables 264 | ModManager.exe 265 | ModdingTools/ModManager.exe 266 | /ModdingTools/.vshistory 267 | /ModdingTools/GUI/.vshistory 268 | /ModdingTools/Modding/.vshistory/ModObject.cs 269 | /ModdingTools/Properties/.vshistory/Settings.settings 270 | /ModdingTools/UEngine/.vshistory 271 | /Release 272 | *.vshistory --------------------------------------------------------------------------------