Skip to content

Commit 4529708

Browse files
committed
C#: Initial .dbde and .dbdf parsing
1 parent 1adc845 commit 4529708

6 files changed

Lines changed: 247 additions & 73 deletions

File tree

code/C#/DBDefsLib/DBDEnumReader.cs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
using DBDefsLib.Constants;
2+
using DBDefsLib.Structs;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Globalization;
6+
using System.IO;
7+
8+
namespace DBDefsLib
9+
{
10+
/// <summary>
11+
/// This handles both .dbdf and .dbde reading (<see cref="MetaType.FLAGS"/> and <see cref="MetaType.ENUM"/>)
12+
/// </summary>
13+
public class DBDEnumReader
14+
{
15+
private EnumDefinition Read(Stream stream, MetaType metaType)
16+
{
17+
var reader = new StreamReader(stream);
18+
var lines = reader.ReadLines();
19+
20+
reader.Close();
21+
reader.Dispose();
22+
23+
var entries = new List<EnumEntry>();
24+
25+
var lineNumber = 0;
26+
while (lineNumber < lines.Count)
27+
{
28+
var line = lines[lineNumber++];
29+
30+
if (string.IsNullOrWhiteSpace(line))
31+
continue;
32+
33+
var entry = new EnumEntry
34+
{
35+
builds = [],
36+
buildRanges = []
37+
};
38+
39+
// Optional build qualifier: (BUILD range1, range2, build1) ...
40+
if (line.StartsWith("(BUILD "))
41+
{
42+
var closeIndex = line.IndexOf(')');
43+
if (closeIndex < 0)
44+
throw new Exception($"Line {lineNumber}: Missing closing ')' for build qualifier");
45+
46+
var (builds, buildRanges) = Utils.ParseBuildQualifier(line[1..closeIndex], lineNumber);
47+
entry.builds = builds.ToArray();
48+
entry.buildRanges = buildRanges.ToArray();
49+
50+
line = line[(closeIndex + 1)..].TrimStart();
51+
}
52+
53+
// Optional comment after //
54+
if (line.Contains("//"))
55+
{
56+
var commentIndex = line.IndexOf("//", StringComparison.Ordinal);
57+
entry.comment = line[(commentIndex + 2)..].Trim();
58+
line = line[..commentIndex].TrimEnd();
59+
}
60+
61+
// Remaining: "value [name]"
62+
var parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
63+
if (parts.Length == 0)
64+
throw new Exception($"Line {lineNumber}: Empty entry after stripping qualifier/comment");
65+
66+
var valueStr = parts[0];
67+
if (metaType == MetaType.FLAGS)
68+
{
69+
if (!valueStr.StartsWith("0x", StringComparison.OrdinalIgnoreCase) || !ulong.TryParse(valueStr[2..], NumberStyles.HexNumber, null, out entry.value))
70+
throw new Exception($"Line {lineNumber}: Invalid flag value '{valueStr}', expected hex prefixed with 0x");
71+
}
72+
else
73+
{
74+
if (!ulong.TryParse(valueStr, out entry.value))
75+
throw new Exception($"Line {lineNumber}: Invalid enum value '{valueStr}'");
76+
}
77+
78+
if (parts.Length >= 2)
79+
entry.name = parts[1];
80+
81+
entries.Add(entry);
82+
}
83+
84+
return new EnumDefinition { metaType = metaType, entries = entries };
85+
}
86+
87+
public EnumDefinition Read(string file, MetaType metaType)
88+
{
89+
if (!File.Exists(file))
90+
throw new FileNotFoundException($"Unable to find meta file: {file}");
91+
92+
using var stream = File.Open(file, FileMode.Open, FileAccess.Read);
93+
return Read(stream, metaType);
94+
}
95+
}
96+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using DBDefsLib.Constants;
2+
using System.Collections.Generic;
3+
4+
namespace DBDefsLib.Structs
5+
{
6+
public struct EnumDefinition
7+
{
8+
public MetaType metaType;
9+
public List<EnumEntry> entries;
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace DBDefsLib.Structs
2+
{
3+
public record struct EnumEntry
4+
{
5+
public ulong value;
6+
public string name;
7+
public Build[] builds;
8+
public BuildRange[] buildRanges;
9+
public string comment;
10+
}
11+
}

code/C#/DBDefsLib/Utils.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,32 @@ public static List<string> ReadLines(this StreamReader reader)
112112

113113
return list;
114114
}
115+
116+
public static (List<Build> builds, List<BuildRange> buildRanges) ParseBuildQualifier(string qualifier, int lineNumber)
117+
{
118+
if (!qualifier.StartsWith("BUILD "))
119+
throw new Exception($"Line {lineNumber}: Build qualifier does not start with 'BUILD '");
120+
121+
var builds = new List<Build>();
122+
var buildRanges = new List<BuildRange>();
123+
124+
var buildsPart = qualifier["BUILD ".Length..];
125+
var parts = buildsPart.Split(new[] { ", " }, StringSplitOptions.RemoveEmptyEntries);
126+
127+
foreach (var part in parts)
128+
{
129+
if (BuildRange.TryParse(part, out var range))
130+
buildRanges.Add(range);
131+
else if (Build.TryParse(part, out var build))
132+
builds.Add(build);
133+
else
134+
throw new Exception($"Line {lineNumber}: Invalid build or build range: '{part}'");
135+
}
136+
137+
return (builds, buildRanges);
138+
}
115139
}
140+
116141
public static class BinaryWriterExtensions
117142
{
118143
public static void WriteStringBlockString(this BinaryWriter bw, Dictionary<string, int> stringBlock, string stringToWrite)

code/C#/DBDefsTest/Program.cs

Lines changed: 97 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.IO;
88
using System.Linq;
99
using System.Security.Cryptography;
10+
using DBDefsLib.Constants;
1011

1112
namespace DBDTest
1213
{
@@ -20,82 +21,113 @@ class Program
2021

2122
static void Main(string[] args)
2223
{
23-
if (args.Length < 2)
24-
{
25-
Console.WriteLine("Usage: <input (definitions dir or bdbd)> <dbcdir>");
26-
Environment.Exit(1);
27-
}
24+
var dbdmReader = new DBDMReader();
25+
var mappingDefinition = dbdmReader.Read(args[0]);
2826

29-
var inputDir = args[0];
30-
dbcDir = args[1];
31-
32-
if (Directory.Exists(inputDir))
27+
var metaDirectory = Path.GetDirectoryName(args[0]);
28+
foreach (var definition in mappingDefinition)
3329
{
34-
if (!Directory.Exists(dbcDir))
35-
{
36-
throw new DirectoryNotFoundException("Directory " + dbcDir + " does not exist!");
37-
}
30+
if (definition.meta is MetaType.COLOR)
31+
continue;
3832

39-
var sw = new Stopwatch();
40-
sw.Start();
41-
foreach (var file in Directory.GetFiles(inputDir))
42-
{
43-
var reader = new DBDReader();
44-
definitionCache.Add(Path.GetFileNameWithoutExtension(file).ToLower(), reader.Read(file));
45-
}
46-
sw.Stop();
47-
Console.WriteLine("Read " + definitionCache.Count + " database definitions from DBDs in " + sw.ElapsedMilliseconds + "ms!");
48-
}
49-
else if (File.Exists(inputDir) && inputDir.EndsWith(".bdbd", StringComparison.InvariantCultureIgnoreCase))
50-
{
51-
var sw = new Stopwatch();
52-
sw.Start();
53-
using (var stream = File.OpenRead(inputDir))
54-
{
55-
var defs = BDBDReader.Read(stream);
56-
foreach(var def in defs)
57-
{
58-
definitionCache.Add(def.Key.ToLower(), def.Value.dbd);
59-
}
60-
}
61-
sw.Stop();
62-
Console.WriteLine("Read " + definitionCache.Count + " database definitions from BDBD in " + sw.ElapsedMilliseconds + "ms!");
63-
}
33+
var extension = definition.meta == MetaType.ENUM ? ".dbde" : ".dbdf";
34+
var directoryName = definition.meta == MetaType.ENUM ? "enums" : "flags";
6435

65-
var builds = new List<Build>();
36+
var parseFile = Path.Combine(metaDirectory!, directoryName, $"{definition.metaValue}{extension}");
37+
if (!File.Exists(parseFile))
38+
continue;
6639

67-
foreach (var dir in Directory.GetDirectories(dbcDir))
68-
{
69-
builds.Add(new Build(dir.Replace(dbcDir + "\\", "")));
70-
}
71-
72-
builds.Sort();
73-
74-
foreach(var build in builds)
75-
{
76-
if (build.expansion != 8 || build.major != 2) continue;
77-
78-
Console.WriteLine("Checking " + build + "..");
79-
if (Directory.Exists(Path.Combine(dbcDir, build.ToString(), "DBFilesClient")))
40+
try
8041
{
81-
foreach (var file in Directory.GetFiles(Path.Combine(dbcDir, build.ToString(), "DBFilesClient")))
82-
{
83-
LoadDBC(file);
84-
}
42+
var enumReader = new DBDEnumReader();
43+
var enumDef = enumReader.Read(parseFile, definition.meta);
44+
Console.WriteLine($"[{definition.meta}] {definition.metaValue}: {enumDef.entries.Count} entries");
8545
}
86-
else
46+
catch (Exception e)
8747
{
88-
foreach (var file in Directory.GetFiles(Path.Combine(dbcDir, build.ToString())))
89-
{
90-
LoadDBC(file);
91-
}
48+
Console.ForegroundColor = ConsoleColor.Red;
49+
Console.WriteLine($"[ERROR] Failed to read {parseFile}: {e.Message}");
50+
Console.ResetColor();
51+
foundError = true;
9252
}
9353
}
9454

95-
if (foundError)
96-
{
97-
Environment.Exit(1);
98-
}
55+
// if (args.Length < 2)
56+
// {
57+
// Console.WriteLine("Usage: <input (definitions dir or bdbd)> <dbcdir>");
58+
// Environment.Exit(1);
59+
// }
60+
//
61+
// var inputDir = args[0];
62+
// dbcDir = args[1];
63+
//
64+
// if (Directory.Exists(inputDir))
65+
// {
66+
// if (!Directory.Exists(dbcDir))
67+
// {
68+
// throw new DirectoryNotFoundException("Directory " + dbcDir + " does not exist!");
69+
// }
70+
//
71+
// var sw = new Stopwatch();
72+
// sw.Start();
73+
// foreach (var file in Directory.GetFiles(inputDir))
74+
// {
75+
// var reader = new DBDReader();
76+
// definitionCache.Add(Path.GetFileNameWithoutExtension(file).ToLower(), reader.Read(file));
77+
// }
78+
// sw.Stop();
79+
// Console.WriteLine("Read " + definitionCache.Count + " database definitions from DBDs in " + sw.ElapsedMilliseconds + "ms!");
80+
// }
81+
// else if (File.Exists(inputDir) && inputDir.EndsWith(".bdbd", StringComparison.InvariantCultureIgnoreCase))
82+
// {
83+
// var sw = new Stopwatch();
84+
// sw.Start();
85+
// using (var stream = File.OpenRead(inputDir))
86+
// {
87+
// var defs = BDBDReader.Read(stream);
88+
// foreach(var def in defs)
89+
// {
90+
// definitionCache.Add(def.Key.ToLower(), def.Value.dbd);
91+
// }
92+
// }
93+
// sw.Stop();
94+
// Console.WriteLine("Read " + definitionCache.Count + " database definitions from BDBD in " + sw.ElapsedMilliseconds + "ms!");
95+
// }
96+
//
97+
// var builds = new List<Build>();
98+
//
99+
// foreach (var dir in Directory.GetDirectories(dbcDir))
100+
// {
101+
// builds.Add(new Build(dir.Replace(dbcDir + "\\", "")));
102+
// }
103+
//
104+
// builds.Sort();
105+
//
106+
// foreach(var build in builds)
107+
// {
108+
// if (build.expansion != 8 || build.major != 2) continue;
109+
//
110+
// Console.WriteLine("Checking " + build + "..");
111+
// if (Directory.Exists(Path.Combine(dbcDir, build.ToString(), "DBFilesClient")))
112+
// {
113+
// foreach (var file in Directory.GetFiles(Path.Combine(dbcDir, build.ToString(), "DBFilesClient")))
114+
// {
115+
// LoadDBC(file);
116+
// }
117+
// }
118+
// else
119+
// {
120+
// foreach (var file in Directory.GetFiles(Path.Combine(dbcDir, build.ToString())))
121+
// {
122+
// LoadDBC(file);
123+
// }
124+
// }
125+
// }
126+
//
127+
// if (foundError)
128+
// {
129+
// Environment.Exit(1);
130+
// }
99131
}
100132

101133
static void LoadDBC(string filename)

meta/mapping.dbdm

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,6 @@ ENUM SpellEffect::EffectMiscValue[0] DamageClass SpellEffect::EffectAura=69
77
FLAGS Achievement::Flags AchievementFlags
88
FLAGS SpellMisc::Flags[0] SpellAttributes0
99
FLAGS SpellMisc::Flags[1] SpellAttributes1
10-
FLAGS SpellMisc::Flags[10] SpellAttributes10
11-
FLAGS SpellMisc::Flags[11] SpellAttributes11
12-
FLAGS SpellMisc::Flags[12] SpellAttributes12
13-
FLAGS SpellMisc::Flags[13] SpellAttributes13
14-
FLAGS SpellMisc::Flags[14] SpellAttributes14
15-
FLAGS SpellMisc::Flags[15] SpellAttributes15 // Some comment
16-
FLAGS SpellMisc::Flags[16] SpellAttributes16
1710
FLAGS SpellMisc::Flags[2] SpellAttributes2
1811
FLAGS SpellMisc::Flags[3] SpellAttributes3
1912
FLAGS SpellMisc::Flags[4] SpellAttributes4
@@ -22,4 +15,10 @@ FLAGS SpellMisc::Flags[6] SpellAttributes6
2215
FLAGS SpellMisc::Flags[7] SpellAttributes7
2316
FLAGS SpellMisc::Flags[8] SpellAttributes8
2417
FLAGS SpellMisc::Flags[9] SpellAttributes9
25-
18+
FLAGS SpellMisc::Flags[10] SpellAttributes10
19+
FLAGS SpellMisc::Flags[11] SpellAttributes11
20+
FLAGS SpellMisc::Flags[12] SpellAttributes12
21+
FLAGS SpellMisc::Flags[13] SpellAttributes13
22+
FLAGS SpellMisc::Flags[14] SpellAttributes14
23+
FLAGS SpellMisc::Flags[15] SpellAttributes15 // Some comment
24+
FLAGS SpellMisc::Flags[16] SpellAttributes16

0 commit comments

Comments
 (0)