/// <summary> /// Load a mod from a .zip archive at runtime. /// </summary> /// <param name="archive">The path to the mod .zip archive.</param> public static void LoadZip(string archive) { if (!Flags.SupportRuntimeMods) { Logger.Log(LogLevel.Warn, "loader", "Loader disabled!"); return; } if (!File.Exists(archive)) // Relative path? Let's just make it absolute. { archive = Path.Combine(PathMods, archive); } if (!File.Exists(archive)) // It just doesn't exist. { return; } Logger.Log(LogLevel.Verbose, "loader", $"Loading mod .zip: {archive}"); EverestModuleMetadata meta = null; EverestModuleMetadata[] multimetas = null; using (ZipFile zip = new ZipFile(archive)) { foreach (ZipEntry entry in zip.Entries) { if (entry.FileName == "metadata.yaml") { using (MemoryStream stream = entry.ExtractStream()) using (StreamReader reader = new StreamReader(stream)) { try { meta = YamlHelper.Deserializer.Deserialize <EverestModuleMetadata>(reader); meta.PathArchive = archive; meta.PostParse(); } catch (Exception e) { Logger.Log(LogLevel.Warn, "loader", $"Failed parsing metadata.yaml in {archive}: {e}"); FilesWithMetadataLoadFailures.Add(archive); } } continue; } if (entry.FileName == "multimetadata.yaml" || entry.FileName == "everest.yaml" || entry.FileName == "everest.yml") { using (MemoryStream stream = entry.ExtractStream()) using (StreamReader reader = new StreamReader(stream)) { try { if (!reader.EndOfStream) { multimetas = YamlHelper.Deserializer.Deserialize <EverestModuleMetadata[]>(reader); foreach (EverestModuleMetadata multimeta in multimetas) { multimeta.PathArchive = archive; multimeta.PostParse(); } } } catch (Exception e) { Logger.Log(LogLevel.Warn, "loader", $"Failed parsing everest.yaml in {archive}: {e}"); FilesWithMetadataLoadFailures.Add(archive); } } continue; } } } ZipModContent contentMeta = new ZipModContent(archive); EverestModuleMetadata contentMetaParent = null; Action contentCrawl = () => { if (contentMeta == null) { return; } if (contentMetaParent != null) { contentMeta.Mod = contentMetaParent; contentMeta.Name = contentMetaParent.Name; } OnCrawlMod?.Invoke(archive, contentMetaParent); Content.Crawl(contentMeta); contentMeta = null; }; if (multimetas != null) { foreach (EverestModuleMetadata multimeta in multimetas) { multimeta.Multimeta = multimetas; if (contentMetaParent == null) { contentMetaParent = multimeta; } LoadModDelayed(multimeta, contentCrawl); } } else { if (meta == null) { meta = new EverestModuleMetadata() { Name = "_zip_" + Path.GetFileNameWithoutExtension(archive), VersionString = "0.0.0-dummy", PathArchive = archive }; meta.PostParse(); } contentMetaParent = meta; LoadModDelayed(meta, contentCrawl); } }
/// <summary> /// Load a mod from a .zip archive at runtime. /// </summary> /// <param name="archive">The path to the mod .zip archive.</param> public static void LoadZip(string archive) { if (Flags.IsDisabled || !Flags.SupportRuntimeMods) { Logger.Log(LogLevel.Warn, "loader", "Loader disabled!"); return; } if (!File.Exists(archive)) // Relative path? Let's just make it absolute. archive = Path.Combine(PathMods, archive); if (!File.Exists(archive)) // It just doesn't exist. return; Logger.Log(LogLevel.Verbose, "loader", $"Loading mod .zip: {archive}"); EverestModuleMetadata meta = null; EverestModuleMetadata[] multimetas = null; // In case the icon appears before the metadata in the .zip, store it temporarily, set it later. Texture2D icon = null; using (ZipFile zip = new ZipFile(archive)) { foreach (ZipEntry entry in zip.Entries) { if (entry.FileName == "metadata.yaml") { using (MemoryStream stream = entry.ExtractStream()) using (StreamReader reader = new StreamReader(stream)) { try { meta = YamlHelper.Deserializer.Deserialize<EverestModuleMetadata>(reader); meta.PathArchive = archive; meta.PostParse(); } catch (Exception e) { Logger.Log(LogLevel.Warn, "loader", $"Failed parsing metadata.yaml in {archive}: {e}"); } } continue; } if (entry.FileName == "multimetadata.yaml" || entry.FileName == "everest.yaml" || entry.FileName == "everest.yml") { using (MemoryStream stream = entry.ExtractStream()) using (StreamReader reader = new StreamReader(stream)) { try { if (!reader.EndOfStream) { multimetas = YamlHelper.Deserializer.Deserialize<EverestModuleMetadata[]>(reader); foreach (EverestModuleMetadata multimeta in multimetas) { multimeta.PathArchive = archive; multimeta.PostParse(); } } } catch (Exception e) { Logger.Log(LogLevel.Warn, "loader", $"Failed parsing multimetadata.yaml in {archive}: {e}"); } } continue; } if (entry.FileName == "icon.png") { using (Stream stream = entry.ExtractStream()) icon = Texture2D.FromStream(Celeste.Instance.GraphicsDevice, stream); continue; } } } if (meta != null) { if (icon != null) meta.Icon = icon; } ZipModContent contentMeta = new ZipModContent(archive); EverestModuleMetadata contentMetaParent = null; Action contentCrawl = () => { if (contentMeta == null) return; if (contentMetaParent != null) { contentMeta.Mod = contentMetaParent; contentMeta.Name = contentMetaParent.Name; } Content.Crawl(contentMeta); contentMeta = null; }; if (multimetas != null) { foreach (EverestModuleMetadata multimeta in multimetas) { multimeta.Multimeta = multimetas; if (contentMetaParent == null) contentMetaParent = multimeta; LoadModDelayed(multimeta, contentCrawl); } } else { if (meta == null) { meta = new EverestModuleMetadata() { Name = "_zip_" + Path.GetFileNameWithoutExtension(archive), VersionString = "0.0.0-dummy", PathArchive = archive }; meta.PostParse(); } contentMetaParent = meta; LoadModDelayed(meta, contentCrawl); } }