结构阅读理论问题

发布于 2024-10-04 00:58:29 字数 1410 浏览 6 评论 0原文

我有一个 DBC 文件,它是游戏的数据库文件,包含游戏中可用的法术数据,如 ID、法术名称、类别等... 结构是这样的:

    [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;
    }

我用二进制读取器读取文件,并将其编组到结构中。片段:

                    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();

现在变得更复杂,让我们看看 DBC 文件如何存储字符串,例如 SpellName。它不在记录中,字符串包含在文件末尾的“字符串表”块中。记录中的字符串数据包含相对于字符串表中的字符串的数字(偏移量)。 (所以它实际上不是一个字符串)。

我设法将字符串块(位于文件末尾)中的所有字符串读取到 string[] 中。 (这是在开始阅读记录之前不要做的) 然后我会开始阅读记录,但第一个问题是:

1。)我无法阅读它,因为它在我的结构的最后一行“崩溃”(因为它实际上不是一个字符串) 2.)我无法将字符串分配给数字。

当我读取它时,它将是一个数字,但最后,结果,我必须将该字符串分配给SpellName,这被指出了字符串表中的数字。天啊

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 .

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

作妖 2024-10-11 00:58:29
public struct SpellEntry
{
    //...
    private int SpellNameOffset;
    public string SpellName {
        get { return Mumble.GetString(SpellNameOffset); }
    }
}

这很难做到正确,Mumble 必须是静态类,因为您无法向 SpellEntry 添加任何成员。这会搞砸 Marshal.SizeOf(),使其太大。您需要初始化 Mumble,以便其静态 GetString() 方法可以访问字符串表。将 SpellName 属性移到另一个类中可以解决问题,但也会使代码变得丑陋。

这很可能会让你感到非常困惑。如果您有一个使用 BitConverter 的版本,那么使用它肯定会更好。将文件格式与运行时格式分开实际上是一个优点。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文