-
Notifications
You must be signed in to change notification settings - Fork 43
/
chunk.h
executable file
·159 lines (133 loc) · 4.96 KB
/
chunk.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright 2010-2012 Michael J. Nelson
//
// This file is part of pigmap.
//
// pigmap is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// pigmap is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with pigmap. If not, see <http://www.gnu.org/licenses/>.
#ifndef CHUNK_H
#define CHUNK_H
#include <string.h>
#include <string>
#include <vector>
#include <stdint.h>
#include "map.h"
#include "tables.h"
#include "region.h"
// offset into a chunk of a block
struct BlockOffset
{
int64_t x, z, y;
BlockOffset(const BlockIdx& bi)
{
ChunkIdx ci = bi.getChunkIdx();
x = bi.x - ci.x*16;
z = bi.z - ci.z*16;
y = bi.y;
}
};
struct ChunkData
{
uint8_t blockIDs[65536]; // one byte per block (only half of this space used for old-style chunks)
uint8_t blockAdd[32768]; // only in Anvil--extra bits for block ID (4 bits per block)
uint8_t blockData[32768]; // 4 bits per block (only half of this space used for old-style chunks)
bool anvil; // whether this data came from an Anvil chunk or an old-style one
// these guys assume that the BlockIdx actually points to this chunk
// (so they only look at the lower bits)
uint16_t id(const BlockOffset& bo) const
{
if (!anvil)
return (bo.y > 127) ? 0 : blockIDs[(bo.x * 16 + bo.z) * 128 + bo.y];
int i = (bo.y * 16 + bo.z) * 16 + bo.x;
if ((i % 2) == 0)
return ((blockAdd[i/2] & 0xf) << 8) | blockIDs[i];
return ((blockAdd[i/2] & 0xf0) << 4) | blockIDs[i];
}
uint8_t data(const BlockOffset& bo) const
{
int i;
if (!anvil)
{
if (bo.y > 127)
return 0;
i = (bo.x * 16 + bo.z) * 128 + bo.y;
}
else
i = (bo.y * 16 + bo.z) * 16 + bo.x;
if ((i % 2) == 0)
return blockData[i/2] & 0xf;
return (blockData[i/2] & 0xf0) >> 4;
}
bool loadFromOldFile(const std::vector<uint8_t>& filebuf);
bool loadFromAnvilFile(const std::vector<uint8_t>& filebuf);
};
struct ChunkCacheStats
{
int64_t hits, misses;
// types of misses:
int64_t read; // successfully read from disk
int64_t skipped; // assumed not to exist because not required in a full render
int64_t missing; // non-required chunk not present on disk
int64_t reqmissing; // required chunk not present on disk
int64_t corrupt; // found on disk, but failed to read
// when in region mode, the miss stats have slightly different meanings:
// read: chunk was successfully read from region cache (which may or may not have triggered an
// actual read of the region file from disk)
// missing: not present in the region file, or region file missing/corrupt
// corrupt: region file itself is okay, but chunk data within it is corrupt
// skipped/reqmissing: unused
ChunkCacheStats() : hits(0), misses(0), read(0), skipped(0), missing(0), reqmissing(0), corrupt(0) {}
ChunkCacheStats& operator+=(const ChunkCacheStats& ccs);
};
struct ChunkCacheEntry
{
PosChunkIdx ci; // or [-1,-1] if this entry is empty
ChunkData data;
ChunkCacheEntry() : ci(-1,-1) {}
};
#define CACHEBITSX 5
#define CACHEBITSZ 5
#define CACHEXSIZE (1 << CACHEBITSX)
#define CACHEZSIZE (1 << CACHEBITSZ)
#define CACHESIZE (CACHEXSIZE * CACHEZSIZE)
#define CACHEXMASK (CACHEXSIZE - 1)
#define CACHEZMASK (CACHEZSIZE - 1)
struct ChunkCache : private nocopy
{
ChunkCacheEntry entries[CACHESIZE];
ChunkData blankdata; // for use with missing chunks
ChunkTable& chunktable;
RegionTable& regiontable;
ChunkCacheStats& stats;
RegionCache& regioncache;
std::string inputpath;
bool fullrender;
bool regionformat;
std::vector<uint8_t> readbuf; // buffer for decompressing into when reading
ChunkCache(ChunkTable& ctable, RegionTable& rtable, RegionCache& rcache, const std::string& inpath, bool fullr, bool regform, ChunkCacheStats& st)
: chunktable(ctable), regiontable(rtable), regioncache(rcache), inputpath(inpath), fullrender(fullr), regionformat(regform), stats(st)
{
memset(blankdata.blockIDs, 0, 65536);
memset(blankdata.blockData, 0, 32768);
memset(blankdata.blockAdd, 0, 32768);
blankdata.anvil = true;
readbuf.reserve(262144);
}
// look up a chunk and return a pointer to its data
// ...for missing/corrupt chunks, return a pointer to some blank data
ChunkData* getData(const PosChunkIdx& ci);
static int getEntryNum(const PosChunkIdx& ci) {return (ci.x & CACHEXMASK) * CACHEZSIZE + (ci.z & CACHEZMASK);}
void readChunkFile(const PosChunkIdx& ci);
void readFromRegionCache(const PosChunkIdx& ci);
void parseReadBuf(const PosChunkIdx& ci, bool anvil);
};
#endif // CHUNK_H