For the last couple of days, I've been tinkering with reading DBC structures from the .dbc files without manually defining mappers (which is especially needed because of their annoying way to lay out strings (the string table)).
Here's what I'm currently doing:
Code:
public void LoadRecords()
{
_reader.BaseStream.Position = DataStoreHeader.Size;
var list = new List<T>(Header.RecordCount);
var type = typeof(T);
var size = Marshal.SizeOf(type);
for (var i = 0; i < Header.RecordCount; i++)
{
var bytes = _reader.ReadBytes(size);
var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
var obj = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), type);
handle.Free();
list.Add(obj);
}
Records = list.AsReadOnly();
}
Now, obviously, that won't work too well for strings, given that they are stored in the string table. Would anyone have an idea as to how one could grab them and marshal them to a string[] (or just string, if you disregard localization) field in the DBC struct?
Sample struct for AreaTable.dbc that I'm using (with a nice hack for the area name):
Code:
[DataStoreRecord("AreaTable.dbc")]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct AreaTableRecord
{
public int Id;
public int MapId;
public int ZoneId;
public int ExplorationFlag;
public int Flags;
public int SoundPreferences1;
public int SoundPreferences2;
public int SoundAmbience;
public int ZoneMusic;
public int ZoneIntroMusicTable;
public int AreaLevel;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public int[] AreaName;
public int NameFlags;
public int TeamId;
public int Unknown1;
public int Unknown2;
public int Unknown3;
public int Unknown4;
public float MinimumZ;
public float CharacterAmbientLighting;
public int Unknown5;
}
I was considering just annotating each field with a DataStoreIndexAttribute and then define some LocalizedStringAttribute to put on the strings. I could then loop over the type's fields manually and set their values [reason for the index attribute would be that Type.GetFields() doesn't return the fields in a reliable order (see MSDN)]. However, that pretty much beats the purpose of 'nice and clean' automatic marshaling. Then again, it'd still be nicer than defining mapper classes and manually reaidng data.
Any suggestions?