mirror of
https://github.com/kwsch/NHSE.git
synced 2026-04-26 00:28:28 -05:00
Fix: Map Design Import/Export (#751)
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 (old and new). It 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. Byte padding methods added to ArrayUtil for this padding and for future map flag import padding fixes.
This commit is contained in:
parent
18995c7299
commit
e8c5daf745
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
MsgBackupCreateLocation=NHSE pu<70> 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?
|
||||
|
|
|
|||
|
|
@ -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=値を更新しますか?
|
||||
|
|
|
|||
|
|
@ -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=값들을 업데이트하시겠습니까?
|
||||
|
|
|
|||
|
|
@ -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=更新数值?
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -217,15 +217,15 @@ public void SetAcreBytes(ReadOnlySpan<byte> data)
|
|||
|
||||
public const ushort MapDesignNone = 0xF800;
|
||||
|
||||
public Memory<byte> MapDesignTileData => Raw.Slice(Offsets.MyDesignMap, (AcreWidth * LayerFieldItem.TilesPerAcreDim) * (AcreHeight * LayerFieldItem.TilesPerAcreDim) * sizeof(ushort));
|
||||
public ushort[] GetMapDesignTiles() => MemoryMarshal.Cast<byte, ushort>(MapDesignTileData.Span).ToArray();
|
||||
public void SetMapDesignTiles(ReadOnlySpan<ushort> value) => MemoryMarshal.Cast<ushort, byte>(value).CopyTo(MapDesignTileData.Span);
|
||||
public Memory<byte> MapDesignTileData(int w, int h) => Raw.Slice(Offsets.MyDesignMap, (w * 16) * (h * 16) * sizeof(ushort));
|
||||
public ushort[] GetMapDesignTiles(int w, int h) => MemoryMarshal.Cast<byte, ushort>(MapDesignTileData(w, h).Span).ToArray();
|
||||
public void SetMapDesignTiles(ReadOnlySpan<ushort> value, int w, int h) => MemoryMarshal.Cast<ushort, byte>(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;
|
||||
|
|
|
|||
|
|
@ -28,4 +28,64 @@ public static int ReplaceOccurrences(this Span<byte> array, ReadOnlySpan<byte> p
|
|||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pads the specified byte array on the left side with the given padding bytes until it reaches the desired total length.
|
||||
/// </summary>
|
||||
/// <param name="original">The original byte array to pad.</param>
|
||||
/// <param name="totalLength">The desired total length of the resulting array.</param>
|
||||
/// <param name="paddingBytes">The byte pattern to use for padding. If multiple bytes are provided, they will repeat as needed.</param>
|
||||
/// <returns>
|
||||
/// A new byte array of <paramref name="totalLength"/> with padding on the left and the original content on the right.
|
||||
/// If <paramref name="original"/> is already equal to or longer than <paramref name="totalLength"/>, returns the original array unchanged.
|
||||
/// </returns>
|
||||
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;
|
||||
}
|
||||
/// <summary>
|
||||
/// Pads the specified byte array on the right side with the given padding bytes until it reaches the desired total length.
|
||||
/// </summary>
|
||||
/// <param name="original">The original byte array to pad.</param>
|
||||
/// <param name="totalLength">The desired total length of the resulting array.</param>
|
||||
/// <param name="paddingBytes">The byte pattern to use for padding. If multiple bytes are provided, they will repeat as needed.</param>
|
||||
/// <returns>
|
||||
/// A new byte array of <paramref name="totalLength"/> with the original content on the left and padding on the right.
|
||||
/// If <paramref name="original"/> is already equal to or longer than <paramref name="totalLength"/>, returns the original array unchanged.
|
||||
/// </returns>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<int, int> 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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -129,12 +129,12 @@
|
|||
<metadata name="CM_Remove.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>465, 17</value>
|
||||
</metadata>
|
||||
<metadata name="CM_DLBuilding.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>930, 17</value>
|
||||
</metadata>
|
||||
<metadata name="CM_DLField.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>620, 17</value>
|
||||
</metadata>
|
||||
<metadata name="CM_DLBuilding.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>930, 17</value>
|
||||
</metadata>
|
||||
<metadata name="CM_DLMapAcres.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 56</value>
|
||||
</metadata>
|
||||
|
|
|
|||
|
|
@ -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<int, int> 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<byte> 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<int, int> 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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.";
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user