Skip to content

Commit 0d3fb19

Browse files
committed
Allow adding new fields to bdat string tables
1 parent 36cb71b commit 0d3fb19

12 files changed

+243
-60
lines changed

XbTool/XbTool/Bdat/BdatFieldInfo.cs

+33-12
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public enum BdatFieldType
3232
{
3333
Message,
3434
Reference,
35+
OneWayReference,
3536
Item,
3637
Condition,
3738
Character,
@@ -44,6 +45,7 @@ public enum BdatFieldType
4445
ShopTable,
4546
Enum,
4647
Quest,
48+
QuestMenu,
4749
QuestFlag,
4850
QuestFlagIra,
4951
Flag,
@@ -52,7 +54,8 @@ public enum BdatFieldType
5254
EventSetup,
5355
ItemComment,
5456
Layer,
55-
Place
57+
Place,
58+
Enemy
5659
}
5760

5861
public class BdatArrayInfo
@@ -68,22 +71,40 @@ public static class BdatInfoImport
6871
{
6972
public static Dictionary<(string table, string member), BdatFieldInfo> ReadBdatFieldInfo(string prefix)
7073
{
71-
using (FileStream stream = Helpers.OpenDataFile($"{prefix}_fieldInfo.csv"))
72-
using (var reader = new StreamReader(stream))
74+
return ReadBdatFieldInfoImpl($"{prefix}_fieldInfo.csv");
75+
}
76+
77+
public static Dictionary<(string table, string member), BdatFieldInfo> ReadBdatNewFieldInfo(string prefix)
78+
{
79+
return ReadBdatFieldInfoImpl($"{prefix}_newfields.csv");
80+
}
81+
82+
public static Dictionary<(string table, string member), BdatFieldInfo> ReadBdatFieldInfoImpl(string filename)
83+
{
84+
using (FileStream stream = Helpers.TryOpenDataFile(filename))
7385
{
74-
IEnumerable<BdatFieldInfo> csv = new CsvReader(reader, new Configuration { HeaderValidated = null, MissingFieldFound = null }).GetRecords<BdatFieldInfo>();
75-
Dictionary<(string, string), BdatFieldInfo> readBdatFieldInfo = csv.ToDictionary(x => (x.Table, x.Field), x => x);
86+
if(stream == null) return new Dictionary<(string table, string member), BdatFieldInfo>();
7687

77-
foreach (BdatFieldInfo info in readBdatFieldInfo.Values.Where(x => x.EnumTypeString != null))
88+
using (var reader = new StreamReader(stream))
7889
{
79-
info.EnumType = Type.GetType($"XbTool.Types.{info.EnumTypeString}");
80-
}
90+
IEnumerable<BdatFieldInfo> csv =
91+
new CsvReader(reader, new Configuration {HeaderValidated = null, MissingFieldFound = null})
92+
.GetRecords<BdatFieldInfo>();
93+
Dictionary<(string, string), BdatFieldInfo> readBdatFieldInfo =
94+
csv.ToDictionary(x => (x.Table, x.Field), x => x);
8195

82-
foreach (BdatFieldInfo info in readBdatFieldInfo.Values.Where(x => x.Type == BdatFieldType.Flag))
83-
{
84-
info.RefField = "FLG_" + info.RefField;
96+
foreach (BdatFieldInfo info in readBdatFieldInfo.Values.Where(x => x.EnumTypeString != null))
97+
{
98+
info.EnumType = Type.GetType($"XbTool.Types.{info.EnumTypeString}");
99+
}
100+
101+
foreach (BdatFieldInfo info in readBdatFieldInfo.Values.Where(x => x.Type == BdatFieldType.Flag))
102+
{
103+
info.RefField = "FLG_" + info.RefField;
104+
}
105+
106+
return readBdatFieldInfo;
85107
}
86-
return readBdatFieldInfo;
87108
}
88109
}
89110

XbTool/XbTool/Bdat/BdatMember.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class BdatMember
1515
public int FlagVarOffset { get; }
1616
public int FlagIndex { get; }
1717
public uint FlagMask { get; }
18-
public int FlagVarIndex { get; }
18+
public int FlagVarIndex { get; set; }
1919
public BdatFieldInfo Metadata { get; set; }
2020

2121
public BdatMember(string name, BdatMemberType type, BdatValueType valType)

XbTool/XbTool/Bdat/BdatTable.cs

+17-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class BdatTable
2929
public int MemberTableOffset { get; }
3030
public int MemberCount { get; }
3131

32-
public BdatMember[] Members { get; }
32+
public BdatMember[] Members { get; private set; }
3333
private Dictionary<string, BdatMember> MembersDict { get; }
3434
public DataBuffer Data { get; }
3535

@@ -276,6 +276,22 @@ private string ReadStringValue(int valueOffset, BdatValueType type)
276276
throw new ArgumentOutOfRangeException(nameof(type), type, null);
277277
}
278278
}
279+
280+
public void PrependMember(BdatMember newMember)
281+
{
282+
foreach (BdatMember member in Members.Where(x => x.Type == BdatMemberType.Flag))
283+
{
284+
member.FlagVarIndex++;
285+
}
286+
287+
MembersDict.Add(newMember.Name, newMember);
288+
289+
var newMemberArray = new BdatMember[Members.Length + 1];
290+
newMemberArray[0] = newMember;
291+
Array.Copy(Members, 0, newMemberArray, 1, Members.Length);
292+
293+
Members = newMemberArray;
294+
}
279295
}
280296

