0

我目前正在开发 NBT 阅读器和编写器来编辑 Minecraft 地图(玩家数据和块本身)。我已经完成了 NBTData 的读取,并且能够编写一个 level.dat 文件来编辑一些玩家数据。

不幸的是,我仍然无法将我的 NBT 二进制数据写入区域文件,因为 Minecraft 不接受我的压缩方法。每当我尝试加载我编辑的块时,它都会给我一个错误,即它找不到 ZLib 压缩的结尾或者它是一种无效的压缩方法(我通过终端启动我的世界时发现了这些错误)。

我正在使用 Mac OSX 附带的 ZLib 库,并且编辑器是用 C++ 编写的。

这是我的压缩代码:

compressionData* compress(unsigned char* buf, int size)
{
    vector<char> data = vector<char>();
    for(int i = 0;i<size;i++)
        data.push_back(buf[i]);

    int ret;
    z_stream zs;
    char buff[4096];
    std::vector<char> out_data;

    // initialize zlib structure
    memset(&zs, 0, sizeof(zs));
    if(deflateInit(&zs, Z_BEST_COMPRESSION) != Z_OK)
        return false;
    zs.next_in = (Bytef *) data.data();
    zs.avail_in = data.size();

    // deflate blocks
    do {
        zs.next_out = reinterpret_cast<Bytef *>(buff);
        zs.avail_out = 4096;

        // deflate data and place in out_data
        ret = deflate(&zs, Z_FINISH);
        out_data.insert(out_data.end(), buff, buff + zs.total_out);
    } while(ret == Z_OK);

    // check for errors
    deflateEnd(&zs);
    if (ret != Z_STREAM_END)
        return false;

    // assign to data
    data = out_data;

    compressionData *rett = new compressionData();
    rett->buf = (unsigned char*)malloc(data.size());
    SharedStats::getSharedStats()->mallocated++;
    for(int i = 0;i<data.size();i++)
        rett->buf[i] = data.at(i);

    rett->size = (int)data.size();

    return rett;
}

compressionData 对象是一个结构,它只包含一个包含数据的无符号字符数组和一个表示数据长度的 int,以字节为单位。

我应该对 Minecraft 块使用哪种 ZLib 加密方法?原始输入块总是以这三个字节开头:02 78 9C,我的块以 02 78 DA 开头。

来自块的所有数据都写入一个区域文件,Minecraft 确实可以识别它们,只是它不喜欢压缩方法。

伟人,艾伦

4

1 回答 1

1

out_data.insert(out_data.end(), buff, buff + zs.total_out);似乎是不正确的。该total_out字段是所有调用生成的数据总量deflate(),而不是刚刚进行的一次调用。实际的字节数buff4096 - zs.avail_out.

78 9c78 da都是有效的zlib 头文件。它们仅在识别使用的压缩级别上有所不同,这对于解压缩无关紧要。

我不知道02是从哪里来的。

于 2013-05-06T20:41:53.313 回答