Schematics are now exported with an ItemIDs mapping and an itemStackVersion value.
Remove and comment out some dead/unused code. INVEditChest shouldn't be important now that we have an inventory editor.
This commit is contained in:
parent
839ae3c3d3
commit
346f5c7c73
@ -8,14 +8,15 @@ from collections import defaultdict
|
||||
import os
|
||||
|
||||
from logging import getLogger
|
||||
import itertools
|
||||
|
||||
from numpy import array, swapaxes, uint8, zeros
|
||||
from numpy import swapaxes, uint8, zeros
|
||||
import numpy
|
||||
|
||||
from mceditlib.anvil.adapter import AnvilWorldAdapter
|
||||
from mceditlib.anvil.entities import PCEntityRef
|
||||
from mceditlib.anvil.entities import PCTileEntityRef
|
||||
from mceditlib.exceptions import PlayerNotFound
|
||||
from mceditlib.anvil.adapter import VERSION_1_7, VERSION_1_8
|
||||
from mceditlib.anvil.entities import PCEntityRef, PCTileEntityRef, \
|
||||
ItemStackRef
|
||||
from mceditlib.exceptions import PlayerNotFound, LevelFormatError
|
||||
from mceditlib.selection import BoundingBox
|
||||
from mceditlib.fakechunklevel import FakeChunkedLevelAdapter, FakeChunkData
|
||||
from mceditlib.blocktypes import BlockTypeSet, PCBlockTypeSet
|
||||
@ -41,7 +42,10 @@ def blockIDMapping(blocktypes):
|
||||
return mapping
|
||||
|
||||
def itemIDMapping(blocktypes):
|
||||
return nbt.TAG_Compound()
|
||||
mapping = nbt.TAG_Compound()
|
||||
for name, ID in blocktypes.itemTypes.IDsByInternalName.iteritems():
|
||||
mapping[str(ID)] = nbt.TAG_String(name)
|
||||
return mapping
|
||||
|
||||
class SchematicChunkData(FakeChunkData):
|
||||
def addEntity(self, entity):
|
||||
@ -55,8 +59,6 @@ class SchematicFileAdapter(FakeChunkedLevelAdapter):
|
||||
|
||||
"""
|
||||
# XXX use abstract entity ref or select correct ref for contained level format
|
||||
EntityRef = PCEntityRef
|
||||
TileEntityRef = PCTileEntityRef
|
||||
|
||||
ChunkDataClass = SchematicChunkData
|
||||
|
||||
@ -78,6 +80,9 @@ class SchematicFileAdapter(FakeChunkedLevelAdapter):
|
||||
:rtype: SchematicFileAdapter
|
||||
|
||||
"""
|
||||
self.EntityRef = PCEntityRef
|
||||
self.TileEntityRef = PCTileEntityRef
|
||||
|
||||
if filename is None and shape is None:
|
||||
raise ValueError("shape or filename required to create %s" % self.__class__.__name__)
|
||||
|
||||
@ -141,14 +146,35 @@ class SchematicFileAdapter(FakeChunkedLevelAdapter):
|
||||
if "Biomes" in self.rootTag:
|
||||
self.rootTag["Biomes"].value.shape = (l, w)
|
||||
|
||||
if "BlockIDs" in self.rootTag or "ItemIDs" in self.rootTag:
|
||||
self.blocktypes = type(self.blocktypes)()
|
||||
# If BlockIDs is present, it contains an ID->internalName mapping
|
||||
# from the source level's FML tag.
|
||||
|
||||
if "BlockIDs" in self.rootTag:
|
||||
self.blocktypes.addBlockIDsFromSchematicTag(self.rootTag["BlockIDs"])
|
||||
if "ItemIDs" in self.rootTag:
|
||||
self.blocktypes.addItemIDsFromSchematicTag(self.rootTag["ItemIDs"])
|
||||
|
||||
# If itemStackVersion is present, it was exported from MCEdit 2.0.
|
||||
# Its value is either 17 or 18, the values of the version constants.
|
||||
# ItemIDs will also be present.
|
||||
|
||||
# If itemStackVersion is not present, this schematic was exported from
|
||||
# WorldEdit or MCEdit 1.0. The itemStackVersion cannot be determined
|
||||
# without searching the entities for an itemStack and checking
|
||||
# the type of its `id` tag. If no itemStacks are found, the
|
||||
# version defaults to 1.8 which does not need an ItemIDs tag.
|
||||
|
||||
|
||||
if "itemStackVersion" in self.rootTag:
|
||||
itemStackVersion = self.rootTag["itemStackVersion"].value
|
||||
if itemStackVersion not in (VERSION_1_7, VERSION_1_8):
|
||||
raise LevelFormatError("Unknown item stack version %d" % itemStackVersion)
|
||||
if itemStackVersion == VERSION_1_7:
|
||||
itemIDs = self.rootTag.get("ItemIDs")
|
||||
if itemIDs is not None:
|
||||
self.blocktypes.addItemIDsFromSchematicTag(itemIDs)
|
||||
|
||||
self.blocktypes.itemStackVersion = itemStackVersion
|
||||
else:
|
||||
self.blocktypes.itemStackVersion = self.getItemStackVersionFromEntities()
|
||||
|
||||
|
||||
else:
|
||||
@ -160,6 +186,8 @@ class SchematicFileAdapter(FakeChunkedLevelAdapter):
|
||||
rootTag["Entities"] = nbt.TAG_List()
|
||||
rootTag["TileEntities"] = nbt.TAG_List()
|
||||
rootTag["Materials"] = nbt.TAG_String(self.blocktypes.name)
|
||||
rootTag["itemStackVersion"] = nbt.TAG_Byte(self.blocktypes.itemStackVersion)
|
||||
|
||||
|
||||
self._Blocks = zeros((shape[1], shape[2], shape[0]), 'uint16')
|
||||
rootTag["Data"] = nbt.TAG_Byte_Array(zeros((shape[1], shape[2], shape[0]), uint8))
|
||||
@ -169,9 +197,11 @@ class SchematicFileAdapter(FakeChunkedLevelAdapter):
|
||||
self.rootTag = rootTag
|
||||
|
||||
self.rootTag["BlockIDs"] = blockIDMapping(blocktypes)
|
||||
self.rootTag["ItemIDs"] = itemIDMapping(blocktypes)
|
||||
itemMapping = itemIDMapping(blocktypes)
|
||||
if itemMapping is not None:
|
||||
self.rootTag["ItemIDs"] = itemMapping # Only present for Forge 1.7
|
||||
|
||||
#expand blocks and data to chunk edges
|
||||
# Expand blocks and data to chunk edges
|
||||
h16 = (self.Height + 15) & ~0xf
|
||||
l16 = (self.Length + 15) & ~0xf
|
||||
w16 = (self.Width + 15) & ~0xf
|
||||
@ -200,6 +230,21 @@ class SchematicFileAdapter(FakeChunkedLevelAdapter):
|
||||
cx, cy, cz = pos.chunkPos()
|
||||
self.tileEntitiesByChunk[cx, cz].append(tag)
|
||||
|
||||
def getItemStackVersionFromEntities(self):
|
||||
for name, tag, path in nbt.walk(
|
||||
itertools.chain(self.rootTag["Entities"],
|
||||
self.rootTag["TileEntities"])):
|
||||
if ItemStackRef.tagIsItemStack(tag):
|
||||
if tag["id"].tagID == nbt.ID_STRING:
|
||||
return VERSION_1_8
|
||||
if tag["id"].tagID == nbt.ID_SHORT:
|
||||
return VERSION_1_7
|
||||
|
||||
# No itemstacks - use version 1.8 since ItemIDs won't need to
|
||||
# be added to the root tag.
|
||||
return VERSION_1_8
|
||||
|
||||
|
||||
def fakeEntitiesForChunk(self, cx, cz):
|
||||
return self.entitiesByChunk[cx, cz], self.tileEntitiesByChunk[cx, cz]
|
||||
|
||||
@ -494,26 +539,6 @@ class SchematicFileAdapter(FakeChunkedLevelAdapter):
|
||||
return 0
|
||||
return self.Data[x, z, y]
|
||||
|
||||
@classmethod
|
||||
def chestWithItemID(cls, itemID, count=64, damage=0):
|
||||
""" Creates a chest with a stack of 'itemID' in each slot.
|
||||
Optionally specify the count of items in each stack. Pass a negative
|
||||
value for damage to create unnaturally sturdy tools. """
|
||||
rootTag = nbt.TAG_Compound()
|
||||
invTag = nbt.TAG_List()
|
||||
rootTag["Inventory"] = invTag
|
||||
for slot in range(9, 36):
|
||||
itemTag = nbt.TAG_Compound()
|
||||
itemTag["Slot"] = nbt.TAG_Byte(slot)
|
||||
itemTag["Count"] = nbt.TAG_Byte(count)
|
||||
itemTag["id"] = nbt.TAG_Short(itemID)
|
||||
itemTag["Damage"] = nbt.TAG_Short(damage)
|
||||
invTag.append(itemTag)
|
||||
|
||||
chest = INVEditChest(rootTag, "")
|
||||
|
||||
return chest
|
||||
|
||||
def readChunk(self, cx, cz, dimName, create=False):
|
||||
chunk = super(SchematicFileAdapter, self).readChunk(cx, cz, dimName, create)
|
||||
if "Biomes" in self.rootTag:
|
||||
@ -523,108 +548,3 @@ class SchematicFileAdapter(FakeChunkedLevelAdapter):
|
||||
srcBiomes = self.Biomes[x:x + 16, z:z + 16]
|
||||
chunk.Biomes[0:srcBiomes.shape[0], 0:srcBiomes.shape[1]] = srcBiomes
|
||||
return chunk
|
||||
|
||||
#
|
||||
# class INVEditChest(FakeChunkedLevelAdapter):
|
||||
# Width = 1
|
||||
# Height = 1
|
||||
# Length = 1
|
||||
# Blocks = None
|
||||
# Data = array([[[0]]], 'uint8')
|
||||
# Entities = nbt.TAG_List()
|
||||
# Materials = pc_blocktypes
|
||||
#
|
||||
# @classmethod
|
||||
# def _isTagLevel(cls, rootTag):
|
||||
# return "Inventory" in rootTag
|
||||
#
|
||||
# def __init__(self, filename):
|
||||
# self.filename = filename
|
||||
# rootTag = nbt.load(filename)
|
||||
# self.Blocks = array([[[pc_blocktypes.Chest.ID]]], 'uint8')
|
||||
# for item in list(rootTag["Inventory"]):
|
||||
# slot = item["Slot"].value
|
||||
# if slot < 9 or slot >= 36:
|
||||
# rootTag["Inventory"].remove(item)
|
||||
# else:
|
||||
# item["Slot"].value -= 9 # adjust for different chest slot indexes
|
||||
#
|
||||
# self.rootTag = rootTag
|
||||
#
|
||||
# @property
|
||||
# def TileEntities(self):
|
||||
# chestTag = nbt.TAG_Compound()
|
||||
# chestTag["id"] = nbt.TAG_String("Chest")
|
||||
# chestTag["Items"] = nbt.TAG_List(self.rootTag["Inventory"])
|
||||
# chestTag["x"] = nbt.TAG_Int(0)
|
||||
# chestTag["y"] = nbt.TAG_Int(0)
|
||||
# chestTag["z"] = nbt.TAG_Int(0)
|
||||
#
|
||||
# return nbt.TAG_List([chestTag], name="TileEntities")
|
||||
#
|
||||
#
|
||||
# class ZipSchematic (AnvilWorldAdapter):
|
||||
# def __init__(self, filename, create=False):
|
||||
# raise NotImplementedError("No adapter for zipped world/schematic files yet!!!")
|
||||
# self.zipfilename = filename
|
||||
#
|
||||
# tempdir = tempfile.mktemp("schematic")
|
||||
# if create is False:
|
||||
# zf = zipfile.ZipFile(filename)
|
||||
# zf.extractall(tempdir)
|
||||
# zf.close()
|
||||
#
|
||||
# super(ZipSchematic, self).__init__(tempdir, create)
|
||||
# atexit.register(shutil.rmtree, self.worldFolder.filename, True)
|
||||
#
|
||||
#
|
||||
# try:
|
||||
# schematicDat = nbt.load(self.worldFolder.getFilePath("schematic.dat"))
|
||||
#
|
||||
# self.Width = schematicDat['Width'].value
|
||||
# self.Height = schematicDat['Height'].value
|
||||
# self.Length = schematicDat['Length'].value
|
||||
#
|
||||
# if "Materials" in schematicDat:
|
||||
# self.blocktypes = blocktypeClassesByName[schematicDat["Materials"].value]()
|
||||
#
|
||||
# except Exception as e:
|
||||
# print "Exception reading schematic.dat, skipping: {0!r}".format(e)
|
||||
# self.Width = 0
|
||||
# self.Length = 0
|
||||
#
|
||||
# def __del__(self):
|
||||
# shutil.rmtree(self.worldFolder.filename, True)
|
||||
#
|
||||
# def saveChanges(self):
|
||||
# self.saveToFile(self.zipfilename)
|
||||
#
|
||||
# def saveToFile(self, filename):
|
||||
# super(ZipSchematic, self).saveChanges()
|
||||
# schematicDat = nbt.TAG_Compound()
|
||||
# schematicDat.name = "Mega Schematic"
|
||||
#
|
||||
# schematicDat["Width"] = nbt.TAG_Int(self.size[0])
|
||||
# schematicDat["Height"] = nbt.TAG_Int(self.size[1])
|
||||
# schematicDat["Length"] = nbt.TAG_Int(self.size[2])
|
||||
# schematicDat["Materials"] = nbt.TAG_String(self.blocktypes.name)
|
||||
#
|
||||
# schematicDat.save(self.worldFolder.getFilePath("schematic.dat"))
|
||||
#
|
||||
# basedir = self.worldFolder.filename
|
||||
# assert os.path.isdir(basedir)
|
||||
# with closing(zipfile.ZipFile(filename, "w", zipfile.ZIP_STORED)) as z:
|
||||
# for root, dirs, files in os.walk(basedir):
|
||||
# # NOTE: ignore empty directories
|
||||
# for fn in files:
|
||||
# absfn = os.path.join(root, fn)
|
||||
# zfn = absfn[len(basedir) + len(os.sep):] # XXX: relative path
|
||||
# z.write(absfn, zfn)
|
||||
#
|
||||
# def getWorldBounds(self):
|
||||
# return BoundingBox((0, 0, 0), (self.Width, self.Height, self.Length))
|
||||
#
|
||||
# @classmethod
|
||||
# def canOpenFile(cls, filename):
|
||||
# return zipfile.is_zipfile(filename)
|
||||
#
|
||||
|
Reference in New Issue
Block a user