From efdfb70be22af7bea1f9b02ad8ba8f8cc9c7b536 Mon Sep 17 00:00:00 2001 From: "Josh (vector_cmdr)" Date: Sun, 15 Feb 2026 02:06:38 +1100 Subject: [PATCH] Fix: Map Design Import/Export Previous fix for bad map design imports had an incorrect range and no way to manage v2.0.8- and v3.0.0+ dumps. Import/Export for map design patterns now supports both map sizes and will accept 2.0.8 dumps and pad them to work on 3.0.0 as well as trim previously mangled ones, or 3.0.0 dumps down to fit on 2.0.8 saves. Will also warn user for trimmable or unusable dumps. Byte padding methods added to ArrayUtil for this padding and for future flag padding. --- .../Resources/text/de/MessageStrings_de.txt | 1 + .../Resources/text/en/MessageStrings_en.txt | 1 + .../Resources/text/es/MessageStrings_es.txt | 1 + .../Resources/text/fr/MessageStrings_fr.txt | 1 + .../Resources/text/it/MessageStrings_it.txt | 1 + .../Resources/text/jp/MessageStrings_jp.txt | 1 + .../Resources/text/ko/MessageStrings_ko.txt | 1 + .../Resources/text/zhs/MessageStrings_zhs.txt | 1 + .../Resources/text/zht/MessageStrings_zht.txt | 1 + NHSE.Core/Save/Files/MainSave.cs | 12 +- NHSE.Core/Util/ArrayUtil.cs | 60 +++++++++ NHSE.WinForms/Subforms/Map/FieldItemEditor.cs | 32 +++-- .../Subforms/Map/FieldItemEditor.resx | 6 +- NHSE.WinForms/Subforms/Map/MapDumpHelper.cs | 115 ++++++++++++++++++ NHSE.WinForms/Util/MessageStrings.cs | 1 + 15 files changed, 209 insertions(+), 26 deletions(-) diff --git a/NHSE.Core/Resources/text/de/MessageStrings_de.txt b/NHSE.Core/Resources/text/de/MessageStrings_de.txt index 1724f0d..ecf9a3f 100644 --- a/NHSE.Core/Resources/text/de/MessageStrings_de.txt +++ b/NHSE.Core/Resources/text/de/MessageStrings_de.txt @@ -1,6 +1,7 @@ MsgBackupCreateLocation=NHSE can perform automatic backups if you create a folder with the name '{0}' in the same folder as the executable. MsgBackupCreateQuestion=Would you like NHSE to automatically keep a backup of your save data? MsgDataSizeMismatchImport=The size of the imported file (0x{0:X}) does not match the required size (0x{1:X}). +MsgDataTrimmedWarning=It will be trimmed to fit. MsgDataSizeMismatchRAM=Read size (0x{0:X}) != Write size (0x{1:X}). MsgDataDidNotOriginateFromHost_0=Imported data did not originate from Villager0 ({0})'s data. MsgAskUpdateValues=Update values? diff --git a/NHSE.Core/Resources/text/en/MessageStrings_en.txt b/NHSE.Core/Resources/text/en/MessageStrings_en.txt index 5a1891d..27fcd1b 100644 --- a/NHSE.Core/Resources/text/en/MessageStrings_en.txt +++ b/NHSE.Core/Resources/text/en/MessageStrings_en.txt @@ -1,6 +1,7 @@ MsgBackupCreateLocation=NHSE can perform automatic backups if you create a folder with the name '{0}' in the same folder as the executable. MsgBackupCreateQuestion=Would you like NHSE to automatically keep a backup of your save data? MsgDataSizeMismatchImport=The size of the imported file (0x{0:X}) does not match the required size (0x{1:X}). +MsgDataTrimmedWarning=It will be trimmed to fit. MsgDataSizeMismatchRAM=Read size (0x{0:X}) != Write size (0x{1:X}). MsgDataDidNotOriginateFromHost_0=Imported data did not originate from Villager0 ({0})'s data. MsgAskUpdateValues=Update values? diff --git a/NHSE.Core/Resources/text/es/MessageStrings_es.txt b/NHSE.Core/Resources/text/es/MessageStrings_es.txt index 2cf0094..fbdaae5 100644 --- a/NHSE.Core/Resources/text/es/MessageStrings_es.txt +++ b/NHSE.Core/Resources/text/es/MessageStrings_es.txt @@ -1,6 +1,7 @@ MsgBackupCreateLocation=NHSE puede crear un respaldos automáticos si crea una carpeta con el nombre '{0}' en la misma carpeta del ejecutable. MsgBackupCreateQuestion=¿Quisiera que NHSE cree automáticamente un respaldo de sus datos de guardado? MsgDataSizeMismatchImport=El tamaño del archivo importado (0x{0:X}) no coincide con el tamaño requerido (0x{1:X}). +MsgDataTrimmedWarning=Se recortará para que encaje. MsgDataSizeMismatchRAM=Tamaño de lectura (0x{0:X}) != Tamaño de Escritura (0x{1:X}). MsgDataDidNotOriginateFromHost_0=Los datos importados no se originaron de los datos del Aldeano ({0}). MsgAskUpdateValues=¿Actualizar valores? diff --git a/NHSE.Core/Resources/text/fr/MessageStrings_fr.txt b/NHSE.Core/Resources/text/fr/MessageStrings_fr.txt index 0e700b9..fdfe264 100644 --- a/NHSE.Core/Resources/text/fr/MessageStrings_fr.txt +++ b/NHSE.Core/Resources/text/fr/MessageStrings_fr.txt @@ -1,6 +1,7 @@ MsgBackupCreateLocation=NHSE peut effectuer des sauvegardes automatiques si vous créez un dossier portant le nom «{0}» dans le même dossier que l'exécutable. MsgBackupCreateQuestion=Souhaitez-vous que NHSE conserve automatiquement une sauvegarde de vos données de sauvegarde? MsgDataSizeMismatchImport=La taille du fichier importé (0x{0:X}) ne correspond pas à la taille requise (0x{1:X}). +MsgDataTrimmedWarning=Il sera découpé aux dimensions voulues. MsgDataSizeMismatchRAM=Taille de lecture (0x{0:X})! = Taille d'écriture (0x{1:X}). MsgDataDidNotOriginateFromHost_0=Les données importées ne proviennent pas des données de Villager0({0}). MsgAskUpdateValues=Mettre à jour les valeurs? diff --git a/NHSE.Core/Resources/text/it/MessageStrings_it.txt b/NHSE.Core/Resources/text/it/MessageStrings_it.txt index 34a43aa..ea58d59 100644 --- a/NHSE.Core/Resources/text/it/MessageStrings_it.txt +++ b/NHSE.Core/Resources/text/it/MessageStrings_it.txt @@ -1,6 +1,7 @@ MsgBackupCreateLocation=NHSE pu� fare backup automatici se crei una cartella chiamata '{0}' nella stessa cartella dell'eseguibile. MsgBackupCreateQuestion=Vuoi che NHSE faccia automaticamente un backup dei tuoi dati di salvataggio? MsgDataSizeMismatchImport=La dimensione del file importato (0x{0:X}) non corrisponde alla dimensione richiesta (0x{1:X}). +MsgDataTrimmedWarning=Verrà ritagliato per adattarlo. MsgDataSizeMismatchRAM=Dimensione letta (0x{0:X}) != Dimensione da scrivere (0x{1:X}). MsgDataDidNotOriginateFromHost_0=I dati importati non derivano dai dati del Villager0 ({0}). MsgAskUpdateValues=Aggiornare i valori? diff --git a/NHSE.Core/Resources/text/jp/MessageStrings_jp.txt b/NHSE.Core/Resources/text/jp/MessageStrings_jp.txt index 48294c8..10b3260 100644 --- a/NHSE.Core/Resources/text/jp/MessageStrings_jp.txt +++ b/NHSE.Core/Resources/text/jp/MessageStrings_jp.txt @@ -1,6 +1,7 @@ MsgBackupCreateLocation=実行可能ファイルと同じフォルダー内に '{0}' という名前のフォルダーを作成すると、NHSE は自動バックアップを実行できます。 MsgBackupCreateQuestion=NHSE がセーブ データのバックアップを自動的に保存することを希望しますか? MsgDataSizeMismatchImport=インポートされたファイル (0x{0:X}) のサイズが必要なサイズ (0x{1:X}) と一致しません。 +MsgDataTrimmedWarning=フィットするようにトリミングされます。 MsgDataSizeMismatchRAM=読み取りサイズ (0x{0:X}) は書き込みサイズ (0x{1:X}) と等しくありません。 MsgDataDidNotOriginateFromHost_0=インポートされたデータは Villager0 ({0}) のデータからのものではありませんでした。 MsgAskUpdateValues=値を更新しますか? diff --git a/NHSE.Core/Resources/text/ko/MessageStrings_ko.txt b/NHSE.Core/Resources/text/ko/MessageStrings_ko.txt index d493b20..28cd35e 100644 --- a/NHSE.Core/Resources/text/ko/MessageStrings_ko.txt +++ b/NHSE.Core/Resources/text/ko/MessageStrings_ko.txt @@ -1,6 +1,7 @@ MsgBackupCreateLocation=실행 파일과 같은 폴더에 '{0}' 이름으로 폴더를 만들면 NHSE가 자동으로 백업을 수행합니다. MsgBackupCreateQuestion=NHSE가 세이브 데이터를 자동으로 백업하도록 설정하시겠습니까? MsgDataSizeMismatchImport=가져온 파일의 크기(0x{0:X})가 필요한 크기(0x{1:X})와 일치하지 않습니다. +MsgDataTrimmedWarning=크기에 맞춰 다듬어질 것입니다. MsgDataSizeMismatchRAM=읽기 크기(0x{0:X})와 쓰기 크기(0x{1:X})가 다릅니다. MsgDataDidNotOriginateFromHost_0=가져온 데이터는 플레이어0({0})의 데이터가 아닙니다. MsgAskUpdateValues=값들을 업데이트하시겠습니까? diff --git a/NHSE.Core/Resources/text/zhs/MessageStrings_zhs.txt b/NHSE.Core/Resources/text/zhs/MessageStrings_zhs.txt index 8ccfbf7..a476edb 100644 --- a/NHSE.Core/Resources/text/zhs/MessageStrings_zhs.txt +++ b/NHSE.Core/Resources/text/zhs/MessageStrings_zhs.txt @@ -1,6 +1,7 @@ MsgBackupCreateLocation=如果您在本程序根目录创建 '{0}' 文件夹,NHSE可以帮您自动备份存档。 MsgBackupCreateQuestion=您希望NHSE自动备份您的存档吗? MsgDataSizeMismatchImport=导入的文件尺寸(0x{0:X})和必要的文件尺寸(0x{1:X})不匹配。 +MsgDataTrimmedWarning=它会被修剪到合适的尺寸。 MsgDataSizeMismatchRAM=读取大小 (0x{0:X}) != 写入大小 (0x{1:X})。 MsgDataDidNotOriginateFromHost_0=导入的数据不是来自Villager0 ({0})的数据。 MsgAskUpdateValues=更新数值? diff --git a/NHSE.Core/Resources/text/zht/MessageStrings_zht.txt b/NHSE.Core/Resources/text/zht/MessageStrings_zht.txt index 4be2e88..a8c38af 100644 --- a/NHSE.Core/Resources/text/zht/MessageStrings_zht.txt +++ b/NHSE.Core/Resources/text/zht/MessageStrings_zht.txt @@ -1,6 +1,7 @@ MsgBackupCreateLocation=NHSE can perform automatic backups if you create a folder with the name '{0}' in the same folder as the executable. MsgBackupCreateQuestion=Would you like NHSE to automatically keep a backup of your save data? MsgDataSizeMismatchImport=The size of the imported file (0x{0:X}) does not match the required size (0x{1:X}). +MsgDataTrimmedWarning=It will be trimmed to fit. MsgDataSizeMismatchRAM=Read size (0x{0:X}) != Write size (0x{1:X}). MsgDataDidNotOriginateFromHost_0=Imported data did not originate from Villager0 ({0})'s data. MsgAskUpdateValues=Update values? diff --git a/NHSE.Core/Save/Files/MainSave.cs b/NHSE.Core/Save/Files/MainSave.cs index a47e8dc..b16a9a3 100644 --- a/NHSE.Core/Save/Files/MainSave.cs +++ b/NHSE.Core/Save/Files/MainSave.cs @@ -217,15 +217,15 @@ public void SetAcreBytes(ReadOnlySpan data) public const ushort MapDesignNone = 0xF800; - public Memory MapDesignTileData => Raw.Slice(Offsets.MyDesignMap, (AcreWidth * LayerFieldItem.TilesPerAcreDim) * (AcreHeight * LayerFieldItem.TilesPerAcreDim) * sizeof(ushort)); - public ushort[] GetMapDesignTiles() => MemoryMarshal.Cast(MapDesignTileData.Span).ToArray(); - public void SetMapDesignTiles(ReadOnlySpan value) => MemoryMarshal.Cast(value).CopyTo(MapDesignTileData.Span); + public Memory MapDesignTileData(int w, int h) => Raw.Slice(Offsets.MyDesignMap, (w * 16) * (h * 16) * sizeof(ushort)); + public ushort[] GetMapDesignTiles(int w, int h) => MemoryMarshal.Cast(MapDesignTileData(w, h).Span).ToArray(); + public void SetMapDesignTiles(ReadOnlySpan value, int w, int h) => MemoryMarshal.Cast(value).CopyTo(MapDesignTileData(w, h).Span); - public void ClearDesignTiles() + public void ClearDesignTiles(int w, int h) { - var tiles = GetMapDesignTiles(); + var tiles = GetMapDesignTiles(w, h); tiles.AsSpan().Fill(MapDesignNone); - SetMapDesignTiles(tiles); + SetMapDesignTiles(tiles, w, h); } private int FieldItemLayerSize => TotalFieldItemTileCount * Item.SIZE; diff --git a/NHSE.Core/Util/ArrayUtil.cs b/NHSE.Core/Util/ArrayUtil.cs index 76f5475..aa2a789 100644 --- a/NHSE.Core/Util/ArrayUtil.cs +++ b/NHSE.Core/Util/ArrayUtil.cs @@ -28,4 +28,64 @@ public static int ReplaceOccurrences(this Span array, ReadOnlySpan p ++count; } } + + /// + /// Pads the specified byte array on the left side with the given padding bytes until it reaches the desired total length. + /// + /// The original byte array to pad. + /// The desired total length of the resulting array. + /// The byte pattern to use for padding. If multiple bytes are provided, they will repeat as needed. + /// + /// A new byte array of with padding on the left and the original content on the right. + /// If is already equal to or longer than , returns the original array unchanged. + /// + public static byte[] PadLeft(byte[] original, int totalLength, byte[] paddingBytes) + { + int bytesNeeded = totalLength - original.Length; + if (bytesNeeded <= 0) return original; + + byte[] paddedArray = new byte[totalLength]; + int padBytesCount = paddingBytes.Length; + + // Fill the left with padding bytes + for (int i = 0; i < bytesNeeded; i += padBytesCount) + { + for (int j = 0; j < padBytesCount && i + j < bytesNeeded; j++) + paddedArray[i + j] = paddingBytes[j]; + } + + // Copy the original array to the right of the padding + Buffer.BlockCopy(original, 0, paddedArray, bytesNeeded, original.Length); + return paddedArray; + } + /// + /// Pads the specified byte array on the right side with the given padding bytes until it reaches the desired total length. + /// + /// The original byte array to pad. + /// The desired total length of the resulting array. + /// The byte pattern to use for padding. If multiple bytes are provided, they will repeat as needed. + /// + /// A new byte array of with the original content on the left and padding on the right. + /// If is already equal to or longer than , returns the original array unchanged. + /// + public static byte[] PadRight(byte[] original, int totalLength, byte[] paddingBytes) + { + int bytesNeeded = totalLength - original.Length; + if (bytesNeeded <= 0) return original; + + byte[] paddedArray = new byte[totalLength]; + // Copy the original array to the left + Buffer.BlockCopy(original, 0, paddedArray, 0, original.Length); + + int padBytesCount = paddingBytes.Length; + + // Fill the right with padding bytes + for (int i = 0; i < bytesNeeded; i += padBytesCount) + { + for (int j = 0; j < padBytesCount && original.Length + i + j < totalLength; j++) + paddedArray[original.Length + i + j] = paddingBytes[j]; + } + + return paddedArray; + } } \ No newline at end of file diff --git a/NHSE.WinForms/Subforms/Map/FieldItemEditor.cs b/NHSE.WinForms/Subforms/Map/FieldItemEditor.cs index 284c8f7..e199f7f 100644 --- a/NHSE.WinForms/Subforms/Map/FieldItemEditor.cs +++ b/NHSE.WinForms/Subforms/Map/FieldItemEditor.cs @@ -7,8 +7,11 @@ using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Drawing.Imaging; +using System.Drawing.Imaging.Effects; using System.IO; using System.Linq; +using System.Numerics; +using System.Reflection; using System.Windows.Forms; namespace NHSE.WinForms; @@ -34,6 +37,8 @@ public sealed partial class FieldItemEditor : Form, IItemLayerEditor private int DragY = -1; private bool IsDragOperationActive; + private Tuple MapDesignGridSize = new(7, 6); + private bool IsMenuHasActivate = true; public ItemEditor ItemProvider => ItemEdit; @@ -62,6 +67,7 @@ public FieldItemEditor(MainSave sav) Loading = true; + LoadMapDesignSize(); LoadComboBoxes(); LoadBuildings(sav); ReloadMapBackground(); @@ -111,6 +117,12 @@ private void LoadEditors() PG_TerrainTile.SelectedObject = new TerrainTile(); } + private void LoadMapDesignSize() + { + if (SAV.Info.GetKnownRevisionIndex() >= 31) + MapDesignGridSize = new (9, 6); + } + private int ExteriorAcreIndex => CB_Acre.SelectedIndex; private void ChangeAcre(object sender, EventArgs e) @@ -1228,35 +1240,21 @@ private void B_SetAllRoadTiles_Click(object sender, EventArgs e) private void B_ClearPlacedDesigns_Click(object sender, EventArgs e) { - SAV.ClearDesignTiles(); + SAV.ClearDesignTiles(MapDesignGridSize.Item1, MapDesignGridSize.Item2); System.Media.SystemSounds.Asterisk.Play(); } private void B_ExportPlacedDesigns_Click(object sender, EventArgs e) { - using var sfd = new SaveFileDialog(); - sfd.Filter = "nhmd file (*.nhmd)|*.nhmd"; - sfd.FileName = "Island MyDesignMap.nhmd"; - if (sfd.ShowDialog() != DialogResult.OK) + if (!MapDumpHelper.DumpMapDesigns(SAV, MapDesignGridSize)) return; - - string path = sfd.FileName; - var tiles = SAV.MapDesignTileData.Span; - File.WriteAllBytes(path, tiles); System.Media.SystemSounds.Asterisk.Play(); } private void B_ImportPlacedDesigns_Click(object sender, EventArgs e) { - using var ofd = new OpenFileDialog(); - ofd.Filter = "nhmd file (*.nhmd)|*.nhmd"; - ofd.FileName = "Island MyDesignMap.nhmd"; - if (ofd.ShowDialog() != DialogResult.OK) + if (!MapDumpHelper.ImportMapDesigns(SAV, MapDesignGridSize)) return; - - string path = ofd.FileName; - var tiles = File.ReadAllBytes(path); - tiles.CopyTo(SAV.MapDesignTileData.Span); System.Media.SystemSounds.Asterisk.Play(); } diff --git a/NHSE.WinForms/Subforms/Map/FieldItemEditor.resx b/NHSE.WinForms/Subforms/Map/FieldItemEditor.resx index c600636..08f9278 100644 --- a/NHSE.WinForms/Subforms/Map/FieldItemEditor.resx +++ b/NHSE.WinForms/Subforms/Map/FieldItemEditor.resx @@ -129,12 +129,12 @@ 465, 17 - - 930, 17 - 620, 17 + + 930, 17 + 17, 56 diff --git a/NHSE.WinForms/Subforms/Map/MapDumpHelper.cs b/NHSE.WinForms/Subforms/Map/MapDumpHelper.cs index 7ccfe14..14702ed 100644 --- a/NHSE.WinForms/Subforms/Map/MapDumpHelper.cs +++ b/NHSE.WinForms/Subforms/Map/MapDumpHelper.cs @@ -8,6 +8,9 @@ namespace NHSE.WinForms; public static class MapDumpHelper { + private const int DesignDumpSizeAbove31 = 0x6C00; + private const int DesignDumpSizeBelow31 = 0x5400; + public static bool ImportToLayerAcreSingle(LayerFieldItem layerField, string acre, int layerIndex, int relX, int relY) { var name = GetBaseFileName(acre, "acre"); @@ -276,4 +279,116 @@ public static bool ImportToLayerAllFlag(ILayerFieldItemFlag layer, uint layerInd layer.Import(data); return true; } + + public static bool ImportMapDesigns(MainSave sav, Tuple size) + { + using var ofd = new OpenFileDialog(); + ofd.Filter = "nhmd file (*.nhmd)|*.nhmd"; + ofd.FileName = "Island MyDesignMap.nhmd"; + if (ofd.ShowDialog() != DialogResult.OK) + return false; + + string path = ofd.FileName; + + var tiles = File.ReadAllBytes(path); + + var rel = size; + + if (rel.Item1 == 9) + { + if (tiles.Length == DesignDumpSizeAbove31) + { + tiles.CopyTo(sav.MapDesignTileData(rel.Item1, rel.Item2).Span); + } + else if (tiles.Length == DesignDumpSizeBelow31) + { + byte[] padBytes = BitConverter.GetBytes(MainSave.MapDesignNone); + int len = (DesignDumpSizeAbove31 - DesignDumpSizeBelow31) / 2; + + tiles = ArrayUtil.PadLeft(tiles, tiles.Length + len, padBytes); + tiles = ArrayUtil.PadRight(tiles, tiles.Length + len, padBytes); + + using var sfd = new SaveFileDialog(); + sfd.Filter = "nhmd file (*.nhmd)|*.nhmd"; + sfd.FileName = "Island MyDesignMap.nhmd"; + if (sfd.ShowDialog() != DialogResult.OK) + return false; + + string path2 = sfd.FileName; + + File.WriteAllBytes(path2, tiles); + + tiles.CopyTo(sav.MapDesignTileData(rel.Item1, rel.Item2).Span); + } + // account for previous dumps that included extra data after the tile data (oops) + // this can be removed in the future once enough time has passed that everyone has + // re-dumped with the fixed version, but for now it prevents data loss + else if (tiles.Length > DesignDumpSizeAbove31) + { + Span trimTiles = tiles.AsSpan().Slice(0, DesignDumpSizeAbove31); + tiles = trimTiles.ToArray(); + var msg1 = MessageStrings.MsgDataSizeMismatchImport; + var msg2 = MessageStrings.MsgDataTrimmedWarning; + WinFormsUtil.Alert(string.Format(msg1, tiles.Length, DesignDumpSizeAbove31) + " " + msg2); + + using var sfd = new SaveFileDialog(); + sfd.Filter = "nhmd file (*.nhmd)|*.nhmd"; + sfd.FileName = "Island MyDesignMap.nhmd"; + if (sfd.ShowDialog() != DialogResult.OK) + return false; + + string path2 = sfd.FileName; + + File.WriteAllBytes(path2, tiles); + + tiles.CopyTo(sav.MapDesignTileData(rel.Item1, rel.Item2).Span); + } + else + { + var msg = MessageStrings.MsgDataSizeMismatchImport; + WinFormsUtil.Error(string.Format(msg, tiles.Length, DesignDumpSizeAbove31)); + return false; + } + } + else + { + if (tiles.Length == DesignDumpSizeBelow31) + { + tiles.CopyTo(sav.MapDesignTileData(rel.Item1, rel.Item2).Span); + } + else if (tiles.Length == DesignDumpSizeAbove31) + { + int trimAmount = (DesignDumpSizeAbove31 - DesignDumpSizeBelow31) / 2; + int newLength = tiles.Length - (2 * trimAmount); + + tiles = tiles.AsSpan(trimAmount, newLength).ToArray(); + + tiles.CopyTo(sav.MapDesignTileData(rel.Item1, rel.Item2).Span); + } + else + { + var msg = MessageStrings.MsgDataSizeMismatchImport; + WinFormsUtil.Error(string.Format(msg, tiles.Length, DesignDumpSizeBelow31)); + return false; + } + } + + return true; + } + public static bool DumpMapDesigns(MainSave sav, Tuple size) + { + using var sfd = new SaveFileDialog(); + sfd.Filter = "nhmd file (*.nhmd)|*.nhmd"; + sfd.FileName = "Island MyDesignMap.nhmd"; + if (sfd.ShowDialog() != DialogResult.OK) + return false; + + string path = sfd.FileName; + + var tiles = sav.MapDesignTileData(size.Item1, size.Item2).Span; + + File.WriteAllBytes(path, tiles); + + return true; + } } \ No newline at end of file diff --git a/NHSE.WinForms/Util/MessageStrings.cs b/NHSE.WinForms/Util/MessageStrings.cs index 5653d4c..c949c11 100644 --- a/NHSE.WinForms/Util/MessageStrings.cs +++ b/NHSE.WinForms/Util/MessageStrings.cs @@ -7,6 +7,7 @@ public static class MessageStrings public static string MsgBackupCreateQuestion { get; set; } = "Would you NHSE to automatically keep a backup of your save data?"; public static string MsgDataSizeMismatchImport { get; set; } = "The size of the imported file (0x{0:X}) does not match the required size (0x{1:X})."; + public static string MsgDataTrimmedWarning { get; set; } = "It will be trimmed to fit."; public static string MsgDataSizeMismatchRAM { get; set; } = "Read size (0x{0:X}) != Write size (0x{1:X})."; public static string MsgDataDidNotOriginateFromHost_0 { get; set; } = "Imported data did not originate from Villager0 ({0})'s data.";