/// <summary> /// Converts to the format /// </summary> /// <returns>The task</returns> public override async Task ConvertToAsync() { var attr = GameModeSelection.SelectedValue.GetAttribute <OpenSpaceGameModeInfoAttribute>(); var settings = OpenSpaceSettings.GetDefaultSettings(attr.Game, attr.Platform); await ConvertToAsync <OpenSpaceGFFile>(settings, (filePath, format) => { // Create the GF data var gf = new OpenSpaceGFFile { // Set the .gf format GFPixelFormat = Enum.Parse(typeof(OpenSpaceGFFormat), format).CastTo <OpenSpaceGFFormat>() }; // Read the image using var bmp = new Bitmap(filePath); // IDEA: If bmp is not in supported format, then convert it? // Import from the bitmap gf.ImportFromBitmap(settings, new RawBitmapData(bmp), RCPServices.Data.Archive_GF_GenerateMipmaps); // Return the data return(gf); }, new FileFilterItemCollection(ImageHelpers.GetSupportedBitmapExtensions().Select(x => new FileFilterItem($"*{x}", x.Substring(1).ToUpper()))).ToString(), new FileExtension(".gf"), Enum.GetNames(typeof(OpenSpaceGFFormat))); }
/// <summary> /// Default constructor /// </summary> /// <param name="fileEntry">The file data</param> /// <param name="settings">The settings when serializing the data</param> /// <param name="directory">The directory the file is located under</param> public OpenSpaceCntArchiveFileData(OpenSpaceCntFileEntry fileEntry, OpenSpaceSettings settings, string directory) { Directory = directory; FileEntry = fileEntry; FileName = FileEntry.FileName; Settings = settings; }
/// <summary> /// Converts the file data from the specified format /// </summary> /// <param name="inputFormat">The format to convert from</param> /// <param name="outputFormat">The format to convert to</param> /// <param name="currentFileStream">The current file stream</param> /// <param name="inputStream">The input file data stream to convert from</param> /// <param name="outputStream">The output stream for the converted data</param> /// <param name="manager">The manager</param> public void ConvertFrom(FileExtension inputFormat, FileExtension outputFormat, ArchiveFileStream currentFileStream, ArchiveFileStream inputStream, ArchiveFileStream outputStream, IArchiveDataManager manager) { // Load the bitmap using Bitmap bmp = new(inputStream.Stream); // Load the current file GF gf = GetFileContent(currentFileStream, manager); // IDEA: If bmp is not in supported format, then convert it? RawBitmapData rawBitmapData; // Get the bitmap lock using (BitmapLock bmpLock = new(bmp)) { // Get the raw bitmap data rawBitmapData = new RawBitmapData(bmp.Width, bmp.Height, bmpLock.Pixels, bmp.PixelFormat); // Force the new pixel format to be 888 or 8888 if set to do so if (Services.Data.Archive_GF_ForceGF8888Import) { gf.PixelFormat = gf.PixelFormat.SupportsTransparency() ? GF_Format.Format_32bpp_BGRA_8888 : GF_Format.Format_24bpp_BGR_888; } // Check if the format should be updated for transparency if (Services.Data.Archive_GF_UpdateTransparency != UserData_Archive_GF_TransparencyMode.PreserveFormat) { // NOTE: Only 24 and 32 bpp bitmaps are supported // Check if the imported file is transparent bool?isTransparent = bmp.PixelFormat switch { PixelFormat.Format32bppArgb => (Services.Data.Archive_GF_UpdateTransparency == UserData_Archive_GF_TransparencyMode.UpdateBasedOnPixelFormat || bmpLock.UtilizesAlpha()), PixelFormat.Format24bppRgb => false, _ => null }; // NOTE: Currently only supported for formats with 3 or 4 channels // Check if the format should be updated for transparency if (gf.Channels >= 3 && isTransparent != null) { // Update the format gf.PixelFormat = isTransparent.Value ? GF_Format.Format_32bpp_BGRA_8888 : GF_Format.Format_24bpp_BGR_888; } } } byte oldRepeatByte = gf.RepeatByte; OpenSpaceSettings settings = manager.Context !.GetSettings <OpenSpaceSettings>(); // Import the bitmap gf.ImportFromBitmap(settings, rawBitmapData, Services.Data.Archive_GF_GenerateMipmaps); Logger.Debug("The repeat byte has been updated for a .gf file from {0} to {1}", oldRepeatByte, gf.RepeatByte); // Serialize the data to get the bytes manager.Context.WriteStreamData(outputStream.Stream, gf, name: outputStream.Name, leaveOpen: true); }
/// <summary> /// Opens the archive explorer /// </summary> /// <returns>The task</returns> public async Task OpenAsync() { var attr = GameMode.GetAttribute <OpenSpaceGameModeInfoAttribute>(); var settings = OpenSpaceSettings.GetDefaultSettings(attr.Game, attr.Platform); // Show the archive explorer await RCPServices.UI.ShowArchiveExplorerAsync(new OpenSpaceCntArchiveExplorerDataManager(settings), ArchiveFiles.Where(x => x.FileExists)); }
/// <summary> /// Gets the file extension for the level data files /// </summary> /// <param name="gameSettings">The settings</param> /// <returns>The file extension</returns> protected string GetLevelFileExtension(OpenSpaceSettings gameSettings) { return(gameSettings.EngineVersion switch { OpenSpaceEngineVersion.Rayman2 => ".sna", OpenSpaceEngineVersion.Rayman3 => ".lvl", _ => throw new ArgumentOutOfRangeException(nameof(gameSettings.EngineVersion), gameSettings.EngineVersion, null) });
/// <summary> /// Imports an exported save slot to the save slot from the specified path /// </summary> /// <param name="inputFilePath">The input file path</param> /// <returns>The task</returns> protected override Task ImportSaveDataAsync(FileSystemPath inputFilePath) { // Deserialize the input data var data = JsonHelpers.DeserializeFromFile <RaymanMPCSaveData>(inputFilePath); // Import the data BinarySerializableHelpers.WriteToFile(data, SaveSlotFilePath, OpenSpaceSettings.GetDefaultSettings(OpenSpaceGame.RaymanM, Platform.PC), RCPServices.App.GetBinarySerializerLogger()); return(Task.CompletedTask); }
/// <summary> /// Default constructor /// </summary> /// <param name="settings">The settings when serializing the data</param> public OpenSpaceCntArchiveDataManager(OpenSpaceSettings settings) { Settings = settings; Context = new RCPContext(String.Empty, new RCPSerializerSettings() { DefaultEndianness = settings.GetEndian }); Context.AddSettings(settings); }
/// <summary> /// Converts to the format /// </summary> /// <returns>The task</returns> public override async Task ConvertToAsync() { var settings = OpenSpaceSettings.GetDefaultSettings(OpenSpaceGame.Rayman2, Platform.PC); await ConvertToAsync(settings, (filePath, format) => { // Read the data return(DeserializeJSON <Rayman2PCConfigData>(filePath)); }, new FileFilterItem("*.json", "JSON").ToString(), new FileExtension(".cfg"), null, new Rayman12PCSaveDataEncoder()); }
/// <summary> /// Converts to the format /// </summary> /// <returns>The task</returns> public override async Task ConvertToAsync() { var settings = OpenSpaceSettings.GetDefaultSettings(OpenSpaceGame.Rayman3, GameModeSelection.SelectedValue); await ConvertToAsync(settings, (filePath, format) => { // Read the data return(DeserializeJSON <Rayman3PCSaveData>(filePath)); }, new FileFilterItem("*.json", "JSON").ToString(), new FileExtension(".sav"), null, new Rayman3SaveDataEncoder()); }
/// <summary> /// Converts to the format /// </summary> /// <returns>The task</returns> public override async Task ConvertToAsync() { var attr = GameModeSelection.SelectedValue.GetAttribute <OpenSpaceGameModeInfoAttribute>(); var settings = OpenSpaceSettings.GetDefaultSettings(attr.Game, attr.Platform); await ConvertToAsync(settings, (filePath, format) => { // Read the data return(DeserializeJSON <RaymanMPCSaveData>(filePath)); }, new FileFilterItem("*.json", "JSON").ToString(), new FileExtension(".sav")); }
/// <summary> /// Synchronizes the texture info for the selected game data directory /// </summary> /// <returns>The task</returns> public async Task SyncTextureInfoAsync() { OpenSpaceGameModeInfoAttribute attr = GameModeSelection.SelectedValue.GetAttribute <OpenSpaceGameModeInfoAttribute>(); DirectoryBrowserResult result = await Services.BrowseUI.BrowseDirectoryAsync(new DirectoryBrowserViewModel() { Title = Resources.Utilities_SyncTextureInfo_SelectDirHeader, DefaultDirectory = attr.Game?.GetInstallDir(false) ?? FileSystemPath.EmptyPath }); if (result.CanceledByUser) { return; } try { IsLoading = true; TextureInfoEditResult syncResult = await Task.Run(() => { // Get the settings OpenSpaceSettings gameSettings = attr.GetSettings(); // Get the file extension for the level data files var fileExt = GetLevelFileExtension(gameSettings); // Get the level data files var dataFiles = Directory.GetFiles(result.SelectedDirectory, $"*{fileExt}", SearchOption.AllDirectories).Select(x => new FileSystemPath(x)); // Get the .cnt file names var fileNames = GetCntFileNames(gameSettings); // Get the full paths and only keep the ones which exist var cntFiles = fileNames.Select(x => result.SelectedDirectory + x).Where(x => x.FileExists); // Sync the texture info return(EditTextureInfo(gameSettings, dataFiles, cntFiles)); }); await Services.MessageUI.DisplaySuccessfulActionMessageAsync(String.Format(Resources.Utilities_SyncTextureInfo_Success, syncResult.EditedTextures, syncResult.TotalTextures)); } catch (Exception ex) { Logger.Error(ex, "Syncing texture info"); await Services.MessageUI.DisplayExceptionMessageAsync(ex, Resources.Utilities_SyncTextureInfo_Error); } finally { IsLoading = false; } }
/// <summary> /// Converts from the format /// </summary> /// <returns>The task</returns> public override async Task ConvertFromAsync() { var settings = OpenSpaceSettings.GetDefaultSettings(OpenSpaceGame.Rayman3, GameModeSelection.SelectedValue); await ConvertFromAsync <Rayman3PCSaveData>(settings, (data, filePath) => { // Save the data SerializeJSON(data, filePath); }, new FileFilterItem("*.sav", "SAV").ToString(), new[] { ".json" }, Games.Rayman3.GetInstallDir(false), new Rayman3SaveDataEncoder()); }
/// <summary> /// Converts from the format /// </summary> /// <returns>The task</returns> public override async Task ConvertFromAsync() { var settings = OpenSpaceSettings.GetDefaultSettings(OpenSpaceGame.Rayman2, Platform.PC); await ConvertFromAsync <Rayman2PCConfigData>(settings, (data, filePath) => { // Save the data SerializeJSON(data, filePath); }, new FileFilterItem("*.cfg", "CFG").ToString(), new[] { ".json" }, Games.Rayman2.GetInstallDir(false), new Rayman12PCSaveDataEncoder()); }
/// <summary> /// Synchronizes the texture info for the selected game data directory /// </summary> /// <returns>The task</returns> public async Task SyncTextureInfoAsync() { try { IsLoading = true; TextureInfoEditResult syncResult = await Task.Run(() => { // Get the game install directory FileSystemPath installDir = Game.GetInstallDir(); // Get the settings OpenSpaceGameModeInfoAttribute attr = GameMode.GetAttribute <OpenSpaceGameModeInfoAttribute>(); OpenSpaceSettings gameSettings = attr.GetSettings(); // Get the file extension for the level data files string fileExt = GetLevelFileExtension(gameSettings); // Get the level data files IEnumerable <FileSystemPath> dataFiles = GameDataDirNames. Select(x => Directory.GetFiles(installDir + x, $"*{fileExt}", SearchOption.AllDirectories). Select(y => new FileSystemPath(y))). SelectMany(x => x); // Get the .cnt file names string[] fileNames = GetCntFileNames(gameSettings); // Get the full paths and only keep the ones which exist IEnumerable <FileSystemPath> cntFiles = GameDataDirNames. Select(dataDir => fileNames. Select(cnt => installDir + dataDir + cnt). Where(cntPath => cntPath.FileExists)). SelectMany(x => x); // Sync the texture info return(EditTextureInfo(gameSettings, dataFiles, cntFiles)); }); await Services.MessageUI.DisplaySuccessfulActionMessageAsync(String.Format(Resources.Utilities_SyncTextureInfo_Success, syncResult.EditedTextures, syncResult.TotalTextures)); } catch (Exception ex) { Logger.Error(ex, "Syncing texture info"); await Services.MessageUI.DisplayExceptionMessageAsync(ex, Resources.Utilities_SyncTextureInfo_Error); } finally { IsLoading = false; } }
/// <summary> /// Converts from the format /// </summary> /// <returns>The task</returns> public override async Task ConvertFromAsync() { var attr = GameModeSelection.SelectedValue.GetAttribute <OpenSpaceGameModeInfoAttribute>(); var settings = OpenSpaceSettings.GetDefaultSettings(attr.Game, attr.Platform); await ConvertFromAsync <RaymanMPCSaveData>(settings, (data, filePath) => { // Save the data SerializeJSON(data, filePath); }, new FileFilterItem("*.sav", "SAV").ToString(), new[] { ".json" }, GameModeSelection.SelectedValue.GetGame()?.GetInstallDir(false)); }
/// <summary> /// Converts from the format /// </summary> /// <returns>The task</returns> public override async Task ConvertFromAsync() { var attr = GameModeSelection.SelectedValue.GetAttribute <OpenSpaceGameModeInfoAttribute>(); var settings = OpenSpaceSettings.GetDefaultSettings(attr.Game, attr.Platform); await ConvertFromAsync <OpenSpaceGFFile>(settings, (data, filePath) => { // Get a bitmap from the image data using var bmp = data.GetRawBitmapData().GetBitmap(); // Save the image bmp.Save(filePath, ImageHelpers.GetImageFormat(filePath.FileExtension)); }, new FileFilterItem("*.gf", "GF").ToString(), ImageHelpers.GetSupportedBitmapExtensions(), null); }
/// <summary> /// Imports an exported save slot to the save slot from the specified path /// </summary> /// <param name="inputFilePath">The input file path</param> /// <returns>The task</returns> protected override Task ImportSaveDataAsync(FileSystemPath inputFilePath) { // Deserialize the input data var data = JsonHelpers.DeserializeFromFile <Rayman3PCSaveData>(inputFilePath); // Create streams using var decodedDataStream = new MemoryStream(); using var saveFileStream = File.Create(SaveSlotFilePath); // Import the data BinarySerializableHelpers.WriteToStream(data, decodedDataStream, OpenSpaceSettings.GetDefaultSettings(OpenSpaceGame.Rayman3, Platform.PC), RCPServices.App.GetBinarySerializerLogger()); // Set position to 0 decodedDataStream.Position = 0; // Encode the data to the file new Rayman3SaveDataEncoder().Encode(decodedDataStream, saveFileStream); return(Task.CompletedTask); }
/// <summary> /// Get the progression slot view model for the save data from the specified file /// </summary> /// <param name="filePath">The slot file path</param> /// <param name="slotName">The generator for the name of the save slot</param> /// <returns>The progression slot view model</returns> protected ProgressionSlotViewModel GetProgressionSlotViewModel(FileSystemPath filePath, string slotName) { RL.Logger?.LogInformationSource($"Rayman 2 slot {slotName} is being loaded..."); // Make sure the file exists if (!filePath.FileExists) { RL.Logger?.LogInformationSource($"Slot was not loaded due to not being found"); return(null); } // Open the file in a stream using var fileStream = File.Open(filePath, FileMode.Open, FileAccess.Read); // Create a memory stream using var memStream = new MemoryStream(); // Decode the data new Rayman12PCSaveDataEncoder().Decode(fileStream, memStream); // Set the position memStream.Position = 0; // Deserialize and return the data var saveData = BinarySerializableHelpers.ReadFromStream <Rayman2PCSaveData>(memStream, OpenSpaceSettings.GetDefaultSettings(OpenSpaceGame.Rayman2, Platform.PC), RCPServices.App.GetBinarySerializerLogger()); RL.Logger?.LogInformationSource($"Slot has been deserialized"); // Get the bit array var array = saveData.GlobalArrayAsBitFlags(); // Get total amount of Lums and cages var lums = array.Skip(0).Take(800).Select(x => x ? 1 : 0).Sum() + array.Skip(1200).Take(194).Select(x => x ? 1 : 0).Sum() + // Woods of Light array.Skip(1395).Take(5).Select(x => x ? 1 : 0).Sum() + // 1000th Lum (array[1013] ? 1 : 0); var cages = array.Skip(839).Take(80).Select(x => x ? 1 : 0).Sum(); var walkOfLifeTime = saveData.GlobalArray[12] * 10; var walkOfPowerTime = saveData.GlobalArray[11] * 10; // Create the collection with items for cages + lives var progressItems = new List <ProgressionInfoItemViewModel> { new ProgressionInfoItemViewModel(ProgressionIcons.R2_Lum, new LocalizedString(() => $"{lums}/1000")), new ProgressionInfoItemViewModel(ProgressionIcons.R2_Cage, new LocalizedString(() => $"{cages}/80")), }; if (walkOfLifeTime > 120) { progressItems.Add(new ProgressionInfoItemViewModel(ProgressionIcons.R2_Clock, new LocalizedString(() => $"{new TimeSpan(0, 0, 0, 0, walkOfLifeTime):mm\\:ss\\:ff}"), new LocalizedString(() => Resources.R2_BonusLevelName_1))); } if (walkOfPowerTime > 120) { progressItems.Add(new ProgressionInfoItemViewModel(ProgressionIcons.R2_Clock, new LocalizedString(() => $"{new TimeSpan(0, 0, 0, 0, walkOfPowerTime):mm\\:ss\\:ff}"), new LocalizedString(() => Resources.R2_BonusLevelName_2))); } RL.Logger?.LogInformationSource($"General progress info has been set"); // Get the name and percentage var separatorIndex = slotName.LastIndexOf((char)0x20); var name = slotName.Substring(0, separatorIndex); var percentage = slotName.Substring(separatorIndex + 1); RL.Logger?.LogInformationSource($"Slot percentage is {percentage}%"); // Return the data with the collection return(new Rayman2ProgressionSlotViewModel(new LocalizedString(() => $"{name} ({percentage}%)"), progressItems.ToArray(), filePath, this)); }
/// <summary> /// Loads the current save data if available /// </summary> protected override void LoadData() { // Make sure the file exists if (!ConfigFilePath.FileExists) { return; } // Create streams using var saveFileStream = File.OpenRead(ConfigFilePath); using var decodedDataStream = new MemoryStream(); // Decode the save file new Rayman12PCSaveDataEncoder().Decode(saveFileStream, decodedDataStream); // Set position to 0 decodedDataStream.Position = 0; // Get the serialized data var config = BinarySerializableHelpers.ReadFromStream <Rayman2PCConfigData>(decodedDataStream, OpenSpaceSettings.GetDefaultSettings(OpenSpaceGame.Rayman2, Platform.PC), RCPServices.App.GetBinarySerializerLogger()); // Read and set slot data ProgressionSlots.AddRange(config.Slots.Select(x => GetProgressionSlotViewModel(SaveGamePath + $"Slot{x.SlotIndex}" + "General.sav", x.SlotDisplayName))); }
/// <summary> /// Default constructor /// </summary> /// <param name="settings">The settings when serializing the data</param> protected BaseOpenSpaceCntArchiveDataManager(OpenSpaceSettings settings) { Settings = settings; }
/// <summary> /// Exports the save slot from the specified path /// </summary> /// <param name="outputFilePath">The output file path</param> /// <returns>The task</returns> protected override Task ExportSaveDataAsync(FileSystemPath outputFilePath) { // Create streams using var saveFileStream = File.OpenRead(SaveSlotFilePath); using var decodedDataStream = new MemoryStream(); // Decode the save file new Rayman3SaveDataEncoder().Decode(saveFileStream, decodedDataStream); // Set position to 0 decodedDataStream.Position = 0; // Get the serialized data var data = BinarySerializableHelpers.ReadFromStream <Rayman3PCSaveData>(decodedDataStream, OpenSpaceSettings.GetDefaultSettings(OpenSpaceGame.Rayman3, Platform.PC), RCPServices.App.GetBinarySerializerLogger()); // Export the data JsonHelpers.SerializeToFile(data, outputFilePath); return(Task.CompletedTask); }
/// <summary> /// Get the progression slot view models for the save data from the specified file /// </summary> /// <param name="filePath">The slot file path</param> /// <returns>The progression slot view models</returns> protected IEnumerable <ProgressionSlotViewModel> GetProgressionSlotViewModels(FileSystemPath filePath) { RL.Logger?.LogInformationSource($"Rayman M/Arena save file {filePath.Name} is being loaded..."); // Make sure the file exists if (!filePath.FileExists) { RL.Logger?.LogInformationSource($"Slot was not loaded due to not being found"); yield break; } // Deserialize the save data var saveData = BinarySerializableHelpers.ReadFromFile <RaymanMPCSaveData>(filePath, OpenSpaceSettings.GetDefaultSettings(OpenSpaceGame.RaymanM, Platform.PC), RCPServices.App.GetBinarySerializerLogger()); RL.Logger?.LogInformationSource($"Save file has been deserialized"); // Helper for getting the entry with a specific key int[] GetValues(string key) => saveData.Items.First(x => x.Key == key).Values;
/// <summary> /// Exports the save slot from the specified path /// </summary> /// <param name="outputFilePath">The output file path</param> /// <returns>The task</returns> protected override Task ExportSaveDataAsync(FileSystemPath outputFilePath) { // Get the serialized data var data = BinarySerializableHelpers.ReadFromFile <RaymanMPCSaveData>(SaveSlotFilePath, OpenSpaceSettings.GetDefaultSettings(OpenSpaceGame.RaymanM, Platform.PC), RCPServices.App.GetBinarySerializerLogger()); // Export the data JsonHelpers.SerializeToFile(data, outputFilePath); return(Task.CompletedTask); }
/// <summary> /// Default constructor /// </summary> /// <param name="settings">The settings when serializing the data</param> public OpenSpaceCntArchiveExplorerDataManager(OpenSpaceSettings settings) : base(settings) { }
/// <summary> /// Get the progression slot view model for the save data from the specified file /// </summary> /// <param name="filePath">The slot file path</param> /// <returns>The progression slot view model</returns> protected ProgressionSlotViewModel GetProgressionSlotViewModel(FileSystemPath filePath) { RL.Logger?.LogInformationSource($"Rayman 3 slot {filePath.Name} is being loaded..."); // Make sure the file exists if (!filePath.FileExists) { RL.Logger?.LogInformationSource($"Slot was not loaded due to not being found"); return(null); } // Open the file in a stream using var fileStream = File.Open(filePath, FileMode.Open, FileAccess.Read); // Create a memory stream using var memStream = new MemoryStream(); // Decode the data new Rayman3SaveDataEncoder().Decode(fileStream, memStream); // Set the position memStream.Position = 0; // Deserialize the data var saveData = BinarySerializableHelpers.ReadFromStream <Rayman3PCSaveData>(memStream, OpenSpaceSettings.GetDefaultSettings(OpenSpaceGame.Rayman3, Platform.PC), RCPServices.App.GetBinarySerializerLogger()); RL.Logger?.LogInformationSource($"Slot has been deserialized"); var formatInfo = new NumberFormatInfo() { NumberGroupSeparator = " ", NumberDecimalDigits = 0 }; // Create the collection with items for each level + general information var progressItems = new ProgressionInfoItemViewModel[] { new ProgressionInfoItemViewModel(ProgressionIcons.R3_Cage, new LocalizedString(() => $"{saveData.TotalCages}/60")), new ProgressionInfoItemViewModel(ProgressionIcons.R3_Score, new LocalizedString(() => $"{Resources.Progression_R3_TotalHeader}: {saveData.TotalScore.ToString("n", formatInfo)}")), new ProgressionInfoItemViewModel(ProgressionIcons.R3_Score, new LocalizedString(() => $"{Resources.Progression_R3_Level1Header}: {saveData.Levels[0].Score.ToString("n", formatInfo)}")), new ProgressionInfoItemViewModel(ProgressionIcons.R3_Score, new LocalizedString(() => $"{Resources.Progression_R3_Level2Header}: {saveData.Levels[1].Score.ToString("n", formatInfo)}")), new ProgressionInfoItemViewModel(ProgressionIcons.R3_Score, new LocalizedString(() => $"{Resources.Progression_R3_Level3Header}: {saveData.Levels[2].Score.ToString("n", formatInfo)}")), new ProgressionInfoItemViewModel(ProgressionIcons.R3_Score, new LocalizedString(() => $"{Resources.Progression_R3_Level4Header}: {saveData.Levels[3].Score.ToString("n", formatInfo)}")), new ProgressionInfoItemViewModel(ProgressionIcons.R3_Score, new LocalizedString(() => $"{Resources.Progression_R3_Level5Header}: {saveData.Levels[4].Score.ToString("n", formatInfo)}")), new ProgressionInfoItemViewModel(ProgressionIcons.R3_Score, new LocalizedString(() => $"{Resources.Progression_R3_Level6Header}: {saveData.Levels[5].Score.ToString("n", formatInfo)}")), new ProgressionInfoItemViewModel(ProgressionIcons.R3_Score, new LocalizedString(() => $"{Resources.Progression_R3_Level7Header}: {saveData.Levels[6].Score.ToString("n", formatInfo)}")), new ProgressionInfoItemViewModel(ProgressionIcons.R3_Score, new LocalizedString(() => $"{Resources.Progression_R3_Level8Header}: {saveData.Levels[7].Score.ToString("n", formatInfo)}")), new ProgressionInfoItemViewModel(ProgressionIcons.R3_Score, new LocalizedString(() => $"{Resources.Progression_R3_Level9Header}: {saveData.Levels[8].Score.ToString("n", formatInfo)}")) }; RL.Logger?.LogInformationSource($"General progress info has been set"); // Return the data with the collection return(new Rayman3ProgressionSlotViewModel(new LocalizedString(() => $"{filePath.RemoveFileExtension().Name}"), progressItems, filePath, this)); }
/// <summary> /// Imports a bitmap image into the file, keeping the structure based on the properties and generating mipmaps if needed. This will reset the mipmaps, requiring them to be generated again. /// </summary> /// <param name="gf">The GF file data</param> /// <param name="settings">The serializer settings</param> /// <param name="bmp">The bitmap data to import from</param> /// <param name="generateMipmaps">Indicates if mipmaps should be generated for the image</param> public static void ImportFromBitmap(this GF gf, OpenSpaceSettings settings, RawBitmapData bmp, bool generateMipmaps) { // Helper method for writing the pixel data void WritePixelData(RawBitmapData bitmapData, long offset) { // Make sure the pixel format is supported if (bitmapData.PixelFormat != PixelFormat.Format32bppArgb && bitmapData.PixelFormat != PixelFormat.Format24bppRgb) { throw new Exception($"The bitmap pixel format {bitmapData.PixelFormat} is not supported for importing"); } // Get the number of bitmap channels int bmpChannels = Image.GetPixelFormatSize(bitmapData.PixelFormat) / 8; // Get the format GF_Format format = gf.PixelFormat; byte[] bmpColorData = new byte[4]; for (uint y = 0; y < bitmapData.Height; y++) { for (uint x = 0; x < bitmapData.Width; x++) { // Get the offsets for the pixel colors var pixelOffset = (bitmapData.Width * y + x) * gf.Channels + offset; // NOTE: We reverse the Y-axis here since the .gf images are always flipper vertically var rawOffset = (bitmapData.Width * (bitmapData.Height - y - 1) + x) * bmpChannels; // Get the bitmap color bytes for this pixel bmpColorData[0] = bitmapData.PixelData[rawOffset + 0]; bmpColorData[1] = bitmapData.PixelData[rawOffset + 1]; bmpColorData[2] = bitmapData.PixelData[rawOffset + 2]; bmpColorData[3] = bmpChannels == 4 ? bitmapData.PixelData[rawOffset + 3] : (byte)255; // Get the pixels foreach (var b in gf.GetGfPixelBytes(format, bmpColorData)) { gf.PixelData[pixelOffset] = b; pixelOffset++; } } } } // Set size gf.Width = bmp.Width; gf.Height = bmp.Height; // Set the pixel count gf.PixelCount = gf.Width * gf.Height; // Update the mipmap count if (generateMipmaps && gf.SupportsMipmaps(settings)) { gf.MipmapsCount = gf.DeterminePreferredMipmapsCount(); } else { gf.MipmapsCount = 0; } // Enumerate each mipmap size foreach ((int Width, int Height)size in gf.GetExclusiveMipmapSizes()) { // Get the mipmap pixel count var count = size.Width * size.Height; // Add to the total pixel count gf.PixelCount += count; } // Create the data array gf.PixelData = new byte[gf.Channels * gf.PixelCount]; // Set the main pixel data WritePixelData(bmp, 0); // Keep track of the offset long mipmapOffset = gf.Width * gf.Height * gf.Channels; // Generate mipmaps if available if (gf.ExclusiveMipmapCount > 0) { // Get the bitmap using Bitmap bitmap = bmp.GetBitmap(); // Generate every mipmap foreach ((int Width, int Height)size in gf.GetExclusiveMipmapSizes()) { // Resize the bitmap using Bitmap resizedBmp = bitmap.ResizeImage(size.Width, size.Height, false); // Write the mipmap WritePixelData(new RawBitmapData(resizedBmp), mipmapOffset); // Increase the index mipmapOffset += size.Height * size.Width * gf.Channels; } } // Update the repeat byte gf.UpdateRepeatByte(); }
/// <summary> /// Default constructor /// </summary> /// <param name="settings">The settings when serializing the data</param> public OpenSpaceCntArchiveCreatorDataManager(OpenSpaceSettings settings) : base(settings) { }