281297
public class BdatTable<T> : IBdatTable, IReadOnlyList<T> where T : BdatItem

XbTool/XbTool/Bdat/BdatTables.cs

+49-11
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,12 @@ private static BdatTable[] ReadBdatFile(DataBuffer file, string filename)
159159
public void ReadFieldInfo()
160160
{
161161
BdatFields = BdatInfoImport.ReadBdatFieldInfo(Game.ToString().ToLower());
162-
ResolveFieldInfoWildcards();
162+
Dictionary<(string table, string member), BdatFieldInfo> newFields = BdatInfoImport.ReadBdatNewFieldInfo(Game.ToString().ToLower());
163+
164+
ResolveFieldInfoWildcards(newFields, false);
165+
AddNewFields(newFields);
166+
167+
ResolveFieldInfoWildcards(BdatFields, true);
163168

164169
Dictionary<string, BdatTable> tablesDict = Tables.ToDictionary(x => x.Name, x => x);
165170

@@ -256,9 +261,9 @@ public void ReadTableInfo()
256261
}
257262
}
258263

259-
private void ResolveFieldInfoWildcards()
264+
private void ResolveFieldInfoWildcards(Dictionary<(string table, string member), BdatFieldInfo> bdatFields, bool verifyFieldExists)
260265
{
261-
KeyValuePair<(string table, string member), BdatFieldInfo>[] fields = BdatFields.Where(x => x.Value.Table.Contains('*')).ToArray();
266+
KeyValuePair<(string table, string member), BdatFieldInfo>[] fields = bdatFields.Where(x => x.Value.Table.Contains('*')).ToArray();
262267
Dictionary<string, BdatTable> tablesDict = Tables.ToDictionary(x => x.Name, x => x);
263268

264269
foreach (KeyValuePair<(string table, string member), BdatFieldInfo> field in fields)
@@ -268,7 +273,9 @@ private void ResolveFieldInfoWildcards()
268273
Match[] matches = Tables.Select(x => regex.Match(x.Name)).Where(x => x.Success).ToArray();
269274
foreach (Match match in matches)
270275
{
271-
if (!hasFieldWildcard && !tablesDict[match.Value].Members.Select(x => x.Name).Contains(field.Value.Field))
276+
if (!hasFieldWildcard &&
277+
verifyFieldExists &&
278+
!tablesDict[match.Value].Members.Select(x => x.Name).Contains(field.Value.Field))
272279
{
273280
continue;
274281
}
@@ -283,16 +290,16 @@ private void ResolveFieldInfoWildcards()
283290
if (!tablesDict.ContainsKey(newInfo.RefTable)) continue;
284291
}
285292

286-
if (!BdatFields.ContainsKey((newInfo.Table, newInfo.Field)))
293+
if (!bdatFields.ContainsKey((newInfo.Table, newInfo.Field)))
287294
{
288-
BdatFields.Add((newInfo.Table, newInfo.Field), newInfo);
295+
bdatFields.Add((newInfo.Table, newInfo.Field), newInfo);
289296
}
290297
}
291298

