├── ClientApp ├── public │ ├── _samples │ │ └── config.json │ ├── favicon.ico │ └── index.html ├── src │ ├── components │ │ └── Dashboard │ │ │ ├── Dashboard.css │ │ │ ├── index.vue │ │ │ ├── Dashboard.js │ │ │ └── Dashboard.html │ ├── assets │ │ ├── styles │ │ │ ├── _variables.scss │ │ │ └── _bootstrap.scss │ │ ├── icon.png │ │ ├── logo.png │ │ └── logo.svg │ ├── helpers │ │ └── confirmDialog │ │ │ ├── index.vue │ │ │ └── src │ │ │ └── helpers │ │ │ ├── confirmDialog.html │ │ │ └── confirmDialog.js │ ├── services │ │ ├── http-common.js │ │ ├── dashboard-services.js │ │ └── common-services.js │ ├── store │ │ ├── store-config.js │ │ ├── store-modal.js │ │ └── store-confirmDialog.js │ ├── main.js │ └── App.vue ├── vue.config.js ├── babel.config.js ├── README.md ├── Helpers.md └── package.json ├── _config.yml ├── Donation.png ├── Core ├── steam_api64.dll ├── Steamworks.NET.dll ├── Models │ ├── SourceEnum.cs │ ├── GameChange.cs │ ├── DetailChanges.cs │ ├── ModListChanges.cs │ ├── SmMod.cs │ ├── Metadata.cs │ ├── Rules.cs │ ├── LatestReleaseModelGithub.cs │ └── Mod.cs ├── Kenshi_Data │ ├── Enums │ │ ├── ModMode.cs │ │ ├── ItemLoadFlags.cs │ │ ├── State.cs │ │ ├── ChangeType.cs │ │ └── ItemType.cs │ ├── Model │ │ ├── Header.cs │ │ └── Desc.cs │ ├── Changes.cs │ ├── ItemFilter.cs │ └── ConflictManager.cs ├── config.json ├── KenshiToolConfig.cs ├── Helpers.cs ├── SteamWorkshop.cs ├── Constants.cs ├── Logging.cs ├── Core.csproj ├── ModMetadataReader.cs ├── RuleService.cs └── LoadService.cs ├── KenshiModTool ├── icon.png ├── icons │ ├── save.png │ ├── order.png │ ├── Gear_50px.png │ ├── conflicts.png │ ├── softwareUpdate.png │ └── check linkback │ │ ├── link.png │ │ ├── FCS_32.png │ │ ├── Kenshi_32.png │ │ ├── Untitled.png │ │ ├── Error_16px.png │ │ ├── Folder-icon.png │ │ ├── Folder_16px.png │ │ ├── Sort Up_16px.png │ │ ├── Get-Info-icon.png │ │ ├── Sort Down_16px.png │ │ ├── Sort Down_50px.png │ │ ├── kenshi_x64_105.ico │ │ ├── Apps-Steam-icon.png │ │ ├── Buttons │ │ ├── File_32px.png │ │ ├── Info_50px.png │ │ ├── Save_32px.png │ │ ├── Save_50px.png │ │ ├── About_50px.png │ │ ├── Delete_32px.png │ │ ├── Folder_32px.png │ │ ├── Search_16px.png │ │ ├── Search_32px.png │ │ ├── AutoSort_32px.png │ │ ├── Compare_32px.png │ │ ├── Document_32px.png │ │ ├── List View_50px.png │ │ ├── Refresh_32px.png │ │ ├── Refresh_50px.png │ │ ├── Check File_50px.png │ │ ├── Delete File_50px.png │ │ ├── Folder_Game_32px.png │ │ ├── Folder_Mods_32px.png │ │ ├── Synchronize_32px.png │ │ ├── Folder_Steam_32px.png │ │ └── Question Mark_50px.png │ │ ├── Unavailable_16px.png │ │ ├── Unavailable_48px.png │ │ ├── User-Steam-Folder.png │ │ ├── Delete Folder_16px.png │ │ ├── High Priority_16px.png │ │ ├── icons8_Edit_Property.ico │ │ ├── icons8_Edit_Property_16.png │ │ ├── icons8_Edit_Property_32.png │ │ ├── icons8_Edit_Property_48.png │ │ ├── icons8_Edit_Property_64.png │ │ └── forgotten construction set_32512.ico ├── Model │ ├── ComboData.cs │ ├── ModColors.cs │ └── ModFolder.cs ├── Constants │ └── ConstantMessages.cs ├── App.xaml ├── AssemblyInfo.cs ├── Properties │ └── PublishProfiles │ │ ├── Standalone.pubxml │ │ └── FullRelease.pubxml ├── SelectVersion.xaml ├── Configuration.xaml.cs ├── App.xaml.cs ├── CommonService.cs ├── SelectVersion.xaml.cs ├── KenshiModTool.csproj ├── Configuration.xaml ├── Tooling.xaml └── Tooling.xaml.cs ├── KMM-GUI ├── icons │ ├── FCS_32.png │ ├── Untitled.png │ ├── Error_16px.png │ ├── Gear_50px.png │ ├── Kenshi_32.png │ ├── Folder-icon.png │ ├── Folder_16px.png │ ├── Get-Info-icon.png │ ├── Sort Up_16px.png │ ├── Apps-Steam-icon.png │ ├── Sort Down_16px.png │ ├── Sort Down_50px.png │ ├── kenshi_x64_105.ico │ ├── Buttons │ │ ├── About_50px.png │ │ ├── File_32px.png │ │ ├── Info_50px.png │ │ ├── Save_32px.png │ │ ├── Save_50px.png │ │ ├── Compare_32px.png │ │ ├── Delete_32px.png │ │ ├── Folder_32px.png │ │ ├── Refresh_32px.png │ │ ├── Refresh_50px.png │ │ ├── Search_16px.png │ │ ├── Search_32px.png │ │ ├── AutoSort_32px.png │ │ ├── Check File_50px.png │ │ ├── Document_32px.png │ │ ├── List View_50px.png │ │ ├── Delete File_50px.png │ │ ├── Folder_Game_32px.png │ │ ├── Folder_Mods_32px.png │ │ ├── Folder_Steam_32px.png │ │ ├── Synchronize_32px.png │ │ └── Question Mark_50px.png │ ├── Delete Folder_16px.png │ ├── High Priority_16px.png │ ├── Unavailable_16px.png │ ├── Unavailable_48px.png │ ├── User-Steam-Folder.png │ ├── icons8_Edit_Property.ico │ ├── icons8_Edit_Property_16.png │ ├── icons8_Edit_Property_32.png │ ├── icons8_Edit_Property_48.png │ ├── icons8_Edit_Property_64.png │ └── forgotten construction set_32512.ico ├── App.xaml.cs ├── App.xaml ├── AssemblyInfo.cs ├── MainWindow.xaml.cs ├── Mod.cs ├── KenshiModManDotNet.csproj └── MainWindow.xaml ├── TestProject ├── obj │ └── Debug │ │ └── netcoreapp3.1 │ │ ├── TestProject.AssemblyInfoInputs.cache │ │ └── TestProject.AssemblyInfo.cs ├── steam_api64.dll ├── TestProject.csproj └── Program.cs ├── .github └── FUNDING.yml ├── .vs └── KenshiModTool │ └── v16 │ └── TestStore │ └── 0 │ └── testlog.manifest ├── WebServer ├── Controllers │ └── HomeController.cs ├── Builder.cs ├── WebServer.csproj └── Startup.cs ├── LICENSE ├── versioning.ps1 ├── updatelist-standalone.xml ├── updatelist-selfcontained.xml ├── README.md ├── rules by Tag.js ├── KenshiModTool.sln └── .gitignore /ClientApp/public/_samples/config.json: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /ClientApp/src/components/Dashboard/Dashboard.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ClientApp/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "transpileDependencies": [ 3 | ] 4 | } -------------------------------------------------------------------------------- /Donation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/Donation.png -------------------------------------------------------------------------------- /ClientApp/src/assets/styles/_variables.scss: -------------------------------------------------------------------------------- 1 | $body-bg: white; 2 | $body-color: black; 3 | $primary: blue; -------------------------------------------------------------------------------- /Core/steam_api64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/Core/steam_api64.dll -------------------------------------------------------------------------------- /Core/Steamworks.NET.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/Core/Steamworks.NET.dll -------------------------------------------------------------------------------- /KenshiModTool/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icon.png -------------------------------------------------------------------------------- /ClientApp/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /KMM-GUI/icons/FCS_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/FCS_32.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Untitled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Untitled.png -------------------------------------------------------------------------------- /TestProject/obj/Debug/netcoreapp3.1/TestProject.AssemblyInfoInputs.cache: -------------------------------------------------------------------------------- 1 | ebbbe5486fa7a57e58b9310ea998e0a741bab568 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: millerscout 4 | ko_fi: millerscout 5 | -------------------------------------------------------------------------------- /ClientApp/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/ClientApp/public/favicon.ico -------------------------------------------------------------------------------- /KMM-GUI/icons/Error_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Error_16px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Gear_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Gear_50px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Kenshi_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Kenshi_32.png -------------------------------------------------------------------------------- /KenshiModTool/icons/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/save.png -------------------------------------------------------------------------------- /TestProject/steam_api64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/TestProject/steam_api64.dll -------------------------------------------------------------------------------- /ClientApp/src/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/ClientApp/src/assets/icon.png -------------------------------------------------------------------------------- /ClientApp/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/ClientApp/src/assets/logo.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Folder-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Folder-icon.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Folder_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Folder_16px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Get-Info-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Get-Info-icon.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Sort Up_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Sort Up_16px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/order.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Apps-Steam-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Apps-Steam-icon.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Sort Down_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Sort Down_16px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Sort Down_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Sort Down_50px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/kenshi_x64_105.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/kenshi_x64_105.ico -------------------------------------------------------------------------------- /KenshiModTool/icons/Gear_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/Gear_50px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/conflicts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/conflicts.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/About_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/About_50px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/File_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/File_32px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Info_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Info_50px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Save_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Save_32px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Save_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Save_50px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Delete Folder_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Delete Folder_16px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/High Priority_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/High Priority_16px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Unavailable_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Unavailable_16px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Unavailable_48px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Unavailable_48px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/User-Steam-Folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/User-Steam-Folder.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Compare_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Compare_32px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Delete_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Delete_32px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Folder_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Folder_32px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Refresh_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Refresh_32px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Refresh_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Refresh_50px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Search_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Search_16px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Search_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Search_32px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/icons8_Edit_Property.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/icons8_Edit_Property.ico -------------------------------------------------------------------------------- /KenshiModTool/icons/softwareUpdate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/softwareUpdate.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/AutoSort_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/AutoSort_32px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Check File_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Check File_50px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Document_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Document_32px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/List View_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/List View_50px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/icons8_Edit_Property_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/icons8_Edit_Property_16.png -------------------------------------------------------------------------------- /KMM-GUI/icons/icons8_Edit_Property_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/icons8_Edit_Property_32.png -------------------------------------------------------------------------------- /KMM-GUI/icons/icons8_Edit_Property_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/icons8_Edit_Property_48.png -------------------------------------------------------------------------------- /KMM-GUI/icons/icons8_Edit_Property_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/icons8_Edit_Property_64.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Delete File_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Delete File_50px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Folder_Game_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Folder_Game_32px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Folder_Mods_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Folder_Mods_32px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Folder_Steam_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Folder_Steam_32px.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Synchronize_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Synchronize_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/link.png -------------------------------------------------------------------------------- /KMM-GUI/icons/Buttons/Question Mark_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/Buttons/Question Mark_50px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/FCS_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/FCS_32.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Kenshi_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Kenshi_32.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Untitled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Untitled.png -------------------------------------------------------------------------------- /.vs/KenshiModTool/v16/TestStore/0/testlog.manifest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/.vs/KenshiModTool/v16/TestStore/0/testlog.manifest -------------------------------------------------------------------------------- /KMM-GUI/icons/forgotten construction set_32512.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KMM-GUI/icons/forgotten construction set_32512.ico -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Error_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Error_16px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Folder-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Folder-icon.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Folder_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Folder_16px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Sort Up_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Sort Up_16px.png -------------------------------------------------------------------------------- /Core/Models/SourceEnum.cs: -------------------------------------------------------------------------------- 1 | namespace Core.Models 2 | { 3 | public enum SourceEnum 4 | { 5 | Steam, 6 | GameFolder, 7 | Other 8 | } 9 | } -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Get-Info-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Get-Info-icon.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Sort Down_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Sort Down_16px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Sort Down_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Sort Down_50px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/kenshi_x64_105.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/kenshi_x64_105.ico -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Apps-Steam-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Apps-Steam-icon.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/File_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/File_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Info_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Info_50px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Save_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Save_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Save_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Save_50px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Unavailable_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Unavailable_16px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Unavailable_48px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Unavailable_48px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/User-Steam-Folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/User-Steam-Folder.png -------------------------------------------------------------------------------- /ClientApp/src/components/Dashboard/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/About_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/About_50px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Delete_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Delete_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Folder_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Folder_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Search_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Search_16px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Search_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Search_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Delete Folder_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Delete Folder_16px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/High Priority_16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/High Priority_16px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/AutoSort_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/AutoSort_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Compare_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Compare_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Document_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Document_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/List View_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/List View_50px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Refresh_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Refresh_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Refresh_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Refresh_50px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/icons8_Edit_Property.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/icons8_Edit_Property.ico -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Check File_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Check File_50px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Delete File_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Delete File_50px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Folder_Game_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Folder_Game_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Folder_Mods_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Folder_Mods_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Synchronize_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Synchronize_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/icons8_Edit_Property_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/icons8_Edit_Property_16.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/icons8_Edit_Property_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/icons8_Edit_Property_32.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/icons8_Edit_Property_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/icons8_Edit_Property_48.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/icons8_Edit_Property_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/icons8_Edit_Property_64.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Folder_Steam_32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Folder_Steam_32px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/Buttons/Question Mark_50px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/Buttons/Question Mark_50px.png -------------------------------------------------------------------------------- /KenshiModTool/icons/check linkback/forgotten construction set_32512.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/HEAD/KenshiModTool/icons/check linkback/forgotten construction set_32512.ico -------------------------------------------------------------------------------- /ClientApp/src/helpers/confirmDialog/index.vue: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /KenshiModTool/Model/ComboData.cs: -------------------------------------------------------------------------------- 1 | namespace KenshiModTool.Model 2 | { 3 | public class ComboData 4 | { 5 | public int Id { get; set; } 6 | public string Value { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /Core/Models/GameChange.cs: -------------------------------------------------------------------------------- 1 | namespace Core.Models 2 | { 3 | public class GameChange 4 | { 5 | public string State { get; set; } 6 | public string ModName { get; set; } 7 | public object Value { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Core/Models/DetailChanges.cs: -------------------------------------------------------------------------------- 1 | namespace Core.Models 2 | { 3 | public class DetailChanges 4 | { 5 | public string Type { get; set; } 6 | public string Name { get; set; } 7 | public string PropertyKey { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Core/Kenshi_Data/Enums/ModMode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Core.Kenshi_Data.Enums 6 | { 7 | public enum ModMode 8 | { 9 | BASE, 10 | ACTIVE, 11 | LOCKED, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Core/Kenshi_Data/Enums/ItemLoadFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Core.Kenshi_Data.Enums 6 | { 7 | public enum ItemLoadFlags 8 | { 9 | MODIFIED = 1, 10 | RENAMED = 2, 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Core/Models/ModListChanges.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | 3 | namespace Core.Models 4 | { 5 | public class ModListChanges 6 | { 7 | public ConcurrentStack Mod { get; set; } 8 | public ConcurrentStack ChangeList { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /KenshiModTool/Constants/ConstantMessages.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace KenshiModTool 6 | { 7 | public static class ConstantMessages 8 | { 9 | public const string GameFolderNotConfiguredCorrectly = "Game folder not configured correctly."; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ClientApp/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /Core/Kenshi_Data/Enums/State.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Core.Kenshi_Data.Enums 6 | { 7 | public enum State 8 | { 9 | UNKNOWN, 10 | INVALID, 11 | ORIGINAL, 12 | OWNED, 13 | MODIFIED, 14 | LOCKED, 15 | REMOVED, 16 | LOCKED_REMOVED, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /KenshiModTool/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Core/Kenshi_Data/Enums/ChangeType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Core.Kenshi_Data.Enums 6 | { 7 | public enum ChangeType 8 | { 9 | NAME, 10 | VALUE, 11 | NEWREF, 12 | MODREF, 13 | DELREF, 14 | NEWINST, 15 | MODINST, 16 | INSTVALUE, 17 | INVALIDREF, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /TestProject/TestProject.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | Debug;Release;Standalone;SelfContained 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Core/Kenshi_Data/Model/Header.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Core.Kenshi_Data.Model 6 | { 7 | public class Header 8 | { 9 | public string Author = ""; 10 | public string Description = ""; 11 | public int Version = 1; 12 | public List Dependencies; 13 | public List Referenced; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /KMM-GUI/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace KenshiModManDotNet 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ClientApp/src/services/http-common.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | export const $http = axios.create({ 4 | baseURL: `` 5 | }); 6 | 7 | $http.interceptors.response.use( 8 | function(response) { 9 | return response; 10 | }, 11 | function(error) { 12 | if (error.response.status === 500) { 13 | alert("(WIP custom message) Error") 14 | } else { 15 | return Promise.reject(error); 16 | } 17 | } 18 | ); 19 | -------------------------------------------------------------------------------- /KMM-GUI/App.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ClientApp/README.md: -------------------------------------------------------------------------------- 1 | # kmm 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /KenshiModTool/Model/ModColors.cs: -------------------------------------------------------------------------------- 1 | namespace KenshiModTool.Model 2 | { 3 | public static class ModColors 4 | { 5 | public static string SearchColor { get; set; } = "#ff9632"; 6 | public static string RequisiteNotFoundColor { get; set; } = "red"; 7 | public static string HasConflictsColor { get; set; } = "purple"; 8 | public static string SomeErrorWhileReadingMetadataColor { get; set; } = "gray"; 9 | } 10 | } -------------------------------------------------------------------------------- /Core/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "gamePath": "", 3 | "SteamModsPath": "", 4 | "SteamPageUrl": "https://steamcommunity.com/sharedfiles/filedetails/?id=", 5 | "NexusPageUrl": "https://www.nexusmods.com/kenshi/search/?gsearch=", 6 | "ConflictAnalyzerPath": "C:\\project\\ModConflictManager\\publish\\x64\\Mod Conflict Manager.exe", 7 | "masterlistSource": "millerscout/kmm-masterlist", 8 | "MaxLogFiles": "5", 9 | "CheckForUpdatesAutomatically": true 10 | } -------------------------------------------------------------------------------- /WebServer/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Core; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace WebServer.Controllers 5 | { 6 | [ApiController] 7 | [Route("Home")] 8 | public class HomeController : ControllerBase 9 | { 10 | public HomeController() 11 | { 12 | LoadService.Setup(); 13 | } 14 | 15 | [HttpGet("index")] 16 | public IActionResult Get() => Ok(LoadService.GetListOfMods()); 17 | } 18 | } -------------------------------------------------------------------------------- /ClientApp/src/services/dashboard-services.js: -------------------------------------------------------------------------------- 1 | import { $http } from "@/services/http-common"; 2 | import storeConfig from "@/store/store-config.js"; 3 | 4 | const services = { 5 | Get 6 | }; 7 | export default services; 8 | 9 | function Get() { 10 | if (storeConfig.state.isSandBox) { 11 | return $http.get(`/_samples/modlist.json`) 12 | } else { 13 | // return $http.get(`Home/Get`); 14 | return $http.get(`http://localhost:5000/Home/index`); 15 | } 16 | } -------------------------------------------------------------------------------- /Core/Models/SmMod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Core.Models 5 | { 6 | public class SmMod 7 | { 8 | public Guid UniqueIdentifier { get; set; } 9 | public string FileName { get; set; } 10 | public List References { get; set; } 11 | public List Dependencies { get; set; } 12 | public bool OrderedAutomatically { get; set; } = false; 13 | public int Order { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /ClientApp/src/helpers/confirmDialog/src/helpers/confirmDialog.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | {{dialog.body}} 16 | 17 |
-------------------------------------------------------------------------------- /ClientApp/src/services/common-services.js: -------------------------------------------------------------------------------- 1 | import { $http } from "@/services/http-common"; 2 | import storeConfig from "@/store/store-config.js"; 3 | 4 | const services = { 5 | getConfig 6 | }; 7 | export default services; 8 | 9 | function getConfig() { 10 | 11 | if (storeConfig.state.isSandBox) { 12 | return new Promise((resolve) => { 13 | resolve({ 14 | "gamePath": "", 15 | "SteamModsPath": "" 16 | }) 17 | }); 18 | } else { 19 | return $http.get(`Internal/getConfig`); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Core/Models/Metadata.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Core.Models 4 | { 5 | public class Metadata 6 | { 7 | public Metadata() 8 | { 9 | Dependencies = new List(); 10 | Referenced = new List { }; 11 | } 12 | 13 | public string Author = ""; 14 | public string Description = ""; 15 | public int Version = 1; 16 | public List Dependencies; 17 | public List Referenced; 18 | } 19 | } -------------------------------------------------------------------------------- /WebServer/Builder.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace WebServer 6 | { 7 | public static class Builder 8 | { 9 | public static IWebHost CreateWebHostBuilder() => 10 | WebHost.CreateDefaultBuilder(new string[0]) 11 | .UseStartup() 12 | .ConfigureLogging(logging => logging.SetMinimumLevel(LogLevel.Warning)) 13 | .UseUrls("http://0.0.0.0:5000/") 14 | .Build(); 15 | } 16 | } -------------------------------------------------------------------------------- /ClientApp/Helpers.md: -------------------------------------------------------------------------------- 1 | # Helpers 2 | 3 | ### How to show confirm menu 4 | 5 | ``` javascript 6 | this.$store 7 | .dispatch("storeDialog/confirm", { 8 | title: `The Title `, 9 | body: `Are you sure?` 10 | }) 11 | .then(confirmation => { 12 | if (confirmation) { 13 | //some action 14 | } else { 15 | return; 16 | } 17 | }); 18 | ``` 19 | 20 | ### Sandbox mode 21 | ``` javascript 22 | /// after "const store", add the following line. 23 | store.dispatch("storeConfig/setSandbox", true); 24 | ``` -------------------------------------------------------------------------------- /ClientApp/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | Artboard 46 2 | -------------------------------------------------------------------------------- /ClientApp/src/helpers/confirmDialog/src/helpers/confirmDialog.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'src-helpers-confirm-dialog', 3 | components: {}, 4 | props: [], 5 | data: () => ({ 6 | showDialog: false 7 | }), 8 | computed: { 9 | dialog() { 10 | return this.$store.state.storeDialog; 11 | } 12 | }, 13 | methods: { 14 | confirm() { 15 | this.dialog.resolve(true); 16 | this.$store.commit("dialog/close"); 17 | }, 18 | cancel() { 19 | this.dialog.resolve(false); 20 | this.$store.commit("dialog/close"); 21 | } 22 | } 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /KMM-GUI/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] 11 | -------------------------------------------------------------------------------- /KenshiModTool/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] -------------------------------------------------------------------------------- /Core/KenshiToolConfig.cs: -------------------------------------------------------------------------------- 1 | namespace Core 2 | { 3 | public class KenshiToolConfig 4 | { 5 | public string GamePath { get; set; } 6 | public string ModFolder => System.IO.Path.Combine(LoadService.config.GamePath, "Mods"); 7 | public string SteamModsPath { get; set; } 8 | public string SteamPageUrl { get; set; } 9 | public string NexusPageUrl { get; set; } 10 | public string MasterlistVersion { get; set; } 11 | public string MasterlistSource { get; set; } 12 | public int MaxLogFiles { get; set; } = 5; 13 | public bool CheckForUpdatesAutomatically { get; set; } = true; 14 | } 15 | } -------------------------------------------------------------------------------- /ClientApp/src/store/store-config.js: -------------------------------------------------------------------------------- 1 | import services from "@/services/common-services"; 2 | 3 | const initialState = {}; 4 | 5 | const state = Object.assign({}, initialState); 6 | 7 | const mutations = { 8 | config: function (state, payload) { 9 | state.config = payload 10 | }, 11 | isSandbox: function (state, payload) { 12 | state.isSandBox = payload 13 | }, 14 | }; 15 | 16 | const actions = { 17 | loadConfigs: function ({ commit }) { 18 | commit("config", services.getConfig()); 19 | }, 20 | setSandbox: function ({ commit }, value) { 21 | commit("isSandbox", value); 22 | } 23 | }; 24 | 25 | export default { 26 | namespaced: true, 27 | mutations, 28 | state, 29 | actions 30 | }; 31 | -------------------------------------------------------------------------------- /Core/Models/Rules.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace Core.Models 5 | { 6 | public class Rules 7 | { 8 | public int Order { get; set; } 9 | 10 | [JsonIgnore] 11 | public int MaxRange { get; set; } = 5000; 12 | 13 | public string Name { get; set; } 14 | public List Mod { get; set; } 15 | 16 | [JsonIgnore] 17 | public List ModsOrdered { get; set; } = new List(); 18 | 19 | [JsonIgnore] 20 | public int InitialRange 21 | { 22 | get 23 | { 24 | return MaxRange * Order; 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Core/Kenshi_Data/Model/Desc.cs: -------------------------------------------------------------------------------- 1 | using Core.Kenshi_Data.Enums; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Core.Kenshi_Data.Model 7 | { 8 | public class Desc 9 | { 10 | public ItemType list = ItemType.NULL_ITEM; 11 | public string description = ""; 12 | public string category = "misc"; 13 | public string mask = ""; 14 | public object defaultValue; 15 | public int flags; 16 | public int limit; 17 | public DescCondition condition; 18 | public class DescCondition 19 | { 20 | public string key; 21 | public object values; 22 | public bool match; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /KenshiModTool/Properties/PublishProfiles/Standalone.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | FileSystem 8 | Standalone 9 | Any CPU 10 | netcoreapp3.1 11 | ..\publish\Standalone 12 | win-x64 13 | false 14 | True 15 | False 16 | 17 | -------------------------------------------------------------------------------- /ClientApp/src/store/store-modal.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | active: false, 3 | title: "", 4 | body: "", 5 | resolve: null, 6 | reject: null 7 | }; 8 | 9 | const state = Object.assign({}, initialState); 10 | 11 | const mutations = { 12 | open: (state, payload) => { 13 | Object.assign(state, payload); 14 | }, 15 | close: state => { 16 | this.state = Object.assign(state, initialState); 17 | } 18 | }; 19 | 20 | const actions = { 21 | confirm: ({ commit }, { title, body }) => { 22 | return new Promise((resolve, reject) => { 23 | commit("open", { 24 | active: true, 25 | title, 26 | body, 27 | resolve, 28 | reject 29 | }); 30 | }); 31 | } 32 | }; 33 | 34 | export default { 35 | namespaced: true, 36 | state, 37 | mutations, 38 | actions 39 | }; 40 | -------------------------------------------------------------------------------- /ClientApp/src/store/store-confirmDialog.js: -------------------------------------------------------------------------------- 1 | const initialState = { 2 | active: false, 3 | title: "", 4 | body: "", 5 | resolve: null, 6 | reject: null 7 | }; 8 | 9 | const state = Object.assign({}, initialState); 10 | 11 | const mutations = { 12 | open: (state, payload) => { 13 | Object.assign(state, payload); 14 | }, 15 | close: state => { 16 | this.state = Object.assign(state, initialState); 17 | } 18 | }; 19 | 20 | const actions = { 21 | confirm: ({ commit }, { title, body }) => { 22 | return new Promise((resolve, reject) => { 23 | commit("open", { 24 | active: true, 25 | title, 26 | body, 27 | resolve, 28 | reject 29 | }); 30 | }); 31 | } 32 | }; 33 | 34 | export default { 35 | namespaced: true, 36 | state, 37 | mutations, 38 | actions 39 | }; 40 | -------------------------------------------------------------------------------- /KenshiModTool/Properties/PublishProfiles/FullRelease.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | FileSystem 8 | SelfContained 9 | Any CPU 10 | netcoreapp3.1 11 | ..\publish\FullRelease 12 | win-x64 13 | true 14 | True 15 | False 16 | False 17 | 18 | -------------------------------------------------------------------------------- /KMM-GUI/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace KenshiModManDotNet 17 | { 18 | /// 19 | /// Interaction logic for MainWindow.xaml 20 | /// 21 | public partial class MainWindow : Window 22 | { 23 | public MainWindow() 24 | { 25 | InitializeComponent(); 26 | listviewMods.ItemsSource = Mod.GetDefaultMods(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /KenshiModTool/Model/ModFolder.cs: -------------------------------------------------------------------------------- 1 | using Core; 2 | using Core.Models; 3 | using System; 4 | using System.IO; 5 | 6 | namespace KenshiModTool.Model 7 | { 8 | public class ModFolder 9 | { 10 | public ModFolder(Mod mod) 11 | { 12 | DisplayName = mod.DisplayName; 13 | FilePath = mod.FilePath; 14 | UniqueIdentifier = mod.UniqueIdentifier; 15 | Source = mod.Source; 16 | 17 | var symbLink = System.IO.Path.Combine(LoadService.config.GamePath, "Mods", System.IO.Path.GetFileNameWithoutExtension(mod.FilePath)); 18 | HasSymbLink = Directory.Exists(symbLink) && LoadService.IsSymbolic(symbLink); 19 | } 20 | 21 | public string Color { get; set; } 22 | public Guid UniqueIdentifier { get; } 23 | public SourceEnum Source { get; } 24 | public string DisplayName { get; } 25 | public string FilePath { get; } 26 | public bool HasSymbLink { get; set; } 27 | public bool Selected { get; set; } 28 | } 29 | } -------------------------------------------------------------------------------- /ClientApp/src/main.js: -------------------------------------------------------------------------------- 1 | /* Requisites */ 2 | 3 | import Vue from 'vue' 4 | import App from './App.vue' 5 | import 'roboto-fontface/css/roboto/roboto-fontface.css' 6 | import '@mdi/font/css/materialdesignicons.css' 7 | 8 | import Vuex from "vuex"; 9 | 10 | 11 | import { BootstrapVue, IconsPlugin } from 'bootstrap-vue' 12 | import VueContextMenu from 'vue-context-menu' 13 | 14 | import 'bootstrap/dist/css/bootstrap.css' 15 | 16 | import 'bootstrap-vue/dist/bootstrap-vue.css' 17 | 18 | 19 | Vue.use(BootstrapVue) 20 | Vue.use(IconsPlugin) 21 | Vue.use(VueContextMenu) 22 | /* Internal. */ 23 | import storeConfig from "./store/store-config"; 24 | import storeDialog from "./store/store-confirmDialog"; 25 | 26 | /* configuration */ 27 | Vue.config.productionTip = false 28 | Vue.use(Vuex); 29 | 30 | const store = new Vuex.Store({ 31 | state: {}, 32 | modules: { 33 | storeConfig, 34 | storeDialog, 35 | } 36 | }); 37 | 38 | store.dispatch("storeConfig/setSandbox", false); 39 | store.dispatch("storeConfig/loadConfigs"); 40 | 41 | new Vue({ 42 | render: h => h(App), 43 | store 44 | }).$mount('#app') -------------------------------------------------------------------------------- /TestProject/obj/Debug/netcoreapp3.1/TestProject.AssemblyInfo.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 | using System; 12 | using System.Reflection; 13 | 14 | [assembly: System.Reflection.AssemblyCompanyAttribute("TestProject")] 15 | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 16 | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 17 | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] 18 | [assembly: System.Reflection.AssemblyProductAttribute("TestProject")] 19 | [assembly: System.Reflection.AssemblyTitleAttribute("TestProject")] 20 | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] 21 | 22 | // Generated by the MSBuild WriteCodeFragment class. 23 | 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Antonio M S S Jr. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /KenshiModTool/SelectVersion.xaml: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /WebServer/WebServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | Debug;Release;Standalone;SelfContained 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Core/Helpers.cs: -------------------------------------------------------------------------------- 1 | using Core.Models; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Security.Cryptography; 7 | 8 | namespace Core 9 | { 10 | public static class Helpers 11 | { 12 | public static string SHA256CheckSum(this string filePath) 13 | { 14 | using (SHA256 SHA256 = SHA256Managed.Create()) 15 | { 16 | using (FileStream fileStream = File.OpenRead(filePath)) 17 | return Convert.ToBase64String(SHA256.ComputeHash(fileStream)); 18 | } 19 | } 20 | 21 | public static IEnumerable Filter(this IEnumerable List, bool showRegularMods, bool showSteamMods) 22 | { 23 | if (showRegularMods && showSteamMods) return List; 24 | 25 | if (showRegularMods) 26 | return List.Where(c => c.Source == SourceEnum.GameFolder); 27 | 28 | if (showSteamMods) 29 | return List.Where(c => c.Source == SourceEnum.Steam); 30 | 31 | return List; 32 | } 33 | 34 | public static int Percent(this int val, int qty) => val * 100 / qty; 35 | 36 | public static string GetCurrentApplicationPath() => Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); 37 | 38 | } 39 | } -------------------------------------------------------------------------------- /KenshiModTool/Configuration.xaml.cs: -------------------------------------------------------------------------------- 1 | using Core; 2 | using System.Windows; 3 | 4 | namespace KenshiModTool 5 | { 6 | /// 7 | /// Interaction logic for Configuration.xaml 8 | /// 9 | public partial class Configuration : Window 10 | { 11 | public Configuration() 12 | { 13 | InitializeComponent(); 14 | 15 | if (LoadService.config == null) 16 | { 17 | MessageBox.Show("could not load configs, strange.... if this persists delete config.json."); 18 | this.Close(); 19 | } 20 | txtSteamPath.Text = LoadService.config.SteamModsPath; 21 | txtMasterlist.Text = LoadService.config.MasterlistSource; 22 | TxtGamePath.Text = LoadService.config.GamePath; 23 | chk_updatesAutomatically.IsChecked = LoadService.config.CheckForUpdatesAutomatically; 24 | } 25 | 26 | public void Save(object sender, RoutedEventArgs e) 27 | { 28 | LoadService.config.SteamModsPath = txtSteamPath.Text; 29 | LoadService.config.MasterlistSource = txtMasterlist.Text; 30 | LoadService.config.GamePath = TxtGamePath.Text; 31 | LoadService.config.CheckForUpdatesAutomatically = chk_updatesAutomatically.IsChecked ?? true; 32 | 33 | LoadService.SaveConfig(); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Core/Models/LatestReleaseModelGithub.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | 4 | namespace Core.Models 5 | { 6 | public class LatestReleaseModelGithub 7 | { 8 | [JsonProperty("url")] 9 | public Uri Url { get; set; } 10 | 11 | [JsonProperty("assets_url")] 12 | public Uri AssetsUrl { get; set; } 13 | 14 | [JsonProperty("upload_url")] 15 | public string UploadUrl { get; set; } 16 | 17 | [JsonProperty("html_url")] 18 | public Uri HtmlUrl { get; set; } 19 | 20 | [JsonProperty("id")] 21 | public long Id { get; set; } 22 | 23 | [JsonProperty("node_id")] 24 | public string NodeId { get; set; } 25 | 26 | [JsonProperty("tag_name")] 27 | public string TagName { get; set; } 28 | 29 | [JsonProperty("target_commitish")] 30 | public string TargetCommitish { get; set; } 31 | 32 | [JsonProperty("name")] 33 | public string Name { get; set; } 34 | 35 | [JsonProperty("draft")] 36 | public bool Draft { get; set; } 37 | 38 | [JsonProperty("prerelease")] 39 | public bool Prerelease { get; set; } 40 | 41 | [JsonProperty("created_at")] 42 | public DateTimeOffset CreatedAt { get; set; } 43 | 44 | [JsonProperty("published_at")] 45 | public DateTimeOffset PublishedAt { get; set; } 46 | } 47 | } -------------------------------------------------------------------------------- /ClientApp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kmm", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@mdi/font": "^3.6.95", 12 | "axios": "^0.21.1", 13 | "bootstrap": "^4.4.1", 14 | "bootstrap-vue": "^2.13.1", 15 | "core-js": "^3.6.4", 16 | "roboto-fontface": "*", 17 | "vue": "^2.6.11", 18 | "vue-context-menu": "^2.0.6", 19 | "vuedraggable": "^2.23.2", 20 | "vuex": "^3.3.0" 21 | }, 22 | "devDependencies": { 23 | "@vue/cli-plugin-babel": "~4.3.0", 24 | "@vue/cli-plugin-eslint": "~4.3.0", 25 | "@vue/cli-service": "~4.3.0", 26 | "babel-eslint": "^10.1.0", 27 | "eslint": "^6.7.2", 28 | "eslint-plugin-vue": "^6.2.2", 29 | "sass": "^1.19.0", 30 | "sass-loader": "^8.0.0", 31 | "vue-template-compiler": "^2.6.11" 32 | }, 33 | "eslintConfig": { 34 | "root": true, 35 | "env": { 36 | "node": true 37 | }, 38 | "extends": [ 39 | "plugin:vue/essential", 40 | "eslint:recommended" 41 | ], 42 | "parserOptions": { 43 | "parser": "babel-eslint" 44 | }, 45 | "rules": { 46 | "no-debugger": 0 47 | } 48 | }, 49 | "browserslist": [ 50 | "> 1%", 51 | "last 2 versions", 52 | "not dead" 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /KMM-GUI/Mod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace KenshiModManDotNet 6 | { 7 | public class Mod 8 | { 9 | public bool Enabled { get; set; } 10 | public int Order { get; set; } 11 | public string Source { get; set; } 12 | public string Name { get; set; } 13 | public string Categories { get; set; } 14 | 15 | public override string ToString() 16 | { 17 | return this.Name.ToString(); 18 | } 19 | 20 | public static List GetDefaultMods(){ 21 | 22 | List mods = new List(); 23 | 24 | mods.Add(new Mod { Enabled = false, Name = "Test Mod 1", Categories = "Buildings, Faction, Armour", Order = -1, Source = "User" }); 25 | mods.Add(new Mod { Enabled = true, Name = "Test Mod 2", Categories = "NPC, Buildings", Order = 0, Source = "Steam" }); 26 | mods.Add(new Mod { Enabled = true, Name = "Test Mod 3", Categories = "Buildings, Faction, Armour", Order = 1, Source = "Steam" }); 27 | mods.Add(new Mod { Enabled = false, Name = "Test Mod 4", Categories = "Armour", Order = -1, Source = "User" }); 28 | mods.Add(new Mod { Enabled = true, Name = "Test Mod 5", Categories = "NPC, Faction, Armour", Order = 2, Source = "Steam" }); 29 | 30 | return mods; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /versioning.ps1: -------------------------------------------------------------------------------- 1 | #inspiration from https://gist.github.com/kumichou/acefc48476957aad6b0c9abf203c304c 2 | [CmdletBinding()] 3 | Param( 4 | [Parameter(Mandatory=$True,Position=1)] 5 | [string]$bumpKind 6 | ) 7 | 8 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 9 | 10 | function UpdateVersionForUpdater($versionName){ 11 | $zipName = $versionName; 12 | if($versionName -eq 'selfcontained'){ $zipName = "FullRelease"} 13 | echo "https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v$($newVersion)/$($zipName).zip" 14 | if(checkStatus("https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v$($newVersion)/$($zipName).zip")==1){ 15 | $xml = Get-Content -Path "updatelist-$($versionName).xml" 16 | $xml = $xml -replace "", "`n 17 | $($newVersion).0.0 18 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v$($newVersion)/$($zipName).zip 19 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v$($newVersion) 20 | " 21 | 22 | Set-Content -Path "updatelist-$($versionName).xml" -Value $xml -Force 23 | 24 | } 25 | } 26 | 27 | UpdateVersionForUpdater("standalone") 28 | UpdateVersionForUpdater("selfcontained") 29 | 30 | Invoke-Expression "git add . | Write-Verbose" 31 | Invoke-Expression "git commit -m 'updatelist Bump.' | Write-Verbose" 32 | Invoke-Expression "git push | Write-Verbose" -------------------------------------------------------------------------------- /Core/SteamWorkshop.cs: -------------------------------------------------------------------------------- 1 | using Steamworks; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace Core 7 | { 8 | public static class SteamWorkshop 9 | { 10 | public static object syncObject = new object(); 11 | 12 | public static PublishedFileId_t FID(this ulong id) => new PublishedFileId_t(id); 13 | 14 | public static bool Init() 15 | { 16 | if (!File.Exists("steam_appid.txt")) File.WriteAllText("steam_appid.txt", "233860"); 17 | 18 | return SteamAPI.Init(); 19 | } 20 | 21 | public static void ShutDown() 22 | { 23 | SteamAPI.Shutdown(); 24 | } 25 | 26 | public static IEnumerable GetAllModIds() 27 | { 28 | if (Init()) 29 | { 30 | 31 | var amount = SteamUGC.GetNumSubscribedItems(); 32 | var ids = new PublishedFileId_t[amount]; 33 | SteamUGC.GetSubscribedItems(ids, amount); 34 | 35 | return ids.Select(t => t.m_PublishedFileId); 36 | } 37 | return default; 38 | } 39 | 40 | public static void Subscribe(ulong id) 41 | { 42 | if (Init()) 43 | { 44 | SteamUGC.SubscribeItem(id.FID()); 45 | } 46 | } 47 | 48 | public static void Unsubscribe(ulong id) 49 | { 50 | if (Init()) 51 | { 52 | SteamUGC.UnsubscribeItem(id.FID()); 53 | } 54 | 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /Core/Constants.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Core 4 | { 5 | public static class Constants 6 | { 7 | public static List SkippableMods = new List{ 8 | "gamedata.base", "rebirth.mod", "newwworld.mod","dialogue.mod" 9 | }; 10 | 11 | public const string modChangesFileName = "modChanges.json"; 12 | public const string DetailChangesFileName = "detailChanges.json"; 13 | public const string Errorfile = "error.log"; 14 | public const string Logfile = "info.log"; 15 | public const string BackupSubscribeList = "bkpsubscribedList"; 16 | public const string ConfigFile = "config.json"; 17 | public const string MasterlistFile = "masterlist.json"; 18 | public const string SteamRegistryKey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Valve\\Steam"; 19 | public const string DefaultSteamDirectory = "C:\\Program Files (x86)\\Steam"; 20 | 21 | #if RELEASE 22 | #error Should Not compile if there's no updatelist configured. (DO NOT CHANGE THIS) 23 | ///the automation is tied to publish using Selfcontained OR Standalone Symbols. 24 | #endif 25 | #if SELFCONTAINED 26 | public const string UpdateListUrl = "https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/master/updatelist-selfcontained.xml"; 27 | #endif 28 | #if STANDALONE 29 | public const string UpdateListUrl = "https://raw.githubusercontent.com/millerscout/Kenshi-Mod-Manager/master/updatelist-standalone.xml"; 30 | #endif 31 | #if DEBUG 32 | public const string UpdateListUrl = "http://localhost:5000/list.xml"; 33 | #endif 34 | } 35 | } -------------------------------------------------------------------------------- /Core/Logging.cs: -------------------------------------------------------------------------------- 1 | using MMDHelpers.CSharp.Extensions; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace Core 10 | { 11 | public static class Logging 12 | { 13 | private static readonly object sync = new object(); 14 | public static void Write(string filename, params string[] texts) 15 | { 16 | if (texts.Length == 0) return; 17 | lock (sync) 18 | { 19 | filename 20 | .ToCurrentPath() 21 | .WriteToFile(new List { string.Join("", texts.Select(c => $"{DateTime.Now} - {c} {Environment.NewLine}")) }); 22 | 23 | } 24 | } 25 | 26 | public static void Write(string filename, IEnumerable texts) 27 | { 28 | if (texts.Count() == 0) return; 29 | lock (sync) 30 | { 31 | filename 32 | .ToCurrentPath() 33 | .WriteToFile(new List { string.Join("", texts.Select(c => $"{DateTime.Now} - {c} {Environment.NewLine}")) }); 34 | 35 | } 36 | } 37 | 38 | public static void Write(string filename, Exception ex) 39 | { 40 | lock (sync) 41 | { 42 | filename 43 | .ToCurrentPath() 44 | .WriteToFile(new List { $"{DateTime.Now} - {ex.Message}.{Environment.NewLine}", $"{ex.StackTrace} {Environment.NewLine}" }); 45 | } 46 | 47 | } 48 | 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /KenshiModTool/App.xaml.cs: -------------------------------------------------------------------------------- 1 | //using Microsoft.AspNetCore.Hosting; 2 | using Core; 3 | using Microsoft.AppCenter; 4 | using Microsoft.AppCenter.Analytics; 5 | using Microsoft.AppCenter.Crashes; 6 | using Newtonsoft.Json; 7 | using System; 8 | using System.IO; 9 | using System.Windows; 10 | 11 | namespace KenshiModTool 12 | { 13 | /// 14 | /// Interaction logic for App.xaml 15 | /// 16 | public partial class App : Application 17 | { 18 | public App() : base() 19 | { 20 | AppCenter.Start("18ca8610-280d-4fe8-8275-c876357993a4", typeof(Analytics), typeof(Crashes)); 21 | this.Dispatcher.UnhandledException += OnDispatcherUnhandledException; 22 | AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 23 | 24 | 25 | #if DEBUG 26 | AppCenter.SetEnabledAsync(false); 27 | #endif 28 | } 29 | 30 | public void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 31 | { 32 | 33 | Logging.Write(Constants.Errorfile, $"{JsonConvert.SerializeObject(e.ExceptionObject)}"); 34 | return; 35 | } 36 | 37 | public void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) 38 | { 39 | MessageBox.Show("Unhandled exception occurred: \n" + e.Exception.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); 40 | 41 | Logging.Write(Constants.Errorfile, $"{e.Exception.Message}"); 42 | Logging.Write(Constants.Errorfile, $"{e.Exception.StackTrace}"); 43 | return; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /updatelist-standalone.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2.7.0.0 5 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.7/standalone.zip 6 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.7 7 | 8 | 9 | 2.6.0.0 10 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.6/standalone.zip 11 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.6 12 | 13 | 14 | 2.5.0.0 15 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.5/standalone.zip 16 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.5 17 | 18 | 19 | 2.4.0.0 20 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.4/standalone.zip 21 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.4 22 | 23 | 24 | 2.3.0.0 25 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.3/standalone.zip 26 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.3 27 | 28 | 29 | 2.2.0.0 30 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.2/standalone.zip 31 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.2 32 | 33 | 34 | 2.1.0.0 35 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.1/Standalone.zip 36 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.1 37 | 38 | -------------------------------------------------------------------------------- /updatelist-selfcontained.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2.7.0.0 5 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.7/FullRelease.zip 6 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.7 7 | 8 | 9 | 2.6.0.0 10 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.6/FullRelease.zip 11 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.6 12 | 13 | 14 | 2.5.0.0 15 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.5/FullRelease.zip 16 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.5 17 | 18 | 19 | 2.4.0.0 20 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.4/FullRelease.zip 21 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.4 22 | 23 | 24 | 2.3.0.0 25 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.3/FullRelease.zip 26 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.3 27 | 28 | 29 | 2.2.0.0 30 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.2/FullRelease.zip 31 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.2 32 | 33 | 34 | 2.1.0.0 35 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/download/v2.1/FullRelease.zip 36 | https://github.com/millerscout/Kenshi-Mod-Manager/releases/tag/v2.1 37 | 38 | -------------------------------------------------------------------------------- /WebServer/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.FileProviders; 6 | using System.IO; 7 | 8 | namespace WebServer 9 | { 10 | public class Startup 11 | { 12 | public Startup(IConfiguration configuration) 13 | { 14 | Configuration = configuration; 15 | } 16 | 17 | public IConfiguration Configuration { get; } 18 | 19 | // This method gets called by the runtime. Use this method to add services to the container. 20 | public void ConfigureServices(IServiceCollection services) 21 | { 22 | services.AddMvcCore(option => option.EnableEndpointRouting = false); 23 | services.AddCors(options => 24 | { 25 | options.AddPolicy("AllowMyOrigin", 26 | builder => builder.WithOrigins("http://localhost:8080")); 27 | }); 28 | services.AddControllers().AddNewtonsoftJson(); 29 | } 30 | 31 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 32 | { 33 | if (env.IsDevelopment()) 34 | { 35 | app.UseDeveloperExceptionPage(); 36 | } 37 | DefaultFilesOptions options = new DefaultFilesOptions(); 38 | options.DefaultFileNames.Add("index.html"); 39 | app.UseDefaultFiles(options); 40 | app.UseStaticFiles(new StaticFileOptions 41 | { 42 | FileProvider = new PhysicalFileProvider( 43 | Path.Combine(Directory.GetCurrentDirectory(), "dist")), 44 | RequestPath = "", 45 | ServeUnknownFileTypes = true 46 | }); 47 | 48 | app.UseCors("AllowMyOrigin"); 49 | 50 | app.UseMvc(); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Core/Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 2.0.0.0 6 | 2.0.0 7 | true 8 | Kenshi.ModTool.Core 9 | Kenshi.ModTool.Core 10 | Kenshi.ModTool.Core 11 | A Helper for many tools that i'm working on. 12 | 13 | check it on: https://github.com/millerscout/Kenshi-Mod-Manager 14 | millerscout 15 | English 16 | ModTool, Gaming, Kenshi 17 | https://github.com/millerscout/Kenshi-Mod-Manager 18 | Debug;Release;Standalone;SelfContained 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ..\..\ForgottenConstructionSet\forgotten construction set\dependencies\Steamworks.NET.dll 31 | 32 | 33 | 34 | 35 | 36 | Never 37 | 38 | 39 | Never 40 | 41 | 42 | Always 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ClientApp/src/components/Dashboard/Dashboard.js: -------------------------------------------------------------------------------- 1 | import draggable from 'vuedraggable' 2 | import dashboardServices from "@/services/dashboard-services.js"; 3 | import contextMenu from 'vue-context-menu' 4 | export default { 5 | name: 'Dashboard', 6 | components: { 7 | draggable, 8 | contextMenu 9 | }, 10 | data: () => ({ 11 | selected: ['A', 'B', 'C', 'D', 'E'], 12 | headers: [], 13 | mods: [], 14 | detail: null, 15 | showDialog: false, 16 | sort: false, 17 | active: false, 18 | newMenuData: {}, 19 | options: [ 20 | { item: 'A', name: 'Active', notEnabled: true }, 21 | { item: 'B', name: 'Order', notEnabled: true }, 22 | { item: 'C', name: 'Name' }, 23 | { item: 'D', name: 'Author' }, 24 | { item: 'E', name: 'Categories' }, 25 | { item: 'F', name: 'Sort' } 26 | ] 27 | 28 | }), 29 | created() { 30 | this.fetchData(); 31 | }, 32 | methods: { 33 | Detail(item) { 34 | this.detail = item; 35 | }, 36 | fetchData() { 37 | 38 | dashboardServices.Get().then((result) => { 39 | this.mods = result.data; 40 | }) 41 | this.headers = [{ 42 | text: 'order' 43 | 44 | }, 45 | { 46 | text: 'Mod name', 47 | align: 'start', 48 | value: 'name', 49 | }, 50 | { text: 'Author', value: 'author' }, 51 | { text: 'Category', value: 'category' }, 52 | ] 53 | 54 | for (let i = 0; i < 10; i++) { 55 | this.mods.push({ order: i, name: `mod_${i}`, author: `author ${i}`, category: `cat 1, cat 2, cat 3` }) 56 | } 57 | 58 | }, 59 | CheckModPage_Click() {}, 60 | ActiveMods() {}, 61 | DeactiveMods() {}, 62 | ToggleActive() {}, 63 | }, 64 | mounted() {} 65 | } -------------------------------------------------------------------------------- /KenshiModTool/CommonService.cs: -------------------------------------------------------------------------------- 1 | using Core; 2 | using System; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Windows; 6 | 7 | namespace KenshiModTool 8 | { 9 | public static class CommonService 10 | { 11 | internal static void StartGame() 12 | { 13 | ProcessStartInfo psi; 14 | if (LoadService.config.SteamModsPath != "NONE") 15 | { 16 | psi = new ProcessStartInfo 17 | { 18 | FileName = "steam://rungameid/233860", 19 | UseShellExecute = true 20 | }; 21 | } 22 | else 23 | { 24 | if (!File.Exists(Path.Combine(LoadService.config.GamePath, "kenshi_x64.exe"))) 25 | { 26 | MessageBox.Show("i can't open the game, may you check the path ?"); 27 | return; 28 | } 29 | psi = new ProcessStartInfo 30 | { 31 | FileName = Path.Combine(LoadService.config.GamePath, "kenshi_x64.exe"), 32 | WorkingDirectory = LoadService.config.GamePath 33 | }; 34 | } 35 | Process.Start(psi); 36 | } 37 | 38 | internal static void StartFCS() 39 | { 40 | var psi = new ProcessStartInfo 41 | { 42 | FileName = Path.Combine(LoadService.config.GamePath, "forgotten construction set.exe"), 43 | WorkingDirectory = LoadService.config.GamePath 44 | }; 45 | Process.Start(psi); 46 | } 47 | 48 | internal static void OpenFolder(string path, Action action) 49 | { 50 | if (Directory.Exists(path)) 51 | { 52 | var psi = new ProcessStartInfo 53 | { 54 | FileName = path, 55 | UseShellExecute = true 56 | }; 57 | Process.Start(psi); 58 | } 59 | else 60 | { 61 | action(); 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /KMM-GUI/KenshiModManDotNet.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | netcoreapp3.1 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | PreserveNewest 41 | 42 | 43 | Never 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /ClientApp/src/assets/styles/_bootstrap.scss: -------------------------------------------------------------------------------- 1 | 2 | // Custom components Bootstrap 3 | // 4 | // @see http://getbootstrap.com/docs/4.1/getting-started/theming/ for more details. 5 | // 6 | 7 | // Functions, Variables and Mixis (Required) 8 | @import "../../../node_modules/bootstrap/scss/functions"; 9 | @import "../../../node_modules/bootstrap/scss/variables"; 10 | @import "../../../node_modules/bootstrap/scss/mixins"; 11 | 12 | 13 | 14 | // Layout, Content and Components (Optional) 15 | @import "../../../node_modules/bootstrap/scss/root"; 16 | @import "../../../node_modules/bootstrap/scss/reboot"; 17 | @import "../../../node_modules/bootstrap/scss/type"; 18 | @import "../../../node_modules/bootstrap/scss/images"; 19 | @import "../../../node_modules/bootstrap/scss/code"; 20 | @import "../../../node_modules/bootstrap/scss/grid"; 21 | @import "../../../node_modules/bootstrap/scss/tables"; 22 | @import "../../../node_modules/bootstrap/scss/forms"; 23 | @import "../../../node_modules/bootstrap/scss/buttons"; 24 | @import "../../../node_modules/bootstrap/scss/transitions"; 25 | @import "../../../node_modules/bootstrap/scss/dropdown"; 26 | @import "../../../node_modules/bootstrap/scss/button-group"; 27 | @import "../../../node_modules/bootstrap/scss/input-group"; 28 | @import "../../../node_modules/bootstrap/scss/custom-forms"; 29 | @import "../../../node_modules/bootstrap/scss/nav"; 30 | @import "../../../node_modules/bootstrap/scss/navbar"; 31 | @import "../../../node_modules/bootstrap/scss/card"; 32 | @import "../../../node_modules/bootstrap/scss/breadcrumb"; 33 | @import "../../../node_modules/bootstrap/scss/pagination"; 34 | @import "../../../node_modules/bootstrap/scss/badge"; 35 | @import "../../../node_modules/bootstrap/scss/jumbotron"; 36 | @import "../../../node_modules/bootstrap/scss/alert"; 37 | @import "../../../node_modules/bootstrap/scss/progress"; 38 | @import "../../../node_modules/bootstrap/scss/media"; 39 | @import "../../../node_modules/bootstrap/scss/list-group"; 40 | @import "../../../node_modules/bootstrap/scss/close"; 41 | @import "../../../node_modules/bootstrap/scss/modal"; 42 | @import "../../../node_modules/bootstrap/scss/tooltip"; 43 | @import "../../../node_modules/bootstrap/scss/popover"; 44 | @import "../../../node_modules/bootstrap/scss/carousel"; 45 | @import "../../../node_modules/bootstrap/scss/utilities"; 46 | @import "../../../node_modules/bootstrap/scss/print"; -------------------------------------------------------------------------------- /KenshiModTool/SelectVersion.xaml.cs: -------------------------------------------------------------------------------- 1 | //using System; 2 | //using System.Collections.Generic; 3 | //using System.IO; 4 | //using System.Linq; 5 | //using System.Text; 6 | //using System.Windows; 7 | //using System.Windows.Controls; 8 | //using System.Windows.Data; 9 | //using System.Windows.Documents; 10 | //using System.Windows.Input; 11 | //using System.Windows.Media; 12 | //using System.Windows.Media.Imaging; 13 | //using System.Windows.Shapes; 14 | //using WebWindows; 15 | 16 | //namespace KenshiModTool 17 | //{ 18 | // /// 19 | // /// Interaction logic for SelectVersion.xaml 20 | // /// 21 | // public partial class SelectVersion : Window 22 | // { 23 | // public SelectVersion() 24 | // { 25 | // InitializeComponent(); 26 | // } 27 | 28 | // WebWindow window; 29 | // private void NewVersion(object sender, RoutedEventArgs e) 30 | // { 31 | // this.Close(); 32 | // for future versions: 33 | // https://www.nuget.org/packages/WebWindow 34 | // window = new WebWindow("Kenshi Mod Tool by MillerScout",(WebWindowOptions options)=>{ 35 | // }); 36 | // var workingArea = window.Monitors.FirstOrDefault().WorkArea; 37 | // window.Location = new System.Drawing.Point() 38 | // { 39 | // X = Convert.ToInt32(Math.Max(workingArea.X, workingArea.X + (workingArea.Width - window.Width) / 2)), 40 | // Y = Convert.ToInt32(Math.Max(workingArea.Y, workingArea.Y + (workingArea.Height - window.Height) / 2)) 41 | // }; 42 | // window.SizeChanged += Window_SizeChanged; 43 | 44 | 45 | // window.SetIconFile(System.IO.Path.Combine(Directory.GetCurrentDirectory(), "icon.ico")); 46 | // window.NavigateToUrl("http://localhost:5000/index.html"); 47 | 48 | 49 | // window.WaitForExit(); 50 | 51 | // } 52 | 53 | // private void Window_SizeChanged(object sender, System.Drawing.Size e) 54 | // { 55 | // window.Height = e.Height <= 600 ? 600 : e.Height; 56 | // window.Width = e.Width <= 800 ? 800 : e.Width; 57 | // } 58 | 59 | // private void OldVersion(object sender, RoutedEventArgs e) 60 | // { 61 | // var main = new MainWindow(); 62 | // main.Show(); 63 | 64 | // this.Close(); 65 | // } 66 | // } 67 | //} 68 | -------------------------------------------------------------------------------- /Core/ModMetadataReader.cs: -------------------------------------------------------------------------------- 1 | using Core.Models; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace Core 9 | { 10 | public static class ModMetadataReader 11 | { 12 | public static byte[] StrByteBuffer = new byte[4096]; 13 | 14 | public static Metadata LoadMetadata(string filename) 15 | { 16 | Metadata header = (Metadata)null; 17 | FileStream fileStream; 18 | try 19 | { 20 | fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read); 21 | } 22 | catch (FileNotFoundException ex) 23 | { 24 | return (Metadata)null; 25 | } 26 | BinaryReader file = new BinaryReader((Stream)fileStream); 27 | try 28 | { 29 | if (file.ReadInt32() > 15) 30 | header = MountMetadata(file); 31 | } 32 | catch (EndOfStreamException ex) 33 | { 34 | } 35 | file.Close(); 36 | fileStream.Close(); 37 | return header; 38 | } 39 | 40 | public static Metadata MountMetadata(BinaryReader file) 41 | { 42 | Metadata header = new Metadata(); 43 | header.Version = file.ReadInt32(); 44 | header.Author = Read(file); 45 | header.Description = Read(file); 46 | header.Dependencies = new List((IEnumerable)Read(file).Split(',').Where(m => !Constants.SkippableMods.Contains(m.ToLower()))); 47 | header.Referenced = new List((IEnumerable)Read(file).Split(',').Where(m => !Constants.SkippableMods.Contains(m.ToLower()))); 48 | if (header.Dependencies.Count == 1 && header.Dependencies[0] == "") 49 | header.Dependencies.Clear(); 50 | if (header.Referenced.Count == 1 && header.Referenced[0] == "") 51 | header.Referenced.Clear(); 52 | return header; 53 | } 54 | 55 | public static string Read(BinaryReader file) 56 | { 57 | int count = file.ReadInt32(); 58 | if (count <= 0) 59 | return string.Empty; 60 | if (count > StrByteBuffer.Length) 61 | Array.Resize(ref StrByteBuffer, StrByteBuffer.Length * 2); 62 | file.Read(StrByteBuffer, 0, count); 63 | return Encoding.UTF8.GetString(StrByteBuffer, 0, count); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /KenshiModTool/KenshiModTool.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WinExe 5 | netcoreapp3.1 6 | true 7 | 2.7 8 | 2.7 9 | Debug;Release;Standalone;SelfContained 10 | 11 | 12 | 13 | TRACE;SELFCONTAINED,STANDALONE 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | PreserveNewest 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /ClientApp/src/App.vue: -------------------------------------------------------------------------------- 1 | 65 | 66 | 88 | 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Kenshi Mod Manager by MillerScout 3 | 4 |

This mod was created to organize mods and the auto-sort is based on this 5 | Post. 6 |

7 |

8 | 9 | 10 | 11 |

12 |

This project is being Part of the Genesis Modding Guild, you can look up for support there at #kmm-tool

13 | 14 | 15 | # How to Use? 16 | 17 |

18 | 19 | Found on Youtube from hekheler this video is a better explanation that i couldn't write properly :) 20 |

21 | 22 | # Requisite: 23 | [.Net Core 3.1.7](https://dotnet.microsoft.com/download/dotnet-core/thank-you/runtime-desktop-3.1.7-windows-x64-installer) 24 | 25 |

26 | 27 |

28 | 29 | # Features 30 | 31 | - Faster way to organize mods. 32 | - shortcut to go to Mod's Page either (nexus/steam workshop) 33 | - Show Categories (Steam) 34 | - Toggle Active (Context Menu) 35 | - Active Mod (Context Menu) 36 | - Deactive Mod (Context Menu) 37 | - save profile mods (current Active and mod order) 38 | - load profile. 39 | - Search through mods using Name or SubscriptionId(steam). 40 | - Basic dependency detection (dependency order is not checked yet). 41 | - List deep changes from mods and list them for modders (alpha) 42 | - Unsubscribe from steammods. 43 | - logging subscribed mods on folder. 44 | 45 | # Road Map 46 | 47 |
Click here 48 | 49 | # Conflict Checker 50 | Click on "Show conflicts", but beware it is slow if there's alot of mods, i did my best to optimize but there's alot of work to be done. 51 | 52 | # Index mods 53 | this feature write the data from mod to JSON format 54 | 55 | # Licence 56 | 57 | Feel free to modify this project, don't forget to credit me :) 58 | 59 | # Donation 60 | 61 |

62 | 63 | Buy me a coffee 64 | 65 |

66 | 67 | # How generate builds (this is a reminder for me) 68 | 69 | merge changes to master then follow the process: 70 | 71 | for minor version 72 | ``` 73 | $ build-all.bat minor 74 | $ git push 75 | ``` 76 | 77 | for major version 78 | ``` 79 | $ build-all.bat major 80 | $ git push 81 | 82 | ``` 83 | 84 | to generate a new oauth 85 | https://github.com/settings/tokens?type=beta 86 | -------------------------------------------------------------------------------- /KenshiModTool/Configuration.xaml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 61 | -------------------------------------------------------------------------------- /Core/Models/Mod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | 7 | namespace Core.Models 8 | { 9 | public class Mod 10 | { 11 | public Guid UniqueIdentifier = Guid.NewGuid(); 12 | public SourceEnum Source { get; set; } 13 | public string Id { get; set; } 14 | public string Description { get; set; } 15 | public string Author { get; set; } 16 | public string Version { get; set; } 17 | public int Order { get; set; } 18 | public IEnumerable Categories { get; set; } 19 | public IEnumerable TypesChanged { get; set; } 20 | public string FilePath { get; set; } 21 | public bool Active { get; set; } 22 | public string Color { get; set; } 23 | public ConcurrentStack Conflicts { get; set; } = new ConcurrentStack(); 24 | 25 | public Mod setActive(bool newValue) 26 | { 27 | this.Active = newValue; 28 | return this; 29 | } 30 | 31 | public string Url 32 | { 33 | get 34 | { 35 | if (Source == SourceEnum.Steam) 36 | { 37 | return LoadService.config.SteamPageUrl + Id; 38 | } 39 | else return LoadService.config.NexusPageUrl + DisplayName; 40 | } 41 | } 42 | 43 | public string DisplayName 44 | { 45 | get 46 | { 47 | return Path.HasExtension(FilePath) ? 48 | Path.GetFileNameWithoutExtension(FilePath) : 49 | $"[Error]: {Path.GetFileNameWithoutExtension(FilePath)}"; 50 | } 51 | } 52 | 53 | public string FileName 54 | { 55 | get 56 | { 57 | return Path.GetFileName(FilePath); 58 | } 59 | } 60 | 61 | public string DisplayCategories 62 | { 63 | get 64 | { 65 | if (Categories == null || Categories.Count() == 0) 66 | return ""; 67 | return string.Join(",", Categories); 68 | } 69 | } 70 | 71 | public List Dependencies = new List(); 72 | 73 | /// 74 | /// don`t know what is this used for... but seems something important while ordering. 75 | /// 76 | public List References = new List(); 77 | 78 | public IEnumerable AllDependencies => Dependencies.Concat(References).Where(c => !Constants.SkippableMods.Contains(c.ToLower())); 79 | public bool OrderedAutomatically { get; set; } 80 | } 81 | 82 | public class Conflict 83 | { 84 | public string ItemChangeName { get; set; } 85 | 86 | public List Items { get; set; } 87 | public string Name { get; set; } 88 | public string Property { get; set; } 89 | } 90 | 91 | public class ConflictItem 92 | { 93 | public string Mod { get; set; } 94 | public object ItemValue { get; set; } 95 | public bool Priority { get; set; } 96 | public string State { get; set; } 97 | public int Order { get; set; } 98 | } 99 | } -------------------------------------------------------------------------------- /Core/Kenshi_Data/Enums/ItemType.cs: -------------------------------------------------------------------------------- 1 | namespace Core.Kenshi_Data.Enums 2 | { 3 | public enum ItemType 4 | { 5 | BUILDING = 0, 6 | CHARACTER = 1, 7 | WEAPON = 2, 8 | ARMOUR = 3, 9 | ITEM = 4, 10 | ANIMAL_ANIMATION = 5, 11 | ATTACHMENT = 6, 12 | RACE = 7, 13 | LOCATION = 8, 14 | WAR_SAVESTATE = 9, 15 | FACTION = 10, 16 | NULL_ITEM = 11, 17 | ZONE_MAP = 12, 18 | TOWN = 13, 19 | WORLDMAP_CHARACTER = 14, 20 | CHARACTER_APPEARANCE_OLD = 15, 21 | LOCATIONAL_DAMAGE = 16, 22 | COMBAT_TECHNIQUE = 17, 23 | DIALOGUE = 18, 24 | DIALOGUE_LINE = 19, 25 | TECHTREE = 20, 26 | RESEARCH = 21, 27 | AI_TASK = 22, 28 | AI_STATE = 23, 29 | ANIMATION = 24, 30 | STATS = 25, 31 | PERSONALITY = 26, 32 | CONSTANTS = 27, 33 | BIOMES = 28, 34 | BUILDING_PART = 29, 35 | INSTANCE_COLLECTION = 30, 36 | DIALOG_ACTION = 31, 37 | TEMPORARY_INFO = 32, 38 | MOD_FILENAME = 33, 39 | PLATOON = 34, 40 | GAMESTATE_BUILDING = 35, 41 | GAMESTATE_CHARACTER = 36, 42 | GAMESTATE_FACTION = 37, 43 | GAMESTATE_TOWN_INSTANCE_LIST = 38, 44 | STATE = 39, 45 | SAVED_STATE = 40, 46 | INVENTORY_STATE = 41, 47 | INVENTORY_ITEM_STATE = 42, 48 | REPEATABLE_BUILDING_PART_SLOT = 43, 49 | MATERIAL_SPEC = 44, 50 | MATERIAL_SPECS_COLLECTION = 45, 51 | CONTAINER = 46, 52 | MATERIAL_SPECS_CLOTHING = 47, 53 | GAMESTATE_BUILDING_INTERIOR = 48, 54 | VENDOR_LIST = 49, 55 | MATERIAL_SPECS_WEAPON = 50, 56 | WEAPON_MANUFACTURER = 51, 57 | SQUAD_TEMPLATE = 52, 58 | ROAD = 53, 59 | LOCATION_NODE = 54, 60 | COLOR_DATA = 55, 61 | CAMERA = 56, 62 | MEDICAL_STATE = 57, 63 | MEDICAL_PART_STATE = 58, 64 | FOLIAGE_LAYER = 59, 65 | FOLIAGE_MESH = 60, 66 | GRASS = 61, 67 | BUILDING_FUNCTIONALITY = 62, 68 | DAY_SCHEDULE = 63, 69 | NEW_GAME_STARTOFF = 64, 70 | GAMESTATE_CRAFTING = 65, 71 | CHARACTER_APPEARANCE = 66, 72 | GAMESTATE_AI = 67, 73 | WILDLIFE_BIRDS = 68, 74 | MAP_FEATURES = 69, 75 | DIPLOMATIC_ASSAULTS = 70, 76 | SINGLE_DIPLOMATIC_ASSAULT = 71, 77 | AI_PACKAGE = 72, 78 | DIALOGUE_PACKAGE = 73, 79 | GUN_DATA = 74, 80 | HUMAN_CHARACTER = 75, 81 | ANIMAL_CHARACTER = 76, 82 | UNIQUE_SQUAD_TEMPLATE = 77, 83 | FACTION_TEMPLATE = 78, 84 | AI_SCHEDULE = 79, 85 | WEATHER = 80, 86 | SEASON = 81, 87 | EFFECT = 82, 88 | ITEM_PLACEMENT_GROUP = 83, 89 | WORD_SWAPS = 84, 90 | NEST = 85, 91 | NEST_ITEM = 86, 92 | CHARACTER_PHYSICS_ATTACHMENT = 87, 93 | LIGHT = 88, 94 | HEAD = 89, 95 | BLUEPRINT = 90, 96 | SHOP_TRADER_CLASS = 91, 97 | FOLIAGE_BUILDING = 92, 98 | FACTION_CAMPAIGN = 93, 99 | GAMESTATE_TOWN = 94, 100 | BIOME_GROUP = 95, 101 | EFFECT_FOG_VOLUME = 96, 102 | FARM_DATA = 97, 103 | FARM_PART = 98, 104 | ENVIRONMENT_RESOURCES = 99, 105 | RACE_GROUP = 100, 106 | ARTIFACTS = 101, 107 | MAP_ITEM = 102, 108 | BUILDINGS_SWAP = 103, 109 | ITEMS_CULTURE = 104, 110 | ANIMATION_EVENT = 105, 111 | TUTORIAL = 106, 112 | CROSSBOW = 107, 113 | TERRAIN_DECALS = 108, 114 | AMBIENT_SOUND = 109, 115 | WORLD_EVENT_STATE = 110, 116 | LIMB_REPLACEMENT = 111, 117 | ANIMATION_FILE = 112, 118 | BOAT = 113, 119 | GAMESTATE_BOAT = 114, 120 | BUILD_GRID = 115, 121 | OBJECT_TYPE_MAX = 116, 122 | } 123 | } -------------------------------------------------------------------------------- /ClientApp/src/components/Dashboard/Dashboard.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 25 | 26 | 27 | 28 | 32 | 35 | 38 | 41 | 44 | 47 | 48 | 49 | 50 |
7 | Active 8 | 10 | Order 11 | 13 | Name 14 | 16 | Author 17 | 19 | Categories 20 | 22 | Tag Changes 23 |
29 | 30 | 31 | 33 | 34 | 36 |
{{item.fileName}}
37 |
39 |
{{item.author}}
40 |
42 |
{{item.categories}}
43 |
45 |
{{item.typesChanged}}
46 |
51 |
52 | 53 | Mod Details 54 | 55 | 56 | 60 | 61 | 62 | 63 |
64 |

Author: {{detail.author}}

65 |

Version: {{detail.version}}

66 |

Path: {{detail.filePath}}

67 |

Url: {{detail.url}}

68 |

Description: {{detail.description}}

69 |
70 | 71 |
72 |
73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 |
  • Visit mod page
  • 81 |
  • Active Selected Mods
  • 82 |
  • Deactive Selected Mods
  • 83 |
  • Toggle Active Selected Mods
  • 84 |
    85 | 86 | 87 |
    -------------------------------------------------------------------------------- /rules by Tag.js: -------------------------------------------------------------------------------- 1 | [{ 2 | "Order": 0, 3 | "Name": "Ui, Graphics, Performance,BaseFixes", 4 | "Tags": [ 5 | "MAP_FEATURES", 6 | "WEATHER", 7 | "BIOMES", 8 | "GRASS", 9 | "WILDLIFE_BIRDS", 10 | "FOLIAGE_LAYER", 11 | "FOLIAGE_MESH", 12 | "SQUAD_TEMPLATE", 13 | "UNIQUE_SQUAD_TEMPLATE", 14 | "COLOR_DATA", 15 | "EFFECT", 16 | "EFFECT_FOG_VOLUME", 17 | "SEASON", 18 | "WORD_SWAPS", 19 | "BIOME_GROUP", 20 | ] 21 | 22 | }, 23 | { 24 | "Order": 1, 25 | "Name": "Animations", 26 | "Tags": [ 27 | "COMBAT_TECHNIQUE", 28 | "ANIMAL_ANIMATION", 29 | "ANIMATION", 30 | "ANIMATION_EVENT", 31 | "ANIMATION_FILE" 32 | ] 33 | }, 34 | { 35 | "Order": 2, 36 | "Name": "New Races, RaceEdits,StartMods", 37 | "Tags": [ 38 | "HEAD", 39 | "PERSONALITY", 40 | "CHARACTER", 41 | "CHARACTER_PHYSICS_ATTACHMENT", 42 | "TOWN", 43 | "RACE", 44 | "RACE_GROUP", 45 | "NEW_GAME_STARTOFF", 46 | "AI_TASK", 47 | "AI_PACKAGE", 48 | "AI_SCHEDULE", 49 | "VENDOR_LIST", 50 | ] 51 | 52 | }, 53 | { 54 | "Order": 3, 55 | "Name": "GameStart Minor Additions (New Npc's and animals)", 56 | "Tags": [ 57 | "WORLD_EVENT_STATE", 58 | "ANIMAL_CHARACTER", 59 | "DIALOGUE_PACKAGE", 60 | "DIALOGUE", 61 | "DIALOGUE_LINE" 62 | ] 63 | 64 | }, 65 | { 66 | "Order": 4, 67 | "Name": "FactionEdits, simple additions", 68 | "Tags": [ 69 | "ITEMS_CULTURE", 70 | "FACTION", 71 | "FACTION_TEMPLATE", 72 | "FACTION_CAMPAIGN", 73 | ] 74 | 75 | }, 76 | { 77 | "Order": 5, 78 | "Name": "Buildings", 79 | "Tags": [ 80 | "LIGHT", 81 | "MAP_ITEM", 82 | "AMBIENT_SOUND", 83 | "BUILD_GRID", 84 | "ENVIRONMENT_RESOURCES", 85 | "BUILDING", 86 | "BUILDING_PART", 87 | "BUILDING_FUNCTIONALITY", 88 | "REPEATABLE_BUILDING_PART_SLOT", 89 | "FARM_DATA", 90 | "FARM_PART", 91 | "BUILDINGS_SWAP", 92 | "MATERIAL_SPEC", 93 | "MATERIAL_SPECS_COLLECTION", 94 | "CONTAINER", 95 | ] 96 | 97 | }, 98 | { 99 | "Order": 6, 100 | "Name": "Armor/Weapons", 101 | "Tags": [ 102 | "NEST_ITEM", 103 | "ITEM_PLACEMENT_GROUP", 104 | "MATERIAL_SPECS_CLOTHING", 105 | "MATERIAL_SPECS_WEAPON", 106 | "WEAPON_MANUFACTURER", 107 | "ATTACHMENT", 108 | "CROSSBOW", 109 | "WEAPON", 110 | "ARMOUR", 111 | "ITEM", 112 | "LIMB_REPLACEMENT", 113 | ] 114 | }, 115 | { 116 | "Order": 7, 117 | "Name": "Overhauls & Big additions/world changes", 118 | "Tags": [ 119 | "DIPLOMATIC_ASSAULTS", 120 | "SINGLE_DIPLOMATIC_ASSAULT", 121 | 122 | ] 123 | }, 124 | { 125 | "Order": 8, 126 | "Name": "Balance", 127 | "Tags": [ 128 | "RESEARCH", 129 | "STATS", 130 | "LOCATIONAL_DAMAGE", 131 | ] 132 | }, 133 | 134 | { 135 | "Order": 9, 136 | "Name": "Patches", 137 | "Tags": [ 138 | "CONSTANTS", 139 | ] 140 | }, 141 | { 142 | "Order": 10, 143 | "Name": "Economy", 144 | "Tags": [] 145 | }, 146 | { 147 | "Order": 11, 148 | "Name": "Priority (Custom)", 149 | "Tags": [] 150 | }, 151 | 152 | ] -------------------------------------------------------------------------------- /KenshiModTool.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30002.166 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "Core\Core.csproj", "{9081DD71-D907-46D3-9954-2B80F07A60DD}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KenshiModTool", "KenshiModTool\KenshiModTool.csproj", "{0089F16B-115F-4B63-BE39-722DAF969B50}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestProject", "TestProject\TestProject.csproj", "{E0D26283-13FE-41DD-88CA-B32EA57330EB}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebServer", "WebServer\WebServer.csproj", "{FA948549-71E0-4F73-9102-466871F90375}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | SelfContained|Any CPU = SelfContained|Any CPU 19 | Standalone|Any CPU = Standalone|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {9081DD71-D907-46D3-9954-2B80F07A60DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {9081DD71-D907-46D3-9954-2B80F07A60DD}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {9081DD71-D907-46D3-9954-2B80F07A60DD}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {9081DD71-D907-46D3-9954-2B80F07A60DD}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {9081DD71-D907-46D3-9954-2B80F07A60DD}.SelfContained|Any CPU.ActiveCfg = SelfContained|Any CPU 27 | {9081DD71-D907-46D3-9954-2B80F07A60DD}.SelfContained|Any CPU.Build.0 = SelfContained|Any CPU 28 | {9081DD71-D907-46D3-9954-2B80F07A60DD}.Standalone|Any CPU.ActiveCfg = Standalone|Any CPU 29 | {9081DD71-D907-46D3-9954-2B80F07A60DD}.Standalone|Any CPU.Build.0 = Standalone|Any CPU 30 | {0089F16B-115F-4B63-BE39-722DAF969B50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {0089F16B-115F-4B63-BE39-722DAF969B50}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {0089F16B-115F-4B63-BE39-722DAF969B50}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {0089F16B-115F-4B63-BE39-722DAF969B50}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {0089F16B-115F-4B63-BE39-722DAF969B50}.SelfContained|Any CPU.ActiveCfg = SelfContained|Any CPU 35 | {0089F16B-115F-4B63-BE39-722DAF969B50}.SelfContained|Any CPU.Build.0 = SelfContained|Any CPU 36 | {0089F16B-115F-4B63-BE39-722DAF969B50}.Standalone|Any CPU.ActiveCfg = Standalone|Any CPU 37 | {0089F16B-115F-4B63-BE39-722DAF969B50}.Standalone|Any CPU.Build.0 = Standalone|Any CPU 38 | {E0D26283-13FE-41DD-88CA-B32EA57330EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {E0D26283-13FE-41DD-88CA-B32EA57330EB}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {E0D26283-13FE-41DD-88CA-B32EA57330EB}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {E0D26283-13FE-41DD-88CA-B32EA57330EB}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {E0D26283-13FE-41DD-88CA-B32EA57330EB}.SelfContained|Any CPU.ActiveCfg = SelfContained|Any CPU 43 | {E0D26283-13FE-41DD-88CA-B32EA57330EB}.SelfContained|Any CPU.Build.0 = SelfContained|Any CPU 44 | {E0D26283-13FE-41DD-88CA-B32EA57330EB}.Standalone|Any CPU.ActiveCfg = Standalone|Any CPU 45 | {E0D26283-13FE-41DD-88CA-B32EA57330EB}.Standalone|Any CPU.Build.0 = Standalone|Any CPU 46 | {FA948549-71E0-4F73-9102-466871F90375}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {FA948549-71E0-4F73-9102-466871F90375}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {FA948549-71E0-4F73-9102-466871F90375}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {FA948549-71E0-4F73-9102-466871F90375}.Release|Any CPU.Build.0 = Release|Any CPU 50 | {FA948549-71E0-4F73-9102-466871F90375}.SelfContained|Any CPU.ActiveCfg = SelfContained|Any CPU 51 | {FA948549-71E0-4F73-9102-466871F90375}.SelfContained|Any CPU.Build.0 = SelfContained|Any CPU 52 | {FA948549-71E0-4F73-9102-466871F90375}.Standalone|Any CPU.ActiveCfg = Standalone|Any CPU 53 | {FA948549-71E0-4F73-9102-466871F90375}.Standalone|Any CPU.Build.0 = Standalone|Any CPU 54 | EndGlobalSection 55 | GlobalSection(SolutionProperties) = preSolution 56 | HideSolutionNode = FALSE 57 | EndGlobalSection 58 | GlobalSection(ExtensibilityGlobals) = postSolution 59 | SolutionGuid = {8E27DA7D-14A1-457B-89DC-3B2AC265D456} 60 | EndGlobalSection 61 | EndGlobal 62 | -------------------------------------------------------------------------------- /Core/Kenshi_Data/Changes.cs: -------------------------------------------------------------------------------- 1 | using Core.Kenshi_Data.Enums; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Drawing; 5 | 6 | namespace Core 7 | { 8 | public class Changes 9 | { 10 | public List Children { get; set; } 11 | 12 | public int Level { get; set; } 13 | public Changes Parent { get; private set; } 14 | 15 | public void Add(Changes n) 16 | { 17 | if (this.Children == null) 18 | this.Children = new List(); 19 | this.Children.Add(n); 20 | n.Parent = this; 21 | } 22 | 23 | public int getVisibleChildNodeCount() 24 | { 25 | int num = 0; 26 | if (this.Children != null) 27 | { 28 | foreach (ChangeData child in this.Children) 29 | num += 1 + child.getVisibleChildNodeCount(); 30 | } 31 | return num; 32 | } 33 | 34 | public Changes() 35 | { 36 | this.Level = 0; 37 | } 38 | } 39 | public class ChangeData : Changes 40 | { 41 | public ChangeType Type { get; set; } 42 | 43 | public object OldValue { get; set; } 44 | 45 | public object NewValue { get; set; } 46 | 47 | public string Text { get; set; } 48 | 49 | public string Key { get; set; } 50 | 51 | public Color Colour { get; set; } 52 | 53 | public string Section { get; set; } 54 | 55 | public ChangeData( 56 | ChangeType type, 57 | string section, 58 | string key, 59 | object oldVal, 60 | object newVal, 61 | State state) 62 | { 63 | this.Type = type; 64 | this.OldValue = oldVal; 65 | this.NewValue = newVal; 66 | this.Key = key; 67 | this.Section = section; 68 | this.Colour = GetStateColor(state); 69 | } 70 | 71 | public ChangeData(ChangeType type, string key, State state) 72 | { 73 | this.Type = type; 74 | this.Key = key; 75 | this.Colour = GetStateColor(state); 76 | } 77 | 78 | public override string ToString() 79 | { 80 | return this.OldValue != null && this.NewValue != null ? "[" + this.OldValue.ToString() + "] => [" + this.NewValue.ToString() + "]" : (this.NewValue != null ? "[" + this.NewValue.ToString() + "]" : ""); 81 | } 82 | 83 | public static Color GetStateColor(State state) 84 | { 85 | switch (state) 86 | { 87 | case State.UNKNOWN: 88 | return Color.Red; 89 | 90 | case State.INVALID: 91 | return Color.Red; 92 | 93 | case State.ORIGINAL: 94 | return Color.Black; 95 | 96 | case State.OWNED: 97 | return Color.Green; 98 | 99 | case State.MODIFIED: 100 | return Color.Blue; 101 | 102 | case State.LOCKED: 103 | return Color.DarkOrange; 104 | 105 | case State.REMOVED: 106 | return Color.LightGray; 107 | 108 | case State.LOCKED_REMOVED: 109 | return Color.LightGray; 110 | 111 | default: 112 | return Color.Black; 113 | } 114 | } 115 | } 116 | 117 | public class EnumValue 118 | { 119 | public EnumDictionary type; 120 | 121 | public EnumDictionary Enum 122 | { 123 | get 124 | { 125 | return this.type; 126 | } 127 | } 128 | 129 | public int Value { get; set; } 130 | 131 | public string String 132 | { 133 | get 134 | { 135 | return this.type.Name(this.Value); 136 | } 137 | set 138 | { 139 | this.Value = this.type.Parse(value); 140 | } 141 | } 142 | 143 | public EnumValue(EnumDictionary e, int value) 144 | { 145 | this.type = e; 146 | this.Value = value; 147 | } 148 | 149 | public EnumValue(EnumDictionary e, string value) 150 | { 151 | this.type = e; 152 | this.String = value; 153 | } 154 | 155 | public override string ToString() 156 | { 157 | return this.String; 158 | } 159 | } 160 | 161 | public class EnumDictionary 162 | { 163 | public Dictionary values = new Dictionary(); 164 | public int maxValue; 165 | 166 | public int Parse(string s) 167 | { 168 | return this.values.ContainsKey(s) ? this.values[s] : -1; 169 | } 170 | 171 | public string Name(int i) 172 | { 173 | foreach (KeyValuePair keyValuePair in this.values) 174 | { 175 | if (keyValuePair.Value == i) 176 | return keyValuePair.Key; 177 | } 178 | return (string)null; 179 | } 180 | } 181 | } -------------------------------------------------------------------------------- /Core/RuleService.cs: -------------------------------------------------------------------------------- 1 | using Core.Models; 2 | using Flurl.Http; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Linq; 8 | 9 | namespace Core 10 | { 11 | public static class RuleService 12 | { 13 | public static List ruleList = new List(); 14 | 15 | public static string GetLatestVersion() 16 | { 17 | try 18 | { 19 | LatestReleaseModelGithub latest = $"http://api.github.com/repos/{LoadService.config.MasterlistSource}/releases/latest" 20 | .WithHeader("User-Agent", "kmm-tool") 21 | .GetAsync().ReceiveJson().GetAwaiter().GetResult(); 22 | 23 | return latest.TagName; 24 | } 25 | catch (Exception ex) 26 | { 27 | Logging.Write(Constants.Errorfile, $"Count't verify latest version."); 28 | Logging.Write(Constants.Errorfile, ex); 29 | 30 | return ""; 31 | } 32 | } 33 | 34 | public static List GetRules() 35 | { 36 | var rules = ""; 37 | if (!File.Exists(Constants.MasterlistFile)) 38 | { 39 | rules = UpdateMasterFile(); 40 | } 41 | else 42 | { 43 | rules = File.ReadAllText(Constants.MasterlistFile); 44 | } 45 | if (string.IsNullOrEmpty(rules)) return BaseRules.Get; 46 | 47 | return JsonConvert.DeserializeObject>(rules); 48 | } 49 | 50 | public static string UpdateMasterFile() 51 | { 52 | try 53 | { 54 | var content = $"https://raw.githubusercontent.com/{LoadService.config.MasterlistSource}/{LoadService.config.MasterlistVersion}/masterlist.json".GetStringAsync().GetAwaiter().GetResult(); 55 | 56 | File.WriteAllText(Constants.MasterlistFile, content); 57 | return content; 58 | } 59 | catch (Exception ex) 60 | { 61 | Logging.Write(Constants.Errorfile, "Count't update masterlist to latest version."); 62 | Logging.Write(Constants.Errorfile, ex); 63 | return ""; 64 | } 65 | } 66 | 67 | public static IEnumerable OrderMods(IEnumerable mods) 68 | { 69 | if (ruleList.Count == 0) 70 | ruleList = GetRules(); 71 | 72 | foreach (var rule in ruleList) 73 | { 74 | foreach (var orderedMod in rule.Mod) 75 | { 76 | var mod = mods.FirstOrDefault(c => Path.GetFileName(c.FilePath).Contains(orderedMod)); 77 | if (mod == null) continue; 78 | if (Path.GetFileName(mod.FilePath).Contains(orderedMod)) 79 | { 80 | mod.OrderedAutomatically = true; 81 | 82 | removeModFromOtherList(mod, rule.Order); 83 | 84 | if (!rule.ModsOrdered.Any(q => q.UniqueIdentifier == mod.UniqueIdentifier)) 85 | rule.ModsOrdered.Add(mod); 86 | continue; 87 | } 88 | } 89 | } 90 | 91 | foreach (var item in mods.Where(c => !c.OrderedAutomatically)) 92 | { 93 | ruleList.FirstOrDefault(c => c.Order == 10).ModsOrdered.Add(item); 94 | Console.WriteLine(Path.GetFileName(item.FilePath)); 95 | } 96 | 97 | var ordered = new List(); 98 | 99 | foreach (var rule in ruleList) 100 | { 101 | var index = rule.InitialRange; 102 | 103 | foreach (var mod in rule.ModsOrdered) 104 | { 105 | mod.Order = index; 106 | index++; 107 | } 108 | ordered.AddRange(rule.ModsOrdered.OrderBy(o => o.Order)); 109 | } 110 | 111 | var i = 0; 112 | foreach (var item in ordered.OrderBy(o => o.Order)) 113 | { 114 | item.Order = i; 115 | i++; 116 | } 117 | 118 | foreach (var rule in ruleList) 119 | { 120 | rule.ModsOrdered.Clear(); 121 | } 122 | 123 | var required = ordered.Where(c => c.AllDependencies.Any()).ToList(); 124 | 125 | foreach (var item in required) 126 | { 127 | var oldOrder = item.Order; 128 | 129 | var dependencies = ordered.Where(c => 130 | item.AllDependencies.Any(q => q.IndexOf(c.FileName, StringComparison.CurrentCultureIgnoreCase) >= 0) 131 | ); 132 | 133 | if (!dependencies.Any()) continue; 134 | if (oldOrder > dependencies.Max(c => c.Order)) continue; 135 | 136 | ordered.Remove(ordered.FirstOrDefault(c => c.UniqueIdentifier == item.UniqueIdentifier)); 137 | 138 | ordered.InsertRange( 139 | ordered.IndexOf(dependencies.OrderBy(c => c.Order).Last()) + 1 140 | , new List { item }); 141 | 142 | for (int ii = 0; ii < ordered.Count; ii++) 143 | { 144 | ordered.ElementAt(ii).Order = ii; 145 | } 146 | } 147 | return ordered.OrderBy(o => ordered); 148 | 149 | void removeModFromOtherList(Mod mod, int order) 150 | { 151 | foreach (var rule in ruleList.Where(c => c.Order < order)) 152 | rule.ModsOrdered.Remove(mod); 153 | } 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /TestProject/Program.cs: -------------------------------------------------------------------------------- 1 | using Core; 2 | using Core.Kenshi_Data.Enums; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace TestProject 13 | { 14 | internal class Program 15 | { 16 | public static void Main(string[] args) 17 | { 18 | //bootingupMods(); 19 | conflict(); 20 | 21 | var t = ModMetadataReader.LoadMetadata(@"C:\Program Files (x86)\Steam\steamapps\common\Kenshi\Mods\AidKitsMoreCharges\AidKitsMoreCharges.mod"); 22 | 23 | var readStream = new FileStream(@"C:\Program Files (x86)\Steam\steamapps\common\Kenshi\Mods\AidKitsMoreCharges\AidKitsMoreCharges.mod", FileMode.Open); 24 | BinaryReader file = new BinaryReader(readStream); 25 | int num1 = file.ReadInt32(); 26 | 27 | for (int index = 0; index < num1; ++index) 28 | { 29 | file.ReadInt32(); 30 | //itemType type = (itemType)file.ReadInt32(); 31 | int num2 = file.ReadInt32(); 32 | string name = readString(file); 33 | Console.WriteLine(name); 34 | Console.WriteLine("---------------"); 35 | //string str = fileVersion >= 7 ? GameData.readString(file) : num2.ToString() + "-" + fileName; 36 | 37 | //GameData.Item obj = getItem(str); 38 | 39 | //bool newItem = obj == null; 40 | //if (obj == null) 41 | //{ 42 | // obj = new GameData.Item(type, str); 43 | // this.items.Add(str, obj); 44 | //} 45 | //if (obj.type != type) 46 | // Console.WriteLine("err"); 47 | //int num3 = obj.load(file, name, mode, fileVersion, fileName, newItem) ? 1 : 0; 48 | //if (obj.getState() == State.REMOVED) 49 | //{ 50 | // obj.refreshState(); 51 | // if (mode == ModMode.BASE || obj.getState() == State.OWNED && !false) 52 | // this.items.Remove(obj.stringID); 53 | // else 54 | // obj.flagDeleted(); 55 | //} 56 | //if (num3 == 0 & skipMissing) { } 57 | //this.items.Remove(obj.stringID); 58 | } 59 | string readString(BinaryReader file) 60 | { 61 | int count = file.ReadInt32(); 62 | 63 | if (count <= 0) 64 | return string.Empty; 65 | var arr = new byte[count]; 66 | file.Read(arr, 0, count); 67 | return Encoding.UTF8.GetString(arr, 0, count); 68 | } 69 | } 70 | 71 | public static void bootingupMods() 72 | { 73 | ///Booting Mods. 74 | /// 75 | LoadService.Setup(); 76 | var mods = LoadService.GetListOfMods(); 77 | 78 | var rules = RuleService.GetRules(); 79 | 80 | File.WriteAllText("rules.json", JsonConvert.SerializeObject(rules)); 81 | var orderedList = RuleService.OrderMods(mods); 82 | } 83 | 84 | public static void conflict() 85 | { 86 | var stopwatch = Stopwatch.StartNew(); 87 | 88 | var filename = "changes.json"; 89 | var detailsFilename = "detail.json"; 90 | //if (args.Length > 0) 91 | //{ 92 | // filename = args[0]; 93 | // if (args.Length > 1) 94 | // detailsFilename = args[1]; 95 | 96 | //} 97 | ///Booting Mods. 98 | /// 99 | LoadService.Setup(); 100 | 101 | var mods = LoadService.GetListOfMods(); 102 | 103 | var orderedList = RuleService.OrderMods(mods); 104 | 105 | var changes = new Dictionary>>(); 106 | var cm = new ConflictManager(); 107 | 108 | var ordered = mods.OrderBy(c => c.Order).ToList(); 109 | var baseGameData = new GameData(); 110 | 111 | foreach (var item in new string[6]{ 112 | "gamedata.base", 113 | "Newwworld.mod", 114 | "Dialogue.mod", 115 | "Vitali.mod", 116 | "Nizu.mod", 117 | "rebirth.mod" 118 | }) 119 | { 120 | cm.LoadMods(Path.Combine(LoadService.config.GamePath, "data", item), ModMode.BASE, baseGameData); 121 | } 122 | 123 | foreach (var mod in ordered) 124 | { 125 | cm.LoadMods(mod.FilePath, ModMode.ACTIVE, baseGameData); 126 | } 127 | 128 | baseGameData.resolveAllReferences(); 129 | 130 | cm.LoadBaseChanges(baseGameData); 131 | 132 | baseGameData = null; 133 | 134 | foreach (var mod in ordered) 135 | { 136 | Console.WriteLine($"{mod.DisplayName} Loading..."); 137 | var gd = new GameData(); 138 | 139 | cm.LoadMods(mod.FilePath, ModMode.ACTIVE, gd); 140 | 141 | cm.ListOfGameData.Add(gd); 142 | } 143 | 144 | cm.LoadChanges(); 145 | 146 | stopwatch.Stop(); 147 | Console.WriteLine(stopwatch.ElapsedMilliseconds / 1000 + " Seconds Elapsed"); 148 | 149 | if (!Directory.Exists("reports")) 150 | Directory.CreateDirectory("reports"); 151 | 152 | Console.WriteLine("writing reports"); 153 | var list = new Task[] { 154 | Task.Run(() => { File.WriteAllText(filename, JsonConvert.SerializeObject(cm.conflictIndex)); }), 155 | Task.Run(() => { File.WriteAllText(detailsFilename, JsonConvert.SerializeObject(cm.DetailIndex)); }), 156 | Task.Run(() => { 157 | foreach (var item in cm.listOfTags) 158 | { 159 | File.WriteAllText($"reports/{item.Key}", JsonConvert.SerializeObject(item.Value.Select(c=>c.ToString()))); 160 | } 161 | }) 162 | }; 163 | 164 | Task.WaitAll(list); 165 | } 166 | } 167 | } -------------------------------------------------------------------------------- /KenshiModTool/Tooling.xaml: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 132 | -------------------------------------------------------------------------------- /KenshiModTool/Tooling.xaml.cs: -------------------------------------------------------------------------------- 1 | using Core; 2 | using Core.Models; 3 | using KenshiModTool.Model; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Collections.ObjectModel; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Reflection; 10 | using System.Threading.Tasks; 11 | using System.Windows; 12 | using System.Windows.Controls; 13 | using System.Windows.Input; 14 | 15 | namespace KenshiModTool 16 | { 17 | /// 18 | /// Interaction logic for Tooling.xaml 19 | /// 20 | public partial class Tooling : Window 21 | { 22 | public ObservableCollection ModList = new ObservableCollection(); 23 | public int currentIndexSearch { get; set; } = 0; 24 | public ModFolder[] SearchList { get; set; } = new ModFolder[0]; 25 | 26 | public Tooling() 27 | { 28 | try 29 | { 30 | InitializeComponent(); 31 | 32 | this.Title = $"[v{Assembly.GetExecutingAssembly().GetName().Version.ToString(2)}] - {this.Title}"; 33 | MainGrid.ShowGridLines = false; 34 | lblSearchInfo.Content = ""; 35 | 36 | LoadModList(); 37 | } 38 | catch (Exception ex) 39 | { 40 | Logging.Write(Constants.Errorfile, ex); 41 | } 42 | } 43 | 44 | public void UpdateListBox() 45 | { 46 | foreach (var mod in ModList) 47 | mod.Color = SearchList.Any(s => s.UniqueIdentifier == mod.UniqueIdentifier) ? ModColors.SearchColor : ""; 48 | 49 | ListBox.ItemsSource = new List(); 50 | ListBox.ItemsSource = ModList; 51 | 52 | if (SearchList.Length > 0) 53 | ListBox.ScrollIntoView(SearchList[currentIndexSearch]); 54 | } 55 | 56 | public void TextBox_TextChanged(object sender, TextChangedEventArgs e) 57 | { 58 | currentIndexSearch = 0; 59 | if (string.IsNullOrEmpty(txtSearch.Text)) 60 | { 61 | lblSearchInfo.Content = ""; 62 | SearchList = new ModFolder[0]; 63 | } 64 | else 65 | { 66 | var mod = ModList.FirstOrDefault(c => c.FilePath.Contains(txtSearch.Text)); 67 | 68 | SearchList = ModList.Where(c => c.FilePath.Contains(txtSearch.Text, StringComparison.CurrentCultureIgnoreCase) || c.DisplayName.Contains(txtSearch.Text, StringComparison.CurrentCultureIgnoreCase)).ToArray(); 69 | 70 | if (SearchList.Length == 0) 71 | { 72 | lblSearchInfo.Content = "Couldn't find any mod with the name."; 73 | } 74 | else 75 | { 76 | lblSearchInfo.Content = $"Found: {currentIndexSearch + 1}/{SearchList.Length}."; 77 | } 78 | } 79 | 80 | UpdateListBox(); 81 | } 82 | 83 | public void TxtSearch_KeyDown(object sender, KeyEventArgs e) 84 | { 85 | if (e.Key == Key.Return) 86 | { 87 | if (string.IsNullOrEmpty(txtSearch.Text)) return; 88 | if (SearchList.Length > 0) 89 | { 90 | if (currentIndexSearch == SearchList.Length - 1) 91 | currentIndexSearch = 0; 92 | else 93 | currentIndexSearch++; 94 | 95 | lblSearchInfo.Content = $"Found: {currentIndexSearch + 1}/{SearchList.Length}."; 96 | 97 | ListBox.ScrollIntoView(SearchList[currentIndexSearch]); 98 | } 99 | } 100 | } 101 | 102 | public void BtnClearEmptyFolders_Click(object sender, RoutedEventArgs e) 103 | { 104 | LoadService.FolderCleanUp(LoadService.config.SteamModsPath); 105 | LoadService.FolderCleanUp(LoadService.config.ModFolder); 106 | } 107 | 108 | public void BtnRemoveSymbLinks_Click(object sender, RoutedEventArgs e) 109 | { 110 | var symblist = ModList 111 | .Where(c => c.Source == SourceEnum.Steam && c.HasSymbLink && c.Selected) 112 | .Select(c => System.IO.Path.Combine(LoadService.config.ModFolder, System.IO.Path.GetFileNameWithoutExtension(c.FilePath))); 113 | foreach (var folder in symblist) 114 | { 115 | LoadService.DeleteFolder(folder); 116 | } 117 | 118 | LoadModList(); 119 | } 120 | 121 | public void BtnCreateSymbLinks_Click(object sender, RoutedEventArgs e) 122 | { 123 | var symblist = ModList 124 | .Where(c => c.Source == SourceEnum.Steam && !c.HasSymbLink && c.Selected) 125 | .Select(c => new Tuple( 126 | System.IO.Path.Combine(LoadService.config.ModFolder, System.IO.Path.GetFileNameWithoutExtension(c.FilePath)), 127 | System.IO.Path.GetDirectoryName(c.FilePath) 128 | ) 129 | ); 130 | 131 | if (!symblist.Any()) return; 132 | 133 | var logging = Task.Run(() => 134 | { 135 | var appendLog = new List { 136 | $"{DateTime.Now} - Trying to Create SymbLinks:" 137 | }; 138 | 139 | appendLog.Add($"{DateTime.Now} - Detailed List:"); 140 | appendLog.AddRange(symblist.Select(item => $"{DateTime.Now} From {item.Item2} To {item.Item1}:")); 141 | 142 | Logging.Write(Constants.Logfile, appendLog); 143 | }); 144 | 145 | LoadService.CreateSymbLink(symblist, out string message); 146 | if (!string.IsNullOrEmpty(message)) MessageBox.Show(message); 147 | 148 | logging.Wait(); 149 | LoadModList(); 150 | } 151 | 152 | public void BtnLaunchGame_Click(object sender, RoutedEventArgs e) 153 | { 154 | CommonService.StartGame(); 155 | } 156 | 157 | public void btnReloadMods_Click(object sender, RoutedEventArgs e) 158 | { 159 | currentIndexSearch = 0; 160 | if (string.IsNullOrEmpty(txtSearch.Text)) 161 | { 162 | lblSearchInfo.Content = ""; 163 | SearchList = new ModFolder[0]; 164 | } 165 | 166 | LoadModList(); 167 | } 168 | 169 | public void LoadModList() 170 | { 171 | ModList.Clear(); 172 | 173 | foreach (var mod in LoadService.GetListOfMods()) 174 | ModList.Add(new ModFolder(mod)); 175 | 176 | UpdateListBox(); 177 | } 178 | 179 | public void BtnGameFolder_Click(object sender, RoutedEventArgs e) 180 | { 181 | CommonService.OpenFolder(LoadService.config.GamePath, () => MessageBox.Show("Game folder not configured correctly.")); 182 | } 183 | 184 | public void GameModFolder_Click(object sender, RoutedEventArgs e) 185 | { 186 | CommonService.OpenFolder(LoadService.config.ModFolder, () => MessageBox.Show("Game folder not configured correctly.")); 187 | } 188 | 189 | public void BtnSteamFolder_Click(object sender, RoutedEventArgs e) 190 | { 191 | CommonService.OpenFolder(LoadService.config.SteamModsPath, () => MessageBox.Show("steam folder not configured correctly.")); 192 | } 193 | 194 | public void OpenModFolder_Click(object sender, RoutedEventArgs e) 195 | { 196 | bool failure = false; 197 | foreach (var mod in ListBox.SelectedItems) 198 | { 199 | CommonService.OpenFolder(System.IO.Path.GetDirectoryName(((ModFolder)mod).FilePath), () => { failure = true; }); 200 | } 201 | 202 | if (failure) 203 | { 204 | MessageBox.Show("Game folder not configured correctly."); 205 | } 206 | } 207 | 208 | public void SelectAll_Click(object sender, RoutedEventArgs e) 209 | { 210 | foreach (var item in ModList.Where(c => !c.Selected)) item.Selected = true; 211 | 212 | UpdateListBox(); 213 | } 214 | 215 | public void Invert_Click(object sender, RoutedEventArgs e) 216 | { 217 | foreach (var item in ModList) item.Selected = !item.Selected; 218 | 219 | UpdateListBox(); 220 | } 221 | 222 | public void CreateSymbSelected_Click(object sender, RoutedEventArgs e) 223 | { 224 | if (ListBox.SelectedItems != null && ListBox.SelectedItems.Count > 0) 225 | { 226 | ExecuteSymbLink(ShouldDelete: false); 227 | 228 | LoadModList(); 229 | } 230 | } 231 | 232 | public void ExecuteSymbLink(bool ShouldDelete = true, bool ShouldAdd = true) 233 | { 234 | var symblist = new List>(); 235 | foreach (ModFolder mod in ListBox.SelectedItems) 236 | { 237 | if (mod.HasSymbLink) 238 | { 239 | if (ShouldDelete) 240 | LoadService.DeleteFolder(System.IO.Path.Combine(LoadService.config.ModFolder, System.IO.Path.GetFileNameWithoutExtension(mod.FilePath))); 241 | } 242 | else 243 | { 244 | if (ShouldAdd) 245 | symblist.Add(new Tuple( 246 | System.IO.Path.Combine(LoadService.config.ModFolder, System.IO.Path.GetFileNameWithoutExtension(mod.FilePath)), 247 | System.IO.Path.GetDirectoryName(mod.FilePath) 248 | )); 249 | } 250 | } 251 | 252 | try 253 | { 254 | if (!symblist.Any()) return; 255 | 256 | var appendLog = new List { 257 | $"{DateTime.Now} - Trying to Create SymbLinks:" 258 | }; 259 | 260 | appendLog.Add($"{DateTime.Now} - Detailed List:"); 261 | appendLog.AddRange(symblist.Select(item => $"{DateTime.Now} From {item.Item2} To {item.Item1}:")); 262 | 263 | Logging.Write(Constants.Logfile, appendLog); 264 | } 265 | catch (Exception ex) 266 | { 267 | Logging.Write(Constants.Errorfile, "Failed to write log of symblinks."); 268 | Logging.Write(Constants.Errorfile, ex); 269 | 270 | } 271 | 272 | LoadService.CreateSymbLink(symblist, out string message); 273 | if (!string.IsNullOrEmpty(message)) MessageBox.Show(message); 274 | } 275 | 276 | public void ToggleSymbSelected_Click(object sender, RoutedEventArgs e) 277 | { 278 | if (ListBox.SelectedItems != null && ListBox.SelectedItems.Count > 0) 279 | { 280 | ExecuteSymbLink(); 281 | 282 | LoadModList(); 283 | } 284 | } 285 | 286 | public void RemoveSymbSelected_Click(object sender, RoutedEventArgs e) 287 | { 288 | if (ListBox.SelectedItems != null && ListBox.SelectedItems.Count > 0) 289 | { 290 | ExecuteSymbLink(ShouldAdd: false); 291 | 292 | LoadModList(); 293 | } 294 | } 295 | } 296 | } -------------------------------------------------------------------------------- /Core/LoadService.cs: -------------------------------------------------------------------------------- 1 | using Core.Models; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Security.Permissions; 9 | using System.Security.Principal; 10 | using System.Threading.Tasks; 11 | using System.Xml.Linq; 12 | 13 | namespace Core 14 | { 15 | public static class LoadService 16 | { 17 | public static KenshiToolConfig config { get; set; } 18 | 19 | public static void Setup() 20 | { 21 | if (File.Exists(Constants.Errorfile)) 22 | File.Delete(Constants.Errorfile); 23 | if (File.Exists(Constants.ConfigFile)) 24 | { 25 | config = JsonConvert.DeserializeObject(File.ReadAllText(Constants.ConfigFile)); 26 | } 27 | else 28 | { 29 | config = new KenshiToolConfig 30 | { 31 | GamePath = "", 32 | SteamModsPath = "", 33 | SteamPageUrl = "https://steamcommunity.com/sharedfiles/filedetails/?id=", 34 | NexusPageUrl = "https://www.nexusmods.com/kenshi/search/?gsearch=", 35 | MasterlistSource = "millerscout/kmm-masterlist", 36 | MaxLogFiles = 5 37 | }; 38 | } 39 | 40 | var version = RuleService.GetLatestVersion(); 41 | 42 | if (!string.IsNullOrEmpty(version) && version != config.MasterlistVersion) 43 | { 44 | config.MasterlistVersion = version; 45 | RuleService.UpdateMasterFile(); 46 | } 47 | if (File.Exists(Constants.Logfile)) File.Delete(Constants.Logfile); 48 | } 49 | 50 | public static void SaveConfig() 51 | { 52 | File.WriteAllText("config.json", JsonConvert.SerializeObject(config)); 53 | } 54 | 55 | public static IEnumerable GetListOfMods() 56 | { 57 | var list = new List(); 58 | 59 | var currentMods = LoadService.getCurrentActiveMods(); 60 | 61 | list.AddRange(LoadSteamMods(currentMods)); 62 | list.AddRange(LoadFolderMods(currentMods)); 63 | 64 | var qtdByType = string.Join(", ", 65 | list.GroupBy(c => c.Source).Select(q => $"{q.Key} - {q.Count()}") 66 | ); 67 | 68 | var appendLog = new List { 69 | $"{DateTime.Now} - Loaded: {list.Count()} Mods", 70 | $"{DateTime.Now} - {qtdByType}", 71 | }; 72 | appendLog.Add($"{DateTime.Now} - Detailed List:"); 73 | appendLog.AddRange(list.Select(item => $"{DateTime.Now} - {item.Source} - {item.FilePath}")); 74 | 75 | Logging.Write(Constants.Logfile, appendLog); 76 | return list; 77 | } 78 | 79 | public static IEnumerable LoadFolderMods(List currentMods) 80 | { 81 | return LoadMod(currentMods, Path.Combine(LoadService.config.GamePath, "Mods")); 82 | } 83 | 84 | public static IEnumerable LoadSteamMods(List currentMods) 85 | { 86 | if (LoadService.config.SteamModsPath == "NONE") return new List(); 87 | 88 | return LoadMod(currentMods, LoadService.config.SteamModsPath); 89 | } 90 | 91 | public static bool IsSymbolic(string path) 92 | { 93 | FileInfo pathInfo = new FileInfo(path); 94 | if (pathInfo.Attributes.HasFlag(FileAttributes.Archive)) 95 | { 96 | return new FileInfo(Path.GetDirectoryName(path)).Attributes.HasFlag(FileAttributes.ReparsePoint); 97 | } 98 | 99 | try 100 | { 101 | if (Directory.GetFiles(path).Length > 0) 102 | { 103 | /// valid path 104 | }; 105 | } 106 | catch (Exception ex) 107 | { 108 | DeleteFolder(path); 109 | return true; 110 | } 111 | 112 | return pathInfo.Attributes.HasFlag(FileAttributes.ReparsePoint); 113 | } 114 | 115 | public static void DeleteFolder(string path) 116 | { 117 | if (Directory.Exists(path)) 118 | Directory.Delete(path); 119 | } 120 | 121 | public static void CreateSymbLink(IEnumerable> symblist, out string message) 122 | { 123 | message = ""; 124 | if (!new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator)) 125 | { 126 | Logging.Write(Constants.Logfile, $"{DateTime.Now} - Can't create symblinks, you need to this program as administrator to use this feature."); 127 | message = "Can't create symblinks, you need to this program as administrator to use this feature."; 128 | return; 129 | } 130 | 131 | var sync = new object(); 132 | var infoLogList = new ConcurrentBag(); 133 | var errorLogList = new ConcurrentBag(); 134 | Parallel.ForEach(symblist, (symb) => 135 | { 136 | try 137 | { 138 | if (Directory.Exists(symb.Item1)) 139 | { 140 | infoLogList.Add($"{DateTime.Now} - Folder already exist, maybe you installed manually the mod on kenshi's folder? if not you may delete."); 141 | return; 142 | } 143 | Murphy.SymbolicLink.SymbolicLink.create(symb.Item2, symb.Item1); 144 | } 145 | catch (Exception ex) 146 | { 147 | infoLogList.Add($"{DateTime.Now} - Failed to link folder."); 148 | infoLogList.Add($"{DateTime.Now} - Source: {symb.Item2} >> Target: {symb.Item1}."); 149 | infoLogList.Add($"{ex.Message}"); 150 | infoLogList.Add($"{ex.StackTrace}"); 151 | } 152 | }); 153 | 154 | Logging.Write(Constants.Logfile, infoLogList); 155 | Logging.Write(Constants.Errorfile, errorLogList); 156 | } 157 | 158 | public static void FolderCleanUp(string path) 159 | { 160 | if (!Directory.Exists(path)) return; 161 | foreach (var directory in Directory.GetDirectories(path)) 162 | { 163 | FolderCleanUp(directory); 164 | if (Directory.GetFiles(directory).Length == 0 && 165 | Directory.GetDirectories(directory).Length == 0) 166 | { 167 | Logging.Write(Constants.Logfile, $"{DateTime.Now} - This Directory was deleted, because it was empty: {directory}.{Environment.NewLine}"); 168 | DeleteFolder(directory); 169 | } 170 | } 171 | } 172 | 173 | public static IEnumerable LoadMod(List currentMods, string path) 174 | { 175 | var listMods = new List(); 176 | 177 | if (Directory.Exists(path)) 178 | { 179 | foreach (var item in Directory.GetDirectories(path)) 180 | { 181 | if (IsSymbolic(item)) continue; 182 | 183 | var modName = Directory.GetFiles(item, "*.mod").FirstOrDefault() ?? item; 184 | var mod = new Mod 185 | { 186 | FilePath = modName 187 | }; 188 | 189 | try 190 | { 191 | ReadAndSetInfo(Path.Combine(item, $"_{Path.GetFileNameWithoutExtension(mod.FilePath)}.info"), mod); 192 | } 193 | catch (Exception ex) 194 | { 195 | 196 | Logging.Write(Constants.Errorfile, "Count't load metadata.", $"The mod {mod.FilePath} may be corrupted."); 197 | Logging.Write(Constants.Errorfile, ex); 198 | } 199 | 200 | Func predicate = f => f == Path.GetFileName(mod.FilePath); 201 | mod.Active = currentMods.Any(predicate); 202 | 203 | Metadata metadata = new Metadata { }; 204 | try 205 | { 206 | metadata = ModMetadataReader.LoadMetadata(mod.FilePath); 207 | } 208 | catch (Exception ex) 209 | { 210 | 211 | metadata = new Metadata { Description = $"This mod couldn't be loaded, maybe is corrupted or a empty folder, check the error.log and the mod folder {item}" }; 212 | Logging.Write(Constants.Errorfile, $"Check the folder: {item}"); 213 | } 214 | 215 | if (metadata is null) 216 | { 217 | metadata = new Metadata { Description = $"This mod couldn't be loaded, maybe is corrupted or a empty folder, check the error.log and the mod folder {item}" }; 218 | Logging.Write(Constants.Errorfile, $"Count't load metadata from path: {item}."); 219 | } 220 | else 221 | { 222 | mod.Dependencies = metadata.Dependencies; 223 | mod.Description = metadata.Description; 224 | mod.References = metadata.Referenced; 225 | mod.Version = metadata.Version.ToString(); 226 | mod.Author = metadata.Author; 227 | } 228 | mod.Order = currentMods.IndexOf(Path.GetFileName(mod.FilePath)); 229 | 230 | if (File.Exists($"reports/{mod.FileName}")) 231 | { 232 | mod.TypesChanged = JsonConvert.DeserializeObject>(File.ReadAllText($"reports/{mod.FileName}")); 233 | } 234 | 235 | listMods.Add(mod); 236 | } 237 | } 238 | else 239 | { 240 | Logging.Write(Constants.Errorfile, $"Count't read folder: {path} ."); 241 | Logging.Write(Constants.Errorfile, $"When report this error, you may delete config.json and try again."); 242 | } 243 | return listMods; 244 | } 245 | 246 | public static List getCurrentActiveMods() 247 | { 248 | try 249 | { 250 | return File.ReadAllLines(Path.Combine(config.GamePath, "data", "mods.cfg")).Select(c => c.Trim()).ToList(); 251 | } 252 | catch (Exception ex) 253 | { 254 | Logging.Write(Constants.Errorfile, "Count't read mods.cfg, check your config, you may delete as well, the folder will be requested again."); 255 | Logging.Write(Constants.Errorfile, ex); 256 | return new List(); 257 | } 258 | } 259 | 260 | public static void ReadAndSetInfo(string filename, Mod mod) 261 | { 262 | if (File.Exists(filename)) 263 | { 264 | XDocument xdoc = XDocument.Load(filename); 265 | 266 | var tags = from modData in xdoc.Descendants("ModData") 267 | select new 268 | { 269 | Children = modData.Descendants("tags") 270 | }; 271 | 272 | mod.Categories = tags.SelectMany(t => t.Children.Descendants("string")).Select(q => q.Value); 273 | mod.Id = xdoc.Descendants("id").FirstOrDefault().Value; 274 | mod.Source = SourceEnum.Steam; 275 | } 276 | 277 | mod.Source = mod.FilePath.Contains(LoadService.config.GamePath) 278 | ? SourceEnum.GameFolder : 279 | SourceEnum.Steam; 280 | } 281 | } 282 | } --------------------------------------------------------------------------------