2

我正在尝试从旧游戏格式中获取 PVS(使用视线渲染)信息。它有文档,到目前为止,我已经能够将所有内容翻译成 C++ 代码。然而,这部分让我很困惑。我今天花了几个小时试图了解从哪里开始,但唉,我什么都没有。同样,这仅适用于那些可能面临挑战或可以提供一些建议甚至伪代码来说明我将如何完成此任务的人。

谢谢

Data6 条目(其中有 Size6 个):

Data6Size1 : WORD 告诉 Data6Data 字段中的条目数。

Data6Data : BYTEs 或 WORDs

这是一个复杂的领域。它包含运行长度编码的数据,告诉客户端哪些区域是“附近的”。目的似乎是为了让客户端可以确定该区域中的哪些生物必须检查其 Z 坐标,以便它们会掉到地上(或直到它们降落在某物上)。由于这样做的成本很高,因此只对玩家可见的区域执行此操作而不是对整个区域中的所有生物执行此操作(重复)是有意义的。

我只遇到过流是 BYTE 列表而不是 WORD 的数据。以下讨论描述了对 BYTE 流进行 RLE 编码。

这里的想法是形成一个在一定距离内的所有区域 ID 的排序列表,然后将该列表写入 RLE 编码流以节省空间。程序如下:

  1. 将初始区域 ID 值设置为零。

  2. 如果(排序的)列表中不存在此区域 ID,请向前跳到列表中的第一个。向流中写入一些内容,告诉它跳过了多少个 ID。

  3. 形成一个列表中的连续 ID 块,并向流中写入一些内容,告诉客户端列表中有这么多 ID。

  4. 如果列表中有更多区域 ID,请返回步骤 2。

写入流时,会写入一个或三个字节:

  • 0x00..0x3E 向前跳过这么多区域 ID
  • 0x3F, WORD 向前跳过以下 16 位 WORD 中给定的数量
  • 0x40..0x7F 基于位 3..5 向前跳过,然后包括基于位 0..2 的 ID 数量
  • 0x80..0xBF 包括基于位 3..5 的 ID 数量,然后基于位 0..2 向前跳过
  • 0xC0..0xFE 减去 0xC0,这么多区域 ID 就在附近
  • 0xFF, WORD 后面的 WORD 给出的 region ID 的数量在附近

应该注意的是,0x40..0xBF 范围内的值允许一次跳过和包含不超过七个 ID。此外,它们不需要对区域列表进行编码:它们只是允许更好的压缩。

4

1 回答 1

1

这是我实现该解包器的尝试。没有测试,因为没有示例数据可以用来测试它......(实际上甚至没有编译)

std::vector<int> regions(std::vector<unsigned char>& data6)
{
    int rp = 0, sz = data6.size();
    std::vector<int> result;
    int current_id = 0;
    while (rp < sz)
    {
        int c = data6[rp++];
        if (c <= 0x3E)
        {
            // 0x00..0x3E : skip forward by this many region IDs
            current_id += c;
        }
        else if (c == 0x3F)
        {
            // 0x3F WORD skip forward by the amount given in the following 16-bit WORD
            if (rp + 2 > sz) throw std::runtime_error("Invalid data");
            int count = data[rp] + (data[rp + 1] << 8); // (NOTE: May be H/L ?)
            rp += 2;
            current_id += count;
        }
        else if (c <= 0x7F)
        {
            // 0x40..0x7F skip forward based on bits 3..5,
            // then include the number of IDs based on bits 0..2
            int keep = (c & 7);
            int skip = (c >> 3) & 7;
            current_id += skip;
            for (int i=0; i<keep; i++)
                result.push_back(current_id++);
        }
        else if (c <= 0xBF)
        {
            // 0x80..0xBF include the number of IDs based on bits 3..5,
            // then skip the number of IDs based on bits 0..2
            int skip = (c & 7);
            int keep = (c >> 3) & 7;
            for (int i=0; i<keep; i++)
                result.push_back(current_id++);
            current_id += skip;
        }
        else if (c <= 0xFE)
        {
            // 0xC0..0xFE subtracting 0xC0, this many region IDs are nearby
            int keep = c - 0xC0;
            for (int i=0; i<keep; i++)
                result.push_back(current_id++);
        }
        else
        {
            // 0xFF WORD the number of region IDs given by the following WORD are nearby
            if (rp + 2 > sz) throw std::runtime_error("Invalid data");
            int count = data[rp] + (data[rp + 1] << 8); // (NOTE: May be H/L ?)
            rp += 2;
            for (int i=0; i<count; i++)
                result.push_back(current_id++);
        }
    }
    return result;
}

我假设WORDs 被编码为低/高,但可能是相反的......

于 2011-06-02T09:46:27.240 回答