292-
BdatFields.Remove(field.Key);
299+
bdatFields.Remove(field.Key);
293300
}
294301

295-
fields = BdatFields.Where(x => x.Value.Field.Contains('*')).ToArray();
302+
fields = bdatFields.Where(x => x.Value.Field.Contains('*')).ToArray();
296303

297304
foreach (KeyValuePair<(string table, string member), BdatFieldInfo> field in fields)
298305
{
@@ -316,14 +323,14 @@ private void ResolveFieldInfoWildcards()
316323
}
317324
}
318325

319-
if (!BdatFields.ContainsKey((newInfo.Table, newInfo.Field)))
326+
if (!bdatFields.ContainsKey((newInfo.Table, newInfo.Field)))
320327
{
321-
BdatFields.Add((newInfo.Table, newInfo.Field), newInfo);
328+
bdatFields.Add((newInfo.Table, newInfo.Field), newInfo);
322329
}
323330
}
324331
}
325332

326-
BdatFields.Remove(field.Key);
333+
bdatFields.Remove(field.Key);
327334
}
328335
}
329336

@@ -345,6 +352,36 @@ private void ResolveTableInfoWildcards()
345352
}
346353
}
347354

355+
private void AddNewFields(Dictionary<(string table, string member), BdatFieldInfo> newFields)
356+
{
357+
Dictionary<string, BdatTable> tablesDict = Tables.ToDictionary(x => x.Name, x => x);
358+
359+
int removed = 0;
360+
foreach (KeyValuePair<(string table, string member), BdatFieldInfo> fieldKvp in newFields)
361+
{
362+
BdatFieldInfo field = fieldKvp.Value;
363+
364+
if (!tablesDict.TryGetValue(field.Table, out BdatTable table))
365+
{
366+
removed++;
367+
continue;
368+
}
369+
370+
BdatMember fieldInfo = table.Members.FirstOrDefault(x => x.Name == fieldKvp.Key.member);
371+
if (fieldInfo != null)
372+
{
373+
removed++;
374+
continue;
375+
}
376+
377+
var newMember = new BdatMember(fieldKvp.Key.member, BdatMemberType.None, BdatValueType.None);
378+
table.PrependMember(newMember);
379+
380+
BdatFields.Add(fieldKvp.Key, fieldKvp.Value);
381+
}
382+
if (removed > 0) Console.WriteLine($"Ignoring {removed} invalid new fields.");
383+
}
384+
348385
private static BdatType[] CalculateBdatTypes(BdatTable[] tables)
349386
{
350387
Dictionary<string, string> customTypeNames = ReadTypeNames();
@@ -459,6 +496,7 @@ private void MarkFlagMembers()
459496
private static readonly BdatFieldType[] ReadableFieldTypes =
460497
{
461498
BdatFieldType.Reference,
499+
BdatFieldType.OneWayReference,
462500
BdatFieldType.Message,
463501
BdatFieldType.Item,
464502
BdatFieldType.Enum,

XbTool/XbTool/BdatString/BdatStringTools.cs

+74-29
Original file line numberDiff line numberDiff line change
@@ -84,35 +84,80 @@ public static string GetItemTableXb1(ItemTypeXb1 type)
8484
}
8585
}
8686

