From 4128cc00f6cecf3be5ca2a1818fe55d7215e4923 Mon Sep 17 00:00:00 2001 From: Kurt Date: Fri, 1 May 2020 23:10:04 -0700 Subject: [PATCH] Add item size metadata --- NHSE.Core/NHSE.Core.csproj | 2 + NHSE.Core/Resources/byte/item_size.bin | Bin 0 -> 12984 bytes NHSE.Core/Structures/Item/ItemInfo.cs | 13 +++- NHSE.Core/Structures/Item/ItemSize.cs | 88 +++++++++++++++++++++++++ NHSE.Parsing/GameBCSVDumper.cs | 66 +++++++++++++++++++ 5 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 NHSE.Core/Resources/byte/item_size.bin create mode 100644 NHSE.Core/Structures/Item/ItemSize.cs diff --git a/NHSE.Core/NHSE.Core.csproj b/NHSE.Core/NHSE.Core.csproj index ec5607b..801a179 100644 --- a/NHSE.Core/NHSE.Core.csproj +++ b/NHSE.Core/NHSE.Core.csproj @@ -8,6 +8,7 @@ + @@ -39,6 +40,7 @@ + diff --git a/NHSE.Core/Resources/byte/item_size.bin b/NHSE.Core/Resources/byte/item_size.bin new file mode 100644 index 0000000000000000000000000000000000000000..1e7a8bdb867dc96dd73b9571cb183570b567c730 GIT binary patch literal 12984 zcmeHNiB{vd5*4i%2<~78=nVY-m%h7H$?}#2dV2cIIW0h{^;W4QE4D)^Po+FOlyW$< z5fnN8Jw26E0V(bP`T;b!zy5+$4OT!PKMbI1!S6V5T(?bOslB*vdzLbeqX03GBp2h1 zlg2jgJIC}i&^o;h2~ry%uE-HT9Cn&?G;#jBb_@4g?G|polD)gbLU!$z6ghh|*U9vy zUX|Q3n8FSt3vS+3|0e!OMsgaIaxW7n?7ShT!cNp;xn~oS$Au2wL)C8@L9(}JB20Az z7&7+M2J0onWz(tG8znQwl-ktGiI*Q6A=)&^)Ni~HyGE^}_dN~jUiRfE|GRXQahDnW z3?{q2Ly1z^StR*`$-IK204q)F)Y*^RE0y?T792I7*nI@hjG&;-EjEo9OW7xdu~lyS z2$Dr$rC$fuG;>)41yP4#7{>t%%Z-NK`*7}=9Q25yK1J&>*L~6mnv=)M4UC2D2OyPW zvbsdUx{L(=!C!QrY6G@2gI$`M02ziYM{`)7F+vk@47C&DSj10uhJ@Cj) zomZ7JcdFjekx0by&=@WR8hKPV=Mx|pWax`6eJ}>uVk$%kMYCJ-P4QI%M_61+|1h+t z&FTNEP1jLG#Ocg41&x!m5X7s=)?**LjZnQ>>vEzbtcno&0!OJr{klH(w=X5(v{PcX zmdw!!{*s>aV2Fr0<VDUPDs1X4o)32oa9We%?LLTpi-41ptHmhNy)xG+6F8H7BN*x1sv$O%%MIc7nT7-Pc-N5poc;LtQja6< z2SD?0r$uOM0a+evy{qLgRQz^TWPBU}PbbFV-#FACAktCcX`&hNW`~Vl=)%Z@<CkJgMwq-w zIillbpCj}PjUTL-D>-t7M^=DG=ZG!$g!@UP{{nHr0_(B6U^->cW?+EwSdOs96pzEb zKpFUOsMuBz!4S8hL~#SW(sidB6(|t@gxk7aMQFetwI8*GiHp#7?f}_i*CmBitF?(u8Mez;a<4jx2IvhU^|4BW-d_mI`cKD)k&uu zGaz|Fcp0#4EB`38>?S4raD?jhN$0roqQEZbd5y{vUCTXP?o0$e^I4ii znv`1?FtVe$P#0b{mXI$<6-0v~gfRs?LAD#U;YkDfgkNJ7+lVdi#!`|Fy>N$~K+|c8 zN0+L503~Y#I>a3cNi^QR;H1_-K7lmGR4k*N4o{jb8nU($2DD?N3GLNLYm;$;(()Xb zT80hDVa5~7e{vNB4OPm-SQ>=sdgvYeF@`%Sd9$AdMzK&l7BRSWxW;%% zf2QR%)V#J3no`IYI9=TRE^;bcFG6%Eu!{p>N?O+_jy!#T@gt(;QMa<5{79u)N`Ylj z_!*5E>M?^yDi0Nwk>7>+?hJSGVV5x7s48oU62cHnl3_Qg9bJ0f%SoycG(04Hetv#Fp9d~Lseq_wuoRYZ z-oj~swZg9BYT@+LCCA=ihh|Zn_B6xZv^_QU!fo0Bq5DJ%ZCPW7;vqM@g}5C|n*dL% zds=F8Mhlx1@A}F?Y|rL z%CWZV*DJhGy`<5&JQ_U__vO=Xo8m&BFn$+>$qt22%Qv-+mEuxf_I3GP1(e(sJ0j@%~u5sCsa%X<8nUT4GAL1fTMmEA!WLd-NvqF%s4CI z7S`HmE!pz>*JUa(CZ+aEqdUZYj~wC+&Y$5oRp2x0AK#Sjx_oI0Lc6dP6ZFbO$ZO3T zEdY13{3*rHT+%#9(5}Si6@d>0Kjpz351(qT!?*Tr&2uAg)NP<^fk-J84f=`_H1;~VXI zxDBTeIn;!(m)JhSQWIGFFD#Z0R}Mm+F};i4m9Y-^QXcP)W)1%w@TJz=8nF$77g1D9 z-DH-hbxQPK4*q5w>8I4=-vwV*3@>;oH$M2CDBc8}@GlT91&v6}rrnpI);AoZp{KEJ zdD7ahld0I%adPVU-~DVwf|DG dsN7O*K8^5ZoXs`JO4#H#_nG0B)7Sy1_5Z7|ep>(l literal 0 HcmV?d00001 diff --git a/NHSE.Core/Structures/Item/ItemInfo.cs b/NHSE.Core/Structures/Item/ItemInfo.cs index c12e994..18d416f 100644 --- a/NHSE.Core/Structures/Item/ItemInfo.cs +++ b/NHSE.Core/Structures/Item/ItemInfo.cs @@ -3,6 +3,7 @@ public static class ItemInfo { private static readonly byte[] ItemKinds = ResourceUtil.GetBinaryResource("item_kind.bin"); + private static readonly byte[] ItemSizes = ResourceUtil.GetBinaryResource("item_size.bin"); public static ItemKind GetItemKind(IHeldItem item) => GetItemKind(item.ItemId); public static ItemKind GetItemKind(FieldItem item) => GetItemKind(item.DisplayItemId); @@ -13,5 +14,15 @@ public static ItemKind GetItemKind(ushort id) return ItemKind.Unknown; return (ItemKind) ItemKinds[id]; } + + public static ItemSizeType GetItemSize(IHeldItem item) => GetItemSize(item.ItemId); + public static ItemSizeType GetItemSize(FieldItem item) => GetItemSize(item.DisplayItemId); + + public static ItemSizeType GetItemSize(ushort id) + { + if (id > ItemSizes.Length) + return ItemSizeType.Unknown; + return (ItemSizeType)ItemSizes[id]; + } } -} \ No newline at end of file +} diff --git a/NHSE.Core/Structures/Item/ItemSize.cs b/NHSE.Core/Structures/Item/ItemSize.cs new file mode 100644 index 0000000..c0e838a --- /dev/null +++ b/NHSE.Core/Structures/Item/ItemSize.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; + +namespace NHSE.Core +{ +#pragma warning disable CA1027 // Mark enums with FlagsAttribute + public enum ItemSizeType : byte +#pragma warning restore CA1027 // Mark enums with FlagsAttribute + { + S_0_5x1_0_Wall, + S_1_0x0_5, + S_1_0x0_5_Wall, + S_1_0x1_0, + S_1_0x1_0_Rug, + S_1_0x1_0_Wall, + S_1_0x1_5_Wall, + S_1_0x2_0_Wall, + S_1_5x1_5, + S_2_0x0_5, + S_2_0x1_0, + S_2_0x1_0_Rug, + S_2_0x1_0_Wall, + S_2_0x1_5_Wall, + S_2_0x2_0, + S_2_0x2_0_Rug, + S_2_0x2_0_Wall, + S_3_0x1_0, + S_3_0x2_0, + S_3_0x2_0_Rug, + S_3_0x3_0, + S_3_0x3_0_Rug, + S_4_0x3_0_Rug, + S_4_0x4_0_Rug, + S_5_0x5_0_Rug, + + S_5_0x4_0_Rug, // not used by any items; manually added since it's in ItemSize + Unknown = byte.MaxValue, + } + + public class ItemSize + { + public readonly int Width; + public readonly int Height; + + public ItemSize(int w, int h) + { + Width = w; Height = h; + } + } + + public static class ItemSizeExtensions + { + public const string EnumPrefix = "S_"; + + private static readonly Dictionary Dictionary = new Dictionary + { + {ItemSizeType.S_1_0x1_0 , new ItemSize( 2, 2)}, // 1x1 + {ItemSizeType.S_2_0x1_0 , new ItemSize( 4, 2)}, // 2x1 + {ItemSizeType.S_2_0x2_0 , new ItemSize( 4, 4)}, // 2x2 + {ItemSizeType.S_3_0x1_0 , new ItemSize( 6, 2)}, // 3x1 + {ItemSizeType.S_3_0x2_0 , new ItemSize( 6, 4)}, // 3x2 + {ItemSizeType.S_3_0x3_0 , new ItemSize( 6, 6)}, // 3x3 + {ItemSizeType.S_1_0x0_5 , new ItemSize( 2, 1)}, // 1x0.5 + {ItemSizeType.S_2_0x0_5 , new ItemSize( 4, 1)}, // 2x0.5 + {ItemSizeType.S_1_5x1_5 , new ItemSize( 3, 3)}, // 1.5x1.5 + {ItemSizeType.S_1_0x0_5_Wall, new ItemSize( 2, 1)}, // 1x0.5(壁) + {ItemSizeType.S_0_5x1_0_Wall, new ItemSize( 1, 2)}, // 0.5x1(壁) + {ItemSizeType.S_1_0x1_0_Wall, new ItemSize( 2, 2)}, // 1x1(壁) + {ItemSizeType.S_1_0x1_5_Wall, new ItemSize( 2, 3)}, // 1x1.5 (壁) + {ItemSizeType.S_1_0x2_0_Wall, new ItemSize( 2, 4)}, // 1x2  (壁) + {ItemSizeType.S_2_0x1_0_Wall, new ItemSize( 4, 2)}, // 2x1(壁) + {ItemSizeType.S_2_0x1_5_Wall, new ItemSize( 4, 3)}, // 2x1.5 (壁) + {ItemSizeType.S_2_0x2_0_Wall, new ItemSize( 4, 4)}, // 2x2(壁) + {ItemSizeType.S_1_0x1_0_Rug , new ItemSize( 2, 2)}, // 1x1(ラグ) + {ItemSizeType.S_2_0x1_0_Rug , new ItemSize( 4, 2)}, // 2x1(ラグ) + {ItemSizeType.S_2_0x2_0_Rug , new ItemSize( 4, 4)}, // 2x2(ラグ) + {ItemSizeType.S_3_0x2_0_Rug , new ItemSize( 6, 4)}, // 3x2(ラグ) + {ItemSizeType.S_3_0x3_0_Rug , new ItemSize( 6, 6)}, // 3x3(ラグ) + {ItemSizeType.S_4_0x3_0_Rug , new ItemSize( 8, 6)}, // 4x3(ラグ) + {ItemSizeType.S_4_0x4_0_Rug , new ItemSize( 8, 8)}, // 4x4(ラグ) + {ItemSizeType.S_5_0x4_0_Rug , new ItemSize(10, 8)}, // 5x4(ラグ) + {ItemSizeType.S_5_0x5_0_Rug , new ItemSize(10, 10)}, // 5x5(ラグ) + + }; + + public static int GetWidth(this ItemSizeType s) => Dictionary.TryGetValue(s, out var val) ? val.Width : 1; + public static int GetHeight(this ItemSizeType s) => Dictionary.TryGetValue(s, out var val) ? val.Height : 1; + } +} diff --git a/NHSE.Parsing/GameBCSVDumper.cs b/NHSE.Parsing/GameBCSVDumper.cs index a3332a3..0511ea2 100644 --- a/NHSE.Parsing/GameBCSVDumper.cs +++ b/NHSE.Parsing/GameBCSVDumper.cs @@ -47,6 +47,7 @@ void DumpB(string fn, byte[] bytes) DumpS("eventFlagLand.txt", GetLandEventFlagNames(pathBCSV)); DumpS("ItemKind.txt", GetPossibleEnum(pathBCSV, "ItemParam.bcsv", 0xFC275E86)); + DumpS("ItemSize.txt", GetPossibleEnum(pathBCSV, "ItemParam.bcsv", 0xE06FB090)); DumpS("PlantKind.txt", GetPossibleEnum(pathBCSV, "FgMainParam.bcsv", 0x48EF0398)); DumpS("TerrainKind.txt", GetNumberedEnumValues(pathBCSV, "FieldLandMakingUnitModelParam.bcsv", 0x39B5A93D, 0x54706054)); DumpS("BridgeKind.txt", GetNumberedEnumValues(pathBCSV, "StructureBridgeParam.bcsv", 0x39B5A93D, 0x54706054)); @@ -57,7 +58,9 @@ void DumpB(string fn, byte[] bytes) DumpS("WallKind.txt", GetNumberedEnumValues(pathBCSV, "StructureHouseWallParam.bcsv", 0x39B5A93D, 0x54706054)); DumpB("item_kind.bin", GetItemKindArray(pathBCSV)); + DumpB("item_size.bin", GetItemSizeArray(pathBCSV)); DumpS("plants.txt", GetPlantedNames(pathBCSV)); + DumpS("item_size_dictionary.txt", GetItemSizeDictionary(pathBCSV)); if (csv) BCSVConverter.DumpAll(pathBCSV, dest, delim); @@ -157,6 +160,69 @@ public static byte[] GetItemKindArray(string pathBCSV, string fn = "ItemParam.bc return result; } + public static byte[] GetItemSizeArray(string pathBCSV, string fn = "ItemParam.bcsv") + { + var path = Path.Combine(pathBCSV, fn); + var data = File.ReadAllBytes(path); + var bcsv = new BCSV(data); + + var dict = bcsv.GetFieldDictionary(); + var fType = dict[0xE06FB090]; + var fID = dict[0x54706054]; + + var types = new Dictionary(); + ushort max = 0; + for (int i = 0; i < bcsv.EntryCount; i++) + { + var id = bcsv.ReadValue(i, fID); + var ival = ushort.Parse(id); + var type = bcsv.ReadValue(i, fType).TrimEnd('\0'); + type = ItemSizeExtensions.EnumPrefix + type; // can't start with numbers + + if (!Enum.TryParse(type, out var k)) + throw new InvalidEnumArgumentException($"{type} is not a known enum value @ index {i}. Update the enum index first."); + types.Add(ival, k); + + if (ival > max) + max = ival; + } + + byte[] result = new byte[max + 1]; + foreach (var kvp in types) + result[kvp.Key] = (byte)kvp.Value; + + return result; + } + + public static string[] GetItemSizeDictionary(string pathBCSV, string fn = "ItemSize.bcsv") + { + var path = Path.Combine(pathBCSV, fn); + var data = File.ReadAllBytes(path); + var bcsv = new BCSV(data); + + var dict = bcsv.GetFieldDictionary(); + + var fw = dict[0x16B8F524]; + var fh = dict[0xBCB13DAF]; + var fs = dict[0x87BF00E8]; + var fc = dict[0x977ADFCE]; + + string[] result = new string[bcsv.EntryCount]; + + const string prefix = nameof(ItemSizeType) + "." + ItemSizeExtensions.EnumPrefix; + for (int i = 0; i < bcsv.EntryCount; i++) + { + var w = bcsv.ReadValue(i, fw).TrimEnd('\0'); + var h = bcsv.ReadValue(i, fh).TrimEnd('\0'); + var s = bcsv.ReadValue(i, fs).TrimEnd('\0'); + var c = bcsv.ReadValue(i, fc).TrimEnd('\0'); + + result[i] = $"{{{prefix}{s,-12}, new ItemSize({w,2}, {h,2})}}, // {c}"; + } + + return result; + } + public static List GetRecipeList(string pathBCSV, string fn = "RecipeCraftParam.bcsv") { var bcsv = BCSVConverter.GetBCSV(pathBCSV, fn);