Question

Iam have a DBC file, which is a database file for a game, containing ingame usable spell data, like ID, SpellName, Category etc... Struct is something like this:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    public struct SpellEntry
    {
        public uint ID;
        public uint Category;
        public float speed;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.I4)]
        public int[] Reagent;
        public int EquippedItemClass;
        [MarshalAs(UnmanagedType.LPStr)] // Crash here
        public string SpellName;
    }

Iam reading the file with a binary reader, and marshaling it to the struct. Snippet:

                    binReader.BaseStream.Seek(DBCFile.HEADER_SIZE + (index * 4 * 234), SeekOrigin.Begin);
                    buff = binReader.ReadBytes(buff.Length);
                    GCHandle handdle = GCHandle.Alloc(buff, GCHandleType.Pinned);
                    Spell.SpellEntry testspell = (Spell.SpellEntry)Marshal.PtrToStructure(handdle.AddrOfPinnedObject(), typeof(Spell.SpellEntry));
                    handdle.Free();

Now to be more complex, lets see how does the DBC file storing the strings, for example the SpellName. Its not in the records, strings are contained in the end of the file, in a "string table" block. The string data in the records contains a number (offset) to the string in the string table. (so its not really a string).

I managed to read all the strings from the string block (at the end of the file), to a string[]. (this is dont before start reading the records) Then I would start reading the records, but first problem Is :

1.) I cant read it, because it "crashes" on the last line of my struct (because its not a string really) 2.) I cant assign a string to the number.

When I read it, it will be a number, but at the end, as a result, I have to assign that string to the SpellName, thats got pointed by the number, in the string table. Jeez .

Was it helpful?

Solution

public struct SpellEntry
{
    //...
    private int SpellNameOffset;
    public string SpellName {
        get { return Mumble.GetString(SpellNameOffset); }
    }
}

This is hard to get right, Mumble must be a static class since you cannot add any members to SpellEntry. That screws up Marshal.SizeOf(), making it too large. You'll need to initialize Mumble so that its static GetString() method can access the string table. Moving the SpellName property into another class solves the problem but makes the code ugly too.

This is liable to confuse you badly. If you got a version going that uses BitConverter then you're definitely better off by using it instead. Separating the file format from the runtime format is in fact an asset here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top