87-
public static string GetQuestTableXb1(int id)
87+
public static string GetQuestJournalTableXb1(int id) => $"JNL_quest{GetQuestTableSuffixXb1(id)}";
88+
public static string GetQuestMenuTableXb1(int id) => $"MNU_qt{GetQuestTableSuffixXb1(id)}";
89+
90+
private static string GetQuestTableSuffixXb1(int id)
91+
{
92+
if (id > 1200) return "2601";
93+
if (id > 1000) return "2501";
94+
if (id > 960) return "2201";
95+
if (id > 920) return "2101";
96+
if (id > 890) return "2001";
97+
if (id > 850) return "1901";
98+
if (id > 849) return "1801";
99+
if (id > 810) return "1701";
100+
if (id > 809) return "1602";
101+
if (id > 750) return "1601";
102+
if (id > 720) return "1501";
103+
if (id > 680) return "1401";
104+
if (id > 640) return "1301";
105+
if (id > 625) return "1202";
106+
if (id > 610) return "1201";
107+
if (id > 535) return "1101";
108+
if (id > 495) return "1001";
109+
if (id > 465) return "0901";
110+
if (id > 464) return "0801";
111+
if (id > 350) return "0701";
112+
if (id > 310) return "0601";
113+
if (id > 275) return "0501";
114+
if (id > 260) return "0402";
115+
if (id > 173) return "0401";
116+
if (id > 115) return "0301";
117+
if (id > 85) return "0201";
118+
return "0101";
119+
}
120+
121+
public static string GetEnemyTableXb1(int id) => $"BTL_enelist{GetEnemyTableSuffixXb1(id)}";
122+
123+
private static string GetEnemyTableSuffixXb1(int id)
88124
{
89-
if (id > 1200) return "JNL_quest2601";
90-
if (id > 1000) return "JNL_quest2501";
91-
if (id > 960) return "JNL_quest2201";
92-
if (id > 920) return "JNL_quest2101";
93-
if (id > 890) return "JNL_quest2001";
94-
if (id > 850) return "JNL_quest1901";
95-
if (id > 849) return "JNL_quest1801";
96-
if (id > 810) return "JNL_quest1701";
97-
if (id > 809) return "JNL_quest1602";
98-
if (id > 750) return "JNL_quest1601";
99-
if (id > 720) return "JNL_quest1501";
100-
if (id > 680) return "JNL_quest1401";
101-
if (id > 640) return "JNL_quest1301";
102-
if (id > 625) return "JNL_quest1202";
103-
if (id > 610) return "JNL_quest1201";
104-
if (id > 535) return "JNL_quest1101";
105-
if (id > 495) return "JNL_quest1001";
106-
if (id > 465) return "JNL_quest0901";
107-
if (id > 464) return "JNL_quest0801";
108-
if (id > 350) return "JNL_quest0701";
109-
if (id > 310) return "JNL_quest0601";
110-
if (id > 275) return "JNL_quest0501";
111-
if (id > 260) return "JNL_quest0402";
112-
if (id > 173) return "JNL_quest0401";
113-
if (id > 115) return "JNL_quest0301";
114-
if (id > 85) return "JNL_quest0201";
115-
return "JNL_quest0101";
125+
if (id > 3500) return "6001";
126+
if (id > 3450) return "5901";
127+
if (id > 3400) return "5801";
128+
if (id > 3350) return "5701";
129+
if (id > 3300) return "5601";
130+
if (id > 3250) return "5501";
131+
if (id > 3200) return "5401";
132+
if (id > 3150) return "5301";
133+
if (id > 3100) return "5201";
134+
if (id > 3050) return "5101";
135+
if (id > 2900) return "2601";
136+
if (id > 2700) return "2501";
137+
if (id > 2600) return "2401";
138+
if (id > 2500) return "2301";
139+
if (id > 2400) return "2201";
140+
if (id > 2300) return "2101";
141+
if (id > 2200) return "2001";
142+
if (id > 2100) return "1901";
143+
if (id > 1900) return "1701";
144+
if (id > 1700) return "1601";
145+
if (id > 1600) return "1501";
146+
if (id > 1500) return "1401";
147+
if (id > 1400) return "1301";
148+
if (id > 1300) return "1202";
149+
if (id > 1200) return "1201";
150+
if (id > 1100) return "1101";
151+
if (id > 1000) return "1001";
152+
if (id > 900) return "0901";
153+
if (id > 700) return "0701";
154+
if (id > 600) return "0601";
155+
if (id > 500) return "0501";
156+
if (id > 400) return "0402";
157+
if (id > 300) return "0401";
158+
if (id > 200) return "0301";
159+
if (id > 100) return "0201";
160+
return "0101";
116161
}
117162

118163
public static string GetItemTableXbx(ItemTypeXbx type)
@@ -425,7 +470,7 @@ public static string GetTaskTableXb1(TaskTypeXb1 taskType, int itemId)
425470
case TaskTypeXb1.TalkNpc:
426471
return "FLD_npclist";
427472
case TaskTypeXb1.CompleteQuest:
428-
return GetQuestTableXb1(itemId);
473+
return GetQuestJournalTableXb1(itemId);
429474
case TaskTypeXb1.InteractObject:
430475
break;
431476
}

0 commit comments

Comments
 (0)