diff --git a/NHSE.Core/Structures/Villager/Villager1.cs b/NHSE.Core/Structures/Villager/Villager1.cs
index 99d1720..8b82d3a 100644
--- a/NHSE.Core/Structures/Villager/Villager1.cs
+++ b/NHSE.Core/Structures/Villager/Villager1.cs
@@ -3,6 +3,9 @@
namespace NHSE.Core
{
+ ///
+ /// Villager object format starting from release thru update 1.4
+ ///
public sealed class Villager1 : IVillager
{
public const int SIZE = 0x12AB0;
@@ -125,4 +128,4 @@ public void SetFriendshipAll(byte value = byte.MaxValue)
}
}
}
-}
\ No newline at end of file
+}
diff --git a/NHSE.Core/Structures/Villager/Villager2.cs b/NHSE.Core/Structures/Villager/Villager2.cs
index 9799bd4..f6b9013 100644
--- a/NHSE.Core/Structures/Villager/Villager2.cs
+++ b/NHSE.Core/Structures/Villager/Villager2.cs
@@ -3,6 +3,9 @@
namespace NHSE.Core
{
+ ///
+ /// Villager object format starting with update 1.5
+ ///
public sealed class Villager2 : IVillager
{
public const int SIZE = 0x13230; // + 160*0xC (0x780) -- GSaveLightMemory increased size.
@@ -125,4 +128,4 @@ public void SetFriendshipAll(byte value = byte.MaxValue)
}
}
}
-}
\ No newline at end of file
+}
diff --git a/NHSE.Core/Structures/Villager/VillagerConverter.cs b/NHSE.Core/Structures/Villager/VillagerConverter.cs
new file mode 100644
index 0000000..77c97b8
--- /dev/null
+++ b/NHSE.Core/Structures/Villager/VillagerConverter.cs
@@ -0,0 +1,77 @@
+using System;
+
+namespace NHSE.Core
+{
+ public static class VillagerConverter
+ {
+ public static bool IsCompatible(int size, int expect)
+ {
+ switch (expect)
+ {
+ case Villager1.SIZE:
+ case Villager2.SIZE:
+ return size == Villager1.SIZE || size == Villager2.SIZE;
+
+ default:
+ return false;
+ }
+ }
+
+ public static byte[] GetCompatible(byte[] data, int expect)
+ {
+ if (data.Length == expect)
+ return data;
+
+ return expect switch
+ {
+ Villager1.SIZE when data.Length == Villager2.SIZE => Convert12(data),
+ Villager2.SIZE when data.Length == Villager1.SIZE => Convert21(data),
+ _ => data
+ };
+ }
+
+ public static byte[] Convert12(byte[] v1)
+ {
+ byte[] v2 = new byte[Villager2.SIZE];
+
+ // Copy pre-GSaveLightMemory[160]
+ Array.Copy(v1, 0, v2, 0, 0x2f84);
+
+ // Copy each entry, with each adding 0xC empty bytes.
+ for (int i = 0; i < 160; i++)
+ {
+ var src = 0x2f84 + (0x14C * i);
+ var dest = 0x2f84 + (0x158 * i);
+
+ Array.Copy(v1, src, v2, dest, 0x14C);
+ }
+
+ // Copy after-GSaveLightMemory[160]
+ Array.Copy(v1, 0xff04, v2, 0x10684, v1.Length - 0xff04);
+
+ return v2;
+ }
+
+ public static byte[] Convert21(byte[] v2)
+ {
+ byte[] v1 = new byte[Villager1.SIZE];
+
+ // Copy pre-GSaveLightMemory[160]
+ Array.Copy(v2, 0, v1, 0, 0x2f84);
+
+ // Copy each entry, with each skipping last 0xC bytes.
+ for (int i = 0; i < 160; i++)
+ {
+ var src = 0x2f84 + (0x14C * i);
+ var dest = 0x2f84 + (0x158 * i);
+
+ Array.Copy(v2, dest, v1, src, 0x14C);
+ }
+
+ // Copy after-GSaveLightMemory[160]
+ Array.Copy(v2, 0x10684, v1, 0xff04, v2.Length - 0x10684);
+
+ return v1;
+ }
+ }
+}
diff --git a/NHSE.WinForms/Controls/VillagerEditor.cs b/NHSE.WinForms/Controls/VillagerEditor.cs
index 7ee79a9..af28ae4 100644
--- a/NHSE.WinForms/Controls/VillagerEditor.cs
+++ b/NHSE.WinForms/Controls/VillagerEditor.cs
@@ -132,13 +132,20 @@ private void B_LoadVillager_Click(object sender, EventArgs e)
var path = ofd.FileName;
var expectLength = SAV.Offsets.VillagerSize;
var fi = new FileInfo(path);
- if (fi.Length != expectLength)
+ if (VillagerConverter.IsCompatible((int)fi.Length, expectLength))
{
WinFormsUtil.Error(string.Format(MessageStrings.MsgDataSizeMismatchImport, fi.Length, expectLength), path);
return;
}
var data = File.ReadAllBytes(ofd.FileName);
+ data = VillagerConverter.GetCompatible(data, expectLength);
+ if (data.Length != expectLength)
+ {
+ WinFormsUtil.Error(string.Format(MessageStrings.MsgDataSizeMismatchImport, fi.Length, expectLength), path);
+ return;
+ }
+
var v = SAV.Offsets.ReadVillager(data);
var player0 = Origin;
if (!v.IsOriginatedFrom(player0))