forked from equalpants/pigmap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
region.h
executable file
·179 lines (145 loc) · 6.17 KB
/
region.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Copyright 2011 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 REGION_H
#define REGION_H
#include <stdint.h>
#include "map.h"
#include "tables.h"
// offset into a region of a chunk
struct ChunkOffset
{
int64_t x, z;
ChunkOffset(const ChunkIdx& ci)
{
RegionIdx ri = ci.getRegionIdx();
x = ci.x - ri.x*32;
z = ci.z - ri.z*32;
}
};
struct string84
{
std::string s;
explicit string84(const std::string& sss) : s(sss) {}
};
struct RegionFileReader
{
// region file is broken into 4096-byte sectors; first sector is the header that holds the
// chunk offsets, remaining sectors are chunk data
// chunk offsets are big-endian; lower (that is, 4th) byte is size in sectors, upper 3 bytes are
// sector offset *in region file* (one more than the offset into chunkdata)
// offsets are indexed by Z*32 + X
std::vector<uint32_t> offsets;
// each set of chunk data contains:
// -a 4-byte big-endian data length (not including the length field itself)
// -a single-byte version: 1 for gzip, 2 for zlib (this byte *is* included in the length)
// -length - 1 bytes of actual compressed data
std::vector<uint8_t> chunkdata;
// whether this data was read from an Anvil region file or an old-style one
bool anvil;
RegionFileReader()
{
offsets.resize(32 * 32);
chunkdata.reserve(8388608);
}
void swap(RegionFileReader& rfr)
{
offsets.swap(rfr.offsets);
chunkdata.swap(rfr.chunkdata);
std::swap(anvil, rfr.anvil);
}
// extract values from the offsets
static int getIdx(const ChunkOffset& co) {return co.z*32 + co.x;}
uint32_t getSizeSectors(int idx) const {return fromBigEndian(offsets[idx]) & 0xff;}
uint32_t getSectorOffset(int idx) const {return fromBigEndian(offsets[idx]) >> 8;}
bool containsChunk(const ChunkOffset& co) {return offsets[getIdx(co)] != 0;}
// attempt to read a region file; return 0 for success, -1 for file not found, -2 for
// other errors
// looks for an Anvil region file (.mca) first, then an old-style one (.mcr)
int loadFromFile(const RegionIdx& ri, const std::string& inputpath);
// attempt to decompress a chunk into a buffer; return 0 for success, -1 for missing chunk,
// -2 for other errors
// (this is not const only because zlib won't take const pointers for input)
int decompressChunk(const ChunkOffset& co, std::vector<uint8_t>& buf);
// attempt to read only the header (i.e. the chunk offsets) from a region file; return 0
// for success, -1 for file not found, -2 for other errors
// looks for an Anvil region file (.mca) first, then an old-style one (.mcr)
int loadHeaderOnly(const RegionIdx& ri, const std::string& inputpath);
// open a region file, load only its header, and return a list of chunks it contains (i.e. the ones that
// actually currently exist)
// ...returns 0 for success, -1 for file not found, -2 for other errors
int getContainedChunks(const RegionIdx& ri, const string84& inputpath, std::vector<ChunkIdx>& chunks);
};
// iterates over the chunks in a region
struct RegionChunkIterator
{
bool end; // true once we've reached the end
ChunkIdx current; // if end == false, holds the current chunk
ChunkIdx basechunk;
// constructor initializes to to first chunk in provided region
RegionChunkIterator(const RegionIdx& ri);
// move to the next chunk, or to the end
void advance();
};
struct RegionCacheStats
{
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 region not present on disk
int64_t reqmissing; // required region not present on disk
int64_t corrupt; // found on disk, but failed to read
RegionCacheStats() : hits(0), misses(0), read(0), skipped(0), missing(0), reqmissing(0), corrupt(0) {}
RegionCacheStats& operator+=(const RegionCacheStats& rs);
};
struct RegionCacheEntry
{
PosRegionIdx ri; // or [-1, -1] if this entry is empty
RegionFileReader regionfile;
RegionCacheEntry() : ri(-1,-1) {}
};
#define RCACHEBITSX 1
#define RCACHEBITSZ 1
#define RCACHEXSIZE (1 << RCACHEBITSX)
#define RCACHEZSIZE (1 << RCACHEBITSZ)
#define RCACHESIZE (RCACHEXSIZE * RCACHEZSIZE)
#define RCACHEXMASK (RCACHEXSIZE - 1)
#define RCACHEZMASK (RCACHEZSIZE - 1)
struct RegionCache : private nocopy
{
RegionCacheEntry entries[RCACHESIZE];
ChunkTable& chunktable;
RegionTable& regiontable;
RegionCacheStats& stats;
std::string inputpath;
bool fullrender;
// readbuf is an extra less-important cache entry--when a new region is read, it's this entry which will be trashed
// and its storage used for the read (which might fail), but if the read succeeds, the new region is swapped
// into its proper place in the cache, and the previous tenant there moves here
RegionCacheEntry readbuf;
RegionCache(ChunkTable& ctable, RegionTable& rtable, const std::string& inpath, bool fullr, RegionCacheStats& st)
: chunktable(ctable), regiontable(rtable), inputpath(inpath), fullrender(fullr), stats(st)
{
}
// attempt to decompress a chunk into a buffer; return 0 for success, -1 for missing chunk,
// -2 for other errors
// (this is not const only because zlib won't take const pointers for input)
int getDecompressedChunk(const PosChunkIdx& ci, std::vector<uint8_t>& buf, bool& anvil);
static int getEntryNum(const PosRegionIdx& ri) {return (ri.x & RCACHEXMASK) * RCACHEZSIZE + (ri.z & RCACHEZMASK);}
void readRegionFile(const PosRegionIdx& ri);
};
#endif // REGION_H