diff --git a/ModManager/AddonEnableSystem/AddonEnablerException.cs b/ModManager/AddonEnableSystem/AddonEnablerException.cs deleted file mode 100644 index 221091d..0000000 --- a/ModManager/AddonEnableSystem/AddonEnablerException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace ModManager.AddonEnableSystem -{ - public class AddonEnablerException : Exception - { - public AddonEnablerException(string message) : base(message) - { - } - } -} \ No newline at end of file diff --git a/ModManager/AddonEnableSystem/AddonEnablerRegistry.cs b/ModManager/AddonEnableSystem/AddonEnablerRegistry.cs deleted file mode 100644 index 8cfaab0..0000000 --- a/ModManager/AddonEnableSystem/AddonEnablerRegistry.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace ModManager.AddonEnableSystem -{ - public class AddonEnablerRegistry : Singleton - { - private readonly List> _addonEnablers = new(); - - public void Add(string enablerId, IAddonEnabler enabler) - { - if (_addonEnablers.Exists(pair => pair.Key.Equals(enablerId))) - { - throw new AddonEnablerException($"Enabler with id: `{enablerId}` is already added to the list"); - } - - _addonEnablers.Insert(0, new KeyValuePair(enablerId, enabler)); - } - - public void Remove(string enablerId) - { - _addonEnablers.Remove(_addonEnablers.First(pair => pair.Key.Equals(enablerId))); - } - - public IEnumerable GetAddonEnablers() - { - return _addonEnablers.Select(pair => pair.Value); - } - } -} \ No newline at end of file diff --git a/ModManager/AddonEnableSystem/AddonEnablerService.cs b/ModManager/AddonEnableSystem/AddonEnablerService.cs deleted file mode 100644 index ade86ac..0000000 --- a/ModManager/AddonEnableSystem/AddonEnablerService.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Collections.Generic; -using ModManager.AddonSystem; - -namespace ModManager.AddonEnableSystem -{ - public class AddonEnablerService : Singleton - { - private readonly AddonEnablerRegistry _addonEnablerRegistry = AddonEnablerRegistry.Instance; - - public static readonly IEnumerable IgnoreExtensions = new[] - { - Names.Extensions.Disabled, - Names.Extensions.Remove - }; - - public void Enable(Manifest manifest) - { - foreach (var enabler in _addonEnablerRegistry.GetAddonEnablers()) - { - if (enabler.Enable(manifest)) - { - return; - } - } - - throw new AddonEnablerException($"{manifest.ModName} could not be enabled by any mod enabler"); - } - - public void Disable(Manifest manifest) - { - foreach (var enabler in _addonEnablerRegistry.GetAddonEnablers()) - { - if (enabler.Disable(manifest)) - { - return; - } - } - - throw new AddonEnablerException($"{manifest.ModName} could not be disabled by any mod enabler"); - } - } -} \ No newline at end of file diff --git a/ModManager/AddonEnableSystem/IAddonEnabler.cs b/ModManager/AddonEnableSystem/IAddonEnabler.cs deleted file mode 100644 index 8d882b1..0000000 --- a/ModManager/AddonEnableSystem/IAddonEnabler.cs +++ /dev/null @@ -1,11 +0,0 @@ -using ModManager.AddonSystem; - -namespace ModManager.AddonEnableSystem -{ - public interface IAddonEnabler - { - bool Enable(Manifest manifest); - - bool Disable(Manifest manifest); - } -} \ No newline at end of file diff --git a/ModManager/AddonInstallerSystem/AddonInstallerRegistry.cs b/ModManager/AddonInstallerSystem/AddonInstallerRegistry.cs deleted file mode 100644 index 66deb33..0000000 --- a/ModManager/AddonInstallerSystem/AddonInstallerRegistry.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace ModManager.AddonInstallerSystem -{ - public class AddonInstallerRegistry : Singleton - { - private readonly List> _addonInstallers = new(); - - public void Add(string installerId, IAddonInstaller addonInstaller) - { - if (_addonInstallers.Exists(pair => pair.Key.Equals(installerId))) - { - throw new AddonInstallerException($"Addon installer with id: `{installerId}` is already added to the list"); - } - - _addonInstallers.Insert(0, new KeyValuePair(installerId, addonInstaller)); - } - - public void Remove(string installerId) - { - _addonInstallers.Remove(_addonInstallers.First(pair => pair.Key.Equals(installerId))); - } - - public IEnumerable GetAddonInstallers() - { - return _addonInstallers.Select(pair => pair.Value); - } - } -} \ No newline at end of file diff --git a/ModManager/AddonInstallerSystem/AddonInstallerService.cs b/ModManager/AddonInstallerSystem/AddonInstallerService.cs index c2a136a..69e97f6 100644 --- a/ModManager/AddonInstallerSystem/AddonInstallerService.cs +++ b/ModManager/AddonInstallerSystem/AddonInstallerService.cs @@ -1,18 +1,30 @@ -using Modio.Models; +using System.Collections.Generic; using ModManager.AddonSystem; +using Timberborn.Modding; +using Mod = Modio.Models.Mod; namespace ModManager.AddonInstallerSystem { - public class AddonInstallerService : Singleton + public class AddonInstallerService { - private readonly AddonInstallerRegistry _addonInstallerRegistry = AddonInstallerRegistry.Instance; + private readonly ModRepository _modRepository; + + private readonly IEnumerable _addonInstallers; + + public AddonInstallerService(ModRepository modRepository, IEnumerable addonInstallers) + { + _modRepository = modRepository; + _addonInstallers = addonInstallers; + } public void Install(Mod mod, string zipLocation) { - foreach (var installer in _addonInstallerRegistry.GetAddonInstallers()) + foreach (var installer in _addonInstallers) { if (installer.Install(mod, zipLocation)) { + _modRepository.Load(); + return; } } @@ -20,25 +32,29 @@ public void Install(Mod mod, string zipLocation) throw new AddonInstallerException($"{mod.Name} could not be installed by any installer"); } - public void Uninstall(Manifest manifest) + public void Uninstall(ModManagerManifest modManagerManifest) { - foreach (var installer in _addonInstallerRegistry.GetAddonInstallers()) + foreach (var installer in _addonInstallers) { - if (installer.Uninstall(manifest)) + if (installer.Uninstall(modManagerManifest)) { + _modRepository.Load(); + return; } } - throw new AddonInstallerException($"{manifest.ModName} could not be uninstalled by any installer"); + throw new AddonInstallerException($"{modManagerManifest.ModName} could not be uninstalled by any installer"); } - public void ChangeVersion(Mod mod, File file, string zipLocation) + public void ChangeVersion(Mod mod, string zipLocation) { - foreach (var installer in _addonInstallerRegistry.GetAddonInstallers()) + foreach (var installer in _addonInstallers) { - if (installer.ChangeVersion(mod, file, zipLocation)) + if (installer.ChangeVersion(mod, zipLocation)) { + _modRepository.Load(); + return; } } diff --git a/ModManager/AddonInstallerSystem/AddonRemovalService.cs b/ModManager/AddonInstallerSystem/AddonRemovalService.cs deleted file mode 100644 index 94413b9..0000000 --- a/ModManager/AddonInstallerSystem/AddonRemovalService.cs +++ /dev/null @@ -1,17 +0,0 @@ -using ModManager.StartupSystem; -using System; - -namespace ModManager.AddonInstallerSystem -{ - public class AddonRemovalService : Singleton, ILoadable - { - public AddonRemovalService() - { - } - - public void Load(ModManagerStartupOptions startupOptions) - { - throw new NotImplementedException(); - } - } -} diff --git a/ModManager/AddonInstallerSystem/IAddonInstaller.cs b/ModManager/AddonInstallerSystem/IAddonInstaller.cs index 4429011..0523e51 100644 --- a/ModManager/AddonInstallerSystem/IAddonInstaller.cs +++ b/ModManager/AddonInstallerSystem/IAddonInstaller.cs @@ -7,8 +7,8 @@ public interface IAddonInstaller { public bool Install(Mod mod, string zipLocation); - public bool Uninstall(Manifest manifest); + public bool Uninstall(ModManagerManifest modManagerManifest); - public bool ChangeVersion(Mod mod, File file, string zipLocation); + public bool ChangeVersion(Mod mod, string zipLocation); } } \ No newline at end of file diff --git a/ModManager/AddonSystem/AddonService.cs b/ModManager/AddonSystem/AddonService.cs index d8b941c..09908ad 100644 --- a/ModManager/AddonSystem/AddonService.cs +++ b/ModManager/AddonSystem/AddonService.cs @@ -1,27 +1,35 @@ using Modio.Models; -using ModManager.AddonEnableSystem; -using ModManager.AddonInstallerSystem; using ModManager.ModIoSystem; using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net.Http; using System.Threading.Tasks; +using ModManager.AddonInstallerSystem; using ModManager.VersionSystem; using File = Modio.Models.File; +using Mod = Modio.Models.Mod; +using Mono.Security.Cryptography; +using System.Security.Cryptography; +using System.Threading; namespace ModManager.AddonSystem { - public class AddonService : Singleton, IAddonService + public class AddonService { - private readonly InstalledAddonRepository _installedAddonRepository = InstalledAddonRepository.Instance; - private readonly AddonInstallerService _addonInstallerService = AddonInstallerService.Instance; - private readonly AddonEnablerService _addonEnablerService = AddonEnablerService.Instance; + public static AddonService? Instance; + + private readonly InstalledAddonRepository _installedAddonRepository; + private readonly AddonInstallerService _addonInstallerService; private readonly Dictionary _imageCache = new(); - private readonly HttpClient _httpClient = new(); + public AddonService(InstalledAddonRepository installedAddonRepository, AddonInstallerService addonInstallerService) + { + Instance = this; + _installedAddonRepository = installedAddonRepository; + _addonInstallerService = addonInstallerService; + } public void Install(Mod mod, string zipLocation) { @@ -43,38 +51,18 @@ public void Uninstall(uint modId) _addonInstallerService.Uninstall(manifest); } - public void ChangeVersion(Mod mod, File file, string zipLocation) + public void ChangeVersion(Mod mod, string zipLocation) { if (!mod.IsInstalled()) { throw new AddonException($"Cannot change version of {mod.Name}. Mod is not installed."); } - if (_installedAddonRepository.Get(mod.Id).Version == file.Version) - { - throw new AddonException($"{mod.Name} is already installed with version {file.Version}."); - } - - _addonInstallerService.ChangeVersion(mod, file, zipLocation); - } - - public void Enable(uint modId) - { - if (!_installedAddonRepository.TryGet(modId, out var manifest)) + if (_installedAddonRepository.Get(mod.Id).Version == mod.Modfile!.Version) { - throw new AddonException($"Cannot enable modId: {modId}. Mod is not installed."); + throw new AddonException($"{mod.Name} is already installed with version {mod.Modfile!.Version}."); } - _addonEnablerService.Enable(manifest); - } - - public void Disable(uint modId) - { - if (!_installedAddonRepository.TryGet(modId, out var manifest)) - { - throw new AddonException($"Cannot disable modId: {modId}. Mod is not installed."); - } - - _addonEnablerService.Disable(manifest); + _addonInstallerService.ChangeVersion(mod, zipLocation); } public IAsyncEnumerable GetDependencies(Mod mod) @@ -88,13 +76,13 @@ private static async IAsyncEnumerable GetUniqueDependencies(Mod mod, { list.Add(mod); - var dependencies = ModIoModDependenciesRegistry.Get(mod); + var dependencies = await ModIoModDependenciesRegistry.Get(mod); foreach (var dependency in dependencies) { yield return dependency; - var dependencyMod = ModIoModRegistry.Get(dependency); + var dependencyMod = await ModIoModRegistry.Get(dependency); if (list.Contains(dependencyMod)) continue; @@ -105,26 +93,45 @@ private static async IAsyncEnumerable GetUniqueDependencies(Mod mod, } } - public async Task<(string location, Mod Mod)> Download(Mod mod, File file) + public async Task<(string location, Mod Mod)> Download(Mod mod, CancellationToken cancellationToken, Action progress) { - if (file.IsModInstalled()) + if (mod.IsInstalled()) { if (!_installedAddonRepository.TryGet(mod.Id, out var manifest)) { throw new AddonException($"Couldn't find installed mod'd manifest."); } - if (manifest.Version == file.Version) + if (manifest.Version == mod.Modfile!.Version) { - throw new AddonException($"Mod {mod.Name} is already installed with version {file.Version}."); + throw new AddonException($"Mod {mod.Name} is already installed with version {mod.Modfile!.Version}."); } } - mod.Modfile = file; - + progress(0); Directory.CreateDirectory($"{Paths.ModManager.Temp}"); - var tempZipLocation = Path.Combine(Paths.ModManager.Temp, $"{mod.Id}_{file.Version}.zip"); + var tempZipLocation = Path.Combine(Paths.ModManager.Temp, $"{mod.Id}_{mod.Modfile!.Version}.zip"); + + var length = mod.Modfile!.FileSize; + var position = 0; + var streamProgress = new Progress((count) => + { + position += count; + progress((float)position / length); + }); + + using var stream = new FileInfo(tempZipLocation).Create(); + using var md5sum = MD5.Create(); + using var cstream = new CryptoStream(stream, md5sum, CryptoStreamMode.Write); + using var pstream = new ProgressStream.ProgressStream(cstream, writeProgress: streamProgress); + + await ModIo.Client.Download(ModIoGameInfo.GameId, mod.Id, mod.Modfile!.Id, pstream, cancellationToken); + cstream.FlushFinalBlock(); + + var wantMd5 = CryptoConvert.FromHex(mod.Modfile!.FileHash!.Md5); + if (!CryptographicOperations.FixedTimeEquals(wantMd5, md5sum.Hash)) { + throw new AddonException($"Mod {mod.Name} download hash mismatch for version {mod.Modfile!.Version}."); + } - await ModIo.Client.Download(ModIoGameInfo.GameId, mod.Id, file.Id, new FileInfo(tempZipLocation)); (string, Mod) result = new(tempZipLocation, mod); return result; } @@ -136,14 +143,14 @@ public async Task GetImage(Uri uri) return imageBytes; } - var byteArray = await _httpClient.GetByteArrayAsync(uri); + var byteArray = await ModIo.HttpClient.GetByteArrayAsync(uri); _imageCache[uri] = byteArray; return byteArray; } public async Task TryGetCompatibleVersion(uint modId, bool downloadHighestInsteadOfLive) { - var orderedFiles = await ModIoModFilesRegistry.GetDescAsync(modId); + var orderedFiles = await ModIoModFilesRegistry.GetDesc(modId); var latestCompatibleFile = orderedFiles.FirstOrDefault(file => VersionStatusService.GetVersionStatus(file) == VersionStatus.Compatible); if (latestCompatibleFile != null) { diff --git a/ModManager/AddonSystem/IAddonService.cs b/ModManager/AddonSystem/IAddonService.cs deleted file mode 100644 index 2f52857..0000000 --- a/ModManager/AddonSystem/IAddonService.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Modio.Models; -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace ModManager.AddonSystem -{ - public interface IAddonService - { - void Install(Mod mod, string zipLocation); - - void Uninstall(uint modId); - - void ChangeVersion(Mod mod, File file, string zipLocation); - - void Enable(uint modId); - - void Disable(uint modId); - - IAsyncEnumerable GetDependencies(Mod mod); - - Task<(string location, Mod Mod)> Download(Mod mod, File file); - - Task GetImage(Uri uri); - - Task TryGetCompatibleVersion(uint modId, bool downloadHighestInsteadOfLive); - } -} \ No newline at end of file diff --git a/ModManager/AddonSystem/InstalledAddonRepository.cs b/ModManager/AddonSystem/InstalledAddonRepository.cs index a6322f5..1b738ae 100644 --- a/ModManager/AddonSystem/InstalledAddonRepository.cs +++ b/ModManager/AddonSystem/InstalledAddonRepository.cs @@ -1,22 +1,30 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using ModManager.ManifestLocationFinderSystem; -using ModManager.StartupSystem; +using Timberborn.SingletonSystem; namespace ModManager.AddonSystem { - public class InstalledAddonRepository : Singleton, ILoadable + public class InstalledAddonRepository : ILoadableSingleton { - private Dictionary _installedMods = new(); + public static InstalledAddonRepository Instance = null!; + + private readonly ManifestLocationFinderService _manifestLocationFinderService; + + private Dictionary _installedMods = new(); - private readonly ManifestLocationFinderService _manifestLocationFinderService = ManifestLocationFinderService.Instance; + public InstalledAddonRepository(ManifestLocationFinderService manifestLocationFinderService) + { + Instance = this; + _manifestLocationFinderService = manifestLocationFinderService; + } - public bool TryGet(uint modId, out Manifest manifest) + public bool TryGet(uint modId, out ModManagerManifest modManagerManifest) { - return _installedMods.TryGetValue(modId, out manifest); + return _installedMods.TryGetValue(modId, out modManagerManifest); } - public Manifest Get(uint modId) + public ModManagerManifest Get(uint modId) { return _installedMods[modId]; } @@ -31,19 +39,19 @@ public void Remove(uint modId) _installedMods.Remove(modId); } - public void Add(Manifest manifest) + public void Add(ModManagerManifest modManagerManifest) { - _installedMods.Add(manifest.ModId, manifest); + _installedMods.Add(modManagerManifest.ResourceId, modManagerManifest); } - public IEnumerable All() + public IEnumerable All() { return _installedMods.Values; } - public void Load(ModManagerStartupOptions startupOptions) + public void Load() { - _installedMods = _manifestLocationFinderService.FindAll().ToDictionary(manifest => manifest.ModId); + _installedMods = _manifestLocationFinderService.FindAll().ToDictionary(manifest => manifest.ResourceId); } } } \ No newline at end of file diff --git a/ModManager/AddonSystem/Manifest.cs b/ModManager/AddonSystem/Manifest.cs deleted file mode 100644 index 8b891b7..0000000 --- a/ModManager/AddonSystem/Manifest.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Modio.Models; -using Newtonsoft.Json; - -namespace ModManager.AddonSystem -{ - public class Manifest - { - public const string FileName = "manifest.json"; - - public Manifest() - { - - } - - public Manifest(Mod mod, File file, string installationRootPath) - { - RootPath = installationRootPath; - AuthorName = mod.SubmittedBy!.Username!; - FileId = file.Id; - ModId = mod.Id; - ModName = mod.Name!; - Summary = mod.Summary!; - Version = file.Version!; - Changelogs = file.Changelog!; - Tags = mod.Tags.Select(tag => tag.Name!).ToList(); - } - - public virtual Manifest Update(Mod mod, File file) - { - AuthorName = mod.SubmittedBy!.Username!; - FileId = file.Id; - ModId = mod.Id; - ModName = mod.Name!; - Summary = mod.Summary!; - Version = file.Version!; - Changelogs = file.Changelog!; - Tags = mod.Tags.Select(tag => tag.Name!).ToList(); - - return this; - } - - [JsonIgnore] - public string RootPath { get; set; } = null!; - - [JsonIgnore] - public bool Enabled { get; set; } = true; - - public string AuthorName { get; set; } = null!; - - public uint FileId { get; set; } - - public uint ModId { get; set; } - - public string ModName { get; set; } = null!; - - [JsonProperty(Required = Required.AllowNull)] - public string? Summary { get; set; } - - [JsonProperty(Required = Required.AllowNull)] - public string? Version { get; set; } - - [JsonProperty(Required = Required.AllowNull)] - public string? Changelogs { get; set; } - - [JsonProperty(Required = Required.AllowNull)] - public List? Tags { get; set; } - } -} diff --git a/ModManager/AddonSystem/ModManagerManifest.cs b/ModManager/AddonSystem/ModManagerManifest.cs new file mode 100644 index 0000000..9222452 --- /dev/null +++ b/ModManager/AddonSystem/ModManagerManifest.cs @@ -0,0 +1,43 @@ +using Modio.Models; +using Newtonsoft.Json; + +namespace ModManager.AddonSystem +{ + public class ModManagerManifest + { + public const string FileName = "mod_manager_manifest.json"; + + [JsonConstructor] + public ModManagerManifest() + { + } + + public ModManagerManifest(string installLocation, Mod mod) + { + RootPath = installLocation; + ResourceId = mod.Id; + Version = mod.Modfile!.Version; + } + + public ModManagerManifest( + string installLocation, + Mod mod, + string version) + { + RootPath = installLocation; + ResourceId = mod.Id; + Version = version; + } + + [JsonIgnore] + public string RootPath { get; set; } = null!; + + public uint ResourceId { get; set; } + + [JsonProperty(Required = Required.AllowNull)] + public string? ModName { get; set; } + + [JsonProperty(Required = Required.AllowNull)] + public string? Version { get; set; } + } +} diff --git a/ModManager/BepInExSystem/BepInExExtractor.cs b/ModManager/BepInExSystem/BepInExExtractor.cs deleted file mode 100644 index e59d630..0000000 --- a/ModManager/BepInExSystem/BepInExExtractor.cs +++ /dev/null @@ -1,144 +0,0 @@ -using Modio.Models; -using ModManager.ExtractorSystem; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace ModManager.BepInExSystem -{ - public class BepInExExtractor : IAddonExtractor - { - private const string _bepInExPackName = "BepInExPack"; - - private List _foldersToIgnore = new() { "" }; - - // TODO: Add actual extract logic from bepinex. - // Atm bepinex must be installed already for mod manager to work - // and updated to the pack in unlikely - public bool Extract(string addonZipLocation, Mod modInfo, out string extractLocation, bool overWrite = true) - { - extractLocation = ""; - if (modInfo.Name != _bepInExPackName) - { - return false; - } - extractLocation = Path.Combine(Paths.GameRoot, "BepInEx", "plugins", $"{modInfo.NameId}_{modInfo.Id}_{modInfo.Modfile.Version}"); - if (!Directory.Exists(extractLocation)) - { - Directory.CreateDirectory(extractLocation); - } - System.IO.File.Delete(addonZipLocation); - - return true; - } - - //public bool Extract(string addonZipLocation, Mod modInfo, out string extractLocation, bool overWrite = true) - //{ - // extractLocation = ""; - // if (modInfo.Name != _bepInExPackName) - // { - // return false; - // } - - // //ZipFile.ExtractToDirectory(addonZipLocation, Paths.GameRoot, true); - - // string modFolderName = $"{modInfo.NameId}_{modInfo.Id}_{modInfo.Modfile.Version}"; - // ClearOldModFiles(modInfo, modFolderName); - - // extractLocation = Path.Combine(Paths.GameRoot, "BepInEx", "plugins", $"{modInfo.NameId}_{modInfo.Id}_{modInfo.Modfile.Version}"); - // if (!Directory.Exists(extractLocation)) - // { - // Directory.CreateDirectory(extractLocation); - // } - - // System.IO.File.Delete(addonZipLocation); - - // return true; - //} - - private void ClearOldModFiles(Mod modInfo, string modFolderName) - { - if (TryGetExistingModFolder(modInfo, out var dirs)) - { - var dirInfo = new DirectoryInfo(dirs); - if (dirInfo.Name.Equals(modFolderName)) - { - return; - } - dirInfo.MoveTo(Path.Combine(Paths.Mods, modFolderName)); - DeleteModFiles(modFolderName); - } - } - private bool TryGetExistingModFolder(Mod modInfo, out string dirs) - { - dirs = null; - try - { - dirs = Directory.GetDirectories(Paths.Mods, $"{modInfo.NameId}_{modInfo.Id}*").SingleOrDefault(); - } - catch (InvalidOperationException ex) - { - throw new AddonExtractorException($"Found multiple folders for \"{modInfo.Name}\""); - } - catch (Exception) - { - throw; - } - if (dirs != null) - { - return true; - } - - return false; - } - private void DeleteModFiles(string modFolderName) - { - var modDirInfo = new DirectoryInfo(Path.Combine(Paths.Mods, modFolderName)); - var modSubFolders = modDirInfo.GetDirectories("*", SearchOption.AllDirectories) - .Where(folder => !_foldersToIgnore.Contains(folder.FullName.Split(Path.DirectorySeparatorChar).Last())); - foreach (var subDirectory in modSubFolders.Reverse()) - { - DeleteFilesFromFolder(subDirectory); - TryDeleteFolder(subDirectory); - } - - DeleteFilesFromFolder(modDirInfo); - TryDeleteFolder(modDirInfo); - } - - private void DeleteFilesFromFolder(DirectoryInfo dir) - { - foreach (var file in dir.GetFiles().Where(file => !file.Name.EndsWith(Names.Extensions.Remove))) - { - try - { - file.Delete(); - } - catch (UnauthorizedAccessException ex) - { - file.MoveTo($"{file.FullName}{Names.Extensions.Remove}"); - } - catch (Exception ex) - { - throw ex; - } - } - } - - private void TryDeleteFolder(DirectoryInfo dir) - { - try - { - if (dir.EnumerateDirectories().Any() == false && dir.EnumerateFiles().Any() == false) - { - dir.Delete(); - } - } - catch (Exception) - { - throw; - } - } - } -} diff --git a/ModManager/BepInExSystem/BepInExRegisterer.cs b/ModManager/BepInExSystem/BepInExRegisterer.cs deleted file mode 100644 index 8911e9a..0000000 --- a/ModManager/BepInExSystem/BepInExRegisterer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using ModManager.ExtractorSystem; -using ModManager.StartupSystem; - -namespace ModManager.BepInExSystem -{ - public class BepInExRegisterer : Singleton, ILoadable - { - public const string RegistryId = "BepInEx"; - - public void Load(ModManagerStartupOptions startupOptions) - { - AddonExtractorRegistry.Instance.Add(RegistryId, new BepInExExtractor()); - } - } -} diff --git a/ModManager/ExtractorSystem/AddonExtractorRegistry.cs b/ModManager/ExtractorSystem/AddonExtractorRegistry.cs deleted file mode 100644 index 02c5219..0000000 --- a/ModManager/ExtractorSystem/AddonExtractorRegistry.cs +++ /dev/null @@ -1,31 +0,0 @@ -using ModManager.AddonInstallerSystem; -using System.Collections.Generic; -using System.Linq; - -namespace ModManager.ExtractorSystem -{ - public class AddonExtractorRegistry : Singleton - { - private readonly List> _addonExtractors = new(); - - public void Add(string extractorId, IAddonExtractor addonExtractor) - { - if (_addonExtractors.Exists(pair => pair.Key.Equals(extractorId))) - { - throw new AddonInstallerException($"Addon extractor with id: `{extractorId}` is already added to the list"); - } - - _addonExtractors.Insert(0, new KeyValuePair(extractorId, addonExtractor)); - } - - public void Remove(string installerId) - { - _addonExtractors.Remove(_addonExtractors.First(pair => pair.Key.Equals(installerId))); - } - - public IEnumerable GetAddonExtractor() - { - return _addonExtractors.Select(pair => pair.Value); - } - } -} diff --git a/ModManager/ExtractorSystem/AddonExtractorService.cs b/ModManager/ExtractorSystem/AddonExtractorService.cs index bc61ff9..c1a7d59 100644 --- a/ModManager/ExtractorSystem/AddonExtractorService.cs +++ b/ModManager/ExtractorSystem/AddonExtractorService.cs @@ -1,14 +1,20 @@ -using Modio.Models; +using System.Collections.Generic; +using Modio.Models; namespace ModManager.ExtractorSystem { - public class AddonExtractorService : Singleton + public class AddonExtractorService { - private readonly AddonExtractorRegistry _addonExtractorRegistry = AddonExtractorRegistry.Instance; + private readonly IEnumerable _addonInstallers; + + public AddonExtractorService(IEnumerable addonInstallers) + { + _addonInstallers = addonInstallers; + } public string Extract(Mod addonInfo, string addonZipLocation, bool overwrite = true) { - foreach (var extractor in _addonExtractorRegistry.GetAddonExtractor()) + foreach (var extractor in _addonInstallers) { if (extractor.Extract(addonZipLocation, addonInfo, out var extractLocation)) { diff --git a/ModManager/LoggingSystem/LoggingEventEventArgs.cs b/ModManager/LoggingSystem/LoggingEventEventArgs.cs deleted file mode 100644 index 5094c64..0000000 --- a/ModManager/LoggingSystem/LoggingEventEventArgs.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace ModManager.LoggingSystem -{ - public class LoggingEventEventArgs : EventArgs - { - public string Message { get; set; } - public LoggingLevels LoggingLevel { get; set; } - } -} diff --git a/ModManager/LoggingSystem/LoggingLevels.cs b/ModManager/LoggingSystem/LoggingLevels.cs deleted file mode 100644 index 4a5efad..0000000 --- a/ModManager/LoggingSystem/LoggingLevels.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ModManager.LoggingSystem -{ - public enum LoggingLevels - { - Debug, - Info, - Warning, - Error - } -} diff --git a/ModManager/LoggingSystem/ModManagerLogger.cs b/ModManager/LoggingSystem/ModManagerLogger.cs deleted file mode 100644 index fe1c80c..0000000 --- a/ModManager/LoggingSystem/ModManagerLogger.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace ModManager.LoggingSystem -{ - public interface IModManagerLogger - { - void LogInfo(string message); - - void LogWarning(string message); - - void LogError(string message); - - event EventHandler LoggingEvent; - } -} diff --git a/ModManager/ManifestLocationFinderSystem/IManifestLocationFinder.cs b/ModManager/ManifestLocationFinderSystem/IManifestLocationFinder.cs index 2bd667d..bc9f427 100644 --- a/ModManager/ManifestLocationFinderSystem/IManifestLocationFinder.cs +++ b/ModManager/ManifestLocationFinderSystem/IManifestLocationFinder.cs @@ -5,8 +5,6 @@ namespace ModManager.ManifestLocationFinderSystem { public interface IManifestLocationFinder { - public IEnumerable Find(); - - IEnumerable FindRemovable(); + public IEnumerable Find(); } } \ No newline at end of file diff --git a/ModManager/ManifestLocationFinderSystem/ManifestException.cs b/ModManager/ManifestLocationFinderSystem/ManifestException.cs deleted file mode 100644 index 23d7417..0000000 --- a/ModManager/ManifestLocationFinderSystem/ManifestException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace ModManager.ManifestLocationFinderSystem -{ - public class ManifestException : Exception - { - public ManifestException(string message) : base(message) - { - } - } -} \ No newline at end of file diff --git a/ModManager/ManifestLocationFinderSystem/ManifestLocationFinderRegistry.cs b/ModManager/ManifestLocationFinderSystem/ManifestLocationFinderRegistry.cs index 966864d..dd4242f 100644 --- a/ModManager/ManifestLocationFinderSystem/ManifestLocationFinderRegistry.cs +++ b/ModManager/ManifestLocationFinderSystem/ManifestLocationFinderRegistry.cs @@ -1,30 +1,19 @@ using System.Collections.Generic; -using System.Linq; namespace ModManager.ManifestLocationFinderSystem { - public class ManifestLocationFinderRegistry : Singleton + public class ManifestLocationFinderRegistry { - private readonly List> _manifestLocationFinders = new(); + private readonly IEnumerable _manifestLocationFinders; - public void Add(string manifestLocationFinderId, IManifestLocationFinder manifestLocationFinder) + public ManifestLocationFinderRegistry(IEnumerable manifestLocationFinders) { - if (_manifestLocationFinders.Exists(pair => pair.Key.Equals(manifestLocationFinderId))) - { - throw new ManifestException($"Manifest location finder with id: `{manifestLocationFinderId}` is already added to the list"); - } - - _manifestLocationFinders.Insert(0, new KeyValuePair(manifestLocationFinderId, manifestLocationFinder)); - } - - public void Remove(string manifestLocationFinderId) - { - _manifestLocationFinders.Remove(_manifestLocationFinders.First(pair => pair.Key.Equals(manifestLocationFinderId))); + _manifestLocationFinders = manifestLocationFinders; } public IEnumerable GetManifestLocationFinders() { - return _manifestLocationFinders.Select(pair => pair.Value); + return _manifestLocationFinders; } } } \ No newline at end of file diff --git a/ModManager/ManifestLocationFinderSystem/ManifestLocationFinderService.cs b/ModManager/ManifestLocationFinderSystem/ManifestLocationFinderService.cs index 7fdf546..585f525 100644 --- a/ModManager/ManifestLocationFinderSystem/ManifestLocationFinderService.cs +++ b/ModManager/ManifestLocationFinderSystem/ManifestLocationFinderService.cs @@ -4,11 +4,16 @@ namespace ModManager.ManifestLocationFinderSystem { - public class ManifestLocationFinderService : Singleton + public class ManifestLocationFinderService { - private readonly ManifestLocationFinderRegistry _manifestLocationFinderRegistry = ManifestLocationFinderRegistry.Instance; + private readonly ManifestLocationFinderRegistry _manifestLocationFinderRegistry; - public IEnumerable FindAll() + public ManifestLocationFinderService(ManifestLocationFinderRegistry manifestLocationFinderRegistry) + { + _manifestLocationFinderRegistry = manifestLocationFinderRegistry; + } + + public IEnumerable FindAll() { return _manifestLocationFinderRegistry.GetManifestLocationFinders().SelectMany(manifestLocationFinder => manifestLocationFinder.Find()); } diff --git a/ModManager/ManifestValidatorSystem/ManifestValidatorRegistry.cs b/ModManager/ManifestValidatorSystem/ManifestValidatorRegistry.cs deleted file mode 100644 index 177871d..0000000 --- a/ModManager/ManifestValidatorSystem/ManifestValidatorRegistry.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace ModManager.ManifestValidatorSystem -{ - public class ManifestValidatorRegistry : Singleton - { - private readonly List> _manifestValidators = new(); - - public void Add(string validatorId, IManifestValidator manifestValidator) - { - if (_manifestValidators.Exists(pair => pair.Key.Equals(validatorId))) - { - throw new ManifestValidatorException($"Manifest validator with id: `{validatorId}` is already added to the list"); - } - - _manifestValidators.Insert(0, new KeyValuePair(validatorId, manifestValidator)); - } - - public void Remove(string installerId) - { - _manifestValidators.Remove(_manifestValidators.First(pair => pair.Key.Equals(installerId))); - } - - public IEnumerable GetManifestValidator() - { - return _manifestValidators.Select(pair => pair.Value); - } - } -} diff --git a/ModManager/ManifestValidatorSystem/ManifestValidatorService.cs b/ModManager/ManifestValidatorSystem/ManifestValidatorService.cs index fbd6c62..39d97af 100644 --- a/ModManager/ManifestValidatorSystem/ManifestValidatorService.cs +++ b/ModManager/ManifestValidatorSystem/ManifestValidatorService.cs @@ -1,12 +1,20 @@ -namespace ModManager.ManifestValidatorSystem +using System.Collections.Generic; +using Timberborn.SingletonSystem; + +namespace ModManager.ManifestValidatorSystem { - public class ManifestValidatorService : Singleton + public class ManifestValidatorService : ILoadableSingleton { - private readonly ManifestValidatorRegistry _manifestValidatorRegistry = ManifestValidatorRegistry.Instance; + private readonly IEnumerable _manifestValidators; + + public ManifestValidatorService(IEnumerable manifestValidators) + { + _manifestValidators = manifestValidators; + } - public void ValidateManifests() + public void Load() { - foreach (var validator in _manifestValidatorRegistry.GetManifestValidator()) + foreach (var validator in _manifestValidators) { validator.ValidateManifests(); } diff --git a/ModManager/MapSystem/MapEnabler.cs b/ModManager/MapSystem/MapEnabler.cs deleted file mode 100644 index f0e5052..0000000 --- a/ModManager/MapSystem/MapEnabler.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.IO; -using System.Linq; -using ModManager.AddonEnableSystem; -using ModManager.AddonSystem; - -namespace ModManager.MapSystem -{ - public class MapEnabler : IAddonEnabler - { - public bool Enable(Manifest manifest) - { - if (manifest is not MapManifest mapManifest) - { - return false; - } - - var enabledFilePaths = mapManifest.MapFileNames.Select(mapFileName => Path.Combine(Paths.Maps, mapFileName + Names.Extensions.TimberbornMap)).ToList(); - - foreach (var enabledFilePath in enabledFilePaths) - { - if (!File.Exists(enabledFilePath + Names.Extensions.Disabled)) - { - continue; - } - - File.Move(enabledFilePath + Names.Extensions.Disabled, enabledFilePath); - manifest.Enabled = true; - } - return true; - } - - public bool Disable(Manifest manifest) - { - if (manifest is not MapManifest mapManifest) - { - return false; - } - - var mapFilePaths = mapManifest.MapFileNames.Select(mapFileName => Path.Combine(Paths.Maps, mapFileName + Names.Extensions.TimberbornMap)).ToList(); - - foreach (var mapFilePath in mapFilePaths) - { - if (!File.Exists(mapFilePath)) - { - continue; - } - - File.Move(mapFilePath, mapFilePath + Names.Extensions.Disabled); - manifest.Enabled = false; - } - - return true; - } - } -} \ No newline at end of file diff --git a/ModManager/MapSystem/MapExtractor.cs b/ModManager/MapSystem/MapExtractor.cs index f3b8558..2d94751 100644 --- a/ModManager/MapSystem/MapExtractor.cs +++ b/ModManager/MapSystem/MapExtractor.cs @@ -15,11 +15,12 @@ public bool Extract(string addonZipLocation, Mod modInfo, out string extractLoca { return false; } + using (var zipFile = ZipFile.OpenRead(addonZipLocation)) { var timberFiles = zipFile.Entries - .Where(x => x.Name.Contains(".timber")) - .ToList(); + .Where(x => x.Name.Contains(".timber")) + .ToList(); if (timberFiles.Count() == 0) { @@ -45,4 +46,4 @@ public bool Extract(string addonZipLocation, Mod modInfo, out string extractLoca return true; } } -} +} \ No newline at end of file diff --git a/ModManager/MapSystem/MapInstaller.cs b/ModManager/MapSystem/MapInstaller.cs index fc73e64..70846d1 100644 --- a/ModManager/MapSystem/MapInstaller.cs +++ b/ModManager/MapSystem/MapInstaller.cs @@ -1,94 +1,89 @@ -using Modio.Models; -using ModManager.AddonInstallerSystem; +using ModManager.AddonInstallerSystem; using ModManager.AddonSystem; using ModManager.ExtractorSystem; using ModManager.PersistenceSystem; -using ModManager.StartupSystem; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; +using Timberborn.Modding; using File = Modio.Models.File; +using Mod = Modio.Models.Mod; namespace ModManager.MapSystem { public class MapInstaller : IAddonInstaller { - private readonly PersistenceService _persistenceService; - private readonly InstalledAddonRepository _installedAddonRepository; + private readonly AddonExtractorService _addonExtractorService; - private readonly AddonExtractorService _extractor; - - private readonly MapManifestFinder _mapManifestFinder; + private readonly PersistenceService _persistenceService = PersistenceService.Instance; + private readonly MapManifestFinder _mapManifestFinder = new(); - public MapInstaller(ModManagerStartupOptions startupOptions) + public MapInstaller(InstalledAddonRepository installedAddonRepository, AddonExtractorService addonExtractorService) { - _persistenceService = PersistenceService.Instance; - _installedAddonRepository = InstalledAddonRepository.Instance; - _extractor = AddonExtractorService.Instance; - _mapManifestFinder = new MapManifestFinder(startupOptions.Logger); + _installedAddonRepository = installedAddonRepository; + _addonExtractorService = addonExtractorService; } public bool Install(Mod mod, string zipLocation) { - if(!mod.Tags.Any(x => x.Name == "Map")) + if (!mod.Tags.Any(x => x.Name == "Map")) { return false; } + List timberFileNames = new(); using (var zipFile = ZipFile.OpenRead(zipLocation)) { timberFileNames = zipFile.Entries - .Where(x => x.Name.Contains(".timber")) - .Select(x => x.Name.Replace(Names.Extensions.TimberbornMap, "")) - .ToList(); + .Where(x => x.Name.Contains(".timber")) + .Select(x => x.Name.Replace(Names.Extensions.TimberbornMap, "")) + .ToList(); } - for(var i = 0; i < timberFileNames.Count(); i++) + for (var i = 0; i < timberFileNames.Count(); i++) { var files = Directory.GetFiles(Paths.Maps, timberFileNames[i]); - if(files.Length > 0) + if (files.Length > 0) { timberFileNames[i] += $"_{files.Length + 1}"; } } - var installLocation = _extractor.Extract(mod, zipLocation); - var manifest = new MapManifest(mod, - mod.Modfile, - installLocation, - timberFileNames); + var installLocation = _addonExtractorService.Extract(mod, zipLocation); + + var manifest = new MapModManagerManifest(installLocation, mod, timberFileNames); var manifests = _mapManifestFinder.Find() - .Select(a => (MapManifest)a) - .ToList(); + .Select(a => (MapModManagerManifest)a) + .ToList(); manifests.Add(manifest); - var mapManifestPath = Path.Combine(installLocation, MapManifest.FileName); + var mapManifestPath = Path.Combine(installLocation, MapModManagerManifest.FileName); _persistenceService.SaveObject(manifests, mapManifestPath); _installedAddonRepository.Add(manifest); return true; } - public bool Uninstall(Manifest manifest) + public bool Uninstall(ModManagerManifest modManagerManifest) { - if (manifest is not MapManifest) + if (modManagerManifest is not MapModManagerManifest) { return false; } - var manifestPath = Path.Combine(Paths.Maps, MapManifest.FileName); - var manifests = _mapManifestFinder.Find().Select(a => (MapManifest)a).ToList(); - manifests.Remove(manifests.Where(x => x.ModId == manifest.ModId).SingleOrDefault()); + var manifestPath = Path.Combine(Paths.Maps, MapModManagerManifest.FileName); + var manifests = _mapManifestFinder.Find().Select(a => (MapModManagerManifest)a).ToList(); + manifests.Remove(manifests.SingleOrDefault(x => x.ResourceId == modManagerManifest.ResourceId)); _persistenceService.SaveObject(manifests, manifestPath); - _installedAddonRepository.Remove(manifest.ModId); + _installedAddonRepository.Remove(modManagerManifest.ResourceId); - foreach(var mapFileName in ((MapManifest)manifest).MapFileNames) + foreach (var mapFileName in ((MapModManagerManifest)modManagerManifest).MapFileNames) { var files = Directory.GetFiles(Paths.Maps, $"{mapFileName}{Names.Extensions.TimberbornMap}*"); - foreach(var file in files) + foreach (var file in files) { System.IO.File.Delete(file); } @@ -97,7 +92,7 @@ public bool Uninstall(Manifest manifest) return true; } - public bool ChangeVersion(Mod mod, File file, string zipLocation) + public bool ChangeVersion(Mod mod, string zipLocation) { if (!mod.Tags.Any(x => x.Name == "Map")) { @@ -108,9 +103,9 @@ public bool ChangeVersion(Mod mod, File file, string zipLocation) using (var zipFile = ZipFile.OpenRead(zipLocation)) { timberFileNames = zipFile.Entries - .Where(x => x.Name.Contains(".timber")) - .Select(x => x.Name.Replace(Names.Extensions.TimberbornMap, "")) - .ToList(); + .Where(x => x.Name.Contains(".timber")) + .Select(x => x.Name.Replace(Names.Extensions.TimberbornMap, "")) + .ToList(); } for (var i = 0; i < timberFileNames.Count(); i++) @@ -121,22 +116,20 @@ public bool ChangeVersion(Mod mod, File file, string zipLocation) timberFileNames[i] += $"_{files.Length + 1}"; } } - var installLocation = _extractor.Extract(mod, zipLocation); - var manifest = new MapManifest(mod, - mod.Modfile, - installLocation, - timberFileNames); + var installLocation = _addonExtractorService.Extract(mod, zipLocation); + + var manifest = new MapModManagerManifest(installLocation, mod, timberFileNames); var manifests = _mapManifestFinder.Find() - .Where(a => a.ModId != mod.Id) - .Select(a => (MapManifest)a) - .ToList(); + .Where(a => a.ResourceId != mod.Id) + .Select(a => (MapModManagerManifest)a) + .ToList(); manifests.Add(manifest); - var mapManifestPath = Path.Combine(installLocation, MapManifest.FileName); + var mapManifestPath = Path.Combine(installLocation, MapModManagerManifest.FileName); _persistenceService.SaveObject(manifests, mapManifestPath); - _installedAddonRepository.Remove(manifest.ModId); + _installedAddonRepository.Remove(manifest.ResourceId); _installedAddonRepository.Add(manifest); return true; diff --git a/ModManager/MapSystem/MapManifest.cs b/ModManager/MapSystem/MapManifest.cs deleted file mode 100644 index 1ad2851..0000000 --- a/ModManager/MapSystem/MapManifest.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Modio.Models; -using ModManager.AddonSystem; -using System.Collections.Generic; - -namespace ModManager.MapSystem -{ - public class MapManifest : Manifest - { - public new const string FileName = Manifest.FileName; - - public List MapFileNames { get; set; } = null!; - - public MapManifest() - { - } - - public MapManifest(Mod mod, File file, string installationRootPath, List mapFleNames) - : base(mod, file, installationRootPath) - { - MapFileNames = mapFleNames; - } - - public override Manifest Update(Mod mod, File file) - { - //MapFileNames = $"{mod.NameId!.Trim()}_{file.Id}"; - return base.Update(mod, file); - } - } -} \ No newline at end of file diff --git a/ModManager/MapSystem/MapManifestFinder.cs b/ModManager/MapSystem/MapManifestFinder.cs index 3d4c030..427eaa8 100644 --- a/ModManager/MapSystem/MapManifestFinder.cs +++ b/ModManager/MapSystem/MapManifestFinder.cs @@ -3,75 +3,48 @@ using System.IO; using System.Linq; using ModManager.AddonSystem; -using ModManager.LoggingSystem; using ModManager.ManifestLocationFinderSystem; using ModManager.PersistenceSystem; using Newtonsoft.Json; +using UnityEngine; namespace ModManager.MapSystem { - public class MapManifestFinder : IManifestLocationFinder { - private readonly PersistenceService _persistenceService; - - private IModManagerLogger _logger; - - public MapManifestFinder(IModManagerLogger logger) - { - _persistenceService = PersistenceService.Instance; - _logger = logger; - } + private readonly PersistenceService _persistenceService = PersistenceService.Instance; - public IEnumerable Find() + public IEnumerable Find() { - var manifestPath = Path.Combine(Paths.Maps, MapManifest.FileName); + var manifestPath = Path.Combine(Paths.Maps, MapModManagerManifest.FileName); if (!File.Exists(manifestPath)) { - return new List(); + return new List(); } try { - var manifests = _persistenceService.LoadObject>(manifestPath, false); + var manifests = _persistenceService.LoadObject>(manifestPath, false); UpdateManifestInfo(manifests); return manifests; } - catch (JsonSerializationException ex) + catch (JsonSerializationException) { - _logger.LogWarning($"Failed to serialize JSON in file {manifestPath}. It is advised to delete the file."); - return new List(); + Debug.LogWarning($"Failed to serialize JSON in file {manifestPath}. It is advised to delete the file."); + return new List(); } catch (Exception) { throw; } } - - public IEnumerable FindRemovable() - { - throw new NotImplementedException(); - } - - private void UpdateManifestInfo(List manifests) + + private void UpdateManifestInfo(List manifests) { foreach (var mapManifest in manifests) { mapManifest.RootPath = Paths.Maps; - - var mapNames = mapManifest.MapFileNames - .Select(mapname => mapname + Names.Extensions.TimberbornMap); - var enabled = true; - foreach (var mapName in mapNames) - { - if (Directory.GetFiles(Paths.Maps, mapName).FirstOrDefault()?.EndsWith(Names.Extensions.Disabled) ?? false) - { - enabled = false; - break; - } - } - mapManifest.Enabled = enabled; } } } diff --git a/ModManager/MapSystem/MapManifestValidator.cs b/ModManager/MapSystem/MapManifestValidator.cs index 119cb81..f6ef35e 100644 --- a/ModManager/MapSystem/MapManifestValidator.cs +++ b/ModManager/MapSystem/MapManifestValidator.cs @@ -1,6 +1,5 @@ using ModManager.ManifestValidatorSystem; using ModManager.PersistenceSystem; -using ModManager.StartupSystem; using System.IO; using System.Linq; @@ -8,27 +7,17 @@ namespace ModManager.MapSystem { public class MapManifestValidator : IManifestValidator { - private readonly PersistenceService _persistenceService; - private readonly MapManifestFinder _mapManifestFinder; - - public MapManifestValidator(ModManagerStartupOptions startupOptions) - { - _persistenceService = PersistenceService.Instance; - _mapManifestFinder = new MapManifestFinder(startupOptions.Logger); - } + private readonly PersistenceService _persistenceService = PersistenceService.Instance; + private readonly MapManifestFinder _mapManifestFinder = new(); public void ValidateManifests() { - var mapManifests = _mapManifestFinder.Find().Select(a => (MapManifest)a).ToList(); + var mapManifests = _mapManifestFinder.Find().Select(a => (MapModManagerManifest)a).ToList(); var oldManifestCount = mapManifests.Count; foreach (var mapManifest in mapManifests.ToList()) { - var fileNames = - mapManifest.MapFileNames - .Select(filename => Path.Combine(Paths.Maps, - $"{filename}{Names.Extensions.TimberbornMap}")) - .ToList(); + var fileNames = mapManifest.MapFileNames.Select(filename => Path.Combine(Paths.Maps, $"{filename}{Names.Extensions.TimberbornMap}")).ToList(); var filesDontExist = true; @@ -49,7 +38,7 @@ public void ValidateManifests() if(oldManifestCount != newManifestCount ) { - var mapManifestPath = Path.Combine(Paths.Maps, MapManifest.FileName); + var mapManifestPath = Path.Combine(Paths.Maps, MapModManagerManifest.FileName); _persistenceService.SaveObject(mapManifests, mapManifestPath); } } diff --git a/ModManager/MapSystem/MapModManagerManifest.cs b/ModManager/MapSystem/MapModManagerManifest.cs new file mode 100644 index 0000000..0a0bccd --- /dev/null +++ b/ModManager/MapSystem/MapModManagerManifest.cs @@ -0,0 +1,25 @@ +using Modio.Models; +using ModManager.AddonSystem; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace ModManager.MapSystem +{ + public class MapModManagerManifest : ModManagerManifest + { + public new const string FileName = ModManagerManifest.FileName; + + public List MapFileNames { get; set; } = null!; + + [JsonConstructor] + public MapModManagerManifest() + { + } + + public MapModManagerManifest(string installLocation, Mod mod, List mapFleNames) + : base(installLocation, mod) + { + MapFileNames = mapFleNames; + } + } +} \ No newline at end of file diff --git a/ModManager/MapSystem/MapRegisterer.cs b/ModManager/MapSystem/MapRegisterer.cs deleted file mode 100644 index b91f747..0000000 --- a/ModManager/MapSystem/MapRegisterer.cs +++ /dev/null @@ -1,23 +0,0 @@ -using ModManager.AddonEnableSystem; -using ModManager.AddonInstallerSystem; -using ModManager.ExtractorSystem; -using ModManager.ManifestLocationFinderSystem; -using ModManager.ManifestValidatorSystem; -using ModManager.StartupSystem; - -namespace ModManager.MapSystem -{ - public class MapRegisterer : Singleton, ILoadable - { - public const string RegistryId = "Map"; - - public void Load(ModManagerStartupOptions startupOptions) - { - AddonInstallerRegistry.Instance.Add(RegistryId, new MapInstaller(startupOptions)); - AddonEnablerRegistry.Instance.Add(RegistryId, new MapEnabler()); - ManifestLocationFinderRegistry.Instance.Add(RegistryId, new MapManifestFinder(startupOptions.Logger)); - AddonExtractorRegistry.Instance.Add(RegistryId, new MapExtractor()); - ManifestValidatorRegistry.Instance.Add(RegistryId, new MapManifestValidator(startupOptions)); - } - } -} \ No newline at end of file diff --git a/ModManager/ModIoSystem/ModIo.cs b/ModManager/ModIoSystem/ModIo.cs index 2473ad4..f24e5b5 100644 --- a/ModManager/ModIoSystem/ModIo.cs +++ b/ModManager/ModIoSystem/ModIo.cs @@ -1,10 +1,28 @@ using System; +using System.Net; +using System.Net.Http; using Modio; namespace ModManager.ModIoSystem { public class ModIo { + private static HttpClient _httpClient = null!; + + internal static HttpClient HttpClient + { + get + { + if (_httpClient == null) + { + throw new NullReferenceException("Tried to access ModIo.HttpClient before startup has run."); + } + + return _httpClient; + } + private set => _httpClient = value; + } + private static Client _client = null!; public static Client Client @@ -27,9 +45,18 @@ public static Client Client public static GameTagsClient GameTagsClient => GameClient.Tags; - public static void InitializeClient(string apiKey) + public static void InitializeClient(string apiKey, uint gameId) { - Client = new Client(new Credentials(apiKey)); + HttpClient = new(new HttpClientHandler() + { +#pragma warning disable CS0618 // Type or member is obsolete + Proxy = WebProxy.GetDefaultProxy() +#pragma warning restore CS0618 // Type or member is obsolete + }); + Client = Client.GetBuilder(apiKey) + .WithGameHost(gameId) + .WithHttpClient(HttpClient) + .Build(); } } } \ No newline at end of file diff --git a/ModManager/ModIoSystem/ModIoExtensions.cs b/ModManager/ModIoSystem/ModIoExtensions.cs index 73f184d..81a7940 100644 --- a/ModManager/ModIoSystem/ModIoExtensions.cs +++ b/ModManager/ModIoSystem/ModIoExtensions.cs @@ -1,5 +1,6 @@ using Modio.Models; using ModManager.AddonSystem; +using Mod = Modio.Models.Mod; namespace ModManager.ModIoSystem { @@ -14,15 +15,5 @@ public static bool IsInstalled(this Dependency dependency) { return InstalledAddonRepository.Instance.Has(dependency.ModId); } - - public static bool IsEnabled(this Mod mod) - { - return InstalledAddonRepository.Instance.TryGet(mod.Id, out var manifest) && manifest.Enabled; - } - - public static bool IsModInstalled(this File mod) - { - return InstalledAddonRepository.Instance.Has(mod.ModId); - } } } \ No newline at end of file diff --git a/ModManager/ModIoSystem/ModIoModDependenciesRegistry.cs b/ModManager/ModIoSystem/ModIoModDependenciesRegistry.cs index f7f5dbf..acd44de 100644 --- a/ModManager/ModIoSystem/ModIoModDependenciesRegistry.cs +++ b/ModManager/ModIoSystem/ModIoModDependenciesRegistry.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; using System.Threading.Tasks; using Modio.Models; using Timberborn.Common; @@ -7,21 +9,30 @@ namespace ModManager.ModIoSystem { public abstract class ModIoModDependenciesRegistry { - private static readonly Dictionary> ModDependenciesCache = new(); + private static readonly ConcurrentDictionary>>> ModDependenciesCache = new(); - public static IReadOnlyList Get(uint modId) + public static async Task> Get(uint modId) { - return ModDependenciesCache.GetOrAdd(modId, () => Task.Run(() => RetrieveMod(modId)).Result); + var lazy = ModDependenciesCache.GetOrAdd(modId, () => new Lazy>>(() => RetrieveMod(modId))); + try + { + return await lazy.Value; + } + catch + { + ModDependenciesCache.TryUpdate(modId, new Lazy>>(() => RetrieveMod(modId)), lazy); + throw; + } } - public static IReadOnlyList Get(Mod mod) + public static async Task> Get(Mod mod) { - return ModDependenciesCache.GetOrAdd(mod.Id, () => Task.Run(() => RetrieveMod(mod.Id)).Result); + return await Get(mod.Id); } - public static IReadOnlyList Get(Dependency dependency) + public static async Task> Get(Dependency dependency) { - return ModDependenciesCache.GetOrAdd(dependency.ModId, () => Task.Run(() => RetrieveMod(dependency.ModId)).Result); + return await Get(dependency.ModId); } private static async Task> RetrieveMod(uint modId) diff --git a/ModManager/ModIoSystem/ModIoModFilesRegistry.cs b/ModManager/ModIoSystem/ModIoModFilesRegistry.cs index 784c661..0338510 100644 --- a/ModManager/ModIoSystem/ModIoModFilesRegistry.cs +++ b/ModManager/ModIoSystem/ModIoModFilesRegistry.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Modio.Filters; @@ -9,36 +11,25 @@ namespace ModManager.ModIoSystem { public abstract class ModIoModFilesRegistry { - private static readonly Dictionary> ModIoModFiles = new(); + private static readonly ConcurrentDictionary>>> ModIoModFiles = new(); - public static IEnumerable Get(uint modId) + public static async Task> Get(uint modId) { - lock (ModIoModFiles) + var lazy = ModIoModFiles.GetOrAdd(modId, () => new Lazy>>(() => RetrieveFiles(modId))); + try { - return ModIoModFiles.GetOrAdd(modId, () => Task.Run(() => RetrieveFiles(modId)).Result); + return await lazy.Value; } - } - - public static Task> GetAsync(uint modId) - { - lock (ModIoModFiles) + catch { - if (ModIoModFiles.TryGetValue(modId, out var files)) - return Task.FromResult(files); - ModIoModFiles.Add(modId, Task.Run(() => RetrieveFiles(modId)).Result); - return Task.FromResult(ModIoModFiles[modId]); + ModIoModFiles.TryUpdate(modId, new Lazy>>(() => RetrieveFiles(modId)), lazy); + throw; } } - - public static Task> GetDescAsync(uint modId) + + public static async Task> GetDesc(uint modId) { - lock (ModIoModFiles) - { - if (ModIoModFiles.TryGetValue(modId, out var files)) - return Task.FromResult>(files.OrderByDescending(file => file.Id).ToList().AsReadOnly()); - ModIoModFiles.Add(modId, Task.Run(() => RetrieveFiles(modId)).Result); - return Task.FromResult>(ModIoModFiles[modId].OrderByDescending(file => file.Id).ToList().AsReadOnly()); - } + return (await Get(modId)).OrderByDescending(file => file.Id).ToList().AsReadOnly(); } private static async Task> RetrieveFiles(uint modId) diff --git a/ModManager/ModIoSystem/ModIoModRegistry.cs b/ModManager/ModIoSystem/ModIoModRegistry.cs index 49c78c6..1de69f6 100644 --- a/ModManager/ModIoSystem/ModIoModRegistry.cs +++ b/ModManager/ModIoSystem/ModIoModRegistry.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Concurrent; using System.Threading.Tasks; using Modio.Models; using Timberborn.Common; @@ -7,16 +8,25 @@ namespace ModManager.ModIoSystem { public abstract class ModIoModRegistry { - private static readonly Dictionary ModCache = new(); + private static readonly ConcurrentDictionary>> ModCache = new(); - public static Mod Get(uint modId) + public static async Task Get(uint modId) { - return ModCache.GetOrAdd(modId, () => Task.Run(() => RetrieveMod(modId)).Result); + var lazy = ModCache.GetOrAdd(modId, () => new Lazy>(() => RetrieveMod(modId))); + try + { + return await lazy.Value; + } + catch + { + ModCache.TryUpdate(modId, new Lazy>(() => RetrieveMod(modId)), lazy); + throw; + } } - public static Mod Get(Dependency dependency) + public static async Task Get(Dependency dependency) { - return ModCache.GetOrAdd(dependency.ModId, () => Task.Run(() => RetrieveMod(dependency.ModId)).Result); + return await Get(dependency.ModId); } private static async Task RetrieveMod(uint modId) diff --git a/ModManager/ModManager.csproj b/ModManager/ModManager.csproj index c1819d3..a61f6b8 100644 --- a/ModManager/ModManager.csproj +++ b/ModManager/ModManager.csproj @@ -7,19 +7,24 @@ MODMANAGER_VERSION + + embedded + + - false - - none + true + + true - - + - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -27,22 +32,41 @@ libs\Modio.dll libs/ + + libs\ProgressStream.dll + libs/ + - - - $(SolutionDir)Timberborn\TimberAPI - + + + + + libs/ + + + libs/ + + + libs/ + + + libs/ + + + libs/ + + - - $(SolutionDir)Timberborn\BepInEx\plugins\$(SolutionName) + + $(USERPROFILE)\Documents\Timberborn\Mods\$(SolutionName)\version-1.0.6 + $(registry:HKEY_CURRENT_USER\Software\Valve\Steam@SteamPath)\steamapps\common\Timberborn\ - - - - - - + + + + + \ No newline at end of file diff --git a/ModManager/ModManagerSystem/ModManagerExtractor.cs b/ModManager/ModManagerSystem/ModManagerExtractor.cs index da6bdae..a239ef8 100644 --- a/ModManager/ModManagerSystem/ModManagerExtractor.cs +++ b/ModManager/ModManagerSystem/ModManagerExtractor.cs @@ -5,16 +5,21 @@ using System.IO; using System.IO.Compression; using System.Linq; -using System.Reflection; +using ModManager.StartupSystem; namespace ModManager.ModManagerSystem { - public class ModManagerExtractor : IAddonExtractor + public class ModManagerExtractor : Singleton, IAddonExtractor, ILoadable { - private string _modManagerFolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + private string? _modManagerFolderPath; private const string _modManagerPackageName = "Mod Manager"; private List _foldersToIgnore = new() { "temp" }; - + + public void Load(ModManagerStartupOptions startupOptions) + { + _modManagerFolderPath = startupOptions.ModManagerPath; + } + public bool Extract(string addonZipLocation, Mod modInfo, out string extractLocation, bool overWrite = true) { extractLocation = ""; @@ -22,8 +27,8 @@ public bool Extract(string addonZipLocation, Mod modInfo, out string extractLoca { return false; } - ClearOldModFiles(_modManagerFolderPath); - extractLocation = _modManagerFolderPath; + ClearOldModFiles(_modManagerFolderPath!); + extractLocation = _modManagerFolderPath!; ZipFile.ExtractToDirectory(addonZipLocation, Paths.Mods, overWrite); System.IO.File.Delete(addonZipLocation); @@ -65,17 +70,17 @@ private void DeleteFilesFromFolder(DirectoryInfo dir) } file.Delete(); } - catch (UnauthorizedAccessException ex) + catch (UnauthorizedAccessException) { file.MoveTo($"{file.FullName}{Names.Extensions.Remove}"); } - catch (IOException ex) + catch (IOException) { try { file.MoveTo($"{file.FullName}{Names.Extensions.Remove}"); } - catch(IOException ex2) + catch(IOException) { throw; } diff --git a/ModManager/ModManagerSystem/ModManagerRegisterer.cs b/ModManager/ModManagerSystem/ModManagerRegisterer.cs deleted file mode 100644 index bc76854..0000000 --- a/ModManager/ModManagerSystem/ModManagerRegisterer.cs +++ /dev/null @@ -1,15 +0,0 @@ -using ModManager.ExtractorSystem; -using ModManager.StartupSystem; - -namespace ModManager.ModManagerSystem -{ - public class ModManagerRegisterer : Singleton, ILoadable - { - public const string RegistryId = "ModManager"; - - public void Load(ModManagerStartupOptions startupOptions) - { - AddonExtractorRegistry.Instance.Add(RegistryId, new ModManagerExtractor()); - } - } -} diff --git a/ModManager/ModSystem/ModEnabler.cs b/ModManager/ModSystem/ModEnabler.cs deleted file mode 100644 index a871b4b..0000000 --- a/ModManager/ModSystem/ModEnabler.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.IO; -using System.Linq; -using ModManager.AddonEnableSystem; -using ModManager.AddonSystem; - -namespace ModManager.ModSystem -{ - public class ModEnabler : IAddonEnabler - { - public bool Enable(Manifest manifest) - { - string[] disabledFilePaths = Directory.GetFiles(manifest.RootPath, "*" + Names.Extensions.Disabled, SearchOption.AllDirectories); - - foreach (var filePath in disabledFilePaths) - { - var enabledFilePath = filePath.Remove(filePath.Length - Names.Extensions.Disabled.Length, Names.Extensions.Disabled.Length); - - File.Move(filePath, enabledFilePath); - } - - manifest.Enabled = true; - - return true; - } - - public bool Disable(Manifest manifest) - { - string[] filePaths = Directory.GetFiles(manifest.RootPath, "*", SearchOption.AllDirectories); - - var filePathsWithoutExcludedExtensions = filePaths.Where(filePath => ! AddonEnablerService.IgnoreExtensions.Contains(Path.GetExtension(filePath))).ToArray(); - - foreach (var filePath in filePathsWithoutExcludedExtensions) - { - File.Move(filePath, filePath + Names.Extensions.Disabled); - } - - manifest.Enabled = false; - - return true; - } - } -} \ No newline at end of file diff --git a/ModManager/ModSystem/ModExtractor.cs b/ModManager/ModSystem/ModExtractor.cs index 860e58d..5d73f32 100644 --- a/ModManager/ModSystem/ModExtractor.cs +++ b/ModManager/ModSystem/ModExtractor.cs @@ -5,6 +5,8 @@ using System.IO; using System.IO.Compression; using System.Linq; +using ModManager.AddonSystem; +using File = System.IO.File; namespace ModManager.ModSystem { @@ -16,15 +18,15 @@ public bool Extract(string addonZipLocation, Mod modInfo, out string extractLoca { extractLocation = ""; if (!modInfo.Tags.Any(x => x.Name == "Mod")) - { return false; - } - var modFolderName = $"{modInfo.NameId}_{modInfo.Id}_{modInfo.Modfile.Version}"; + + var modFolderName = $"{modInfo.NameId}_{modInfo.Id}_{modInfo.Modfile?.Version}"; ClearOldModFiles(modInfo, modFolderName); extractLocation = Path.Combine(Paths.Mods, modFolderName); - ZipFile.ExtractToDirectory(addonZipLocation, extractLocation, overWrite); - System.IO.File.Delete(addonZipLocation); - + if (!Directory.Exists(extractLocation)) + Directory.CreateDirectory(extractLocation); + ExtractZipWithoutCommonRoot(addonZipLocation, extractLocation); + File.Delete(addonZipLocation); return true; } @@ -32,35 +34,40 @@ private void ClearOldModFiles(Mod modInfo, string modFolderName) { if (TryGetExistingModFolder(modInfo, out var dirs)) { - var dirInfo = new DirectoryInfo(dirs); - if (dirInfo.Name.Equals(modFolderName)) + var directoryInfo = new DirectoryInfo(dirs); + if (directoryInfo.Name.Equals(modFolderName)) { return; } - dirInfo.MoveTo(Path.Combine(Paths.Mods, modFolderName)); + + directoryInfo.MoveTo(Path.Combine(Paths.Mods, modFolderName)); DeleteModFiles(modFolderName); } } - private bool TryGetExistingModFolder(Mod modInfo, out string dirs) + + private bool TryGetExistingModFolder(Mod modInfo, out string? directoryPath) { - dirs = null; + directoryPath = null; try { - dirs = Directory.GetDirectories(Paths.Mods, $"{modInfo.NameId}_{modInfo.Id}*").SingleOrDefault(); + directoryPath ??= Directory.GetDirectories(Paths.Mods, $"{modInfo.NameId}_{modInfo.Id}*").SingleOrDefault(); + + if (InstalledAddonRepository.Instance.TryGet(modInfo.Id, out var modManagerManifest)) + directoryPath ??= modManagerManifest.RootPath; } - catch (InvalidOperationException ex) + catch (InvalidOperationException) { throw new AddonExtractorException($"Found multiple folders for \"{modInfo.Name}\""); } - if (dirs != null) + if (directoryPath != null) { return true; } return false; } - + private void DeleteModFiles(string modFolderName) { var modDirInfo = new DirectoryInfo(Path.Combine(Paths.Mods, modFolderName)); @@ -85,7 +92,7 @@ private void DeleteFilesFromFolder(DirectoryInfo dir) { file.Delete(); } - catch (UnauthorizedAccessException ex) + catch (UnauthorizedAccessException) { file.MoveTo($"{file.FullName}{Names.Extensions.Remove}"); } @@ -103,5 +110,57 @@ private void TryDeleteFolder(DirectoryInfo dir) dir.Delete(); } } + + private static void ExtractZipWithoutCommonRoot(string zipFilePath, string extractPath) + { + using var archive = ZipFile.OpenRead(zipFilePath); + + var allPaths = archive.Entries + .Where(e => !string.IsNullOrEmpty(e.Name)) + .Select(e => e.FullName) + .ToList(); + + var commonRoot = GetCommonRoot(allPaths); + + foreach (var entry in archive.Entries) + { + if (string.IsNullOrEmpty(entry.Name)) + continue; + + var relativePath = entry.FullName.StartsWith(commonRoot) + ? entry.FullName.Substring(commonRoot.Length).TrimStart('/') + : entry.FullName; + + var destinationFilePath = Path.Combine(extractPath, relativePath); + + Directory.CreateDirectory(Path.GetDirectoryName(destinationFilePath)); + + entry.ExtractToFile(destinationFilePath, overwrite: true); + } + } + + private static string GetCommonRoot(IReadOnlyCollection paths) + { + if (!paths.Any()) return ""; + + var splitPaths = paths.Select(path => path.Split('/')).ToList(); + var minLength = splitPaths.Min(splitPath => splitPath.Length); + + var commonRoot = ""; + for (var i = 0; i < minLength; i++) + { + var segment = splitPaths[0][i]; + if (splitPaths.All(p => p[i] == segment)) + { + commonRoot = commonRoot == "" ? segment : $"{commonRoot}/{segment}"; + } + else + { + break; + } + } + + return commonRoot + "/"; + } } -} +} \ No newline at end of file diff --git a/ModManager/ModSystem/ModInstaller.cs b/ModManager/ModSystem/ModInstaller.cs index 14de6ba..9229e18 100644 --- a/ModManager/ModSystem/ModInstaller.cs +++ b/ModManager/ModSystem/ModInstaller.cs @@ -1,41 +1,48 @@ using System; using System.IO; using System.Linq; -using Modio.Models; using ModManager.AddonInstallerSystem; using ModManager.AddonSystem; using ModManager.ExtractorSystem; using ModManager.MapSystem; using ModManager.PersistenceSystem; +using ModManager.PlayerPrefsSystem; +using Mod = Modio.Models.Mod; namespace ModManager.ModSystem { public class ModInstaller : IAddonInstaller { - private readonly InstalledAddonRepository _installedAddonRepository = InstalledAddonRepository.Instance; - private readonly AddonExtractorService _addonExtractorService = AddonExtractorService.Instance; + private readonly InstalledAddonRepository _installedAddonRepository; + private readonly AddonExtractorService _addonExtractorService; + private readonly PersistenceService _persistenceService = PersistenceService.Instance; + public ModInstaller(InstalledAddonRepository installedAddonRepository, AddonExtractorService addonExtractorService) + { + _installedAddonRepository = installedAddonRepository; + _addonExtractorService = addonExtractorService; + } + public bool Install(Mod mod, string zipLocation) { if (!mod.Tags.Any(x => x.Name == "Mod")) return false; var installLocation = _addonExtractorService.Extract(mod, zipLocation); - var manifest = new Manifest(mod, mod.Modfile!, installLocation); - var modManifestPath = Path.Combine(installLocation, Manifest.FileName); + var manifest = new ModManagerManifest(installLocation, mod); + var modManifestPath = Path.Combine(installLocation, ModManagerManifest.FileName); _persistenceService.SaveObject(manifest, modManifestPath); _installedAddonRepository.Add(manifest); - return true; } - public bool Uninstall(Manifest manifest) + public bool Uninstall(ModManagerManifest modManagerManifest) { - if (manifest is not Manifest && manifest is MapManifest) + if (modManagerManifest is not ModManagerManifest && modManagerManifest is MapModManagerManifest) return false; - _installedAddonRepository.Remove(manifest.ModId); + _installedAddonRepository.Remove(modManagerManifest.ResourceId); - var modDirInfo = new DirectoryInfo(Path.Combine(manifest.RootPath)); + var modDirInfo = new DirectoryInfo(Path.Combine(modManagerManifest.RootPath)); var modSubFolders = modDirInfo.GetDirectories("*", SearchOption.AllDirectories); foreach (var subDirectory in modSubFolders.Reverse()) { @@ -48,51 +55,52 @@ public bool Uninstall(Manifest manifest) return true; } - public bool ChangeVersion(Mod mod, Modio.Models.File file, string zipLocation) + public bool ChangeVersion(Mod mod, string zipLocation) { if (!mod.Tags.Any(x => x.Name == "Mod")) return false; - mod.Modfile= file; + var playerPrefs = PlayerPrefsHelper.GetPlayerPrefs(mod.Id); var installLocation = _addonExtractorService.Extract(mod, zipLocation); - var manifest = new Manifest(mod, mod.Modfile, installLocation); - var modManifestPath = Path.Combine(installLocation, Manifest.FileName); + var manifest = new ModManagerManifest(installLocation, mod); + var modManifestPath = Path.Combine(installLocation, ModManagerManifest.FileName); _persistenceService.SaveObject(manifest, modManifestPath); _installedAddonRepository.Remove(mod.Id); _installedAddonRepository.Add(manifest); + PlayerPrefsHelper.RestorePlayerPrefs(manifest, playerPrefs); return true; } - private void DeleteFilesFromFolder(DirectoryInfo dir) + private void DeleteFilesFromFolder(DirectoryInfo directoryInfo) { - foreach (var file in dir.GetFiles()) + foreach (var file in directoryInfo.GetFiles()) { try { file.Delete(); } - catch(UnauthorizedAccessException ex) + catch (UnauthorizedAccessException) { file.MoveTo($"{file.FullName}{Names.Extensions.Remove}"); } - catch(Exception ex) + catch (Exception ex) { throw ex; } } } - private void TryDeleteFolder(DirectoryInfo dir) + private void TryDeleteFolder(DirectoryInfo directoryInfo) { - if (dir.EnumerateDirectories().Any() == false && dir.EnumerateFiles().Any() == false) + if (directoryInfo.EnumerateDirectories().Any() == false && directoryInfo.EnumerateFiles().Any() == false) { - dir.Delete(); + directoryInfo.Delete(); } else { - dir.MoveTo($"{dir.FullName}{Names.Extensions.Remove}"); + directoryInfo.MoveTo($"{directoryInfo.FullName}{Names.Extensions.Remove}"); } } } diff --git a/ModManager/ModSystem/ModManifestFinder.cs b/ModManager/ModSystem/ModManifestFinder.cs index 2f56bfa..9d44234 100644 --- a/ModManager/ModSystem/ModManifestFinder.cs +++ b/ModManager/ModSystem/ModManifestFinder.cs @@ -2,77 +2,70 @@ using System.Collections.Generic; using System.IO; using ModManager.AddonSystem; -using ModManager.LoggingSystem; using ModManager.ManifestLocationFinderSystem; using ModManager.PersistenceSystem; using Newtonsoft.Json; +using UnityEngine; namespace ModManager.ModSystem { public class ModManifestFinder : IManifestLocationFinder { - private readonly PersistenceService _persistenceService; + private readonly PersistenceService _persistenceService = PersistenceService.Instance; - private IModManagerLogger _logger; - - public ModManifestFinder(IModManagerLogger logger) - { - _persistenceService = PersistenceService.Instance; - _logger = logger; - } - - public IEnumerable Find() + public IEnumerable Find() { - - foreach (var enabledManifest in Directory.GetFiles(Paths.Mods, Manifest.FileName, SearchOption.AllDirectories)) + foreach (var directory in Directory.GetDirectories(Paths.Mods, "*")) { - var manifest = LoadManifest(enabledManifest); - if (manifest == null) - { - continue; - } - yield return manifest; + foreach (var enabledManifest in Directory.GetFiles(directory, ModManagerManifest.FileName)) + { + var manifest = LoadManifest(enabledManifest); + if (manifest == null) + { + continue; + } + yield return manifest; - } + } - foreach (var disabledManifest in Directory.GetFiles(Paths.Mods, Manifest.FileName + Names.Extensions.Disabled, SearchOption.AllDirectories)) - { - var manifest = LoadManifest(disabledManifest); - if (manifest == null) + foreach (var disabledManifest in Directory.GetFiles(directory, ModManagerManifest.FileName + Names.Extensions.Disabled)) { - continue; + var manifest = LoadManifest(disabledManifest); + if (manifest == null) + { + continue; + } + yield return manifest; } - yield return manifest; - } - foreach (var enabledManifest in Directory.GetFiles(Paths.Mods, Manifest.FileName + Names.Extensions.Remove, SearchOption.AllDirectories)) - { - var manifest = LoadManifest(enabledManifest); - if (manifest == null) + foreach (var enabledManifest in Directory.GetFiles(directory, ModManagerManifest.FileName + Names.Extensions.Remove)) { - continue; + var manifest = LoadManifest(enabledManifest); + if (manifest == null) + { + continue; + } + yield return manifest; } - yield return manifest; } } - public IEnumerable FindRemovable() + public IEnumerable FindRemovable() { - return new List(); + return new List(); } - private Manifest? LoadManifest(string manifestPath) + private ModManagerManifest? LoadManifest(string manifestPath) { try { - var manifest = _persistenceService.LoadObject(manifestPath, false); - manifest.Enabled = !Path.GetExtension(manifestPath).Equals(Names.Extensions.Disabled); + var manifest = _persistenceService.LoadObject(manifestPath, false); manifest.RootPath = Path.GetDirectoryName(manifestPath)!; return manifest; } - catch (JsonSerializationException ex) + catch (JsonSerializationException) { - _logger.LogWarning($"Failed to serialize JSON in file {manifestPath} It is advised to delete the file."); + Debug.LogWarning($"Failed to serialize JSON in file {manifestPath} It is advised to delete the file."); return null; } catch (Exception ex) diff --git a/ModManager/ModSystem/ModRegisterer.cs b/ModManager/ModSystem/ModRegisterer.cs deleted file mode 100644 index e18b57d..0000000 --- a/ModManager/ModSystem/ModRegisterer.cs +++ /dev/null @@ -1,21 +0,0 @@ -using ModManager.AddonEnableSystem; -using ModManager.AddonInstallerSystem; -using ModManager.ExtractorSystem; -using ModManager.ManifestLocationFinderSystem; -using ModManager.StartupSystem; - -namespace ModManager.ModSystem -{ - public class ModRegisterer : Singleton, ILoadable - { - public const string RegistryId = "Mod"; - - public void Load(ModManagerStartupOptions startupOptions) - { - AddonInstallerRegistry.Instance.Add(RegistryId, new ModInstaller()); - AddonEnablerRegistry.Instance.Add(RegistryId, new ModEnabler()); - ManifestLocationFinderRegistry.Instance.Add(RegistryId, new ModManifestFinder(startupOptions.Logger)); - AddonExtractorRegistry.Instance.Add(RegistryId, new ModExtractor()); - } - } -} \ No newline at end of file diff --git a/ModManager/Names.cs b/ModManager/Names.cs index 616485f..dd5036b 100644 --- a/ModManager/Names.cs +++ b/ModManager/Names.cs @@ -9,8 +9,6 @@ public class Extensions public const string Remove = ".remove"; public const string TimberbornMap = ".timber"; - - public const string Hidden = ".hidden"; } } } \ No newline at end of file diff --git a/ModManager/Paths.cs b/ModManager/Paths.cs index e241dc6..e41234c 100644 --- a/ModManager/Paths.cs +++ b/ModManager/Paths.cs @@ -1,7 +1,6 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; +using System.IO; using ModManager.StartupSystem; +using Timberborn.PlatformUtilities; namespace ModManager { @@ -14,9 +13,7 @@ public void Load(ModManagerStartupOptions startupOptions) Mods = startupOptions.ModInstallationPath; EnsurePathExists(Mods); - EnsurePathExists(ModManager.Data); EnsurePathExists(ModManager.Temp); - EnsurePathExists(ModManager.User); } private static void EnsurePathExists(string path) @@ -33,15 +30,11 @@ private static void EnsurePathExists(string path) public static string Mods { get; set; } = null!; - public static readonly string Maps = Path.Combine(RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Documents", "Timberborn") : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Timberborn"), "Maps"); + public static readonly string Maps = Path.Combine(UserDataFolder.Folder, "Maps"); public static class ModManager { - public static string Data { get; set; } = Path.Combine(ModManagerRoot, "data"); - - public static string User { get; set; } = Path.Combine(ModManagerRoot, "user"); - - public static string Temp { get; set; } = Path.Combine(ModManagerRoot, "temp"); + public static string Temp { get; set; } = Path.GetTempPath(); } } } \ No newline at end of file diff --git a/ModManager/PlayerPrefsSystem/PlayerModPrefs.cs b/ModManager/PlayerPrefsSystem/PlayerModPrefs.cs new file mode 100644 index 0000000..c471799 --- /dev/null +++ b/ModManager/PlayerPrefsSystem/PlayerModPrefs.cs @@ -0,0 +1,10 @@ +namespace ModManager.PlayerPrefsSystem +{ + public record ModPlayerPrefs + { + internal string? EnabledKey; + internal int Enabled; + internal string? PriorityKey; + internal int Priority; + } +} \ No newline at end of file diff --git a/ModManager/PlayerPrefsSystem/PlayerPrefsHelper.cs b/ModManager/PlayerPrefsSystem/PlayerPrefsHelper.cs new file mode 100644 index 0000000..6ce64a7 --- /dev/null +++ b/ModManager/PlayerPrefsSystem/PlayerPrefsHelper.cs @@ -0,0 +1,111 @@ +using System.IO; +using ModManager.AddonSystem; +using ModManager.StaticInstanceSystem; +using Timberborn.Modding; +using Timberborn.Versioning; +using UnityEngine; +using Mod = Modio.Models.Mod; +using TimberbornMod = Timberborn.Modding.Mod; + +namespace ModManager.PlayerPrefsSystem +{ + public static class PlayerPrefsHelper + { + private static bool TryLoadMod(ModManagerManifest modManagerManifest, out TimberbornMod? timberbornMod) + { + if (modManagerManifest.RootPath == Paths.Maps) + { + timberbornMod = null; + return false; + } + var modDirectory = new ModDirectory(new DirectoryInfo(modManagerManifest.RootPath), true, "Local", GameVersions.CurrentVersion, false); + if (ModRepository.TryGetModDirectory(modDirectory, out var versionedModDirectory)) + { + modDirectory = versionedModDirectory; + } + return StaticInstanceLoader.ModLoader.TryLoadMod(modDirectory, out timberbornMod); + } + + public static bool IsEnabled(ModManagerManifest modManagerManifest) + { + return TryLoadMod(modManagerManifest, out var timberbornMod) && ModPlayerPrefsHelper.IsModEnabled(timberbornMod); + } + + public static bool IsEnabled(Mod mod) + { + if (!InstalledAddonRepository.Instance.TryGet(mod.Id, out var modManagerManifest)) + return false; + + return IsEnabled(modManagerManifest); + } + + public static bool TrySetEnabled(uint modId, bool enabled) + { + if (!InstalledAddonRepository.Instance.TryGet(modId, out var modManagerManifest)) + return false; + if (!TryLoadMod(modManagerManifest, out var timberbornMod)) + return false; + + ModPlayerPrefsHelper.ToggleMod(enabled, timberbornMod); + return true; + } + + public static bool CanBeEnabledOrDisabled(ModManagerManifest modManagerManifest) + { + if (modManagerManifest.RootPath == Paths.Maps) + return false; + + return TryLoadMod(modManagerManifest, out _); + } + + public static bool CanBeEnabledOrDisabled(Mod mod) + { + if (!InstalledAddonRepository.Instance.TryGet(mod.Id, out var modManagerManifest)) + return false; + + return CanBeEnabledOrDisabled(modManagerManifest); + } + + public static ModPlayerPrefs? GetPlayerPrefs(uint modId) + { + if (!InstalledAddonRepository.Instance.TryGet(modId, out var modManagerManifest)) + return null; + if (!TryLoadMod(modManagerManifest, out var timberbornMod)) + return null; + var modPrefs = new ModPlayerPrefs(); + string modEnabledKey = ModPlayerPrefsHelper.GetModEnabledKey(timberbornMod); + if (PlayerPrefs.HasKey(modEnabledKey)) + { + modPrefs.EnabledKey = modEnabledKey; + modPrefs.Enabled = PlayerPrefs.GetInt(modEnabledKey); + } + string modPriorityKey = ModPlayerPrefsHelper.GetModPriorityKey(timberbornMod); + if (PlayerPrefs.HasKey(modPriorityKey)) + { + modPrefs.PriorityKey = modPriorityKey; + modPrefs.Priority = PlayerPrefs.GetInt(modPriorityKey); + } + return modPrefs; + } + + public static void RestorePlayerPrefs(ModManagerManifest modManagerManifest, ModPlayerPrefs? previousPrefs) + { + if (previousPrefs == null) + return; + if (!TryLoadMod(modManagerManifest, out var timberbornMod)) + return; + string modEnabledKey = ModPlayerPrefsHelper.GetModEnabledKey(timberbornMod); + if (previousPrefs.EnabledKey != null && previousPrefs.EnabledKey != modEnabledKey) + { + PlayerPrefs.SetInt(modEnabledKey, previousPrefs.Enabled); + PlayerPrefs.DeleteKey(previousPrefs.EnabledKey); + } + string modPriorityKey = ModPlayerPrefsHelper.GetModPriorityKey(timberbornMod); + if (previousPrefs.PriorityKey != null && previousPrefs.PriorityKey != modPriorityKey) + { + PlayerPrefs.SetInt(modPriorityKey, previousPrefs.Priority); + PlayerPrefs.DeleteKey(previousPrefs.PriorityKey); + } + } + } +} \ No newline at end of file diff --git a/ModManager/StartupSystem/ModManagerConfigurator.cs b/ModManager/StartupSystem/ModManagerConfigurator.cs new file mode 100644 index 0000000..9f1e097 --- /dev/null +++ b/ModManager/StartupSystem/ModManagerConfigurator.cs @@ -0,0 +1,38 @@ +using Bindito.Core; +using ModManager.AddonInstallerSystem; +using ModManager.AddonSystem; +using ModManager.ExtractorSystem; +using ModManager.ManifestLocationFinderSystem; +using ModManager.MapSystem; +using ModManager.ModManagerSystem; +using ModManager.ModSystem; + +namespace ModManager.StartupSystem +{ + [Context("MainMenu")] + public class ModManagerConfigurator : IConfigurator + { + public void Configure(IContainerDefinition containerDefinition) + { + containerDefinition.Bind().AsSingleton(); + + containerDefinition.Bind().AsSingleton(); + containerDefinition.Bind().AsSingleton(); + containerDefinition.Bind().AsSingleton(); + containerDefinition.Bind().AsSingleton(); + + containerDefinition.MultiBind().To().AsSingleton(); + containerDefinition.MultiBind().To().AsSingleton(); + containerDefinition.MultiBind().To().AsSingleton(); + + containerDefinition.MultiBind().To().AsSingleton(); + containerDefinition.MultiBind().To().AsSingleton(); + containerDefinition.MultiBind().To().AsSingleton(); + + containerDefinition.MultiBind().To().AsSingleton(); + + containerDefinition.Bind().AsSingleton(); + containerDefinition.Bind().AsSingleton(); + } + } +} \ No newline at end of file diff --git a/ModManager/StartupSystem/ModManagerStartup.cs b/ModManager/StartupSystem/ModManagerStartup.cs index 47e9400..6097d11 100644 --- a/ModManager/StartupSystem/ModManagerStartup.cs +++ b/ModManager/StartupSystem/ModManagerStartup.cs @@ -1,11 +1,7 @@ using System; using System.Collections.Generic; -using ModManager.AddonSystem; -using ModManager.BepInExSystem; -using ModManager.MapSystem; using ModManager.ModIoSystem; using ModManager.ModManagerSystem; -using ModManager.ModSystem; namespace ModManager.StartupSystem { @@ -17,13 +13,8 @@ public class ModManagerStartup : Singleton { Paths.Instance, ModIoGameInfo.Instance, - ModRegisterer.Instance, - MapRegisterer.Instance, - BepInExRegisterer.Instance, - ModManagerRegisterer.Instance, - - InstalledAddonRepository.Instance, - RemoveFilesOnStartup.Instance + + ModManagerExtractor.Instance }; public static void Run(string apiKey, Action options) @@ -32,7 +23,7 @@ public static void Run(string apiKey, Action options) options(modManagerOptions); - ModIo.InitializeClient(apiKey); + ModIo.InitializeClient(apiKey, modManagerOptions.GameId); IsLoaded = true; diff --git a/ModManager/StartupSystem/ModManagerStartupOptions.cs b/ModManager/StartupSystem/ModManagerStartupOptions.cs index 04d512b..6709616 100644 --- a/ModManager/StartupSystem/ModManagerStartupOptions.cs +++ b/ModManager/StartupSystem/ModManagerStartupOptions.cs @@ -1,6 +1,4 @@ -using ModManager.LoggingSystem; - -namespace ModManager.StartupSystem +namespace ModManager.StartupSystem { public class ModManagerStartupOptions { @@ -15,7 +13,5 @@ public class ModManagerStartupOptions public string GamePath { get; set; } = null!; public string ModManagerPath { get; set; } = null!; - - public IModManagerLogger Logger { get; set; } = null!; } } \ No newline at end of file diff --git a/ModManager/StartupSystem/RemoveFilesOnStartup.cs b/ModManager/StartupSystem/RemoveFilesOnStartup.cs index c1d97fc..73721cd 100644 --- a/ModManager/StartupSystem/RemoveFilesOnStartup.cs +++ b/ModManager/StartupSystem/RemoveFilesOnStartup.cs @@ -1,19 +1,25 @@ using System.IO; using ModManager.AddonSystem; using ModManager.PersistenceSystem; +using Timberborn.SingletonSystem; namespace ModManager.StartupSystem { - public class RemoveFilesOnStartup : Singleton, ILoadable + public class RemoveFilesOnStartup : ILoadableSingleton { - private readonly InstalledAddonRepository _addonRepository = InstalledAddonRepository.Instance; + private readonly InstalledAddonRepository _addonRepository; private readonly PathRemovalService _removalService = PathRemovalService.Instance; - public void Load(ModManagerStartupOptions startupOptions) + public RemoveFilesOnStartup(InstalledAddonRepository addonRepository) { - DeleteRemoveTaggedFiles(Paths.GameRoot); - DeleteRemoveTaggedDirectories(Paths.GameRoot); + _addonRepository = addonRepository; + } + + public void Load() + { + // DeleteRemoveTaggedFiles(Paths.GameRoot); + // DeleteRemoveTaggedDirectories(Paths.GameRoot); foreach (var manifest in _addonRepository.All()) { diff --git a/ModManager/StaticInstanceSystem/BootstrapperModManagerConfigurator.cs b/ModManager/StaticInstanceSystem/BootstrapperModManagerConfigurator.cs new file mode 100644 index 0000000..34b713a --- /dev/null +++ b/ModManager/StaticInstanceSystem/BootstrapperModManagerConfigurator.cs @@ -0,0 +1,13 @@ +using Bindito.Core; + +namespace ModManager.StaticInstanceSystem +{ + [Context("Bootstrapper")] + public class BootstrapperModManagerConfigurator : Configurator + { + protected override void Configure() + { + Bind().AsSingleton().AsExported(); + } + } +} \ No newline at end of file diff --git a/ModManager/StaticInstanceSystem/StaticInstanceLoader.cs b/ModManager/StaticInstanceSystem/StaticInstanceLoader.cs new file mode 100644 index 0000000..a3dffdd --- /dev/null +++ b/ModManager/StaticInstanceSystem/StaticInstanceLoader.cs @@ -0,0 +1,14 @@ +using Timberborn.Modding; + +namespace ModManager.StaticInstanceSystem +{ + public class StaticInstanceLoader + { + public StaticInstanceLoader(ModLoader modLoader) + { + ModLoader = modLoader; + } + + public static ModLoader ModLoader { get; set; } = null!; + } +} \ No newline at end of file diff --git a/ModManager/VersionSystem/VersionComparer.cs b/ModManager/VersionSystem/VersionComparer.cs index 4ecd55f..24cf862 100644 --- a/ModManager/VersionSystem/VersionComparer.cs +++ b/ModManager/VersionSystem/VersionComparer.cs @@ -1,19 +1,19 @@ using System.Linq; +using System.Text.RegularExpressions; namespace ModManager.VersionSystem { public static class VersionComparer { + private static readonly Regex digits = new("\\d+"); + public static bool IsVersionHigher(string? version1, string? version2) { if (string.IsNullOrEmpty(version1)) { return false; } if (string.IsNullOrEmpty(version2)) { return true; } - version1 = version1.Replace(" ", ""); - version2 = version2.Replace(" ", ""); - - var version1Parts = version1.Split('.'); - var version2Parts = version2.Split('.'); + var version1Parts = digits.Matches(version1).Select(m => m.Value).ToList(); + var version2Parts = digits.Matches(version2).Select(m => m.Value).ToList(); for (var i = 0; i < version1Parts.Count(); i++) { @@ -42,8 +42,8 @@ public static bool IsSameVersion(string? version1, string? version2) if (version1 == null || version2 == null) return false; - version1 = version1.Replace(" ", ""); - version2 = version2.Replace(" ", ""); + version1 = version1.Trim(); + version2 = version2.Trim(); return version1 == version2; } diff --git a/ModManager/VersionSystem/VersionStatusService.cs b/ModManager/VersionSystem/VersionStatusService.cs index 6db59df..09bdfac 100644 --- a/ModManager/VersionSystem/VersionStatusService.cs +++ b/ModManager/VersionSystem/VersionStatusService.cs @@ -1,9 +1,7 @@ using System.Collections.Generic; using System.Linq; using Modio.Models; -using ModManager.ModIoSystem; using Timberborn.Common; -using UnityEngine; namespace ModManager.VersionSystem { @@ -21,18 +19,6 @@ public static VersionStatus GetVersionStatus(File? file) return VersionStatusCache.GetOrAdd(file.Id, () => FindVersionStatus(file)); } - public static VersionStatus GetVersionStatus(uint modId, string? version) - { - if (string.IsNullOrEmpty(version)) - return VersionStatus.Unknown; - var file = ModIoModFilesRegistry.Get(modId).FirstOrDefault(file => file.Version == version); - if (file == null) - return VersionStatus.Unknown; - if (VersionStatusCache.TryGetValue(file.Id, out var versionStatus)) - return versionStatus; - return VersionStatusCache.GetOrAdd(file.Id, () => FindVersionStatus(file)); - } - private static VersionStatus FindVersionStatus(File file) { var gameVersion = GameVersionGetter.Get(); diff --git a/ModManager/libs/Microsoft.Bcl.AsyncInterfaces.dll b/ModManager/libs/Microsoft.Bcl.AsyncInterfaces.dll deleted file mode 100644 index be25bdb..0000000 Binary files a/ModManager/libs/Microsoft.Bcl.AsyncInterfaces.dll and /dev/null differ diff --git a/ModManager/libs/Modio.dll b/ModManager/libs/Modio.dll index a13a756..3e2076e 100644 Binary files a/ModManager/libs/Modio.dll and b/ModManager/libs/Modio.dll differ diff --git a/ModManager/libs/ProgressStream.dll b/ModManager/libs/ProgressStream.dll new file mode 100644 index 0000000..802776f Binary files /dev/null and b/ModManager/libs/ProgressStream.dll differ diff --git a/ModManager/libs/System.Buffers.dll b/ModManager/libs/System.Buffers.dll deleted file mode 100644 index c0970c0..0000000 Binary files a/ModManager/libs/System.Buffers.dll and /dev/null differ diff --git a/ModManager/libs/System.Numerics.Vectors.dll b/ModManager/libs/System.Numerics.Vectors.dll deleted file mode 100644 index 1020577..0000000 Binary files a/ModManager/libs/System.Numerics.Vectors.dll and /dev/null differ diff --git a/ModManager/libs/System.Text.Encodings.Web.dll b/ModManager/libs/System.Text.Encodings.Web.dll deleted file mode 100644 index 6aa0cbe..0000000 Binary files a/ModManager/libs/System.Text.Encodings.Web.dll and /dev/null differ diff --git a/ModManager/libs/System.Text.Json.dll b/ModManager/libs/System.Text.Json.dll deleted file mode 100644 index 7133409..0000000 Binary files a/ModManager/libs/System.Text.Json.dll and /dev/null differ diff --git a/ModManagerUI/CrashGuardSystem/BoxBuilder.cs b/ModManagerUI/CrashGuardSystem/BoxBuilder.cs deleted file mode 100644 index dbb342a..0000000 --- a/ModManagerUI/CrashGuardSystem/BoxBuilder.cs +++ /dev/null @@ -1,167 +0,0 @@ -using System; -using Timberborn.Core; -using Timberborn.CoreUI; -using Timberborn.Localization; -using UnityEngine; -using UnityEngine.UIElements; - -namespace ModManagerUI.CrashGuardSystem -{ - public class BoxBuilder - { - private readonly ILoc _loc; - private readonly VisualElement _root; - private Action? _confirmAction = EmptyCallback; - private Action? _cancelAction; - private Action? _infoAction; - private string? _confirmText; - private string? _cancelText; - private string? _infoText; - - public BoxBuilder( - ILoc loc, - VisualElement root) - { - _loc = loc; - _root = root; - } - - public BoxBuilder SetMessage(string text) - { - _root.Q