nbt: eagerly load the entire MCR on chunk load
During the first call to get_chunk, we can simply read the whole region file into a BytesIO object. By then re-reading location and timestamp data, we might make scrambled maps a lot less likely. Hopefully mitigates #1888.
This commit is contained in:
@@ -219,12 +219,16 @@ class MCRFileReader(object):
|
|||||||
_location_table_format = struct.Struct(">1024I")
|
_location_table_format = struct.Struct(">1024I")
|
||||||
_timestamp_table_format = struct.Struct(">1024i")
|
_timestamp_table_format = struct.Struct(">1024i")
|
||||||
_chunk_header_format = struct.Struct(">I B")
|
_chunk_header_format = struct.Struct(">I B")
|
||||||
|
_preloaded = False
|
||||||
|
|
||||||
def __init__(self, fileobj):
|
def __init__(self, fileobj):
|
||||||
"""This creates a region object from the given file-like
|
"""This creates a region object from the given file-like
|
||||||
object. Chances are you want to use load_region instead."""
|
object. Chances are you want to use load_region instead."""
|
||||||
self._file = fileobj
|
self._file = fileobj
|
||||||
|
self.load_pre_data()
|
||||||
|
|
||||||
|
def load_pre_data(self):
|
||||||
|
self._file.seek(0)
|
||||||
# read in the location table
|
# read in the location table
|
||||||
location_data = self._file.read(4096)
|
location_data = self._file.read(4096)
|
||||||
if not len(location_data) == 4096:
|
if not len(location_data) == 4096:
|
||||||
@@ -245,6 +249,7 @@ class MCRFileReader(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
self._file.close()
|
self._file.close()
|
||||||
|
del self._file
|
||||||
self._file = None
|
self._file = None
|
||||||
|
|
||||||
def get_chunks(self):
|
def get_chunks(self):
|
||||||
@@ -272,6 +277,16 @@ class MCRFileReader(object):
|
|||||||
z = z % 32
|
z = z % 32
|
||||||
return self._locations[int(x + z * 32)] >> 8 != 0
|
return self._locations[int(x + z * 32)] >> 8 != 0
|
||||||
|
|
||||||
|
def preload_chunks(self):
|
||||||
|
if not self._preloaded:
|
||||||
|
self._file.seek(0)
|
||||||
|
pl_data = BytesIO(self._file.read())
|
||||||
|
self._file.close()
|
||||||
|
self._file = pl_data
|
||||||
|
# re-read location, timestamps
|
||||||
|
self.load_pre_data()
|
||||||
|
self._preloaded = True
|
||||||
|
|
||||||
def load_chunk(self, x, z):
|
def load_chunk(self, x, z):
|
||||||
"""Return a (name, data) tuple for the given chunk, or
|
"""Return a (name, data) tuple for the given chunk, or
|
||||||
None if the given chunk doesn't exist in this region file. If
|
None if the given chunk doesn't exist in this region file. If
|
||||||
@@ -279,6 +294,7 @@ class MCRFileReader(object):
|
|||||||
modulo'd into this range (x % 32, etc.) This is so you can
|
modulo'd into this range (x % 32, etc.) This is so you can
|
||||||
provide chunk coordinates in global coordinates, and still
|
provide chunk coordinates in global coordinates, and still
|
||||||
have the chunks load out of regions properly."""
|
have the chunks load out of regions properly."""
|
||||||
|
self.preload_chunks()
|
||||||
x = x % 32
|
x = x % 32
|
||||||
z = z % 32
|
z = z % 32
|
||||||
location = self._locations[int(x + z * 32)]
|
location = self._locations[int(x + z * 32)]
|
||||||
|
|||||||
Reference in New Issue
Block a user