public bool MarkInstalled(ModMetadata meta, ModVersion version, ModDownloadResult downloadDetails) { ModStatus status = GetModStatus(meta); switch (status) { case ModStatus.Installed: ModVersions.Delete(m => m.MetadataId == meta.Id); ModVersions.Insert(version); return(true); case ModStatus.NotInstalled: Mods.Insert(meta); ModVersions.Insert(version); return(true); // Already added as requested, need to modify it case ModStatus.Requested: ModVersion requested = ModVersions.FindOne(v => v.GetModVersion() == version.GetModVersion()); requested.Filename = downloadDetails.Filename; requested.Checksum = downloadDetails.Checksum; return(ModVersions.Update(requested)); } return(false); }
void LoadMod(ModMetadata mod) { if (!Game.IsModInstalled(mod.Id)) { var widgetArgs = new WidgetArgs { { "modId", mod.Id } }; Ui.OpenWindow("INSTALL_MOD_PANEL", widgetArgs); return; } if (!IsModInstalled(mod)) { var widgetArgs = new WidgetArgs { { "continueLoading", () => Game.RunAfterTick(() => Game.InitializeMod(mod.Id, new Arguments())) }, { "modId", mod.Id } }; Ui.OpenWindow("CONTENT_PROMPT_PANEL", widgetArgs); return; } Game.RunAfterTick(() => { Ui.CloseWindow(); sheetBuilder.Dispose(); Game.InitializeMod(mod.Id, null); }); }
public Task <ModVersion> GetModVersion(ModMetadata metadata, string version) { if (metadata == null) { throw new Exception("Metadata is not defined; cannot get mod versions with it."); } if (!(metadata is CurseforgeModMetadata)) { throw new Exception("Metadata needs to be a curseforge metadata object."); } CurseforgeModMetadata cfMeta = metadata as CurseforgeModMetadata; bool hasVersion = cfMeta.Versions.ContainsKey(cfMeta.MinecraftVersion); if (!hasVersion) { throw new Exception("Mod does not have versions for the requested Minecraft version."); } IEnumerable <ModVersion> versions = cfMeta.Versions[cfMeta.MinecraftVersion]; if (version == null) { return(Task.FromResult(versions.First())); } ModVersion mv = versions.First(v => v.GetModVersion() == version); return(Task.FromResult(mv)); }
/// <summary> /// Handles the mods versions {modid} command. /// </summary> /// <param name="domain">Domain handler to use for lookup.</param> /// <param name="modIdentifier">Mod to lookup versions for.</param> public static void HandleModVersions(IDomain domain, string modIdentifier) { IDomainHandler handler = domain.GetDomainHandler(); ModMetadata meta = handler.GetModMetadata(Modifi.DefaultPack.MinecraftVersion, modIdentifier).Result; IEnumerable <ModVersion> latestVersions = handler.GetRecentVersions(meta).Result; // ModHelper.PrintModInformation(meta); foreach (ModVersion version in latestVersions) { Console.Write("["); Console.ForegroundColor = ConsoleColor.Gray; Console.Write(version.GetModVersion()); Console.ForegroundColor = ConsoleColor.White; Console.Write("] "); Console.ForegroundColor = ConsoleColor.Yellow; Console.Write(version.GetVersionName()); Console.ForegroundColor = ConsoleColor.White; Console.Write(" ("); Console.ForegroundColor = ConsoleColor.Magenta; Console.Write(version.GetReleaseType()); Console.ForegroundColor = ConsoleColor.White; Console.Write(")"); Console.ResetColor(); Console.WriteLine(); } }
public ModMetadataBuilder WithVersion(string version) { Version parsed = new Version(version); _modMetadata = new ModMetadata(_modMetadata?.Name, parsed, _modMetadata?.Description); return(this); }
void LoadMod(ModMetadata mod) { if (!modPrerequisitesFulfilled[mod.Id]) { var widgetArgs = new WidgetArgs { { "modId", mod.Id } }; Ui.OpenWindow("INSTALL_MOD_PANEL", widgetArgs); return; } if (!modInstallStatus[mod]) { var widgetArgs = new WidgetArgs { { "continueLoading", () => Game.RunAfterTick(() => Game.InitializeMod(Game.Settings.Game.Mod, new Arguments())) }, { "mirrorListUrl", mod.Content.PackageMirrorList }, { "modId", mod.Id } }; Ui.OpenWindow("INSTALL_PANEL", widgetArgs); return; } Game.RunAfterTick(() => { Ui.CloseWindow(); sheetBuilder.Dispose(); Game.InitializeMod(mod.Id, null); }); }
public Task <IEnumerable <ModVersion> > GetRecentVersions(ModMetadata meta, int count = 5, ModReleaseType releaseType = ModReleaseType.Any) { if (!(meta is CurseforgeModMetadata)) { throw new Exception("Metadata is not of Curseforge's type. Cannot fetch mod versions with this."); } CurseforgeModMetadata metaCF = (CurseforgeModMetadata)meta; if (String.IsNullOrEmpty(metaCF.MinecraftVersion)) { throw new Exception("Minecraft version was not set on metadata, cannot properly fetch versions."); } if (!metaCF.Versions.ContainsKey(metaCF.MinecraftVersion)) { return(null); } IEnumerable <ModVersion> versions = metaCF.Versions[metaCF.MinecraftVersion]; if (releaseType != ModReleaseType.Any) { versions = versions.Where(v => v.GetReleaseType() == releaseType); } IEnumerable <ModVersion> limitedList = versions.Take(count); foreach (ModVersion mv in limitedList) { mv.MetadataId = meta.Id; } return(Task.FromResult(limitedList)); }
public ModCircularDependencyException(ModMetadata modMetadata, ModMetadata dependency) : base($"Circular dependency found between mods " + $"`{modMetadata.Name} (v{modMetadata.Version})` and " + $"`{dependency.Name} (v{dependency.Version})`.") { this.modMetadata = modMetadata; this.dependency = dependency; }
static void LoadMod(ModMetadata mod) { Game.RunAfterTick(() => { Ui.CloseWindow(); Game.InitializeWithMod(mod.Id, null); }); }
public ModVersion GetMod(ModMetadata meta) { if (meta == null) { return(null); } return(GetMod(meta.GetModIdentifier())); }
public ModMetadataActor() { Receive <LoadModMetadataCommand>(command => { bool exists = Directory.Exists(command.Path); if (!exists) { // TODO : User friendly message } string modInfoXmlPath = Path.Combine(command.Path, ModInfoXml); var modInfoXml = XDocument.Load(modInfoXmlPath); var modInfo = (from name in modInfoXml.Descendants() select new { Name = name.Element("Name")?.Value, Id = name.Element("Id")?.Value, Version = name.Element("Version")?.Value, Signature = name.Element("Signature")?.Value }).FirstOrDefault(); var dataFolderPath = Path.Combine(command.Path, "data"); var databasePath = Path.Combine(dataFolderPath, DefaultDatabaseName); if (!File.Exists(databasePath)) { // TODO : User friendly message } var stringTables = Directory.GetFiles(dataFolderPath, "*.gst"); if (!stringTables.Any()) { // TODO : User friendly message } var builder = ImmutableDictionary.CreateBuilder <string, StringTableMetadata>(); foreach (var stringTable in stringTables) { string lang = stringTable.Split('.')[1]; var tableMetadata = new StringTableMetadata(lang, stringTable); builder.Add(lang, tableMetadata); } var stringTableMetadata = builder.ToImmutable(); var modMetadata = new ModMetadata(modInfo.Id, modInfo.Name, modInfo.Version, modInfo.Signature, dataFolderPath, databasePath, stringTableMetadata); var readedEvent = new ModMetadataLoadedEvent(modMetadata); command.Sender.Tell(readedEvent); }); }
void LoadMod(ModMetadata mod) { Game.RunAfterTick(() => { Ui.CloseWindow(); sheetBuilder.Dispose(); Game.InitializeMod(mod.Id, null); }); }
public DesignViewModel(IApplicationActorContext applicationActorContext, ModMetadata modMetadata) { TabHeaderTitle = "Desings"; _designViewActorRef = applicationActorContext.ActorSystem.ActorOf(Props.Create(() => new DesignsViewActor(this, modMetadata)).WithDispatcher("akka.actor.synchronized-dispatcher")); CloseCommand = new DelegateCommand(OnDesignViewClosed); _designViewActorRef.Tell(new LoadDesignsCommand(_designViewActorRef)); }
public Task <ModVersion> GetLatestVersion(ModMetadata meta, ModReleaseType releaseType = ModReleaseType.Any) { if (!(meta is CurseforgeModMetadata)) { throw new Exception("Metadata is not of Curseforge's type. Cannot fetch mod versions with this."); } IEnumerable <ModVersion> versions = GetRecentVersions(meta, 1, releaseType).Result; return(Task.FromResult(versions.First())); }
public static void HandleModInformation(IDomain domain, string modIdentifier, string modVersion = null) { ModMetadata meta = domain.GetDomainHandler().GetModMetadata(Modifi.DefaultPack.MinecraftVersion, modIdentifier).Result; ILogger log = Modifi.DefaultLogger; log.Information(meta.GetName()); if (meta.HasDescription()) { log.Information(meta.GetDescription()); } }
public bool MarkRequested(ModMetadata meta, ModVersion version) { if (GetModStatus(meta) != ModStatus.NotInstalled) { throw new Exception("Mod is already marked requested, or already installed."); } Mods.Insert(meta); ModVersions.Insert(version); return(true); }
void SelectMod(ModMetadata mod) { selectedMod = mod; selectedAuthor = "By " + (mod.Author ?? "unknown author"); selectedDescription = (mod.Description ?? "").Replace("\\n", "\n"); var selectedIndex = Array.IndexOf(allMods, mod); if (selectedIndex - modOffset > 4) { modOffset = selectedIndex - 4; } }
public void ResolveDependencies_CircularDependency_ThrowsException() { ModMetadata firstDep = _metadataBuilder.WithName("Dep One").Build(); ModMetadata secondDep = _metadataBuilder.WithName("Dep Two").Build(); ModMetadata thirdDep = _metadataBuilder.WithName("Dep Three").Build(); firstDep.Dependencies.Add(secondDep); secondDep.Dependencies.Add(thirdDep); thirdDep.Dependencies.Add(firstDep); Assert.Throws <ModCircularDependencyException>(() => firstDep.TryResolveDependencies(new[] { firstDep, secondDep, thirdDep })); }
public ModVersion GetMod(string modIdentifier) { ModMetadata meta = Mods.FindOne(x => x.GetModIdentifier() == modIdentifier); if (meta == null) { return(null); } Guid v = meta.Id; return(ModVersions.FindOne(x => x.MetadataId == meta.Id)); }
public void ResolveDependencies_NotAllDependenciesLoaded_ReturnsFalse() { ModMetadata firstDep = _metadataBuilder.WithName("Dep One").Build(); ModMetadata secondDep = _metadataBuilder.WithName("Dep Two").Build(); ModMetadata rootMod = _metadataBuilder .WithName("Root Mod") .WithVersion("1.0") .WithDependency(firstDep) .WithDependency(secondDep) .Build(); Assert.IsFalse(rootMod.TryResolveDependencies(new[] { firstDep })); }
void SelectMod(ModMetadata mod) { selectedMod = mod; selectedAuthor = "By " + (mod.Author ?? "unknown author"); selectedDescription = (mod.Description ?? "").Replace("\\n", "\n"); var selectedIndex = Array.IndexOf(allMods, mod); if (selectedIndex - modOffset > 4) { modOffset = selectedIndex - 4; } loadButton.Text = modInstallStatus[mod] ? "Load Mod" : "Install Assets"; }
public static ModDownloadResult?HandleModDownload(IDomain domain, string modIdentifier, string modVersion = null) { IDomainHandler handler = domain.GetDomainHandler(); // Fetch the mod version information from the Curseforge API try { ModMetadata meta = handler.GetModMetadata(Modifi.DefaultPack.MinecraftVersion, modIdentifier).Result; ModVersion mod = handler.GetModVersion(meta, modVersion).Result; return(handler.DownloadMod(mod, Settings.ModPath).Result); } catch (Exception) { return(null); } }
/// <summary> /// Gets the installation status for a mod. /// </summary> /// <param name="meta">Mod to get status for</param> /// <returns></returns> public ModStatus GetModStatus(ModMetadata meta) { ModMetadata installed = this.Mods.FindOne(x => x.GetModIdentifier() == meta.GetModIdentifier()); if (installed == null) { return(ModStatus.NotInstalled); } ModVersion installedVersion = GetMod(meta); // If we have a request in meta, but no requested version, error. // Delete the meta information and let the user know to re-request the mod. // TODO: Make new exception for this if (installedVersion == null) { this.Mods.Delete(x => x.GetModIdentifier() == installed.GetModIdentifier()); throw new Exception("Mod metadata was in requests, but no matching version was found with it."); } // Check filename exists - if not, mod is requested and not yet downloaded string filename = installedVersion.Filename; if (filename == null) { return(ModStatus.Requested); } // Filename exists- check if properly downloaded string path = Path.Combine(Settings.ModPath, filename); if (File.Exists(path)) { // If our checksum matches, the mod is installed if (ModUtilities.ChecksumMatches(path, installedVersion.Checksum)) { return(ModStatus.Installed); } else { // TODO: Should we remove the mod metadata if the checksum failed here? throw new Exception("Checksum does not match version information."); } } return(ModStatus.Requested); }
public DesignOperationsActor(ModMetadata modMetadata) { Receive <LoadDesignsCommand>(command => { var connectionString = new FbConnectionStringBuilder { Database = modMetadata.ModDatabasePath, ServerType = FbServerType.Embedded, UserID = "SYSDBA", Password = "******", ClientLibrary = "fbembed.dll" }.ToString(); using (SuperPowerEditorDbContext context = new SuperPowerEditorDbContext(connectionString)) { List <Design> designs = context.Designs.Include(nameof(Design.CountryDesignerRef)).ToList(); command.Sender.Tell(new DesignsLoadedEvent(designs)); } }); }
/// <summary> /// Prints out some mod information in a standardized manner. /// </summary> /// <param name="meta"></param> public static void PrintModInformation(ModMetadata meta, bool header = false) { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine(); Console.WriteLine(meta.GetName()); Console.ForegroundColor = ConsoleColor.White; if (meta.HasDescription()) { Console.WriteLine(); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(meta.GetDescription()); } if (header) { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("".PadLeft(Console.BufferWidth - 10, '=')); } Console.ResetColor(); }
private void MigrateModJsonPreClientVersion2() { foreach (var mod in _parkitect.Assets[AssetType.Mod]) { var metaPath = Path.Combine(mod.InstallationPath, "modinfo.meta"); if (!File.Exists(metaPath)) { var oldData = JsonConvert.DeserializeObject <OldModJsonFile>( File.ReadAllText(Path.Combine(mod.InstallationPath, "mod.json"))); var meta = new ModMetadata { Tag = oldData.Tag, Repository = oldData.Repository, Id = null, InstalledVersion = DateTime.Now }; File.WriteAllText(metaPath, JsonConvert.SerializeObject(meta)); } } }
public ModStringTableActor(ModMetadata modMetadata) { var dataPath = modMetadata.DataPath; var spStringTable = new SpStringTable(); spStringTable.Load(dataPath); Receive <LoadStringTableValueFromIdCommand>(command => { try { string spString = spStringTable.GetString(command.StId, command.Lang); //string spString = "Deniz"; Sender.Tell(new StringTableValueLoadedEvent(command.StId, spString, command.Lang), Self); } catch (Exception e) { Console.WriteLine(e); throw; } }); }
public ModBrowserLogic(Widget widget) { var panel = widget; var loadButton = panel.Get <ButtonWidget>("LOAD_BUTTON"); loadButton.OnClick = () => LoadMod(selectedMod); loadButton.IsDisabled = () => selectedMod.Id == Game.ModData.Manifest.Mod.Id; panel.Get <ButtonWidget>("QUIT_BUTTON").OnClick = Game.Exit; modList = panel.Get("MOD_LIST"); modTemplate = modList.Get <ButtonWidget>("MOD_TEMPLATE"); panel.Get <LabelWidget>("MOD_DESC").GetText = () => selectedDescription; panel.Get <LabelWidget>("MOD_TITLE").GetText = () => selectedMod.Title; panel.Get <LabelWidget>("MOD_AUTHOR").GetText = () => selectedAuthor; panel.Get <LabelWidget>("MOD_VERSION").GetText = () => selectedMod.Version; var prevMod = panel.Get <ButtonWidget>("PREV_MOD"); prevMod.OnClick = () => { modOffset -= 1; RebuildModList(); }; prevMod.IsVisible = () => modOffset > 0; var nextMod = panel.Get <ButtonWidget>("NEXT_MOD"); nextMod.OnClick = () => { modOffset += 1; RebuildModList(); }; nextMod.IsVisible = () => modOffset + 5 < allMods.Length; panel.Get <RGBASpriteWidget>("MOD_PREVIEW").GetSprite = () => { Sprite ret = null; previews.TryGetValue(selectedMod.Id, out ret); return(ret); }; sheetBuilder = new SheetBuilder(SheetType.BGRA); allMods = ModMetadata.AllMods.Values.Where(m => !m.Hidden) .OrderBy(m => m.Title) .ToArray(); // Load preview images, and eat any errors foreach (var mod in allMods) { try { using (var preview = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "preview.png"))) if (preview.Width == 296 && preview.Height == 196) { previews.Add(mod.Id, sheetBuilder.Add(preview)); } } catch (Exception) { } try { using (var logo = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "logo.png"))) if (logo.Width == 96 && logo.Height == 96) { logos.Add(mod.Id, sheetBuilder.Add(logo)); } } catch (Exception) { } } ModMetadata initialMod = null; ModMetadata.AllMods.TryGetValue(Game.Settings.Game.PreviousMod, out initialMod); SelectMod(initialMod ?? ModMetadata.AllMods["ra"]); RebuildModList(); }
void SelectMod(ModMetadata mod) { selectedMod = mod; selectedAuthor = "By " + (mod.Author ?? "unknown author"); selectedDescription = (mod.Description ?? "").Replace("\\n", "\n"); var selectedIndex = Array.IndexOf(allMods, mod); if (selectedIndex - modOffset > 4) modOffset = selectedIndex - 4; loadButton.Text = modInstallStatus[mod] ? "Load Mod" : "Install Assets"; }
void LoadMod(ModMetadata mod) { if (!modInstallStatus[mod]) { var widgetArgs = new WidgetArgs { { "continueLoading", () => Game.RunAfterTick(() => Game.InitializeMod(Game.Settings.Game.Mod, new Arguments())) }, { "mirrorListUrl", mod.Content.PackageMirrorList }, { "modId", mod.Id } }; Ui.OpenWindow("INSTALL_PANEL", widgetArgs); return; } Game.RunAfterTick(() => { Ui.CloseWindow(); sheetBuilder.Dispose(); Game.InitializeMod(mod.Id, null); }); }
static bool IsModInstalled(ModMetadata mod) { return(mod.Content.TestFiles.All(file => File.Exists(Path.GetFullPath(Platform.ResolvePath(file))))); }
static bool IsModInstalled(ModMetadata mod) { return mod.Content.TestFiles.All(file => File.Exists(Path.GetFullPath(Platform.ResolvePath(file)))); }
void SelectMod(ModMetadata mod) { selectedMod = mod; selectedAuthor = "By " + mod.Author ?? "unknown author"; selectedDescription = (mod.Description ?? "").Replace("\\n", "\n"); var selectedIndex = Array.IndexOf(allMods, mod); if (selectedIndex - modOffset > 4) modOffset = selectedIndex - 4; }
public async Task <IAsset> StoreAsset(IDownloadedAsset downloadedAsset) { switch (downloadedAsset.ApiAsset.Type) { case AssetType.Blueprint: case AssetType.Savegame: case AssetType.Scenario: { // Create the directory where the asset should be stored and create a path to where the asset should be stored. var storagePath = _parkitect.Paths.GetAssetPath(downloadedAsset.ApiAsset.Type); var assetPath = Path.Combine(storagePath, downloadedAsset.FileName); Directory.CreateDirectory(storagePath); _log.WriteLine($"Storing asset to {assetPath}."); // If the file already exists, add a number behind the file name. if (File.Exists(assetPath)) { _log.WriteLine("Asset already exists, comparing hashes."); // Compute hash of downloaded asset to match with installed hash. var validHash = downloadedAsset.Stream.CreateMD5Checksum(); if (validHash.SequenceEqual(File.OpenRead(assetPath).CreateMD5Checksum())) { _log.WriteLine("Asset hashes match, aborting."); return(null); } _log.WriteLine("Asset hashes mismatch, computing new file name."); // Separate the filename and the extension. var attempt = 1; var fileName = Path.GetFileNameWithoutExtension(downloadedAsset.FileName); var fileExtension = Path.GetExtension(downloadedAsset.FileName); // Update the path to where the the asset should be stored by adding a number behind the name until an available filename has been found. do { assetPath = Path.Combine(storagePath, $"{fileName} ({++attempt}){fileExtension}"); if (File.Exists(assetPath) && validHash.SequenceEqual(File.OpenRead(assetPath).CreateMD5Checksum())) { return(null); } } while (File.Exists(assetPath)); _log.WriteLine($"Newly computed path is {assetPath}."); } _log.WriteLine("Writing asset to file."); // Write the stream to a file at the asset path. using (var fileStream = File.Create(assetPath)) { downloadedAsset.Stream.Seek(0, SeekOrigin.Begin); await downloadedAsset.Stream.CopyToAsync(fileStream); } var meta = new AssetMetadata { Id = downloadedAsset.ApiAsset.Id // InstalledVersion = downloadedAsset.ApiAsset.UpdatedAt }; // TODO: Re-add installed version _assetMetadataStorage.StoreMetadata(downloadedAsset.ApiAsset.Type, assetPath, meta); var cachedData = await _assetCachedDataStorage.GetData(downloadedAsset.ApiAsset.Type, meta, assetPath); Asset createdAsset = null; switch (downloadedAsset.ApiAsset.Type) { case AssetType.Blueprint: createdAsset = new BlueprintAsset(assetPath, meta, cachedData); break; case AssetType.Savegame: createdAsset = new SavegameAsset(assetPath, meta, cachedData as AssetWithImageCachedData); break; case AssetType.Scenario: createdAsset = new ScenarioAsset(assetPath, meta, cachedData as AssetWithImageCachedData); break; } OnAssetAdded(new AssetEventArgs(createdAsset)); return(createdAsset); } case AssetType.Mod: { _log.WriteLine("Attempting to open mod stream."); using (var zip = new ZipArchive(downloadedAsset.Stream, ZipArchiveMode.Read)) { // Compute name of main directory inside archive. var mainFolder = zip.Entries.FirstOrDefault()?.FullName; if (mainFolder == null) { throw new Exception("invalid archive"); } _log.WriteLine($"Mod archive main folder is {mainFolder}."); // Find the mod.json file. Yay for / \ path divider compatibility. var modJsonPath = Path.Combine(mainFolder, "mod.json").Replace('/', '\\'); var modJson = zip.Entries.FirstOrDefault(e => e.FullName.Replace('/', '\\') == modJsonPath); // Read mod.json. if (modJson == null) { throw new Exception("mod is missing mod.json file"); } using (var streamReader = new StreamReader(modJson.Open())) { var modInformationString = await streamReader.ReadToEndAsync(); var modInformation = JsonConvert.DeserializeObject <ModInformation>(modInformationString); var meta = new ModMetadata { Id = downloadedAsset.ApiAsset.Id, // InstalledVersion = downloadedAsset.ApiAsset.UpdatedAt, Tag = downloadedAsset.Info.Tag, Repository = downloadedAsset.Info.Repository }; // TODO: Re-add installed version var installationPath = Path.Combine(_parkitect.Paths.GetAssetPath(AssetType.Mod), downloadedAsset.Info.Repository.Replace('/', '@')); // TODO: Should actually try and look if the mod has been updated since and delete the whole folder. if (Directory.Exists(installationPath)) { if (File.Exists(Path.Combine(installationPath, "modinfo.meta"))) { File.Delete(Path.Combine(installationPath, "modinfo.meta")); } if (File.Exists(Path.Combine(installationPath, "moddata.cache"))) { File.Delete(Path.Combine(installationPath, "moddata.cache")); } } _log.WriteLine($"mod.json was deserialized to mod object '{modInformation}'."); // Set default mod properties. modInformation.IsEnabled = true; modInformation.IsDevelopment = false; // Find previous version of mod. // TODO uninstall previous versions // Install mod. _log.WriteLine("Copying mod to mods folder."); foreach (var entry in zip.Entries) { if (!entry.FullName.StartsWith(mainFolder)) { continue; } // Compute path. var partDir = entry.FullName.Substring(mainFolder.Length); var path = Path.Combine(installationPath, partDir); var ignoredFiles = new[] { "moddata.cache", "modinfo.meta", "mod.log" }; if (ignoredFiles.Contains(partDir)) { continue; } if (string.IsNullOrEmpty(entry.Name)) { _log.WriteLine($"Creating directory '{path}'."); Directory.CreateDirectory(path); } else { _log.WriteLine($"Storing mod file '{path}'."); using (var openStream = entry.Open()) using (var fileStream = File.OpenWrite(path)) await openStream.CopyToAsync(fileStream); } } _log.WriteLine("Register installation to API."); _website.API.RegisterDownload(downloadedAsset.ApiAsset.Id); _assetMetadataStorage.StoreMetadata(downloadedAsset.ApiAsset.Type, installationPath, meta); var cachedData = await _assetCachedDataStorage.GetData(downloadedAsset.ApiAsset.Type, meta, installationPath); modInformationString = JsonConvert.SerializeObject(modInformation); File.WriteAllText(Path.Combine(installationPath, "mod.json"), modInformationString); var createdAsset = new ModAsset(installationPath, meta, cachedData as AssetWithImageCachedData, modInformation); OnAssetAdded(new AssetEventArgs(createdAsset)); return(createdAsset); } } } default: throw new Exception("unknown asset type"); } }