AString cSchematicFileSerializer::SaveToSchematicNBT(const cBlockArea & a_BlockArea)
{
	cFastNBTWriter Writer("Schematic");
	Writer.AddShort("Width",  static_cast<Int16>(a_BlockArea.m_Size.x));
	Writer.AddShort("Height", static_cast<Int16>(a_BlockArea.m_Size.y));
	Writer.AddShort("Length", static_cast<Int16>(a_BlockArea.m_Size.z));
	Writer.AddString("Materials", "Alpha");
	if (a_BlockArea.HasBlockTypes())
	{
		Writer.AddByteArray("Blocks", reinterpret_cast<const char *>(a_BlockArea.GetBlockTypes()), a_BlockArea.GetBlockCount());
	}
	else
	{
		AString Dummy(a_BlockArea.GetBlockCount(), 0);
		Writer.AddByteArray("Blocks", Dummy.data(), Dummy.size());
	}
	if (a_BlockArea.HasBlockMetas())
	{
		Writer.AddByteArray("Data", reinterpret_cast<const char *>(a_BlockArea.GetBlockMetas()), a_BlockArea.GetBlockCount());
	}
	else
	{
		AString Dummy(a_BlockArea.GetBlockCount(), 0);
		Writer.AddByteArray("Data", Dummy.data(), Dummy.size());
	}

	Writer.AddInt("WEOffsetX", a_BlockArea.m_WEOffset.x);
	Writer.AddInt("WEOffsetY", a_BlockArea.m_WEOffset.y);
	Writer.AddInt("WEOffsetZ", a_BlockArea.m_WEOffset.z);

	// TODO: Save entities and block entities
	Writer.BeginList("Entities", TAG_Compound);
	Writer.EndList();
	Writer.BeginList("TileEntities", TAG_Compound);
	Writer.EndList();
	Writer.Finish();

	return Writer.GetResult();
}
Beispiel #2
0
void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy)
{
	// Block types are compulsory, block metas are voluntary
	if (!HasBlockTypes() || !a_Src.HasBlockTypes())
	{
		LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__);
		return;
	}
	
	// Dst is *this, Src is a_Src
	int SrcOffX = std::max(0, -a_RelX);  // Offset in Src where to start reading
	int DstOffX = std::max(0,  a_RelX);  // Offset in Dst where to start writing
	int SizeX   = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX);  // How many blocks to copy

	int SrcOffY = std::max(0, -a_RelY);  // Offset in Src where to start reading
	int DstOffY = std::max(0,  a_RelY);  // Offset in Dst where to start writing
	int SizeY   = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY);  // How many blocks to copy

	int SrcOffZ = std::max(0, -a_RelZ);  // Offset in Src where to start reading
	int DstOffZ = std::max(0,  a_RelZ);  // Offset in Dst where to start writing
	int SizeZ   = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ);  // How many blocks to copy

	const NIBBLETYPE * SrcMetas = a_Src.GetBlockMetas();
	NIBBLETYPE * DstMetas = m_BlockMetas;
	bool IsDummyMetas = ((SrcMetas == NULL) || (DstMetas == NULL));
	
	if (IsDummyMetas)
	{
		SrcMetas = new NIBBLETYPE[a_Src.GetBlockCount()];
		DstMetas = new NIBBLETYPE[GetBlockCount()];
	}
	
	switch (a_Strategy)
	{
		case msOverwrite:
		{
			InternalMergeBlocks(
				m_BlockTypes, a_Src.GetBlockTypes(),
				DstMetas, SrcMetas,
				SizeX, SizeY, SizeZ,
				SrcOffX, SrcOffY, SrcOffZ,
				DstOffX, DstOffY, DstOffZ,
				a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
				m_SizeX, m_SizeY, m_SizeZ,
				MergeCombinatorOverwrite
			);
			break;
		}  // case msOverwrite
		
		case msFillAir:
		{
			InternalMergeBlocks(
				m_BlockTypes, a_Src.GetBlockTypes(),
				DstMetas, SrcMetas,
				SizeX, SizeY, SizeZ,
				SrcOffX, SrcOffY, SrcOffZ,
				DstOffX, DstOffY, DstOffZ,
				a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
				m_SizeX, m_SizeY, m_SizeZ,
				MergeCombinatorFillAir
			);
			break;
		}  // case msFillAir
		
		case msImprint:
		{
			InternalMergeBlocks(
				m_BlockTypes, a_Src.GetBlockTypes(),
				DstMetas, SrcMetas,
				SizeX, SizeY, SizeZ,
				SrcOffX, SrcOffY, SrcOffZ,
				DstOffX, DstOffY, DstOffZ,
				a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
				m_SizeX, m_SizeY, m_SizeZ,
				MergeCombinatorImprint
			);
			break;
		}  // case msImprint
		
		case msLake:
		{
			InternalMergeBlocks(
				m_BlockTypes, a_Src.GetBlockTypes(),
				DstMetas, SrcMetas,
				SizeX, SizeY, SizeZ,
				SrcOffX, SrcOffY, SrcOffZ,
				DstOffX, DstOffY, DstOffZ,
				a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
				m_SizeX, m_SizeY, m_SizeZ,
				MergeCombinatorLake
			);
			break;
		}  // case msLake
		
		default:
		{
			LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
			ASSERT(!"Unknown block area merge strategy");
			break;
		}
	}  // switch (a_Strategy)
	
	if (IsDummyMetas)
	{
		delete[] SrcMetas;
		delete[] DstMetas;
	}
}
bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cParsedNBT & a_NBT)
{
	int TMaterials = a_NBT.FindChildByName(a_NBT.GetRoot(), "Materials");
	if ((TMaterials > 0) && (a_NBT.GetType(TMaterials) == TAG_String))
	{
		AString Materials = a_NBT.GetString(TMaterials);
		if (Materials.compare("Alpha") != 0)
		{
			LOG("Materials tag is present and \"%s\" instead of \"Alpha\". Possibly a wrong-format schematic file.", Materials.c_str());
			return false;
		}
	}
	int TSizeX = a_NBT.FindChildByName(a_NBT.GetRoot(), "Width");
	int TSizeY = a_NBT.FindChildByName(a_NBT.GetRoot(), "Height");
	int TSizeZ = a_NBT.FindChildByName(a_NBT.GetRoot(), "Length");
	if (
		(TSizeX < 0) || (TSizeY < 0) || (TSizeZ < 0) ||
		(a_NBT.GetType(TSizeX) != TAG_Short) ||
		(a_NBT.GetType(TSizeY) != TAG_Short) ||
		(a_NBT.GetType(TSizeZ) != TAG_Short)
	)
	{
		LOG("Dimensions are missing from the schematic file (%d, %d, %d), (%d, %d, %d)",
			TSizeX, TSizeY, TSizeZ,
			(TSizeX >= 0) ? a_NBT.GetType(TSizeX) : -1,
			(TSizeY >= 0) ? a_NBT.GetType(TSizeY) : -1,
			(TSizeZ >= 0) ? a_NBT.GetType(TSizeZ) : -1
		);
		return false;
	}

	int SizeX = a_NBT.GetShort(TSizeX);
	int SizeY = a_NBT.GetShort(TSizeY);
	int SizeZ = a_NBT.GetShort(TSizeZ);
	if ((SizeX < 1) || (SizeX > 65535) || (SizeY < 1) || (SizeY > cChunkDef::Height) || (SizeZ < 1) || (SizeZ > 65535))
	{
		LOG("Dimensions are invalid in the schematic file: %d, %d, %d", SizeX, SizeY, SizeZ);
		return false;
	}

	int TBlockTypes = a_NBT.FindChildByName(a_NBT.GetRoot(), "Blocks");
	int TBlockMetas = a_NBT.FindChildByName(a_NBT.GetRoot(), "Data");
	if ((TBlockTypes < 0) || (a_NBT.GetType(TBlockTypes) != TAG_ByteArray))
	{
		LOG("BlockTypes are invalid in the schematic file: %d", TBlockTypes);
		return false;
	}
	bool AreMetasPresent = (TBlockMetas > 0) && (a_NBT.GetType(TBlockMetas) == TAG_ByteArray);

	a_BlockArea.Clear();
	a_BlockArea.SetSize(SizeX, SizeY, SizeZ, AreMetasPresent ? (cBlockArea::baTypes | cBlockArea::baMetas) : cBlockArea::baTypes);

	int TOffsetX = a_NBT.FindChildByName(a_NBT.GetRoot(), "WEOffsetX");
	int TOffsetY = a_NBT.FindChildByName(a_NBT.GetRoot(), "WEOffsetY");
	int TOffsetZ = a_NBT.FindChildByName(a_NBT.GetRoot(), "WEOffsetZ");

	if (
		(TOffsetX < 0) || (TOffsetY < 0) || (TOffsetZ < 0) ||
		(a_NBT.GetType(TOffsetX) != TAG_Int) ||
		(a_NBT.GetType(TOffsetY) != TAG_Int) ||
		(a_NBT.GetType(TOffsetZ) != TAG_Int)
	)
	{
		// Not every schematic file has an offset, so we shoudn't give a warn message.
		a_BlockArea.SetWEOffset(0, 0, 0);
	}
	else
	{
		a_BlockArea.SetWEOffset(a_NBT.GetInt(TOffsetX), a_NBT.GetInt(TOffsetY), a_NBT.GetInt(TOffsetZ));
	}

	// Copy the block types and metas:
	size_t NumTypeBytes = a_BlockArea.GetBlockCount();
	if (a_NBT.GetDataLength(TBlockTypes) < NumTypeBytes)
	{
		LOG("BlockTypes truncated in the schematic file (exp %u, got %u bytes). Loading partial.",
			static_cast<unsigned>(NumTypeBytes), static_cast<unsigned>(a_NBT.GetDataLength(TBlockTypes))
		);
		NumTypeBytes = a_NBT.GetDataLength(TBlockTypes);
	}
	memcpy(a_BlockArea.GetBlockTypes(), a_NBT.GetData(TBlockTypes), NumTypeBytes);

	if (AreMetasPresent)
	{
		size_t NumMetaBytes = a_BlockArea.GetBlockCount();
		if (a_NBT.GetDataLength(TBlockMetas) < NumMetaBytes)
		{
			LOG("BlockMetas truncated in the schematic file (exp %u, got %u bytes). Loading partial.",
				static_cast<unsigned>(NumMetaBytes), static_cast<unsigned>(a_NBT.GetDataLength(TBlockMetas))
			);
			NumMetaBytes = a_NBT.GetDataLength(TBlockMetas);
		}
		memcpy(a_BlockArea.GetBlockMetas(), a_NBT.GetData(TBlockMetas), NumMetaBytes);
	}

	return true;
}