读取Minecraft .mca文件Chunk偏移量错误,求原因及解决方法
问题分析与修复方案
你的程序出现错误主要是三个核心问题导致的:
1. 数组索引偏移错误
你将DataUnsigned8的索引从1开始存储,但文件读取的原始数据是从0开始存放在DataRaw中的。计算每个chunk条目位置时,你用id+1、id+2等取值,相当于把每个4字节的条目整体向后偏移了1位,完全读错了头部数据。
比如第一个chunk的正确字节应该是DataUnsigned8[id]、DataUnsigned8[id+1]、DataUnsigned8[id+2](对应offset的3个字节),以及DataUnsigned8[id+3](对应size的1个字节),而非从id+1开始取值。
2. Offset未转换为实际字节位置
根据Minecraft区域文件规则,头部存储的offset是以4KB(8192字节)为单位的块数,不是直接的字节偏移。你需要将计算出的offset值乘以8192,才能得到chunk在文件中的实际起始字节位置——这也是你预期从8192开始的原因。
3. 不必要的二进制数据修改
你给二进制数据添加了DataRaw[n]='\0',这不仅毫无意义,还可能破坏原始数据(甚至触发数组越界风险),二进制数据不需要以字符串结束符收尾。
修复后的完整代码
#include<bits/stdc++.h> #include<fstream> using namespace std; char DataRaw[4100]; uint8_t DataUnsigned8[4100]; struct F4K{int pos,sz,dfn;} _chunk[40][40]; int main() { ifstream file("first4K.sample",ios::binary|ios::in|ios::ate); ifstream::pos_type n=file.tellg(); freopen("offset.out","w",stdout); file.seekg(0); file.read((char*)(&DataRaw),n); file.close(); // 索引从0开始,直接映射原始数据 for (int i=0;i<n;i++) DataUnsigned8[i]=uint8_t(DataRaw[i]); for (int x=0;x<32;x++) { for (int z=0;z<32;z++) { int id=4*(x + z*32); // 解析大端字节序的offset,并转换为实际字节位置 _chunk[x][z].pos = ((DataUnsigned8[id]<<16)|(DataUnsigned8[id+1]<<8)|DataUnsigned8[id+2]) * 8192; _chunk[x][z].sz = DataUnsigned8[id+3]; } } cout<<" X Z offset sz\n-------------------"<<endl; for (int x=0;x<32;x++) { for (int z=0;z<32;z++) cout<<setw(2)<<x<<setw(3)<<z<<setw(9)<<_chunk[x][z].pos<<setw(4)<<_chunk[x][z].sz<<endl; } return 0; }
额外提示
如果某个chunk的offset计算后为0,说明该位置的chunk未被生成,后续处理时可以直接跳过这些条目。
内容的提问来源于stack exchange,提问作者CoderCharlie
相关产品推荐
相关产品推荐

