Refactor: Reorder members and methods of MCInfdevOldLevel to place related methods closer together.
Change version to use TagProperty. Remove some backward compatibility from MCServerChunkGenerator Add # --- Subheaders --- to mark related method groups Fix whitespace according to pep8
This commit is contained in:
parent
f4b40912a3
commit
38cd052bb0
429
infiniteworld.py
429
infiniteworld.py
@ -10,6 +10,7 @@ import itertools
|
|||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from math import floor
|
from math import floor
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
@ -39,6 +40,7 @@ DIM_END = 1
|
|||||||
__all__ = ["ZeroChunk", "AnvilChunk", "ChunkedLevelMixin", "MCInfdevOldLevel", "MCAlphaDimension", "ZipSchematic"]
|
__all__ = ["ZeroChunk", "AnvilChunk", "ChunkedLevelMixin", "MCInfdevOldLevel", "MCAlphaDimension", "ZipSchematic"]
|
||||||
_zeros = {}
|
_zeros = {}
|
||||||
|
|
||||||
|
|
||||||
def ZeroChunk(height=512):
|
def ZeroChunk(height=512):
|
||||||
z = _zeros.get(height)
|
z = _zeros.get(height)
|
||||||
if z is None:
|
if z is None:
|
||||||
@ -46,7 +48,6 @@ def ZeroChunk(height=512):
|
|||||||
return z
|
return z
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class _ZeroChunk(ChunkBase):
|
class _ZeroChunk(ChunkBase):
|
||||||
" a placebo for neighboring-chunk routines "
|
" a placebo for neighboring-chunk routines "
|
||||||
|
|
||||||
@ -86,7 +87,6 @@ class AnvilChunk(LightedChunk):
|
|||||||
for better handling.
|
for better handling.
|
||||||
"""
|
"""
|
||||||
@property
|
@property
|
||||||
|
|
||||||
def filename(self):
|
def filename(self):
|
||||||
cx, cz = self.chunkPosition
|
cx, cz = self.chunkPosition
|
||||||
rx, rz = cx >> 5, cz >> 5
|
rx, rz = cx >> 5, cz >> 5
|
||||||
@ -99,7 +99,6 @@ class AnvilChunk(LightedChunk):
|
|||||||
index=4 * ((cx & 0x1f) + ((cz & 0x1f) * 32))
|
index=4 * ((cx & 0x1f) + ((cz & 0x1f) * 32))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
root_tag = None
|
root_tag = None
|
||||||
|
|
||||||
def __init__(self, world, chunkPosition, create=False):
|
def __init__(self, world, chunkPosition, create=False):
|
||||||
@ -114,13 +113,11 @@ class AnvilChunk(LightedChunk):
|
|||||||
self.SkyLight = zeros((16, 16, self.Height), 'uint8')
|
self.SkyLight = zeros((16, 16, self.Height), 'uint8')
|
||||||
self.SkyLight[:] = 15
|
self.SkyLight[:] = 15
|
||||||
|
|
||||||
|
|
||||||
if create:
|
if create:
|
||||||
self._create()
|
self._create()
|
||||||
else:
|
else:
|
||||||
self._load()
|
self._load()
|
||||||
|
|
||||||
|
|
||||||
def _create(self):
|
def _create(self):
|
||||||
(cx, cz) = self.chunkPosition
|
(cx, cz) = self.chunkPosition
|
||||||
chunkTag = nbt.TAG_Compound()
|
chunkTag = nbt.TAG_Compound()
|
||||||
@ -162,7 +159,6 @@ class AnvilChunk(LightedChunk):
|
|||||||
|
|
||||||
arr[..., y:y + 16] = secarray.swapaxes(0, 2)
|
arr[..., y:y + 16] = secarray.swapaxes(0, 2)
|
||||||
|
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
""" does not recalculate any data or light """
|
""" does not recalculate any data or light """
|
||||||
|
|
||||||
@ -213,7 +209,6 @@ class AnvilChunk(LightedChunk):
|
|||||||
|
|
||||||
self.Blocks[:, :, 1:][badsnow] = self.materials.Air.ID
|
self.Blocks[:, :, 1:][badsnow] = self.materials.Air.ID
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return u"AnvilChunk, coords:{0}, world: {1}, D:{2}, L:{3}".format(self.chunkPosition, self.world.displayName, self.dirty, self.needsLighting)
|
return u"AnvilChunk, coords:{0}, world: {1}, D:{2}, L:{3}".format(self.chunkPosition, self.world.displayName, self.dirty, self.needsLighting)
|
||||||
|
|
||||||
@ -234,7 +229,6 @@ class AnvilChunk(LightedChunk):
|
|||||||
else:
|
else:
|
||||||
computeChunkHeightMap(self.materials, self.Blocks, self.HeightMap)
|
computeChunkHeightMap(self.materials, self.Blocks, self.HeightMap)
|
||||||
|
|
||||||
|
|
||||||
def addEntity(self, entityTag):
|
def addEntity(self, entityTag):
|
||||||
|
|
||||||
def doubleize(name):
|
def doubleize(name):
|
||||||
@ -256,7 +250,6 @@ class AnvilChunk(LightedChunk):
|
|||||||
self.dirty = True
|
self.dirty = True
|
||||||
return super(AnvilChunk, self).removeTileEntitiesInBox(box)
|
return super(AnvilChunk, self).removeTileEntitiesInBox(box)
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def HeightMap(self):
|
def HeightMap(self):
|
||||||
return self.root_tag["Level"]["HeightMap"].value.reshape((16, 16))
|
return self.root_tag["Level"]["HeightMap"].value.reshape((16, 16))
|
||||||
@ -315,6 +308,7 @@ def deflate(data):
|
|||||||
# return zdata
|
# return zdata
|
||||||
return zlib.compress(data)
|
return zlib.compress(data)
|
||||||
|
|
||||||
|
|
||||||
def inflate(data):
|
def inflate(data):
|
||||||
return zlib.decompress(data)
|
return zlib.decompress(data)
|
||||||
|
|
||||||
@ -532,7 +526,6 @@ class ChunkedLevelMixin(MCLevel):
|
|||||||
if i:
|
if i:
|
||||||
info("Finished {2} chunks in {0} ({1} per chunk)".format(d, d / i, i))
|
info("Finished {2} chunks in {0} ({1} per chunk)".format(d, d / i, i))
|
||||||
|
|
||||||
|
|
||||||
def copyBlocksFromInfiniteIter(self, sourceLevel, sourceBox, destinationPoint, blocksToCopy, create=False):
|
def copyBlocksFromInfiniteIter(self, sourceLevel, sourceBox, destinationPoint, blocksToCopy, create=False):
|
||||||
""" copy blocks between two infinite levels by looping through the
|
""" copy blocks between two infinite levels by looping through the
|
||||||
destination's chunks. make a sub-box of the source level for each chunk
|
destination's chunks. make a sub-box of the source level for each chunk
|
||||||
@ -846,7 +839,6 @@ class ChunkedLevelMixin(MCLevel):
|
|||||||
progressInfo = u"{0} Pass {1}: {2} chunks".format(light, i, len(newDirtyChunks))
|
progressInfo = u"{0} Pass {1}: {2} chunks".format(light, i, len(newDirtyChunks))
|
||||||
info(progressInfo)
|
info(progressInfo)
|
||||||
|
|
||||||
|
|
||||||
# propagate light!
|
# propagate light!
|
||||||
# for each of the six cardinal directions, figure a new light value for
|
# for each of the six cardinal directions, figure a new light value for
|
||||||
# adjoining blocks by reducing this chunk's light by light absorption and fall off.
|
# adjoining blocks by reducing this chunk's light by light absorption and fall off.
|
||||||
@ -1027,6 +1019,7 @@ class ChunkedLevelMixin(MCLevel):
|
|||||||
for ch in startingDirtyChunks:
|
for ch in startingDirtyChunks:
|
||||||
ch.needsLighting = False
|
ch.needsLighting = False
|
||||||
|
|
||||||
|
|
||||||
def TagProperty(tagName, tagType, defaultValueFunc=lambda self: None):
|
def TagProperty(tagName, tagType, defaultValueFunc=lambda self: None):
|
||||||
def getter(self):
|
def getter(self):
|
||||||
if tagName not in self.root_tag["Data"]:
|
if tagName not in self.root_tag["Data"]:
|
||||||
@ -1038,152 +1031,8 @@ def TagProperty(tagName, tagType, defaultValueFunc=lambda self: None):
|
|||||||
|
|
||||||
return property(getter, setter)
|
return property(getter, setter)
|
||||||
|
|
||||||
|
|
||||||
class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
||||||
materials = alphaMaterials
|
|
||||||
isInfinite = True
|
|
||||||
parentWorld = None
|
|
||||||
dimNo = 0
|
|
||||||
Height = 256
|
|
||||||
|
|
||||||
@property
|
|
||||||
def displayName(self):
|
|
||||||
# shortname = os.path.basename(self.filename)
|
|
||||||
# if shortname == "level.dat":
|
|
||||||
shortname = os.path.basename(os.path.dirname(self.filename))
|
|
||||||
|
|
||||||
return shortname
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def _isLevel(cls, filename):
|
|
||||||
join = os.path.join
|
|
||||||
exists = os.path.exists
|
|
||||||
|
|
||||||
if exists(join(filename, "chunks.dat")):
|
|
||||||
return False # exclude Pocket Edition folders
|
|
||||||
|
|
||||||
if not os.path.isdir(filename):
|
|
||||||
f = os.path.basename(filename)
|
|
||||||
if f not in ("level.dat", "level.dat_old"):
|
|
||||||
return False
|
|
||||||
filename = os.path.dirname(filename)
|
|
||||||
|
|
||||||
files = os.listdir(filename)
|
|
||||||
if "level.dat" in files or "level.dat_old" in files:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def getWorldBounds(self):
|
|
||||||
if self.chunkCount == 0:
|
|
||||||
return BoundingBox((0, 0, 0), (0, 0, 0))
|
|
||||||
|
|
||||||
allChunks = array(list(self.allChunks))
|
|
||||||
mincx = (allChunks[:, 0]).min()
|
|
||||||
maxcx = (allChunks[:, 0]).max()
|
|
||||||
mincz = (allChunks[:, 1]).min()
|
|
||||||
maxcz = (allChunks[:, 1]).max()
|
|
||||||
|
|
||||||
origin = (mincx << 4, 0, mincz << 4)
|
|
||||||
size = ((maxcx - mincx + 1) << 4, self.Height, (maxcz - mincz + 1) << 4)
|
|
||||||
|
|
||||||
return BoundingBox(origin, size)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "MCInfdevOldLevel(\"" + os.path.split(self.worldDir)[1] + "\")"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SizeOnDisk = TagProperty('SizeOnDisk', nbt.TAG_Long)
|
|
||||||
RandomSeed = TagProperty('RandomSeed', nbt.TAG_Long)
|
|
||||||
Time = TagProperty('Time', nbt.TAG_Long) # Age of the world in ticks. 20 ticks per second; 24000 ticks per day.
|
|
||||||
LastPlayed = TagProperty('LastPlayed', nbt.TAG_Long, lambda self: long(time.time() * 1000))
|
|
||||||
|
|
||||||
LevelName = TagProperty('LevelName', nbt.TAG_String, lambda self: self.displayName)
|
|
||||||
|
|
||||||
MapFeatures = TagProperty('MapFeatures', nbt.TAG_Byte, lambda self: 1)
|
|
||||||
|
|
||||||
GameType = TagProperty('GameType', nbt.TAG_Int, lambda self: 0) # 0 for survival, 1 for creative
|
|
||||||
GAMETYPE_SURVIVAL = 0
|
|
||||||
GAMETYPE_CREATIVE = 1
|
|
||||||
|
|
||||||
VERSION_MCR = 19132
|
|
||||||
VERSION_ANVIL = 19133
|
|
||||||
|
|
||||||
_bounds = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def bounds(self):
|
|
||||||
if self._bounds is None:
|
|
||||||
self._bounds = self.getWorldBounds()
|
|
||||||
return self._bounds
|
|
||||||
|
|
||||||
@property
|
|
||||||
def size(self):
|
|
||||||
return self.bounds.size
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
for rf in (self.regionFiles or {}).values():
|
|
||||||
rf.close()
|
|
||||||
|
|
||||||
self.regionFiles = {}
|
|
||||||
|
|
||||||
self._allChunks = None
|
|
||||||
self._loadedChunks = {}
|
|
||||||
|
|
||||||
def _create(self, filename, random_seed, last_played):
|
|
||||||
|
|
||||||
# create a new level
|
|
||||||
root_tag = nbt.TAG_Compound()
|
|
||||||
root_tag["Data"] = nbt.TAG_Compound()
|
|
||||||
root_tag["Data"]["SpawnX"] = nbt.TAG_Int(0)
|
|
||||||
root_tag["Data"]["SpawnY"] = nbt.TAG_Int(2)
|
|
||||||
root_tag["Data"]["SpawnZ"] = nbt.TAG_Int(0)
|
|
||||||
|
|
||||||
if last_played is None:
|
|
||||||
last_played = long(time.time() * 1000)
|
|
||||||
if random_seed is None:
|
|
||||||
random_seed = long(random.random() * 0xffffffffffffffffL) - 0x8000000000000000L
|
|
||||||
|
|
||||||
self.root_tag = root_tag
|
|
||||||
root_tag["Data"]['version'] = nbt.TAG_Int(self.VERSION_ANVIL)
|
|
||||||
|
|
||||||
self.LastPlayed = long(last_played)
|
|
||||||
self.RandomSeed = long(random_seed)
|
|
||||||
self.SizeOnDisk = 0
|
|
||||||
self.Time = 1
|
|
||||||
self.LevelName = os.path.basename(self.worldDir)
|
|
||||||
|
|
||||||
### if singleplayer:
|
|
||||||
|
|
||||||
self.createPlayer("Player")
|
|
||||||
|
|
||||||
if not os.path.exists(self.worldDir):
|
|
||||||
os.mkdir(self.worldDir)
|
|
||||||
|
|
||||||
def createPlayer(self, playerName):
|
|
||||||
if playerName == "Player":
|
|
||||||
playerTag = self.root_tag["Data"].setdefault(playerName, nbt.TAG_Compound())
|
|
||||||
else:
|
|
||||||
playerTag = nbt.TAG_Compound()
|
|
||||||
|
|
||||||
playerTag['Air'] = nbt.TAG_Short(300)
|
|
||||||
playerTag['AttackTime'] = nbt.TAG_Short(0)
|
|
||||||
playerTag['DeathTime'] = nbt.TAG_Short(0)
|
|
||||||
playerTag['Fire'] = nbt.TAG_Short(-20)
|
|
||||||
playerTag['Health'] = nbt.TAG_Short(20)
|
|
||||||
playerTag['HurtTime'] = nbt.TAG_Short(0)
|
|
||||||
playerTag['Score'] = nbt.TAG_Int(0)
|
|
||||||
playerTag['FallDistance'] = nbt.TAG_Float(0)
|
|
||||||
playerTag['OnGround'] = nbt.TAG_Byte(0)
|
|
||||||
|
|
||||||
playerTag["Inventory"] = nbt.TAG_List()
|
|
||||||
|
|
||||||
playerTag['Motion'] = nbt.TAG_List([nbt.TAG_Double(0) for i in range(3)])
|
|
||||||
playerTag['Pos'] = nbt.TAG_List([nbt.TAG_Double([0.5, 2.8, 0.5][i]) for i in range(3)])
|
|
||||||
playerTag['Rotation'] = nbt.TAG_List([nbt.TAG_Float(0), nbt.TAG_Float(0)])
|
|
||||||
|
|
||||||
if playerName != "Player":
|
|
||||||
playerTag.save(self.getPlayerPath(playerName))
|
|
||||||
|
|
||||||
def __init__(self, filename=None, create=False, random_seed=None, last_played=None):
|
def __init__(self, filename=None, create=False, random_seed=None, last_played=None):
|
||||||
"""
|
"""
|
||||||
@ -1250,7 +1099,38 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
self.players.append("Player")
|
self.players.append("Player")
|
||||||
|
|
||||||
self.preloadDimensions()
|
self.preloadDimensions()
|
||||||
# self.preloadChunkPositions()
|
|
||||||
|
# --- Load, save, create ---
|
||||||
|
|
||||||
|
def _create(self, filename, random_seed, last_played):
|
||||||
|
|
||||||
|
# create a new level
|
||||||
|
root_tag = nbt.TAG_Compound()
|
||||||
|
root_tag["Data"] = nbt.TAG_Compound()
|
||||||
|
root_tag["Data"]["SpawnX"] = nbt.TAG_Int(0)
|
||||||
|
root_tag["Data"]["SpawnY"] = nbt.TAG_Int(2)
|
||||||
|
root_tag["Data"]["SpawnZ"] = nbt.TAG_Int(0)
|
||||||
|
|
||||||
|
if last_played is None:
|
||||||
|
last_played = long(time.time() * 1000)
|
||||||
|
if random_seed is None:
|
||||||
|
random_seed = long(random.random() * 0xffffffffffffffffL) - 0x8000000000000000L
|
||||||
|
|
||||||
|
self.root_tag = root_tag
|
||||||
|
root_tag["Data"]['version'] = nbt.TAG_Int(self.VERSION_ANVIL)
|
||||||
|
|
||||||
|
self.LastPlayed = long(last_played)
|
||||||
|
self.RandomSeed = long(random_seed)
|
||||||
|
self.SizeOnDisk = 0
|
||||||
|
self.Time = 1
|
||||||
|
self.LevelName = os.path.basename(self.worldDir)
|
||||||
|
|
||||||
|
### if singleplayer:
|
||||||
|
|
||||||
|
self.createPlayer("Player")
|
||||||
|
|
||||||
|
if not os.path.exists(self.worldDir):
|
||||||
|
os.mkdir(self.worldDir)
|
||||||
|
|
||||||
def loadLevelDat(self, create=False, random_seed=None, last_played=None):
|
def loadLevelDat(self, create=False, random_seed=None, last_played=None):
|
||||||
|
|
||||||
@ -1273,6 +1153,128 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
info("Error loading level.dat_old. Initializing with defaults.")
|
info("Error loading level.dat_old. Initializing with defaults.")
|
||||||
self._create(self.filename, random_seed, last_played)
|
self._create(self.filename, random_seed, last_played)
|
||||||
|
|
||||||
|
def saveInPlace(self):
|
||||||
|
for level in self.dimensions.itervalues():
|
||||||
|
level.saveInPlace(True)
|
||||||
|
|
||||||
|
dirtyChunkCount = 0
|
||||||
|
if self._loadedChunks:
|
||||||
|
for chunk in self._loadedChunks.itervalues():
|
||||||
|
if chunk.dirty:
|
||||||
|
dirtyChunkCount += 1
|
||||||
|
chunk.save()
|
||||||
|
|
||||||
|
for path, tag in self.playerTagCache.iteritems():
|
||||||
|
tag.save(path)
|
||||||
|
|
||||||
|
self.playerTagCache = {}
|
||||||
|
|
||||||
|
self.root_tag.save(self.filename)
|
||||||
|
info(u"Saved {0} chunks".format(dirtyChunkCount))
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
for rf in (self.regionFiles or {}).values():
|
||||||
|
rf.close()
|
||||||
|
|
||||||
|
self.regionFiles = {}
|
||||||
|
|
||||||
|
self._allChunks = None
|
||||||
|
self._loadedChunks = {}
|
||||||
|
|
||||||
|
# --- Constants ---
|
||||||
|
|
||||||
|
GAMETYPE_SURVIVAL = 0
|
||||||
|
GAMETYPE_CREATIVE = 1
|
||||||
|
|
||||||
|
VERSION_MCR = 19132
|
||||||
|
VERSION_ANVIL = 19133
|
||||||
|
|
||||||
|
# --- Instance variables ---
|
||||||
|
|
||||||
|
materials = alphaMaterials
|
||||||
|
isInfinite = True
|
||||||
|
parentWorld = None
|
||||||
|
dimNo = 0
|
||||||
|
Height = 256
|
||||||
|
_bounds = None
|
||||||
|
|
||||||
|
# --- NBT Tag variables ---
|
||||||
|
|
||||||
|
SizeOnDisk = TagProperty('SizeOnDisk', nbt.TAG_Long)
|
||||||
|
RandomSeed = TagProperty('RandomSeed', nbt.TAG_Long)
|
||||||
|
Time = TagProperty('Time', nbt.TAG_Long) # Age of the world in ticks. 20 ticks per second; 24000 ticks per day.
|
||||||
|
LastPlayed = TagProperty('LastPlayed', nbt.TAG_Long, lambda self: long(time.time() * 1000))
|
||||||
|
|
||||||
|
LevelName = TagProperty('LevelName', nbt.TAG_String, lambda self: self.displayName)
|
||||||
|
|
||||||
|
MapFeatures = TagProperty('MapFeatures', nbt.TAG_Byte, lambda self: 1)
|
||||||
|
|
||||||
|
GameType = TagProperty('GameType', nbt.TAG_Int, lambda self: 0) # 0 for survival, 1 for creative
|
||||||
|
|
||||||
|
version = TagProperty('version', nbt.TAG_Int, lambda s: MCInfdevOldLevel.VERSION_ANVIL)
|
||||||
|
|
||||||
|
# --- World info ---
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "MCInfdevOldLevel(\"" + os.path.split(self.worldDir)[1] + "\")"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def displayName(self):
|
||||||
|
# shortname = os.path.basename(self.filename)
|
||||||
|
# if shortname == "level.dat":
|
||||||
|
shortname = os.path.basename(os.path.dirname(self.filename))
|
||||||
|
|
||||||
|
return shortname
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bounds(self):
|
||||||
|
if self._bounds is None:
|
||||||
|
self._bounds = self.getWorldBounds()
|
||||||
|
return self._bounds
|
||||||
|
|
||||||
|
def getWorldBounds(self):
|
||||||
|
if self.chunkCount == 0:
|
||||||
|
return BoundingBox((0, 0, 0), (0, 0, 0))
|
||||||
|
|
||||||
|
allChunks = array(list(self.allChunks))
|
||||||
|
mincx = (allChunks[:, 0]).min()
|
||||||
|
maxcx = (allChunks[:, 0]).max()
|
||||||
|
mincz = (allChunks[:, 1]).min()
|
||||||
|
maxcz = (allChunks[:, 1]).max()
|
||||||
|
|
||||||
|
origin = (mincx << 4, 0, mincz << 4)
|
||||||
|
size = ((maxcx - mincx + 1) << 4, self.Height, (maxcz - mincz + 1) << 4)
|
||||||
|
|
||||||
|
return BoundingBox(origin, size)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size(self):
|
||||||
|
return self.bounds.size
|
||||||
|
|
||||||
|
# --- Format detection ---
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _isLevel(cls, filename):
|
||||||
|
join = os.path.join
|
||||||
|
exists = os.path.exists
|
||||||
|
|
||||||
|
if exists(join(filename, "chunks.dat")):
|
||||||
|
return False # exclude Pocket Edition folders
|
||||||
|
|
||||||
|
if not os.path.isdir(filename):
|
||||||
|
f = os.path.basename(filename)
|
||||||
|
if f not in ("level.dat", "level.dat_old"):
|
||||||
|
return False
|
||||||
|
filename = os.path.dirname(filename)
|
||||||
|
|
||||||
|
files = os.listdir(filename)
|
||||||
|
if "level.dat" in files or "level.dat_old" in files:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
# --- Dimensions ---
|
||||||
|
|
||||||
def preloadDimensions(self):
|
def preloadDimensions(self):
|
||||||
worldDirs = os.listdir(self.worldDir)
|
worldDirs = os.listdir(self.worldDir)
|
||||||
|
|
||||||
@ -1307,15 +1309,11 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
self.dimensions[dirname] = dim
|
self.dimensions[dirname] = dim
|
||||||
return dim
|
return dim
|
||||||
|
|
||||||
def getRegionForChunk(self, cx, cz):
|
# --- Region I/O ---
|
||||||
rx = cx >> 5
|
|
||||||
rz = cz >> 5
|
|
||||||
return self.getRegionFile(rx, rz)
|
|
||||||
|
|
||||||
def preloadChunkPositions(self):
|
def preloadChunkPositions(self):
|
||||||
self.preloadRegions()
|
self.preloadRegions()
|
||||||
|
|
||||||
|
|
||||||
def findRegionFiles(self):
|
def findRegionFiles(self):
|
||||||
regionDir = os.path.join(self.worldDir, "region")
|
regionDir = os.path.join(self.worldDir, "region")
|
||||||
if not os.path.exists(regionDir):
|
if not os.path.exists(regionDir):
|
||||||
@ -1353,6 +1351,11 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
self.regionFiles[rx, rz] = regionFile
|
self.regionFiles[rx, rz] = regionFile
|
||||||
return regionFile
|
return regionFile
|
||||||
|
|
||||||
|
def getRegionForChunk(self, cx, cz):
|
||||||
|
rx = cx >> 5
|
||||||
|
rz = cz >> 5
|
||||||
|
return self.getRegionFile(rx, rz)
|
||||||
|
|
||||||
def unloadRegions(self):
|
def unloadRegions(self):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
@ -1383,21 +1386,7 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
regionFile.close()
|
regionFile.close()
|
||||||
os.unlink(regionFile.path)
|
os.unlink(regionFile.path)
|
||||||
|
|
||||||
@property
|
# --- Chunk I/O ---
|
||||||
def version(self):
|
|
||||||
if 'version' in self.root_tag['Data']:
|
|
||||||
return self.root_tag['Data']['version'].value
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@version.setter
|
|
||||||
def version(self, val):
|
|
||||||
if 'version' in self.root_tag['Data']:
|
|
||||||
self.root_tag['Data']['version'].value = val
|
|
||||||
|
|
||||||
@version.deleter
|
|
||||||
def version(self):
|
|
||||||
self.root_tag['Data'].pop('version')
|
|
||||||
|
|
||||||
def _loadChunk(self, cx, cz):
|
def _loadChunk(self, cx, cz):
|
||||||
""" load the chunk data from disk, and return its root tag as an NBT_Compound"""
|
""" load the chunk data from disk, and return its root tag as an NBT_Compound"""
|
||||||
@ -1440,11 +1429,6 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
"c.%s.%s.dat" % (base36(cx), base36(cz)))
|
"c.%s.%s.dat" % (base36(cx), base36(cz)))
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def chunkFilenameAt(self, x, y, z):
|
|
||||||
cx = x >> 4
|
|
||||||
cz = z >> 4
|
|
||||||
return self._loadedChunks.get((cx, cz)).filename
|
|
||||||
|
|
||||||
def extractChunksInBox(self, box, parentFolder):
|
def extractChunksInBox(self, box, parentFolder):
|
||||||
for cx, cz in box.chunkPositions:
|
for cx, cz in box.chunkPositions:
|
||||||
if self.containsChunk(cx, cz):
|
if self.containsChunk(cx, cz):
|
||||||
@ -1462,19 +1446,6 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
with file(outputFile, "wb") as f:
|
with file(outputFile, "wb") as f:
|
||||||
chunk.root_tag.save(buf=f)
|
chunk.root_tag.save(buf=f)
|
||||||
|
|
||||||
def heightMapAt(self, x, z):
|
|
||||||
zc = z >> 4
|
|
||||||
xc = x >> 4
|
|
||||||
xInChunk = x & 0xf
|
|
||||||
zInChunk = z & 0xf
|
|
||||||
|
|
||||||
ch = self.getChunk(xc, zc)
|
|
||||||
|
|
||||||
heightMap = ch.HeightMap
|
|
||||||
|
|
||||||
return heightMap[zInChunk, xInChunk]
|
|
||||||
# the heightmap is ordered differently because in minecraft it is a flat array
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def chunkCount(self):
|
def chunkCount(self):
|
||||||
"""Returns the number of chunks in the level. May initiate a costly
|
"""Returns the number of chunks in the level. May initiate a costly
|
||||||
@ -1491,7 +1462,6 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
self.preloadChunkPositions()
|
self.preloadChunkPositions()
|
||||||
return self._allChunks.__iter__()
|
return self._allChunks.__iter__()
|
||||||
|
|
||||||
|
|
||||||
def getChunk(self, cx, cz):
|
def getChunk(self, cx, cz):
|
||||||
""" read the chunk from disk, load it, and return it."""
|
""" read the chunk from disk, load it, and return it."""
|
||||||
|
|
||||||
@ -1511,24 +1481,21 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
for cx, cz in box.chunkPositions:
|
for cx, cz in box.chunkPositions:
|
||||||
self.markDirtyChunk(cx, cz)
|
self.markDirtyChunk(cx, cz)
|
||||||
|
|
||||||
def saveInPlace(self):
|
# --- HeightMaps ---
|
||||||
for level in self.dimensions.itervalues():
|
|
||||||
level.saveInPlace(True)
|
|
||||||
|
|
||||||
dirtyChunkCount = 0
|
def heightMapAt(self, x, z):
|
||||||
if self._loadedChunks:
|
zc = z >> 4
|
||||||
for chunk in self._loadedChunks.itervalues():
|
xc = x >> 4
|
||||||
if chunk.dirty:
|
xInChunk = x & 0xf
|
||||||
dirtyChunkCount += 1
|
zInChunk = z & 0xf
|
||||||
chunk.save()
|
|
||||||
|
|
||||||
for path, tag in self.playerTagCache.iteritems():
|
ch = self.getChunk(xc, zc)
|
||||||
tag.save(path)
|
|
||||||
|
|
||||||
self.playerTagCache = {}
|
heightMap = ch.HeightMap
|
||||||
|
|
||||||
self.root_tag.save(self.filename)
|
return heightMap[zInChunk, xInChunk] # HeightMap indices are backwards
|
||||||
info(u"Saved {0} chunks".format(dirtyChunkCount))
|
|
||||||
|
# --- Entities and TileEntities ---
|
||||||
|
|
||||||
def addEntity(self, entityTag):
|
def addEntity(self, entityTag):
|
||||||
assert isinstance(entityTag, nbt.TAG_Compound)
|
assert isinstance(entityTag, nbt.TAG_Compound)
|
||||||
@ -1583,10 +1550,7 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
info("Removed {0} tile entities".format(count))
|
info("Removed {0} tile entities".format(count))
|
||||||
return count
|
return count
|
||||||
|
|
||||||
def containsPoint(self, x, y, z):
|
# --- Chunk manipulation ---
|
||||||
if y < 0 or y > 127:
|
|
||||||
return False
|
|
||||||
return self.containsChunk(x >> 4, z >> 4)
|
|
||||||
|
|
||||||
def containsChunk(self, cx, cz):
|
def containsChunk(self, cx, cz):
|
||||||
if self._allChunks is not None:
|
if self._allChunks is not None:
|
||||||
@ -1601,6 +1565,11 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
|
|
||||||
return self.getRegionFile(rx, rz).containsChunk(cx, cz)
|
return self.getRegionFile(rx, rz).containsChunk(cx, cz)
|
||||||
|
|
||||||
|
def containsPoint(self, x, y, z):
|
||||||
|
if y < 0 or y > 127:
|
||||||
|
return False
|
||||||
|
return self.containsChunk(x >> 4, z >> 4)
|
||||||
|
|
||||||
def createChunk(self, cx, cz):
|
def createChunk(self, cx, cz):
|
||||||
if self.containsChunk(cx, cz):
|
if self.containsChunk(cx, cz):
|
||||||
raise ValueError("{0}:Chunk {1} already present!".format(self, (cx, cz)))
|
raise ValueError("{0}:Chunk {1} already present!".format(self, (cx, cz)))
|
||||||
@ -1670,7 +1639,7 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
spawnxyz = ["SpawnX", "SpawnY", "SpawnZ"]
|
# --- Player and spawn manipulation ---
|
||||||
|
|
||||||
def playerSpawnPosition(self, player=None):
|
def playerSpawnPosition(self, player=None):
|
||||||
"""
|
"""
|
||||||
@ -1683,7 +1652,7 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
else:
|
else:
|
||||||
playerSpawnTag = self.getPlayerTag(player)
|
playerSpawnTag = self.getPlayerTag(player)
|
||||||
|
|
||||||
return [playerSpawnTag.get(i, dataTag[i]).value for i in self.spawnxyz]
|
return [playerSpawnTag.get(i, dataTag[i]).value for i in ("SpawnX", "SpawnY", "SpawnZ")]
|
||||||
|
|
||||||
def setPlayerSpawnPosition(self, pos, player=None):
|
def setPlayerSpawnPosition(self, pos, player=None):
|
||||||
""" xxx if player is None then it sets the default spawn position for the world """
|
""" xxx if player is None then it sets the default spawn position for the world """
|
||||||
@ -1691,7 +1660,7 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
playerSpawnTag = self.root_tag["Data"]
|
playerSpawnTag = self.root_tag["Data"]
|
||||||
else:
|
else:
|
||||||
playerSpawnTag = self.getPlayerTag(player)
|
playerSpawnTag = self.getPlayerTag(player)
|
||||||
for name, val in zip(self.spawnxyz, pos):
|
for name, val in zip(("SpawnX", "SpawnY", "SpawnZ"), pos):
|
||||||
playerSpawnTag[name] = nbt.TAG_Int(val)
|
playerSpawnTag[name] = nbt.TAG_Int(val)
|
||||||
|
|
||||||
def getPlayerPath(self, player):
|
def getPlayerPath(self, player):
|
||||||
@ -1795,6 +1764,31 @@ class MCInfdevOldLevel(ChunkedLevelMixin, EntityLevel):
|
|||||||
playerTag = self.getPlayerTag(player)
|
playerTag = self.getPlayerTag(player)
|
||||||
return playerTag["playerGameType"].value
|
return playerTag["playerGameType"].value
|
||||||
|
|
||||||
|
def createPlayer(self, playerName):
|
||||||
|
if playerName == "Player":
|
||||||
|
playerTag = self.root_tag["Data"].setdefault(playerName, nbt.TAG_Compound())
|
||||||
|
else:
|
||||||
|
playerTag = nbt.TAG_Compound()
|
||||||
|
|
||||||
|
playerTag['Air'] = nbt.TAG_Short(300)
|
||||||
|
playerTag['AttackTime'] = nbt.TAG_Short(0)
|
||||||
|
playerTag['DeathTime'] = nbt.TAG_Short(0)
|
||||||
|
playerTag['Fire'] = nbt.TAG_Short(-20)
|
||||||
|
playerTag['Health'] = nbt.TAG_Short(20)
|
||||||
|
playerTag['HurtTime'] = nbt.TAG_Short(0)
|
||||||
|
playerTag['Score'] = nbt.TAG_Int(0)
|
||||||
|
playerTag['FallDistance'] = nbt.TAG_Float(0)
|
||||||
|
playerTag['OnGround'] = nbt.TAG_Byte(0)
|
||||||
|
|
||||||
|
playerTag["Inventory"] = nbt.TAG_List()
|
||||||
|
|
||||||
|
playerTag['Motion'] = nbt.TAG_List([nbt.TAG_Double(0) for i in range(3)])
|
||||||
|
playerTag['Pos'] = nbt.TAG_List([nbt.TAG_Double([0.5, 2.8, 0.5][i]) for i in range(3)])
|
||||||
|
playerTag['Rotation'] = nbt.TAG_List([nbt.TAG_Float(0), nbt.TAG_Float(0)])
|
||||||
|
|
||||||
|
if playerName != "Player":
|
||||||
|
playerTag.save(self.getPlayerPath(playerName))
|
||||||
|
|
||||||
|
|
||||||
class MCAlphaDimension (MCInfdevOldLevel):
|
class MCAlphaDimension (MCInfdevOldLevel):
|
||||||
def __init__(self, parentWorld, dimNo, dirname, create=False):
|
def __init__(self, parentWorld, dimNo, dirname, create=False):
|
||||||
@ -1874,7 +1868,6 @@ class ZipSchematic (MCInfdevOldLevel):
|
|||||||
self.Height = 128
|
self.Height = 128
|
||||||
self.Length = 0
|
self.Length = 0
|
||||||
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
MCInfdevOldLevel.close(self)
|
MCInfdevOldLevel.close(self)
|
||||||
self.zipfile.close()
|
self.zipfile.close()
|
||||||
|
@ -315,7 +315,6 @@ class MCServerChunkGenerator(object):
|
|||||||
|
|
||||||
tempWorldDir = os.path.join(tempDir, worldName)
|
tempWorldDir = os.path.join(tempDir, worldName)
|
||||||
tempWorld = infiniteworld.MCInfdevOldLevel(tempWorldDir, create=True, random_seed=level.RandomSeed)
|
tempWorld = infiniteworld.MCInfdevOldLevel(tempWorldDir, create=True, random_seed=level.RandomSeed)
|
||||||
del tempWorld.version # for compatibility with older servers. newer ones will set it again without issue.
|
|
||||||
|
|
||||||
self.tempWorldCache[self.serverVersion, level.RandomSeed] = tempWorld
|
self.tempWorldCache[self.serverVersion, level.RandomSeed] = tempWorld
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user