public static Language FromModExport(ModAsset asset) { Language lang = new Language(); using (BinaryReader reader = new BinaryReader(asset.Stream)) { lang.Id = reader.ReadString(); lang.Label = reader.ReadString(); lang.IconPath = reader.ReadString(); lang.Icon = new MTexture(VirtualContent.CreateTexture(Path.Combine("Dialog", lang.IconPath))); lang.Order = reader.ReadInt32(); lang.FontFace = reader.ReadString(); lang.FontFaceSize = reader.ReadSingle(); lang.SplitRegex = reader.ReadString(); lang.CommaCharacters = reader.ReadString(); lang.PeriodCharacters = reader.ReadString(); lang.Lines = reader.ReadInt32(); lang.Words = reader.ReadInt32(); int count = reader.ReadInt32(); for (int i = 0; i < count; i++) { string key = reader.ReadString(); lang.Dialog[key] = reader.ReadString(); lang.Cleaned[key] = reader.ReadString(); } } return(lang); }
public static void IngestGUIDs(ModAsset asset) { Logger.Log(LogLevel.Verbose, "Audio.IngestGUIDs", asset.PathVirtual); using (Stream stream = asset.Stream) using (StreamReader reader = new StreamReader(asset.Stream)) { string line; while (reader.Peek() != -1) { line = reader.ReadLine().Trim('\r', '\n').Trim(); int indexOfSpace = line.IndexOf(' '); if (indexOfSpace == -1) { continue; } if (!Guid.TryParse(line.Substring(0, indexOfSpace), out Guid id) || cachedPaths.ContainsKey(id)) { continue; } string path = line.Substring(indexOfSpace + 1); EventDescription _event; if (system.getEventByID(id, out _event) <= RESULT.OK) { _event.unloadSampleData(); cachedPaths[id] = path; cachedModEvents[path] = _event; } // TODO: Ingest buses and vcas } } }
private void EverestContentUpdateHook(ModAsset oldAsset, ModAsset newAsset) { if (newAsset != null && newAsset.PathVirtual.StartsWith("SkinModHelperConfig")) { ReloadSettings(); } }
private static void loadTutorialsInDirectory(ModAsset dir) { foreach (ModAsset child in dir.Children) { if (child.Type == typeof(AssetTypeDirectory)) { // crawl in subdirectory. loadTutorialsInDirectory(child); } else if (child.Type == typeof(AssetTypeTutorial)) { // remove Tutorials/ from the tutorial path. string tutorialPath = child.PathVirtual; if (tutorialPath.StartsWith("Tutorials/")) { tutorialPath = tutorialPath.Substring("Tutorials/".Length); } // load tutorial. Logger.Log("PlaybackData", $"Loading tutorial: {tutorialPath}"); byte[] buffer = child.Data; List <Player.ChaserState> tutorial = Import(buffer); Tutorials[tutorialPath] = tutorial; } } }
// Allow loading VirtualTextures from modded AssetMetadatas. public static VirtualTexture CreateTexture(ModAsset metadata) { VirtualTexture virtualTexture = (VirtualTexture)(object)new patch_VirtualTexture(metadata); assets.Add(virtualTexture); return(virtualTexture); }
private void onModAssetUpdate(ModAsset oldAsset, ModAsset newAsset) { if (newAsset != null && newAsset.PathVirtual.StartsWith("ReskinHelperSkins/")) { // reload settings files when one is added or updated. reloadReskinSettingsFiles(); } }
private XmlDocument loadXMLFromModAsset(ModAsset modAsset) { XmlDocument xmlDocument = new XmlDocument(); using (Stream inStream = modAsset.Stream) { xmlDocument.Load(inStream); return(xmlDocument); } }
internal patch_VirtualTexture(ModAsset metadata) { Metadata = metadata; Name = metadata.PathVirtual; if (!Preload()) { Reload(); } }
/// <summary> /// Loads an FMOD Bank from the given asset. /// </summary> public static Bank IngestBank(ModAsset asset) { Logger.Log(LogLevel.Verbose, "Audio.IngestBank", asset.PathVirtual); ingestedModBankPaths.Add(asset.PathVirtual); Bank bank; if (patch_Banks.ModCache.TryGetValue(asset, out bank)) { return(bank); } RESULT loadResult; if (CoreModule.Settings.UnpackFMODBanks) { loadResult = system.loadBankFile(asset.GetCachedPath(), LOAD_BANK_FLAGS.NORMAL, out bank); } else { IntPtr handle; modBankAssets[handle = (IntPtr)(++modBankHandleLast)] = asset; BANK_INFO info = new BANK_INFO() { size = patch_Banks.SizeOfBankInfo, userdata = handle, userdatalength = 0, opencallback = ModBankOpen, closecallback = ModBankClose, readcallback = ModBankRead, seekcallback = ModBankSeek }; loadResult = system.loadBankCustom(info, LOAD_BANK_FLAGS.NORMAL, out bank); } if (loadResult == RESULT.ERR_EVENT_ALREADY_LOADED) { Logger.Log(LogLevel.Warn, "Audio.IngestBank", $"Cannot load {asset.PathVirtual} due to conflicting events!"); return(null); } loadResult.CheckFMOD(); if (Everest.Content.TryGet <AssetTypeGUIDs>(asset.PathVirtual + ".guids", out ModAsset assetGUIDs)) { IngestGUIDs(assetGUIDs); } patch_Banks.ModCache[asset] = bank; bank.getID(out Guid id); cachedBankPaths[id] = $"bank:/mods/{asset.PathVirtual.Substring("Audio/".Length)}"; return(bank); }
public static void LoadCollabIDFile(ModAsset asset) { string fileContents; using (StreamReader reader = new StreamReader(asset.Stream)) { fileContents = reader.ReadToEnd(); } Logger.Log(LogLevel.Info, "CollabUtils2/LobbyHelper", $"Registered new collab ID: {fileContents.Trim()}"); collabNames.Add(fileContents.Trim()); }
private void onModAssetUpdate(ModAsset oldAsset, ModAsset newAsset) { if (newAsset?.PathVirtual == "CollabUtils2CollabID") { LobbyHelper.LoadCollabIDFile(newAsset); } if (newAsset != null && newAsset.PathVirtual.StartsWith("Graphics/CollabUtils2/CrystalHeartSwaps_")) { reloadCrystalHeartSwapSpriteBanks(); } }
private static ObjModel loadModelFile(ModAsset asset, string path) { if (ObjModelCache.TryGetValue(path, out ObjModel cached)) { return(cached); } ObjModel loaded = ObjModelExt.CreateFromStream(asset.Stream, path); ObjModelCache[path] = loaded; return(loaded); }
private static bool resolveModel(MapMeta meta, string modelName, out ModAsset matchingAsset, out string path) { if (Everest.Content.TryGet(Path.Combine(meta.Mountain.MountainModelDirectory, modelName + ".obj"), out matchingAsset) && matchingAsset.Type == typeof(AssetTypeObjModelExport)) { path = Path.Combine(meta.Mountain.MountainModelDirectory, modelName + ".export").Replace("\\", "/"); return(true); } else if (Everest.Content.TryGet(Path.Combine(meta.Mountain.MountainModelDirectory, modelName), out matchingAsset) && matchingAsset.Type == typeof(ObjModel)) { path = Path.Combine(meta.Mountain.MountainModelDirectory, modelName + ".obj").Replace("\\", "/"); return(true); } path = null; return(false); }
public override T Load <T>(string assetName) { ModAsset mapping = Everest.Content.Get(assetName); // If we've got a valid mapping, load it instead of the original asset. if (mapping != null) { return(base.Load <T>(assetName)); } // We don't have any overriding mapping - load from the inner CM instead. T asset = Inner.Load <T>(assetName); asset = (T)Everest.Content.Process(asset, assetName); return(asset); }
/// <summary> /// Loads an FMOD GUID table from the given asset. /// </summary> public static void IngestGUIDs(ModAsset asset) { Logger.Log(LogLevel.Verbose, "Audio.IngestGUIDs", asset.PathVirtual); using (Stream stream = asset.Stream) using (StreamReader reader = new StreamReader(asset.Stream)) { string line; while (reader.Peek() != -1) { line = reader.ReadLine().Trim('\r', '\n').Trim(); int indexOfSpace = line.IndexOf(' '); if (indexOfSpace == -1) { continue; } if (!Guid.TryParse(line.Substring(0, indexOfSpace), out Guid id) || cachedPaths.ContainsKey(id)) { continue; } // only ingest the GUID if the corresponding event exists. if (system.getEventByID(id, out EventDescription _event) > RESULT.OK) { continue; } string path = line.Substring(indexOfSpace + 1); if (!usedGuids.TryGetValue(path, out HashSet <Guid> used)) { usedGuids[path] = used = new HashSet <Guid>(); } if (!used.Add(id)) { continue; } _event.unloadSampleData(); cachedPaths[id] = path; cachedModEvents[path] = _event; // TODO: Ingest buses and vcas } } }
public static Bank IngestBank(ModAsset asset) { Logger.Log(LogLevel.Verbose, "Audio.IngestBank", asset.PathVirtual); Bank bank; if (patch_Banks.ModCache.TryGetValue(asset, out bank)) { return(bank); } if (CoreModule.Settings.UnpackFMODBanks) { system.loadBankFile(asset.GetCachedPath(), LOAD_BANK_FLAGS.NORMAL, out bank).CheckFMOD(); } else { IntPtr handle; modBankAssets[handle = (IntPtr)(++modBankHandleLast)] = asset; BANK_INFO info = new BANK_INFO() { size = patch_Banks.SizeOfBankInfo, userdata = handle, userdatalength = 0, opencallback = ModBankOpen, closecallback = ModBankClose, readcallback = ModBankRead, seekcallback = ModBankSeek }; system.loadBankCustom(info, LOAD_BANK_FLAGS.NORMAL, out bank).CheckFMOD(); } ModAsset assetGUIDs; if (Everest.Content.TryGet <AssetTypeGUIDs>(asset.PathVirtual + ".guids", out assetGUIDs)) { IngestGUIDs(assetGUIDs); } patch_Banks.ModCache[asset] = bank; return(bank); }
public static Bank IngestBank(ModAsset asset) { Logger.Log(LogLevel.Verbose, "Audio.IngestBank", asset.PathMapped); Bank bank; if (patch_Banks.ModCache.TryGetValue(asset, out bank)) { return(bank); } // TODO: Use loadBankCustom with BANK_INFO reading from stream. system.loadBankMemory(asset.Data, LOAD_BANK_FLAGS.NORMAL, out bank).CheckFMOD(); ModAsset assetGUIDs; if (Everest.Content.TryGet <AssetTypeGUIDs>(asset.PathMapped + ".guids", out assetGUIDs)) { IngestGUIDs(assetGUIDs); } patch_Banks.ModCache[asset] = bank; return(bank); }
internal patch_VirtualTexture(ModAsset metadata) { Metadata = metadata; Name = metadata.PathMapped; Preload(); }
/// <summary> /// Feed the given ModAsset into the atlas. /// </summary> public static void Ingest(this Atlas self, ModAsset asset) { // Crawl through all child assets. if (asset.AssetType == typeof(AssetTypeDirectory)) { foreach (ModAsset child in asset.Children) { self.Ingest(child); } return; } // Forcibly add the mod content to the atlas. if (asset.AssetType == typeof(Texture2D)) { Logger.Log(LogLevel.Verbose, "Atlas.Ingest", $"{self.GetDataPath()} + {asset.PathMapped}"); string parentPath = self.GetDataPath(); if (parentPath.StartsWith(Everest.Content.PathContentOrig)) { parentPath = parentPath.Substring(Everest.Content.PathContentOrig.Length + 1); } parentPath = parentPath.Replace('\\', '/'); string path = asset.PathMapped; if (!path.StartsWith(parentPath)) { return; } path = path.Substring(parentPath.Length + 1); VirtualTexture replacementV = VirtualContentExt.CreateTexture(asset); MTexture replacement; MTextureMeta meta = asset.GetMeta <MTextureMeta>(); Dictionary <string, MTexture> textures = self.GetTextures(); MTexture existing; if (textures.TryGetValue(path, out existing)) { // We're the currently active overlay. if (existing.Texture.GetMetadata() == asset) { return; } if (meta != null) { // Apply width and height from existing meta. existing.AddOverride(replacementV, new Vector2(meta.X, meta.Y), meta.Width, meta.Height); } else { // Keep width and height from existing instance. existing.AddOverride(replacementV, existing.DrawOffset, existing.Width, existing.Height); } replacement = existing; } else { if (meta != null) { // Apply width and height from existing meta. replacement = new MTexture(replacementV, new Vector2(meta.X, meta.Y), meta.Width, meta.Height); } else { // Apply width and height from replacement texture. replacement = new MTexture(replacementV); } replacement.SetAtlasPath(path); } self[path] = replacement; return; } }
public IEnumerable <Asset> this[AssetType type] { get { switch (type) { case AssetType.Blueprint: foreach (var path in GetFilesInAssetPath(type)) { var metadata = _assetMetadataStorage.GetMetadata(type, path); var cachedData = _assetCachedDataStorage.GetData(type, metadata, path).Result; yield return(new BlueprintAsset(path, metadata, cachedData)); } break; case AssetType.Savegame: foreach (var path in GetFilesInAssetPath(type)) { var metadata = _assetMetadataStorage.GetMetadata(type, path); var cachedData = _assetCachedDataStorage.GetData(type, metadata, path).Result as AssetWithImageCachedData; yield return(new SavegameAsset(path, metadata, cachedData)); } break; case AssetType.Scenario: foreach (var path in GetFilesInAssetPath(type)) { var metadata = _assetMetadataStorage.GetMetadata(type, path); var cachedData = _assetCachedDataStorage.GetData(type, metadata, path).Result as AssetWithImageCachedData; yield return(new ScenarioAsset(path, metadata, cachedData)); } break; case AssetType.Mod: foreach (var path in GetFilesInAssetPath(type)) { ModAsset result = null; try { var metadata = _assetMetadataStorage.GetMetadata(type, path) as IModMetadata; var modInformationString = File.ReadAllText(Path.Combine(path, "mod.json")); var modInformation = JsonConvert.DeserializeObject <ModInformation>(modInformationString); var cachedData = metadata == null ? new AssetWithImageCachedData() : _assetCachedDataStorage.GetData(type, metadata, path).Result as AssetWithImageCachedData; result = new ModAsset(path, metadata, cachedData, modInformation); } catch (Exception e) { _log.WriteLine($"Failed loading mod at path {path}", LogLevel.Fatal); _log.WriteException(e); } if (result != null) { yield return(result); } } break; default: throw new Exception("Unsupported asset type"); } } }
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"); } }
// Mods can't access patch_ classes directly. // We thus expose any new members through extensions. /// <summary> /// Create a new VirtualTexture based on the passed mod asset. /// </summary> public static VirtualTexture CreateTexture(ModAsset metadata) => patch_VirtualContent.CreateTexture(metadata);
/// <summary> /// Undo the given override applied to the given MTexture. /// </summary> public static void UndoOverride(this MTexture self, ModAsset asset) => ((patch_MTexture)self).UndoOverride(asset);
/// <summary> /// Loads an FMOD Bank from the given asset. /// </summary> public static Bank IngestBank(ModAsset asset) => patch_Audio.IngestBank(asset);
/// <summary> /// Loads an FMOD GUID table from the given asset. /// </summary> public static void IngestGUIDs(ModAsset asset) => patch_Audio.IngestGUIDs(asset);
/// <summary> /// Feed the given ModAsset into the atlas. /// </summary> public static void Ingest(this Atlas atlas, ModAsset asset) { if (asset == null) { return; } // Crawl through all child assets. if (asset.Type == typeof(AssetTypeDirectory)) { lock (asset.Children) { foreach (ModAsset child in asset.Children) { atlas.Ingest(child); } } return; } // Forcibly add the mod content to the atlas. if (asset.Type != typeof(Texture2D)) { return; } string parentPath = atlas.GetDataPath(); if (parentPath.StartsWith(Everest.Content.PathContentOrig)) { parentPath = parentPath.Substring(Everest.Content.PathContentOrig.Length + 1); } parentPath = parentPath.Replace('\\', '/'); string path = asset.PathVirtual; if (!path.StartsWith(parentPath + "/")) { return; } path = path.Substring(parentPath.Length + 1); Logger.Log(LogLevel.Verbose, "Atlas.Ingest", $"{Path.GetFileName(atlas.GetDataPath())} + ({asset.Source?.Name ?? "???"}) {path}"); MTexture mtex; Dictionary <string, MTexture> textures = atlas.GetTextures(); if (textures.TryGetValue(path, out mtex)) { mtex.SetOverride(asset); } else { VirtualTexture vtex = VirtualContentExt.CreateTexture(asset); MTextureMeta meta = asset.GetMeta <MTextureMeta>(); if (meta != null) { // Apply width and height from meta. if (meta.Width == 0) { meta.Width = vtex.Width; } if (meta.Height == 0) { meta.Height = vtex.Height; } mtex = new MTexture(vtex, new Vector2(meta.X, meta.Y), meta.Width, meta.Height); } else { // Apply width and height from replacement texture. mtex = new MTexture(vtex); } mtex.AtlasPath = path; mtex.SetAtlas(atlas); mtex.SetOverride(asset); } atlas.ResetCaches(); atlas[path] = mtex; }
private static SkinModHelperConfig LoadConfigFile(ModAsset skinConfigYaml) { return(skinConfigYaml.Deserialize <SkinModHelperConfig>()); }
/// <summary> /// Feed the given ModAsset into the atlas. /// </summary> public static void Ingest(this Atlas self, ModAsset asset) { // Crawl through all child assets. if (asset.Type == typeof(AssetTypeDirectory)) { foreach (ModAsset child in asset.Children) { self.Ingest(child); } return; } // Forcibly add the mod content to the atlas. if (asset.Type == typeof(Texture2D)) { Logger.Log(LogLevel.Verbose, "Atlas.Ingest", $"{self.GetDataPath()} + {asset.PathVirtual}"); string parentPath = self.GetDataPath(); if (parentPath.StartsWith(Everest.Content.PathContentOrig)) { parentPath = parentPath.Substring(Everest.Content.PathContentOrig.Length + 1); } parentPath = parentPath.Replace('\\', '/'); bool lq = false; string path = asset.PathVirtual; if (path.StartsWith(parentPath + "LQ/")) { lq = true; path = path.Substring(parentPath.Length + 3); } else if (path.StartsWith(parentPath + "/")) { path = path.Substring(parentPath.Length + 1); } else { return; } VirtualTexture vtex = VirtualContentExt.CreateTexture(asset); MTexture mtex; MTextureMeta meta = asset.GetMeta <MTextureMeta>(); if (meta != null) { if (meta.Width == 0) { meta.Width = vtex.Width; } if (meta.Height == 0) { meta.Height = vtex.Height; } } Dictionary <string, MTexture> textures = self.GetTextures(); MTexture existing; if (textures.TryGetValue(path, out existing)) { if (lq && !CoreModule.Settings.LQAtlas) { return; } if (existing.Texture.GetMetadata() == asset) { return; // We're the currently active overlay. } if (meta != null) { // Apply width and height from existing meta. existing.AddOverride(vtex, new Vector2(meta.X, meta.Y), meta.Width, meta.Height); } else { // Keep width and height from existing instance. existing.AddOverride(vtex, existing.DrawOffset, existing.Width, existing.Height); } mtex = existing; } else { if (meta != null) { // Apply width and height from existing meta. mtex = new MTexture(vtex, new Vector2(meta.X, meta.Y), meta.Width, meta.Height); } else { // Apply width and height from replacement texture. mtex = new MTexture(vtex); } mtex.SetAtlasPath(path); } VTextureToMTextureMap[vtex.Name] = mtex; self[path] = mtex; if (!self.Sources.Contains(vtex)) { self.Sources.Add(vtex); } return; } }
/// <summary> /// Feed the given ModAsset into the atlas. /// </summary> public static void Ingest(this Atlas self, ModAsset asset) => ((patch_Atlas)self).Ingest(asset);
public void Ingest(ModAsset asset) { if (asset == null) { return; } // Crawl through all child assets. if (asset.Type == typeof(AssetTypeDirectory)) { lock (asset.Children) { foreach (ModAsset child in asset.Children) { Ingest(child); } } return; } // Forcibly add the mod content to the atlas. if (asset.Type != typeof(Texture2D)) { return; } string path = asset.PathVirtual; if (!path.StartsWith(RelativeDataPath)) { return; } path = path.Substring(RelativeDataPath.Length); if (textures.TryGetValue(path, out MTexture mtex)) { Logger.Log(LogLevel.Verbose, "Atlas.Ingest", $"{Path.GetFileName(DataPath)} + ({asset.Source?.Name ?? "???"}) {path}"); mtex.SetOverride(asset); this[path] = mtex; return; } VirtualTexture vtex; try { vtex = VirtualContentExt.CreateTexture(asset); } catch { // The game is going to crash from this. Log the offending texture to make debugging easier. Logger.Log(LogLevel.Verbose, "Atlas.Ingest", $"Error while loading texture {path} ({asset.Source?.Name ?? "???"}) into atlas {Path.GetFileName(DataPath)}"); throw; } MTextureMeta meta = asset.GetMeta <MTextureMeta>(); if (meta != null) { // Apply width and height from meta. if (meta.Width == 0) { meta.Width = vtex.Width; } if (meta.Height == 0) { meta.Height = vtex.Height; } mtex = new MTexture(vtex, new Vector2(meta.X, meta.Y), meta.Width, meta.Height); } else { // Apply width and height from replacement texture. mtex = new MTexture(vtex); } mtex.AtlasPath = path; mtex.SetAtlas(this); mtex.SetOverride(asset); this[path] = mtex; Sources.Add(vtex); }