From 53e22b11857fed62e2313d6d84d90f88ed412ffb Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Mon, 29 Jul 2013 12:13:03 +0100 Subject: Changed everyting to Unix line endings. --- source/BlockArea.cpp | 4248 +++++++++++++++++++++++++------------------------- 1 file changed, 2124 insertions(+), 2124 deletions(-) (limited to 'source/BlockArea.cpp') diff --git a/source/BlockArea.cpp b/source/BlockArea.cpp index 6134843bb..5c15adfef 100644 --- a/source/BlockArea.cpp +++ b/source/BlockArea.cpp @@ -1,2124 +1,2124 @@ - -// BlockArea.cpp - -// Implements the cBlockArea object representing an area of block data that can be queried from cWorld and then accessed again without further queries -// The object also supports writing the blockdata back into cWorld, even into other coords - -#include "Globals.h" -#include "BlockArea.h" -#include "World.h" -#include "OSSupport/GZipFile.h" -#include "WorldStorage/FastNBT.h" -#include "Blocks/BlockHandler.h" - - - - - -// This wild construct allows us to pass a function argument and still have it inlined by the compiler :) -/// Merges two blocktypes and blockmetas of the specified sizes and offsets using the specified combinator function -template void InternalMergeBlocks( - BLOCKTYPE * a_DstTypes, const BLOCKTYPE * a_SrcTypes, - NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas, - int a_SizeX, int a_SizeY, int a_SizeZ, - int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ, - int a_DstOffX, int a_DstOffY, int a_DstOffZ, - int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ, - int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ, - Combinator a_Combinator -) -{ - for (int y = 0; y < a_SizeY; y++) - { - int SrcBaseY = (y + a_SrcOffY) * a_SrcSizeX * a_SrcSizeZ; - int DstBaseY = (y + a_DstOffY) * a_DstSizeX * a_DstSizeZ; - for (int z = 0; z < a_SizeZ; z++) - { - int SrcBaseZ = SrcBaseY + (z + a_SrcOffZ) * a_SrcSizeX; - int DstBaseZ = DstBaseY + (z + a_DstOffZ) * a_DstSizeX; - int SrcIdx = SrcBaseZ + a_SrcOffX; - int DstIdx = DstBaseZ + a_DstOffX; - for (int x = 0; x < a_SizeX; x++) - { - a_Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]); - ++DstIdx; - ++SrcIdx; - } // for x - } // for z - } // for y -} - - - - - -/// Combinator used for cBlockArea::msOverwrite merging -static void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) -{ - a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; -} - - - - - -/// Combinator used for cBlockArea::msFillAir merging -static void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) -{ - if (a_DstType == E_BLOCK_AIR) - { - a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; - } - // "else" is the default, already in place -} - - - - - -/// Combinator used for cBlockArea::msImprint merging -static void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) -{ - if (a_SrcType != E_BLOCK_AIR) - { - a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; - } - // "else" is the default, already in place -} - - - - - -/// Combinator used for cBlockArea::msLake merging -static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) -{ - // Sponge is the NOP block - if (a_SrcType == E_BLOCK_SPONGE) - { - return; - } - - // Air is always hollowed out - if (a_SrcType == E_BLOCK_AIR) - { - a_DstType = E_BLOCK_AIR; - a_DstMeta = 0; - return; - } - - // Water and lava are never overwritten - switch (a_DstType) - { - case E_BLOCK_WATER: - case E_BLOCK_STATIONARY_WATER: - case E_BLOCK_LAVA: - case E_BLOCK_STATIONARY_LAVA: - { - return; - } - } - - // Water and lava always overwrite - switch (a_SrcType) - { - case E_BLOCK_WATER: - case E_BLOCK_STATIONARY_WATER: - case E_BLOCK_LAVA: - case E_BLOCK_STATIONARY_LAVA: - { - a_DstType = a_SrcType; - a_DstMeta = a_DstMeta; - return; - } - } - - if (a_SrcType == E_BLOCK_STONE) - { - switch (a_DstType) - { - case E_BLOCK_DIRT: - case E_BLOCK_GRASS: - case E_BLOCK_MYCELIUM: - { - a_DstType = E_BLOCK_STONE; - a_DstMeta = 0; - return; - } - } - } - // Everything else is left as it is -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cBlockArea: - -cBlockArea::cBlockArea(void) : - m_SizeX(0), - m_SizeY(0), - m_SizeZ(0), - m_BlockTypes(NULL), - m_BlockMetas(NULL), - m_BlockLight(NULL), - m_BlockSkyLight(NULL) -{ -} - - - - - -cBlockArea::~cBlockArea() -{ - Clear(); -} - - - - - -void cBlockArea::Clear(void) -{ - delete[] m_BlockTypes; m_BlockTypes = NULL; - delete[] m_BlockMetas; m_BlockMetas = NULL; - delete[] m_BlockLight; m_BlockLight = NULL; - delete[] m_BlockSkyLight; m_BlockSkyLight = NULL; - m_SizeX = 0; - m_SizeY = 0; - m_SizeZ = 0; -} - - - - - -void cBlockArea::Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes) -{ - Clear(); - int BlockCount = a_SizeX * a_SizeY * a_SizeZ; - if ((a_DataTypes & baTypes) != 0) - { - m_BlockTypes = new BLOCKTYPE[BlockCount]; - for (int i = 0; i < BlockCount; i++) - { - m_BlockTypes[i] = E_BLOCK_AIR; - } - } - if ((a_DataTypes & baMetas) != 0) - { - m_BlockMetas = new NIBBLETYPE[BlockCount]; - for (int i = 0; i < BlockCount; i++) - { - m_BlockMetas[i] = 0; - } - } - if ((a_DataTypes & baLight) != 0) - { - m_BlockLight = new NIBBLETYPE[BlockCount]; - for (int i = 0; i < BlockCount; i++) - { - m_BlockLight[i] = 0; - } - } - if ((a_DataTypes & baSkyLight) != 0) - { - m_BlockSkyLight = new NIBBLETYPE[BlockCount]; - for (int i = 0; i < BlockCount; i++) - { - m_BlockSkyLight[i] = 0x0f; - } - } - m_SizeX = a_SizeX; - m_SizeY = a_SizeY; - m_SizeZ = a_SizeZ; - m_OriginX = 0; - m_OriginY = 0; - m_OriginZ = 0; -} - - - - - -void cBlockArea::SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ) -{ - m_OriginX = a_OriginX; - m_OriginY = a_OriginY; - m_OriginZ = a_OriginZ; -} - - - - - -bool cBlockArea::Read(cWorld * a_World, int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ, int a_DataTypes) -{ - // Normalize the coords: - if (a_MinBlockX > a_MaxBlockX) - { - std::swap(a_MinBlockX, a_MaxBlockX); - } - if (a_MinBlockY > a_MaxBlockY) - { - std::swap(a_MinBlockY, a_MaxBlockY); - } - if (a_MinBlockZ > a_MaxBlockZ) - { - std::swap(a_MinBlockZ, a_MaxBlockZ); - } - - // Include the Max coords: - a_MaxBlockX += 1; - a_MaxBlockY += 1; - a_MaxBlockZ += 1; - - // Check coords validity: - if (a_MinBlockY < 0) - { - LOGWARNING("%s: MinBlockY less than zero, adjusting to zero", __FUNCTION__); - a_MinBlockY = 0; - } - else if (a_MinBlockY >= cChunkDef::Height) - { - LOGWARNING("%s: MinBlockY more than chunk height, adjusting to chunk height", __FUNCTION__); - a_MinBlockY = cChunkDef::Height - 1; - } - if (a_MaxBlockY < 0) - { - LOGWARNING("%s: MaxBlockY less than zero, adjusting to zero", __FUNCTION__); - a_MaxBlockY = 0; - } - else if (a_MaxBlockY >= cChunkDef::Height) - { - LOGWARNING("%s: MaxBlockY more than chunk height, adjusting to chunk height", __FUNCTION__); - a_MaxBlockY = cChunkDef::Height - 1; - } - - // Allocate the needed memory: - Clear(); - if (!SetSize(a_MaxBlockX - a_MinBlockX, a_MaxBlockY - a_MinBlockY, a_MaxBlockZ - a_MinBlockZ, a_DataTypes)) - { - return false; - } - m_OriginX = a_MinBlockX; - m_OriginY = a_MinBlockY; - m_OriginZ = a_MinBlockZ; - cChunkReader Reader(*this); - - // Convert block coords to chunks coords: - int MinChunkX, MaxChunkX; - int MinChunkZ, MaxChunkZ; - cChunkDef::AbsoluteToRelative(a_MinBlockX, a_MinBlockY, a_MinBlockZ, MinChunkX, MinChunkZ); - cChunkDef::AbsoluteToRelative(a_MaxBlockX, a_MaxBlockY, a_MaxBlockZ, MaxChunkX, MaxChunkZ); - - // Query block data: - if (!a_World->ForEachChunkInRect(MinChunkX, MaxChunkX, MinChunkZ, MaxChunkZ, Reader)) - { - Clear(); - return false; - } - - return true; -} - - - - - -bool cBlockArea::Write(cWorld * a_World, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes) -{ - ASSERT((a_DataTypes & GetDataTypes()) == a_DataTypes); // Are you requesting only the data that I have? - a_DataTypes = a_DataTypes & GetDataTypes(); // For release builds, silently cut off the datatypes that I don't have - - // Check coords validity: - if (a_MinBlockY < 0) - { - LOGWARNING("%s: MinBlockY less than zero, adjusting to zero", __FUNCTION__); - a_MinBlockY = 0; - } - else if (a_MinBlockY >= cChunkDef::Height - m_SizeY) - { - LOGWARNING("%s: MinBlockY + m_SizeY more than chunk height, adjusting to chunk height", __FUNCTION__); - a_MinBlockY = cChunkDef::Height - m_SizeY - 1; - } - - return a_World->WriteBlockArea(*this, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes); -} - - - - - -void cBlockArea::CopyTo(cBlockArea & a_Into) const -{ - if (&a_Into == this) - { - LOGWARNING("Trying to copy a cBlockArea into self, ignoring."); - return; - } - - a_Into.Clear(); - a_Into.SetSize(m_SizeX, m_SizeY, m_SizeZ, GetDataTypes()); - a_Into.m_OriginX = m_OriginX; - a_Into.m_OriginY = m_OriginY; - a_Into.m_OriginZ = m_OriginZ; - int BlockCount = GetBlockCount(); - if (HasBlockTypes()) - { - memcpy(a_Into.m_BlockTypes, m_BlockTypes, BlockCount * sizeof(BLOCKTYPE)); - } - if (HasBlockMetas()) - { - memcpy(a_Into.m_BlockMetas, m_BlockMetas, BlockCount * sizeof(NIBBLETYPE)); - } - if (HasBlockLights()) - { - memcpy(a_Into.m_BlockLight, m_BlockLight, BlockCount * sizeof(NIBBLETYPE)); - } - if (HasBlockSkyLights()) - { - memcpy(a_Into.m_BlockSkyLight, m_BlockSkyLight, BlockCount * sizeof(NIBBLETYPE)); - } -} - - - - - -void cBlockArea::CopyFrom(const cBlockArea & a_From) -{ - a_From.CopyTo(*this); -} - - - - - -void cBlockArea::DumpToRawFile(const AString & a_FileName) -{ - cFile f; - if (!f.Open(a_FileName, cFile::fmWrite)) - { - LOGWARNING("cBlockArea: Cannot open file \"%s\" for raw dump", a_FileName.c_str()); - return; - } - UInt32 SizeX = ntohl(m_SizeX); - UInt32 SizeY = ntohl(m_SizeY); - UInt32 SizeZ = ntohl(m_SizeZ); - f.Write(&SizeX, 4); - f.Write(&SizeY, 4); - f.Write(&SizeZ, 4); - unsigned char DataTypes = GetDataTypes(); - f.Write(&DataTypes, 1); - int NumBlocks = GetBlockCount(); - if (HasBlockTypes()) - { - f.Write(m_BlockTypes, NumBlocks * sizeof(BLOCKTYPE)); - } - if (HasBlockMetas()) - { - f.Write(m_BlockMetas, NumBlocks); - } - if (HasBlockLights()) - { - f.Write(m_BlockLight, NumBlocks); - } - if (HasBlockSkyLights()) - { - f.Write(m_BlockSkyLight, NumBlocks); - } -} - - - - - -bool cBlockArea::LoadFromSchematicFile(const AString & a_FileName) -{ - // Un-GZip the contents: - AString Contents; - cGZipFile File; - if (!File.Open(a_FileName, cGZipFile::fmRead)) - { - LOG("Cannot open the schematic file \"%s\".", a_FileName.c_str()); - return false; - } - int NumBytesRead = File.ReadRestOfFile(Contents); - if (NumBytesRead < 0) - { - LOG("Cannot read GZipped data in the schematic file \"%s\", error %d", a_FileName.c_str(), NumBytesRead); - return false; - } - File.Close(); - - // Parse the NBT: - cParsedNBT NBT(Contents.data(), Contents.size()); - if (!NBT.IsValid()) - { - LOG("Cannot parse the NBT in the schematic file \"%s\".", a_FileName.c_str()); - return false; - } - - return LoadFromSchematicNBT(NBT); -} - - - - - -bool cBlockArea::SaveToSchematicFile(const AString & a_FileName) -{ - cFastNBTWriter Writer("Schematic"); - Writer.AddShort("Width", m_SizeX); - Writer.AddShort("Height", m_SizeY); - Writer.AddShort("Length", m_SizeZ); - Writer.AddString("Materials", "Alpha"); - if (HasBlockTypes()) - { - Writer.AddByteArray("Blocks", (const char *)m_BlockTypes, GetBlockCount()); - } - else - { - AString Dummy(GetBlockCount(), 0); - Writer.AddByteArray("Blocks", Dummy.data(), Dummy.size()); - } - if (HasBlockMetas()) - { - Writer.AddByteArray("Data", (const char *)m_BlockMetas, GetBlockCount()); - } - else - { - AString Dummy(GetBlockCount(), 0); - Writer.AddByteArray("Data", Dummy.data(), Dummy.size()); - } - // TODO: Save entities and block entities - Writer.BeginList("Entities", TAG_Compound); - Writer.EndList(); - Writer.BeginList("TileEntities", TAG_Compound); - Writer.EndList(); - Writer.Finish(); - - // Save to file - cGZipFile File; - if (!File.Open(a_FileName, cGZipFile::fmWrite)) - { - LOG("Cannot open file \"%s\" for writing.", a_FileName.c_str()); - return false; - } - if (!File.Write(Writer.GetResult())) - { - LOG("Cannot write data to file \"%s\".", a_FileName.c_str()); - return false; - } - return true; -} - - - - - -void cBlockArea::Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ) -{ - if ( - (a_AddMinX + a_SubMaxX >= m_SizeX) || - (a_AddMinY + a_SubMaxY >= m_SizeY) || - (a_AddMinZ + a_SubMaxZ >= m_SizeZ) - ) - { - LOGWARNING("cBlockArea:Crop called with more croping than the dimensions: %d x %d x %d with cropping %d, %d and %d", - m_SizeX, m_SizeY, m_SizeZ, - a_AddMinX + a_SubMaxX, a_AddMinY + a_SubMaxY, a_AddMinZ + a_SubMaxZ - ); - return; - } - - if (HasBlockTypes()) - { - CropBlockTypes(a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ); - } - if (HasBlockMetas()) - { - CropNibbles(m_BlockMetas, a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ); - } - if (HasBlockLights()) - { - CropNibbles(m_BlockLight, a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ); - } - if (HasBlockSkyLights()) - { - CropNibbles(m_BlockSkyLight, a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ); - } - m_OriginX += a_AddMinX; - m_OriginY += a_AddMinY; - m_OriginZ += a_AddMinZ; - m_SizeX -= a_AddMinX + a_SubMaxX; - m_SizeY -= a_AddMinY + a_SubMaxY; - m_SizeZ -= a_AddMinZ + a_SubMaxZ; -} - - - - - -void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ) -{ - if (HasBlockTypes()) - { - ExpandBlockTypes(a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ); - } - if (HasBlockMetas()) - { - ExpandNibbles(m_BlockMetas, a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ); - } - if (HasBlockLights()) - { - ExpandNibbles(m_BlockLight, a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ); - } - if (HasBlockSkyLights()) - { - ExpandNibbles(m_BlockSkyLight, a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ); - } - m_OriginX -= a_SubMinX; - m_OriginY -= a_SubMinY; - m_OriginZ -= a_SubMinZ; - m_SizeX += a_SubMinX + a_AddMaxX; - m_SizeY += a_SubMinY + a_AddMaxY; - m_SizeZ += a_SubMinZ + a_AddMaxZ; -} - - - - - -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; - } -} - - - - - -void cBlockArea::Fill(int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight) -{ - if ((a_DataTypes & GetDataTypes()) != a_DataTypes) - { - LOGWARNING("%s: requested datatypes that are not present in the BlockArea object, trimming those away (req 0x%x, stor 0x%x)", - __FUNCTION__, a_DataTypes, GetDataTypes() - ); - a_DataTypes = a_DataTypes & GetDataTypes(); - } - - int BlockCount = GetBlockCount(); - if ((a_DataTypes & baTypes) != 0) - { - for (int i = 0; i < BlockCount; i++) - { - m_BlockTypes[i] = a_BlockType; - } - } - if ((a_DataTypes & baMetas) != 0) - { - for (int i = 0; i < BlockCount; i++) - { - m_BlockMetas[i] = a_BlockMeta; - } - } - if ((a_DataTypes & baLight) != 0) - { - for (int i = 0; i < BlockCount; i++) - { - m_BlockLight[i] = a_BlockLight; - } - } - if ((a_DataTypes & baSkyLight) != 0) - { - for (int i = 0; i < BlockCount; i++) - { - m_BlockSkyLight[i] = a_BlockSkyLight; - } - } -} - - - - - -void cBlockArea::FillRelCuboid(int a_MinRelX, int a_MaxRelX, int a_MinRelY, int a_MaxRelY, int a_MinRelZ, int a_MaxRelZ, - int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, - NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight -) -{ - if ((a_DataTypes & GetDataTypes()) != a_DataTypes) - { - LOGWARNING("%s: requested datatypes that are not present in the BlockArea object, trimming those away (req 0x%x, stor 0x%x)", - __FUNCTION__, a_DataTypes, GetDataTypes() - ); - a_DataTypes = a_DataTypes & GetDataTypes(); - } - - if ((a_DataTypes & baTypes) != 0) - { - for (int y = a_MinRelY; y <= a_MaxRelY; y++) for (int z = a_MinRelZ; z <= a_MaxRelZ; z++) for (int x = a_MinRelX; x <= a_MaxRelX; x++) - { - m_BlockTypes[MakeIndex(x, y, z)] = a_BlockType; - } // for x, z, y - } - if ((a_DataTypes & baMetas) != 0) - { - for (int y = a_MinRelY; y <= a_MaxRelY; y++) for (int z = a_MinRelZ; z <= a_MaxRelZ; z++) for (int x = a_MinRelX; x <= a_MaxRelX; x++) - { - m_BlockMetas[MakeIndex(x, y, z)] = a_BlockMeta; - } // for x, z, y - } - if ((a_DataTypes & baLight) != 0) - { - for (int y = a_MinRelY; y <= a_MaxRelY; y++) for (int z = a_MinRelZ; z <= a_MaxRelZ; z++) for (int x = a_MinRelX; x <= a_MaxRelX; x++) - { - m_BlockLight[MakeIndex(x, y, z)] = a_BlockLight; - } // for x, z, y - } - if ((a_DataTypes & baSkyLight) != 0) - { - for (int y = a_MinRelY; y <= a_MaxRelY; y++) for (int z = a_MinRelZ; z <= a_MaxRelZ; z++) for (int x = a_MinRelX; x <= a_MaxRelX; x++) - { - m_BlockSkyLight[MakeIndex(x, y, z)] = a_BlockSkyLight; - } // for x, z, y - } -} - - - - - -void cBlockArea::RelLine(int a_RelX1, int a_RelY1, int a_RelZ1, int a_RelX2, int a_RelY2, int a_RelZ2, - int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, - NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight -) -{ - // Bresenham-3D algorithm for drawing lines: - int dx = abs(a_RelX2 - a_RelX1); - int dy = abs(a_RelY2 - a_RelY1); - int dz = abs(a_RelZ2 - a_RelZ1); - int sx = (a_RelX1 < a_RelX2) ? 1 : -1; - int sy = (a_RelY1 < a_RelY2) ? 1 : -1; - int sz = (a_RelZ1 < a_RelZ2) ? 1 : -1; - int err = dx - dz; - - if (dx >= std::max(dy, dz)) // x dominant - { - int yd = dy - dx / 2; - int zd = dz - dx / 2; - - while (true) - { - RelSetData(a_RelX1, a_RelY1, a_RelZ1, a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight); - - if (a_RelX1 == a_RelX2) - { - break; - } - - if (yd >= 0) // move along y - { - a_RelY1 += sy; - yd -= dx; - } - - if (zd >= 0) // move along z - { - a_RelZ1 += sz; - zd -= dx; - } - - // move along x - a_RelX1 += sx; - yd += dy; - zd += dz; - } - } - else if (dy >= std::max(dx, dz)) // y dominant - { - int xd = dx - dy / 2; - int zd = dz - dy / 2; - - while (true) - { - RelSetData(a_RelX1, a_RelY1, a_RelZ1, a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight); - - if (a_RelY1 == a_RelY2) - { - break; - } - - if (xd >= 0) // move along x - { - a_RelX1 += sx; - xd -= dy; - } - - if (zd >= 0) // move along z - { - a_RelZ1 += sz; - zd -= dy; - } - - // move along y - a_RelY1 += sy; - xd += dx; - zd += dz; - } - } - else - { - // z dominant - ASSERT(dz >= std::max(dx, dy)); - int xd = dx - dz / 2; - int yd = dy - dz / 2; - - while (true) - { - RelSetData(a_RelX1, a_RelY1, a_RelZ1, a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight); - - if (a_RelZ1 == a_RelZ2) - { - break; - } - - if (xd >= 0) // move along x - { - a_RelX1 += sx; - xd -= dz; - } - - if (yd >= 0) // move along y - { - a_RelY1 += sy; - yd -= dz; - } - - // move along z - a_RelZ1 += sz; - xd += dx; - yd += dy; - } - } // if (which dimension is dominant) -} - - - - - -void cBlockArea::RotateCCW(void) -{ - if (!HasBlockTypes()) - { - LOGWARNING("cBlockArea: Cannot rotate blockmeta without blocktypes!"); - return; - } - - if (!HasBlockMetas()) - { - // There are no blockmetas to rotate, just use the NoMeta function - RotateCCWNoMeta(); - return; - } - - // We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time: - BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ]; - NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ]; - for (int x = 0; x < m_SizeX; x++) - { - int NewZ = m_SizeX - x - 1; - for (int z = 0; z < m_SizeZ; z++) - { - int NewX = z; - for (int y = 0; y < m_SizeY; y++) - { - int NewIdx = NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ; - int OldIdx = MakeIndex(x, y, z); - NewTypes[NewIdx] = m_BlockTypes[OldIdx]; - NewMetas[NewIdx] = BlockHandler(m_BlockTypes[OldIdx])->MetaRotateCCW(m_BlockMetas[OldIdx]); - } // for y - } // for z - } // for x - std::swap(m_BlockTypes, NewTypes); - std::swap(m_BlockMetas, NewMetas); - delete[] NewTypes; - delete[] NewMetas; - - std::swap(m_SizeX, m_SizeZ); -} - - - - - -void cBlockArea::RotateCW(void) -{ - if (!HasBlockTypes()) - { - LOGWARNING("cBlockArea: Cannot rotate blockmeta without blocktypes!"); - return; - } - - if (!HasBlockMetas()) - { - // There are no blockmetas to rotate, just use the NoMeta function - RotateCWNoMeta(); - return; - } - - // We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time: - BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ]; - NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ]; - for (int x = 0; x < m_SizeX; x++) - { - int NewZ = x; - for (int z = 0; z < m_SizeZ; z++) - { - int NewX = m_SizeZ - z - 1; - for (int y = 0; y < m_SizeY; y++) - { - int NewIdx = NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ; - int OldIdx = MakeIndex(x, y, z); - NewTypes[NewIdx] = m_BlockTypes[OldIdx]; - NewMetas[NewIdx] = BlockHandler(m_BlockTypes[OldIdx])->MetaRotateCW(m_BlockMetas[OldIdx]); - } // for y - } // for z - } // for x - std::swap(m_BlockTypes, NewTypes); - std::swap(m_BlockMetas, NewMetas); - delete[] NewTypes; - delete[] NewMetas; - - std::swap(m_SizeX, m_SizeZ); -} - - - - - -void cBlockArea::MirrorXY(void) -{ - if (!HasBlockTypes()) - { - LOGWARNING("cBlockArea: Cannot mirror meta without blocktypes!"); - return; - } - - if (!HasBlockMetas()) - { - // There are no blockmetas to mirror, just use the NoMeta function - MirrorXYNoMeta(); - return; - } - - // We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time: - int HalfZ = m_SizeZ / 2; - int MaxZ = m_SizeZ - 1; - for (int y = 0; y < m_SizeY; y++) - { - for (int z = 0; z < HalfZ; z++) - { - for (int x = 0; x < m_SizeX; x++) - { - int Idx1 = MakeIndex(x, y, z); - int Idx2 = MakeIndex(x, y, MaxZ - z); - std::swap(m_BlockTypes[Idx1], m_BlockTypes[Idx2]); - NIBBLETYPE Meta1 = BlockHandler(m_BlockTypes[Idx2])->MetaMirrorXY(m_BlockMetas[Idx1]); - NIBBLETYPE Meta2 = BlockHandler(m_BlockTypes[Idx1])->MetaMirrorXY(m_BlockMetas[Idx2]); - m_BlockMetas[Idx1] = Meta2; - m_BlockMetas[Idx2] = Meta1; - } // for x - } // for z - } // for y -} - - - - - -void cBlockArea::MirrorXZ(void) -{ - if (!HasBlockTypes()) - { - LOGWARNING("cBlockArea: Cannot mirror meta without blocktypes!"); - return; - } - - if (!HasBlockMetas()) - { - // There are no blockmetas to mirror, just use the NoMeta function - MirrorXZNoMeta(); - return; - } - - // We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time: - int HalfY = m_SizeY / 2; - int MaxY = m_SizeY - 1; - for (int y = 0; y < HalfY; y++) - { - for (int z = 0; z < m_SizeZ; z++) - { - for (int x = 0; x < m_SizeX; x++) - { - int Idx1 = MakeIndex(x, y, z); - int Idx2 = MakeIndex(x, MaxY - y, z); - std::swap(m_BlockTypes[Idx1], m_BlockTypes[Idx2]); - NIBBLETYPE Meta1 = BlockHandler(m_BlockTypes[Idx2])->MetaMirrorXZ(m_BlockMetas[Idx1]); - NIBBLETYPE Meta2 = BlockHandler(m_BlockTypes[Idx1])->MetaMirrorXZ(m_BlockMetas[Idx2]); - m_BlockMetas[Idx1] = Meta2; - m_BlockMetas[Idx2] = Meta1; - } // for x - } // for z - } // for y -} - - - - - -void cBlockArea::MirrorYZ(void) -{ - if (!HasBlockTypes()) - { - LOGWARNING("cBlockArea: Cannot mirror meta without blocktypes!"); - return; - } - - if (!HasBlockMetas()) - { - // There are no blockmetas to mirror, just use the NoMeta function - MirrorYZNoMeta(); - return; - } - - // We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time: - int HalfX = m_SizeX / 2; - int MaxX = m_SizeX - 1; - for (int y = 0; y < m_SizeY; y++) - { - for (int z = 0; z < m_SizeZ; z++) - { - for (int x = 0; x < HalfX; x++) - { - int Idx1 = MakeIndex(x, y, z); - int Idx2 = MakeIndex(MaxX - x, y, z); - std::swap(m_BlockTypes[Idx1], m_BlockTypes[Idx2]); - NIBBLETYPE Meta1 = BlockHandler(m_BlockTypes[Idx2])->MetaMirrorYZ(m_BlockMetas[Idx1]); - NIBBLETYPE Meta2 = BlockHandler(m_BlockTypes[Idx1])->MetaMirrorYZ(m_BlockMetas[Idx2]); - m_BlockMetas[Idx1] = Meta2; - m_BlockMetas[Idx2] = Meta1; - } // for x - } // for z - } // for y -} - - - - - -void cBlockArea::RotateCCWNoMeta(void) -{ - if (HasBlockTypes()) - { - BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ]; - for (int x = 0; x < m_SizeX; x++) - { - int NewZ = m_SizeX - x - 1; - for (int z = 0; z < m_SizeZ; z++) - { - int NewX = z; - for (int y = 0; y < m_SizeY; y++) - { - NewTypes[NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ] = m_BlockTypes[MakeIndex(x, y, z)]; - } // for y - } // for z - } // for x - std::swap(m_BlockTypes, NewTypes); - delete[] NewTypes; - } - if (HasBlockMetas()) - { - NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ]; - for (int x = 0; x < m_SizeX; x++) - { - int NewZ = m_SizeX - x - 1; - for (int z = 0; z < m_SizeZ; z++) - { - int NewX = z; - for (int y = 0; y < m_SizeY; y++) - { - NewMetas[NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ] = m_BlockMetas[MakeIndex(x, y, z)]; - } // for y - } // for z - } // for x - std::swap(m_BlockMetas, NewMetas); - delete[] NewMetas; - } - std::swap(m_SizeX, m_SizeZ); -} - - - - - -void cBlockArea::RotateCWNoMeta(void) -{ - if (HasBlockTypes()) - { - BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ]; - for (int z = 0; z < m_SizeZ; z++) - { - int NewX = m_SizeZ - z - 1; - for (int x = 0; x < m_SizeX; x++) - { - int NewZ = x; - for (int y = 0; y < m_SizeY; y++) - { - NewTypes[NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ] = m_BlockTypes[MakeIndex(x, y, z)]; - } // for y - } // for x - } // for z - std::swap(m_BlockTypes, NewTypes); - delete[] NewTypes; - } - if (HasBlockMetas()) - { - NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ]; - for (int z = 0; z < m_SizeZ; z++) - { - int NewX = m_SizeZ - z - 1; - for (int x = 0; x < m_SizeX; x++) - { - int NewZ = x; - for (int y = 0; y < m_SizeY; y++) - { - NewMetas[NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ] = m_BlockMetas[MakeIndex(x, y, z)]; - } // for y - } // for x - } // for z - std::swap(m_BlockMetas, NewMetas); - delete[] NewMetas; - } - std::swap(m_SizeX, m_SizeZ); -} - - - - - -void cBlockArea::MirrorXYNoMeta(void) -{ - int HalfZ = m_SizeZ / 2; - int MaxZ = m_SizeZ - 1; - if (HasBlockTypes()) - { - for (int y = 0; y < m_SizeY; y++) - { - for (int z = 0; z < HalfZ; z++) - { - for (int x = 0; x < m_SizeX; x++) - { - std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(x, y, MaxZ - z)]); - } // for x - } // for z - } // for y - } // if (HasBlockTypes) - - if (HasBlockMetas()) - { - for (int y = 0; y < m_SizeY; y++) - { - for (int z = 0; z < HalfZ; z++) - { - for (int x = 0; x < m_SizeX; x++) - { - std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(x, y, MaxZ - z)]); - } // for x - } // for z - } // for y - } // if (HasBlockMetas) -} - - - - - -void cBlockArea::MirrorXZNoMeta(void) -{ - int HalfY = m_SizeY / 2; - int MaxY = m_SizeY - 1; - if (HasBlockTypes()) - { - for (int y = 0; y < HalfY; y++) - { - for (int z = 0; z < m_SizeZ; z++) - { - for (int x = 0; x < m_SizeX; x++) - { - std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(x, MaxY - y, z)]); - } // for x - } // for z - } // for y - } // if (HasBlockTypes) - - if (HasBlockMetas()) - { - for (int y = 0; y < HalfY; y++) - { - for (int z = 0; z < m_SizeZ; z++) - { - for (int x = 0; x < m_SizeX; x++) - { - std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(x, MaxY - y, z)]); - } // for x - } // for z - } // for y - } // if (HasBlockMetas) -} - - - - - -void cBlockArea::MirrorYZNoMeta(void) -{ - int HalfX = m_SizeX / 2; - int MaxX = m_SizeX - 1; - if (HasBlockTypes()) - { - for (int y = 0; y < m_SizeY; y++) - { - for (int z = 0; z < m_SizeZ; z++) - { - for (int x = 0; x < HalfX; x++) - { - std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(MaxX - x, y, z)]); - } // for x - } // for z - } // for y - } // if (HasBlockTypes) - - if (HasBlockMetas()) - { - for (int y = 0; y < m_SizeY; y++) - { - for (int z = 0; z < m_SizeZ; z++) - { - for (int x = 0; x < HalfX; x++) - { - std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(MaxX - x, y, z)]); - } // for x - } // for z - } // for y - } // if (HasBlockMetas) -} - - - - - -void cBlockArea::SetRelBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType) -{ - if (m_BlockTypes == NULL) - { - LOGWARNING("cBlockArea: BlockTypes have not been read!"); - return; - } - m_BlockTypes[MakeIndex(a_RelX, a_RelY, a_RelZ)] = a_BlockType; -} - - - - - -void cBlockArea::SetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType) -{ - SetRelBlockType(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType); -} - - - - - -void cBlockArea::SetRelBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockMeta) -{ - SetRelNibble(a_RelX, a_RelY, a_RelZ, a_BlockMeta, m_BlockMetas); -} - - - - - -void cBlockArea::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockMeta) -{ - SetNibble(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta, m_BlockMetas); -} - - - - - -void cBlockArea::SetRelBlockLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockLight) -{ - SetRelNibble(a_RelX, a_RelY, a_RelZ, a_BlockLight, m_BlockLight); -} - - - - - -void cBlockArea::SetBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockLight) -{ - SetNibble(a_BlockX, a_BlockY, a_BlockZ, a_BlockLight, m_BlockLight); -} - - - - - -void cBlockArea::SetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockSkyLight) -{ - SetRelNibble(a_RelX, a_RelY, a_RelZ, a_BlockSkyLight, m_BlockSkyLight); -} - - - - - -void cBlockArea::SetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockSkyLight) -{ - SetNibble(a_BlockX, a_BlockY, a_BlockZ, a_BlockSkyLight, m_BlockSkyLight); -} - - - - - -BLOCKTYPE cBlockArea::GetRelBlockType(int a_RelX, int a_RelY, int a_RelZ) const -{ - if (m_BlockTypes == NULL) - { - LOGWARNING("cBlockArea: BlockTypes have not been read!"); - return E_BLOCK_AIR; - } - return m_BlockTypes[MakeIndex(a_RelX, a_RelY, a_RelZ)]; -} - - - - - -BLOCKTYPE cBlockArea::GetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ) const -{ - return GetRelBlockType(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ); -} - - - - - -NIBBLETYPE cBlockArea::GetRelBlockMeta(int a_RelX, int a_RelY, int a_RelZ) const -{ - return GetRelNibble(a_RelX, a_RelY, a_RelZ, m_BlockMetas); -} - - - - - -NIBBLETYPE cBlockArea::GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ) const -{ - return GetNibble(a_BlockX, a_BlockY, a_BlockZ, m_BlockMetas); -} - - - - - -NIBBLETYPE cBlockArea::GetRelBlockLight(int a_RelX, int a_RelY, int a_RelZ) const -{ - return GetRelNibble(a_RelX, a_RelY, a_RelZ, m_BlockLight); -} - - - - - -NIBBLETYPE cBlockArea::GetBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ) const -{ - return GetNibble(a_BlockX, a_BlockY, a_BlockZ, m_BlockLight); -} - - - - - -NIBBLETYPE cBlockArea::GetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ) const -{ - return GetRelNibble(a_RelX, a_RelY, a_RelZ, m_BlockSkyLight); -} - - - - - -NIBBLETYPE cBlockArea::GetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ) const -{ - return GetNibble(a_BlockX, a_BlockY, a_BlockZ, m_BlockSkyLight); -} - - - - - -void cBlockArea::SetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) -{ - SetRelBlockTypeMeta(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType, a_BlockMeta); -} - - - - - -void cBlockArea::SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) -{ - int idx = MakeIndex(a_RelX, a_RelY, a_RelZ); - if (m_BlockTypes == NULL) - { - LOGWARNING("%s: BlockTypes not available but requested to be written to.", __FUNCTION__); - } - else - { - m_BlockTypes[idx] = a_BlockType; - } - if (m_BlockMetas == NULL) - { - LOGWARNING("%s: BlockMetas not available but requested to be written to.", __FUNCTION__); - } - else - { - m_BlockMetas[idx] = a_BlockMeta; - } -} - - - - - -void cBlockArea::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const -{ - return GetRelBlockTypeMeta(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType, a_BlockMeta); -} - - - - - -void cBlockArea::GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const -{ - int idx = MakeIndex(a_RelX, a_RelY, a_RelZ); - if (m_BlockTypes == NULL) - { - LOGWARNING("cBlockArea: BlockTypes have not been read!"); - a_BlockType = E_BLOCK_AIR; - } - else - { - a_BlockType = m_BlockTypes[idx]; - } - - if (m_BlockMetas == NULL) - { - LOGWARNING("cBlockArea: BlockMetas have not been read!"); - a_BlockMeta = 0; - } - else - { - a_BlockMeta = m_BlockMetas[idx]; - } -} - - - - - -int cBlockArea::GetDataTypes(void) const -{ - int res = 0; - if (m_BlockTypes != NULL) - { - res |= baTypes; - } - if (m_BlockMetas != NULL) - { - res |= baMetas; - } - if (m_BlockLight != NULL) - { - res |= baLight; - } - if (m_BlockSkyLight != NULL) - { - res |= baSkyLight; - } - return res; -} - - - - - -bool cBlockArea::SetSize(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes) -{ - ASSERT(m_BlockTypes == NULL); // Has been cleared - - if (a_DataTypes & baTypes) - { - m_BlockTypes = new BLOCKTYPE[a_SizeX * a_SizeY * a_SizeZ]; - if (m_BlockTypes == NULL) - { - return false; - } - } - if (a_DataTypes & baMetas) - { - m_BlockMetas = new NIBBLETYPE[a_SizeX * a_SizeY * a_SizeZ]; - if (m_BlockMetas == NULL) - { - delete[] m_BlockTypes; - return false; - } - } - if (a_DataTypes & baLight) - { - m_BlockLight = new NIBBLETYPE[a_SizeX * a_SizeY * a_SizeZ]; - if (m_BlockLight == NULL) - { - delete[] m_BlockMetas; - delete[] m_BlockTypes; - return false; - } - } - if (a_DataTypes & baSkyLight) - { - m_BlockSkyLight = new NIBBLETYPE[a_SizeX * a_SizeY * a_SizeZ]; - if (m_BlockSkyLight == NULL) - { - delete[] m_BlockLight; - delete[] m_BlockMetas; - delete[] m_BlockTypes; - return false; - } - } - m_SizeX = a_SizeX; - m_SizeY = a_SizeY; - m_SizeZ = a_SizeZ; - return true; -} - - - - - -int cBlockArea::MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const -{ - ASSERT(a_RelX >= 0); - ASSERT(a_RelX < m_SizeX); - ASSERT(a_RelY >= 0); - ASSERT(a_RelY < m_SizeY); - ASSERT(a_RelZ >= 0); - ASSERT(a_RelZ < m_SizeZ); - - return a_RelX + a_RelZ * m_SizeX + a_RelY * m_SizeX * m_SizeZ; -} - - - - - -void cBlockArea::SetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Value, NIBBLETYPE * a_Array) -{ - if (a_Array == NULL) - { - LOGWARNING("cBlockArea: datatype has not been read!"); - return; - } - a_Array[MakeIndex(a_RelX, a_RelY, a_RelZ)] = a_Value; -} - - - - - -void cBlockArea::SetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Value, NIBBLETYPE * a_Array) -{ - SetRelNibble(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_Value, a_Array); -} - - - - - -NIBBLETYPE cBlockArea::GetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE * a_Array) const -{ - if (a_Array == NULL) - { - LOGWARNING("cBlockArea: datatype has not been read!"); - return 16; - } - return a_Array[MakeIndex(a_RelX, a_RelY, a_RelZ)]; -} - - - - - -NIBBLETYPE cBlockArea::GetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE * a_Array) const -{ - return GetRelNibble(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_Array); -} - - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cBlockArea::cChunkReader: - -cBlockArea::cChunkReader::cChunkReader(cBlockArea & a_Area) : - m_Area(a_Area), - m_OriginX(a_Area.m_OriginX), - m_OriginY(a_Area.m_OriginY), - m_OriginZ(a_Area.m_OriginZ) -{ -} - - - - - -void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLETYPE * a_ChunkSrc) -{ - int SizeY = m_Area.m_SizeY; - int MinY = m_OriginY; - - // SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union) - // OffX, OffZ are the offsets of the current chunk data from the area origin - // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders - int SizeX = cChunkDef::Width; - int SizeZ = cChunkDef::Width; - int OffX, OffZ; - int BaseX, BaseZ; - OffX = m_CurrentChunkX * cChunkDef::Width - m_OriginX; - if (OffX < 0) - { - BaseX = -OffX; - SizeX += OffX; // SizeX is decreased, OffX is negative - OffX = 0; - } - else - { - BaseX = 0; - } - OffZ = m_CurrentChunkZ * cChunkDef::Width - m_OriginZ; - if (OffZ < 0) - { - BaseZ = -OffZ; - SizeZ += OffZ; // SizeZ is decreased, OffZ is negative - OffZ = 0; - } - else - { - BaseZ = 0; - } - // If the chunk extends beyond the area in the X or Z axis, cut off the Size: - if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_OriginX + m_Area.m_SizeX) - { - SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_OriginX + m_Area.m_SizeX); - } - if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_OriginZ + m_Area.m_SizeZ) - { - SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_OriginZ + m_Area.m_SizeZ); - } - - for (int y = 0; y < SizeY; y++) - { - int ChunkY = MinY + y; - int AreaY = y; - for (int z = 0; z < SizeZ; z++) - { - int ChunkZ = BaseZ + z; - int AreaZ = OffZ + z; - for (int x = 0; x < SizeX; x++) - { - int ChunkX = BaseX + x; - int AreaX = OffX + x; - a_AreaDst[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = cChunkDef::GetNibble(a_ChunkSrc, ChunkX, ChunkY, ChunkZ); - } // for x - } // for z - } // for y -} - - - - - -bool cBlockArea::cChunkReader::Coords(int a_ChunkX, int a_ChunkZ) -{ - m_CurrentChunkX = a_ChunkX; - m_CurrentChunkZ = a_ChunkZ; - return true; -} - - - - - -void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes) -{ - if (m_Area.m_BlockTypes == NULL) - { - // Don't want BlockTypes - return; - } - - int SizeY = m_Area.m_SizeY; - int MinY = m_OriginY; - - // SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union) - // OffX, OffZ are the offsets of the current chunk data from the area origin - // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders - int SizeX = cChunkDef::Width; - int SizeZ = cChunkDef::Width; - int OffX, OffZ; - int BaseX, BaseZ; - OffX = m_CurrentChunkX * cChunkDef::Width - m_OriginX; - if (OffX < 0) - { - BaseX = -OffX; - SizeX += OffX; // SizeX is decreased, OffX is negative - OffX = 0; - } - else - { - BaseX = 0; - } - OffZ = m_CurrentChunkZ * cChunkDef::Width - m_OriginZ; - if (OffZ < 0) - { - BaseZ = -OffZ; - SizeZ += OffZ; // SizeZ is decreased, OffZ is negative - OffZ = 0; - } - else - { - BaseZ = 0; - } - // If the chunk extends beyond the area in the X or Z axis, cut off the Size: - if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_OriginX + m_Area.m_SizeX) - { - SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_OriginX + m_Area.m_SizeX); - } - if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_OriginZ + m_Area.m_SizeZ) - { - SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_OriginZ + m_Area.m_SizeZ); - } - - for (int y = 0; y < SizeY; y++) - { - int ChunkY = MinY + y; - int AreaY = y; - for (int z = 0; z < SizeZ; z++) - { - int ChunkZ = BaseZ + z; - int AreaZ = OffZ + z; - for (int x = 0; x < SizeX; x++) - { - int ChunkX = BaseX + x; - int AreaX = OffX + x; - m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = cChunkDef::GetBlock(a_BlockTypes, ChunkX, ChunkY, ChunkZ); - } // for x - } // for z - } // for y -} - - - - - -void cBlockArea::cChunkReader::BlockMeta(const NIBBLETYPE * a_BlockMetas) -{ - if (m_Area.m_BlockMetas == NULL) - { - // Don't want metas - return; - } - CopyNibbles(m_Area.m_BlockMetas, a_BlockMetas); -} - - - - - -void cBlockArea::cChunkReader::BlockLight(const NIBBLETYPE * a_BlockLight) -{ - if (m_Area.m_BlockLight == NULL) - { - // Don't want light - return; - } - CopyNibbles(m_Area.m_BlockLight, a_BlockLight); -} - - - - - -void cBlockArea::cChunkReader::BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) -{ - if (m_Area.m_BlockSkyLight == NULL) - { - // Don't want skylight - return; - } - CopyNibbles(m_Area.m_BlockSkyLight, a_BlockSkyLight); -} - - - - - -void cBlockArea::CropBlockTypes(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ) -{ - int NewSizeX = GetSizeX() - a_AddMinX - a_SubMaxX; - int NewSizeY = GetSizeY() - a_AddMinY - a_SubMaxY; - int NewSizeZ = GetSizeZ() - a_AddMinZ - a_SubMaxZ; - BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[NewSizeX * NewSizeY * NewSizeZ]; - int idx = 0; - for (int y = 0; y < NewSizeY; y++) - { - for (int z = 0; z < NewSizeZ; z++) - { - for (int x = 0; x < NewSizeX; x++) - { - int OldIndex = MakeIndex(x + a_AddMinX, y + a_AddMinY, z + a_AddMinZ); - NewBlockTypes[idx++] = m_BlockTypes[OldIndex]; - } // for x - } // for z - } // for y - delete m_BlockTypes; - m_BlockTypes = NewBlockTypes; -} - - - - - -void cBlockArea::CropNibbles(NIBBLEARRAY & a_Array, int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ) -{ - int NewSizeX = GetSizeX() - a_AddMinX - a_SubMaxX; - int NewSizeY = GetSizeY() - a_AddMinY - a_SubMaxY; - int NewSizeZ = GetSizeZ() - a_AddMinZ - a_SubMaxZ; - NIBBLETYPE * NewNibbles = new NIBBLETYPE[NewSizeX * NewSizeY * NewSizeZ]; - int idx = 0; - for (int y = 0; y < NewSizeY; y++) - { - for (int z = 0; z < NewSizeZ; z++) - { - for (int x = 0; x < NewSizeX; x++) - { - NewNibbles[idx++] = a_Array[MakeIndex(x + a_AddMinX, y + a_AddMinY, z + a_AddMinZ)]; - } // for x - } // for z - } // for y - delete a_Array; - a_Array = NewNibbles; -} - - - - - -void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ) -{ - int NewSizeX = m_SizeX + a_SubMinX + a_AddMaxX; - int NewSizeY = m_SizeY + a_SubMinY + a_AddMaxY; - int NewSizeZ = m_SizeZ + a_SubMinZ + a_AddMaxZ; - int BlockCount = NewSizeX * NewSizeY * NewSizeZ; - BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[BlockCount]; - memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE)); - int OldIndex = 0; - for (int y = 0; y < m_SizeY; y++) - { - int IndexBaseY = (y + a_SubMinY) * m_SizeX * m_SizeZ; - for (int z = 0; z < m_SizeZ; z++) - { - int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_SizeX; - int idx = IndexBaseZ + a_SubMinX; - for (int x = 0; x < m_SizeX; x++) - { - NewBlockTypes[idx++] = m_BlockTypes[OldIndex++]; - } // for x - } // for z - } // for y - delete m_BlockTypes; - m_BlockTypes = NewBlockTypes; -} - - - - - -void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ) -{ - int NewSizeX = m_SizeX + a_SubMinX + a_AddMaxX; - int NewSizeY = m_SizeY + a_SubMinY + a_AddMaxY; - int NewSizeZ = m_SizeZ + a_SubMinZ + a_AddMaxZ; - int BlockCount = NewSizeX * NewSizeY * NewSizeZ; - NIBBLETYPE * NewNibbles = new NIBBLETYPE[BlockCount]; - memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE)); - int OldIndex = 0; - for (int y = 0; y < m_SizeY; y++) - { - int IndexBaseY = (y + a_SubMinY) * m_SizeX * m_SizeZ; - for (int z = 0; z < m_SizeZ; z++) - { - int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_SizeX; - int idx = IndexBaseZ + a_SubMinX; - for (int x = 0; x < m_SizeX; x++) - { - NewNibbles[idx++] = a_Array[OldIndex++]; - } // for x - } // for z - } // for y - delete a_Array; - a_Array = NewNibbles; -} - - - - - -bool cBlockArea::LoadFromSchematicNBT(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, - a_NBT.GetType(TSizeX), a_NBT.GetType(TSizeY), a_NBT.GetType(TSizeZ) - ); - return false; - } - - int SizeX = a_NBT.GetShort(TSizeX); - int SizeY = a_NBT.GetShort(TSizeY); - int SizeZ = a_NBT.GetShort(TSizeZ); - if ((SizeX < 1) || (SizeY < 1) || (SizeZ < 1)) - { - 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); - - Clear(); - SetSize(SizeX, SizeY, SizeZ, AreMetasPresent ? (baTypes | baMetas) : baTypes); - - // Copy the block types and metas: - int NumBytes = m_SizeX * m_SizeY * m_SizeZ; - if (a_NBT.GetDataLength(TBlockTypes) < NumBytes) - { - LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.", - NumBytes, a_NBT.GetDataLength(TBlockTypes) - ); - NumBytes = a_NBT.GetDataLength(TBlockTypes); - } - memcpy(m_BlockTypes, a_NBT.GetData(TBlockTypes), NumBytes); - - if (AreMetasPresent) - { - int NumBytes = m_SizeX * m_SizeY * m_SizeZ; - if (a_NBT.GetDataLength(TBlockMetas) < NumBytes) - { - LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.", - NumBytes, a_NBT.GetDataLength(TBlockMetas) - ); - NumBytes = a_NBT.GetDataLength(TBlockMetas); - } - memcpy(m_BlockMetas, a_NBT.GetData(TBlockMetas), NumBytes); - } - - return true; -} - - - - -void cBlockArea::RelSetData( - int a_RelX, int a_RelY, int a_RelZ, - int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, - NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight -) -{ - int Index = MakeIndex(a_RelX, a_RelY, a_RelZ); - if ((a_DataTypes & baTypes) != 0) - { - m_BlockTypes[Index] = a_BlockType; - } - if ((a_DataTypes & baMetas) != 0) - { - m_BlockMetas[Index] = a_BlockMeta; - } - if ((a_DataTypes & baLight) != 0) - { - m_BlockLight[Index] = a_BlockLight; - } - if ((a_DataTypes & baSkyLight) != 0) - { - m_BlockSkyLight[Index] = a_BlockSkyLight; - } -} - - - - + +// BlockArea.cpp + +// Implements the cBlockArea object representing an area of block data that can be queried from cWorld and then accessed again without further queries +// The object also supports writing the blockdata back into cWorld, even into other coords + +#include "Globals.h" +#include "BlockArea.h" +#include "World.h" +#include "OSSupport/GZipFile.h" +#include "WorldStorage/FastNBT.h" +#include "Blocks/BlockHandler.h" + + + + + +// This wild construct allows us to pass a function argument and still have it inlined by the compiler :) +/// Merges two blocktypes and blockmetas of the specified sizes and offsets using the specified combinator function +template void InternalMergeBlocks( + BLOCKTYPE * a_DstTypes, const BLOCKTYPE * a_SrcTypes, + NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas, + int a_SizeX, int a_SizeY, int a_SizeZ, + int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ, + int a_DstOffX, int a_DstOffY, int a_DstOffZ, + int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ, + int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ, + Combinator a_Combinator +) +{ + for (int y = 0; y < a_SizeY; y++) + { + int SrcBaseY = (y + a_SrcOffY) * a_SrcSizeX * a_SrcSizeZ; + int DstBaseY = (y + a_DstOffY) * a_DstSizeX * a_DstSizeZ; + for (int z = 0; z < a_SizeZ; z++) + { + int SrcBaseZ = SrcBaseY + (z + a_SrcOffZ) * a_SrcSizeX; + int DstBaseZ = DstBaseY + (z + a_DstOffZ) * a_DstSizeX; + int SrcIdx = SrcBaseZ + a_SrcOffX; + int DstIdx = DstBaseZ + a_DstOffX; + for (int x = 0; x < a_SizeX; x++) + { + a_Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]); + ++DstIdx; + ++SrcIdx; + } // for x + } // for z + } // for y +} + + + + + +/// Combinator used for cBlockArea::msOverwrite merging +static void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + a_DstType = a_SrcType; + a_DstMeta = a_SrcMeta; +} + + + + + +/// Combinator used for cBlockArea::msFillAir merging +static void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + if (a_DstType == E_BLOCK_AIR) + { + a_DstType = a_SrcType; + a_DstMeta = a_SrcMeta; + } + // "else" is the default, already in place +} + + + + + +/// Combinator used for cBlockArea::msImprint merging +static void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + if (a_SrcType != E_BLOCK_AIR) + { + a_DstType = a_SrcType; + a_DstMeta = a_SrcMeta; + } + // "else" is the default, already in place +} + + + + + +/// Combinator used for cBlockArea::msLake merging +static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + // Sponge is the NOP block + if (a_SrcType == E_BLOCK_SPONGE) + { + return; + } + + // Air is always hollowed out + if (a_SrcType == E_BLOCK_AIR) + { + a_DstType = E_BLOCK_AIR; + a_DstMeta = 0; + return; + } + + // Water and lava are never overwritten + switch (a_DstType) + { + case E_BLOCK_WATER: + case E_BLOCK_STATIONARY_WATER: + case E_BLOCK_LAVA: + case E_BLOCK_STATIONARY_LAVA: + { + return; + } + } + + // Water and lava always overwrite + switch (a_SrcType) + { + case E_BLOCK_WATER: + case E_BLOCK_STATIONARY_WATER: + case E_BLOCK_LAVA: + case E_BLOCK_STATIONARY_LAVA: + { + a_DstType = a_SrcType; + a_DstMeta = a_DstMeta; + return; + } + } + + if (a_SrcType == E_BLOCK_STONE) + { + switch (a_DstType) + { + case E_BLOCK_DIRT: + case E_BLOCK_GRASS: + case E_BLOCK_MYCELIUM: + { + a_DstType = E_BLOCK_STONE; + a_DstMeta = 0; + return; + } + } + } + // Everything else is left as it is +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cBlockArea: + +cBlockArea::cBlockArea(void) : + m_SizeX(0), + m_SizeY(0), + m_SizeZ(0), + m_BlockTypes(NULL), + m_BlockMetas(NULL), + m_BlockLight(NULL), + m_BlockSkyLight(NULL) +{ +} + + + + + +cBlockArea::~cBlockArea() +{ + Clear(); +} + + + + + +void cBlockArea::Clear(void) +{ + delete[] m_BlockTypes; m_BlockTypes = NULL; + delete[] m_BlockMetas; m_BlockMetas = NULL; + delete[] m_BlockLight; m_BlockLight = NULL; + delete[] m_BlockSkyLight; m_BlockSkyLight = NULL; + m_SizeX = 0; + m_SizeY = 0; + m_SizeZ = 0; +} + + + + + +void cBlockArea::Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes) +{ + Clear(); + int BlockCount = a_SizeX * a_SizeY * a_SizeZ; + if ((a_DataTypes & baTypes) != 0) + { + m_BlockTypes = new BLOCKTYPE[BlockCount]; + for (int i = 0; i < BlockCount; i++) + { + m_BlockTypes[i] = E_BLOCK_AIR; + } + } + if ((a_DataTypes & baMetas) != 0) + { + m_BlockMetas = new NIBBLETYPE[BlockCount]; + for (int i = 0; i < BlockCount; i++) + { + m_BlockMetas[i] = 0; + } + } + if ((a_DataTypes & baLight) != 0) + { + m_BlockLight = new NIBBLETYPE[BlockCount]; + for (int i = 0; i < BlockCount; i++) + { + m_BlockLight[i] = 0; + } + } + if ((a_DataTypes & baSkyLight) != 0) + { + m_BlockSkyLight = new NIBBLETYPE[BlockCount]; + for (int i = 0; i < BlockCount; i++) + { + m_BlockSkyLight[i] = 0x0f; + } + } + m_SizeX = a_SizeX; + m_SizeY = a_SizeY; + m_SizeZ = a_SizeZ; + m_OriginX = 0; + m_OriginY = 0; + m_OriginZ = 0; +} + + + + + +void cBlockArea::SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ) +{ + m_OriginX = a_OriginX; + m_OriginY = a_OriginY; + m_OriginZ = a_OriginZ; +} + + + + + +bool cBlockArea::Read(cWorld * a_World, int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ, int a_DataTypes) +{ + // Normalize the coords: + if (a_MinBlockX > a_MaxBlockX) + { + std::swap(a_MinBlockX, a_MaxBlockX); + } + if (a_MinBlockY > a_MaxBlockY) + { + std::swap(a_MinBlockY, a_MaxBlockY); + } + if (a_MinBlockZ > a_MaxBlockZ) + { + std::swap(a_MinBlockZ, a_MaxBlockZ); + } + + // Include the Max coords: + a_MaxBlockX += 1; + a_MaxBlockY += 1; + a_MaxBlockZ += 1; + + // Check coords validity: + if (a_MinBlockY < 0) + { + LOGWARNING("%s: MinBlockY less than zero, adjusting to zero", __FUNCTION__); + a_MinBlockY = 0; + } + else if (a_MinBlockY >= cChunkDef::Height) + { + LOGWARNING("%s: MinBlockY more than chunk height, adjusting to chunk height", __FUNCTION__); + a_MinBlockY = cChunkDef::Height - 1; + } + if (a_MaxBlockY < 0) + { + LOGWARNING("%s: MaxBlockY less than zero, adjusting to zero", __FUNCTION__); + a_MaxBlockY = 0; + } + else if (a_MaxBlockY >= cChunkDef::Height) + { + LOGWARNING("%s: MaxBlockY more than chunk height, adjusting to chunk height", __FUNCTION__); + a_MaxBlockY = cChunkDef::Height - 1; + } + + // Allocate the needed memory: + Clear(); + if (!SetSize(a_MaxBlockX - a_MinBlockX, a_MaxBlockY - a_MinBlockY, a_MaxBlockZ - a_MinBlockZ, a_DataTypes)) + { + return false; + } + m_OriginX = a_MinBlockX; + m_OriginY = a_MinBlockY; + m_OriginZ = a_MinBlockZ; + cChunkReader Reader(*this); + + // Convert block coords to chunks coords: + int MinChunkX, MaxChunkX; + int MinChunkZ, MaxChunkZ; + cChunkDef::AbsoluteToRelative(a_MinBlockX, a_MinBlockY, a_MinBlockZ, MinChunkX, MinChunkZ); + cChunkDef::AbsoluteToRelative(a_MaxBlockX, a_MaxBlockY, a_MaxBlockZ, MaxChunkX, MaxChunkZ); + + // Query block data: + if (!a_World->ForEachChunkInRect(MinChunkX, MaxChunkX, MinChunkZ, MaxChunkZ, Reader)) + { + Clear(); + return false; + } + + return true; +} + + + + + +bool cBlockArea::Write(cWorld * a_World, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes) +{ + ASSERT((a_DataTypes & GetDataTypes()) == a_DataTypes); // Are you requesting only the data that I have? + a_DataTypes = a_DataTypes & GetDataTypes(); // For release builds, silently cut off the datatypes that I don't have + + // Check coords validity: + if (a_MinBlockY < 0) + { + LOGWARNING("%s: MinBlockY less than zero, adjusting to zero", __FUNCTION__); + a_MinBlockY = 0; + } + else if (a_MinBlockY >= cChunkDef::Height - m_SizeY) + { + LOGWARNING("%s: MinBlockY + m_SizeY more than chunk height, adjusting to chunk height", __FUNCTION__); + a_MinBlockY = cChunkDef::Height - m_SizeY - 1; + } + + return a_World->WriteBlockArea(*this, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes); +} + + + + + +void cBlockArea::CopyTo(cBlockArea & a_Into) const +{ + if (&a_Into == this) + { + LOGWARNING("Trying to copy a cBlockArea into self, ignoring."); + return; + } + + a_Into.Clear(); + a_Into.SetSize(m_SizeX, m_SizeY, m_SizeZ, GetDataTypes()); + a_Into.m_OriginX = m_OriginX; + a_Into.m_OriginY = m_OriginY; + a_Into.m_OriginZ = m_OriginZ; + int BlockCount = GetBlockCount(); + if (HasBlockTypes()) + { + memcpy(a_Into.m_BlockTypes, m_BlockTypes, BlockCount * sizeof(BLOCKTYPE)); + } + if (HasBlockMetas()) + { + memcpy(a_Into.m_BlockMetas, m_BlockMetas, BlockCount * sizeof(NIBBLETYPE)); + } + if (HasBlockLights()) + { + memcpy(a_Into.m_BlockLight, m_BlockLight, BlockCount * sizeof(NIBBLETYPE)); + } + if (HasBlockSkyLights()) + { + memcpy(a_Into.m_BlockSkyLight, m_BlockSkyLight, BlockCount * sizeof(NIBBLETYPE)); + } +} + + + + + +void cBlockArea::CopyFrom(const cBlockArea & a_From) +{ + a_From.CopyTo(*this); +} + + + + + +void cBlockArea::DumpToRawFile(const AString & a_FileName) +{ + cFile f; + if (!f.Open(a_FileName, cFile::fmWrite)) + { + LOGWARNING("cBlockArea: Cannot open file \"%s\" for raw dump", a_FileName.c_str()); + return; + } + UInt32 SizeX = ntohl(m_SizeX); + UInt32 SizeY = ntohl(m_SizeY); + UInt32 SizeZ = ntohl(m_SizeZ); + f.Write(&SizeX, 4); + f.Write(&SizeY, 4); + f.Write(&SizeZ, 4); + unsigned char DataTypes = GetDataTypes(); + f.Write(&DataTypes, 1); + int NumBlocks = GetBlockCount(); + if (HasBlockTypes()) + { + f.Write(m_BlockTypes, NumBlocks * sizeof(BLOCKTYPE)); + } + if (HasBlockMetas()) + { + f.Write(m_BlockMetas, NumBlocks); + } + if (HasBlockLights()) + { + f.Write(m_BlockLight, NumBlocks); + } + if (HasBlockSkyLights()) + { + f.Write(m_BlockSkyLight, NumBlocks); + } +} + + + + + +bool cBlockArea::LoadFromSchematicFile(const AString & a_FileName) +{ + // Un-GZip the contents: + AString Contents; + cGZipFile File; + if (!File.Open(a_FileName, cGZipFile::fmRead)) + { + LOG("Cannot open the schematic file \"%s\".", a_FileName.c_str()); + return false; + } + int NumBytesRead = File.ReadRestOfFile(Contents); + if (NumBytesRead < 0) + { + LOG("Cannot read GZipped data in the schematic file \"%s\", error %d", a_FileName.c_str(), NumBytesRead); + return false; + } + File.Close(); + + // Parse the NBT: + cParsedNBT NBT(Contents.data(), Contents.size()); + if (!NBT.IsValid()) + { + LOG("Cannot parse the NBT in the schematic file \"%s\".", a_FileName.c_str()); + return false; + } + + return LoadFromSchematicNBT(NBT); +} + + + + + +bool cBlockArea::SaveToSchematicFile(const AString & a_FileName) +{ + cFastNBTWriter Writer("Schematic"); + Writer.AddShort("Width", m_SizeX); + Writer.AddShort("Height", m_SizeY); + Writer.AddShort("Length", m_SizeZ); + Writer.AddString("Materials", "Alpha"); + if (HasBlockTypes()) + { + Writer.AddByteArray("Blocks", (const char *)m_BlockTypes, GetBlockCount()); + } + else + { + AString Dummy(GetBlockCount(), 0); + Writer.AddByteArray("Blocks", Dummy.data(), Dummy.size()); + } + if (HasBlockMetas()) + { + Writer.AddByteArray("Data", (const char *)m_BlockMetas, GetBlockCount()); + } + else + { + AString Dummy(GetBlockCount(), 0); + Writer.AddByteArray("Data", Dummy.data(), Dummy.size()); + } + // TODO: Save entities and block entities + Writer.BeginList("Entities", TAG_Compound); + Writer.EndList(); + Writer.BeginList("TileEntities", TAG_Compound); + Writer.EndList(); + Writer.Finish(); + + // Save to file + cGZipFile File; + if (!File.Open(a_FileName, cGZipFile::fmWrite)) + { + LOG("Cannot open file \"%s\" for writing.", a_FileName.c_str()); + return false; + } + if (!File.Write(Writer.GetResult())) + { + LOG("Cannot write data to file \"%s\".", a_FileName.c_str()); + return false; + } + return true; +} + + + + + +void cBlockArea::Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ) +{ + if ( + (a_AddMinX + a_SubMaxX >= m_SizeX) || + (a_AddMinY + a_SubMaxY >= m_SizeY) || + (a_AddMinZ + a_SubMaxZ >= m_SizeZ) + ) + { + LOGWARNING("cBlockArea:Crop called with more croping than the dimensions: %d x %d x %d with cropping %d, %d and %d", + m_SizeX, m_SizeY, m_SizeZ, + a_AddMinX + a_SubMaxX, a_AddMinY + a_SubMaxY, a_AddMinZ + a_SubMaxZ + ); + return; + } + + if (HasBlockTypes()) + { + CropBlockTypes(a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ); + } + if (HasBlockMetas()) + { + CropNibbles(m_BlockMetas, a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ); + } + if (HasBlockLights()) + { + CropNibbles(m_BlockLight, a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ); + } + if (HasBlockSkyLights()) + { + CropNibbles(m_BlockSkyLight, a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ); + } + m_OriginX += a_AddMinX; + m_OriginY += a_AddMinY; + m_OriginZ += a_AddMinZ; + m_SizeX -= a_AddMinX + a_SubMaxX; + m_SizeY -= a_AddMinY + a_SubMaxY; + m_SizeZ -= a_AddMinZ + a_SubMaxZ; +} + + + + + +void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ) +{ + if (HasBlockTypes()) + { + ExpandBlockTypes(a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ); + } + if (HasBlockMetas()) + { + ExpandNibbles(m_BlockMetas, a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ); + } + if (HasBlockLights()) + { + ExpandNibbles(m_BlockLight, a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ); + } + if (HasBlockSkyLights()) + { + ExpandNibbles(m_BlockSkyLight, a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ); + } + m_OriginX -= a_SubMinX; + m_OriginY -= a_SubMinY; + m_OriginZ -= a_SubMinZ; + m_SizeX += a_SubMinX + a_AddMaxX; + m_SizeY += a_SubMinY + a_AddMaxY; + m_SizeZ += a_SubMinZ + a_AddMaxZ; +} + + + + + +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; + } +} + + + + + +void cBlockArea::Fill(int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight) +{ + if ((a_DataTypes & GetDataTypes()) != a_DataTypes) + { + LOGWARNING("%s: requested datatypes that are not present in the BlockArea object, trimming those away (req 0x%x, stor 0x%x)", + __FUNCTION__, a_DataTypes, GetDataTypes() + ); + a_DataTypes = a_DataTypes & GetDataTypes(); + } + + int BlockCount = GetBlockCount(); + if ((a_DataTypes & baTypes) != 0) + { + for (int i = 0; i < BlockCount; i++) + { + m_BlockTypes[i] = a_BlockType; + } + } + if ((a_DataTypes & baMetas) != 0) + { + for (int i = 0; i < BlockCount; i++) + { + m_BlockMetas[i] = a_BlockMeta; + } + } + if ((a_DataTypes & baLight) != 0) + { + for (int i = 0; i < BlockCount; i++) + { + m_BlockLight[i] = a_BlockLight; + } + } + if ((a_DataTypes & baSkyLight) != 0) + { + for (int i = 0; i < BlockCount; i++) + { + m_BlockSkyLight[i] = a_BlockSkyLight; + } + } +} + + + + + +void cBlockArea::FillRelCuboid(int a_MinRelX, int a_MaxRelX, int a_MinRelY, int a_MaxRelY, int a_MinRelZ, int a_MaxRelZ, + int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, + NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight +) +{ + if ((a_DataTypes & GetDataTypes()) != a_DataTypes) + { + LOGWARNING("%s: requested datatypes that are not present in the BlockArea object, trimming those away (req 0x%x, stor 0x%x)", + __FUNCTION__, a_DataTypes, GetDataTypes() + ); + a_DataTypes = a_DataTypes & GetDataTypes(); + } + + if ((a_DataTypes & baTypes) != 0) + { + for (int y = a_MinRelY; y <= a_MaxRelY; y++) for (int z = a_MinRelZ; z <= a_MaxRelZ; z++) for (int x = a_MinRelX; x <= a_MaxRelX; x++) + { + m_BlockTypes[MakeIndex(x, y, z)] = a_BlockType; + } // for x, z, y + } + if ((a_DataTypes & baMetas) != 0) + { + for (int y = a_MinRelY; y <= a_MaxRelY; y++) for (int z = a_MinRelZ; z <= a_MaxRelZ; z++) for (int x = a_MinRelX; x <= a_MaxRelX; x++) + { + m_BlockMetas[MakeIndex(x, y, z)] = a_BlockMeta; + } // for x, z, y + } + if ((a_DataTypes & baLight) != 0) + { + for (int y = a_MinRelY; y <= a_MaxRelY; y++) for (int z = a_MinRelZ; z <= a_MaxRelZ; z++) for (int x = a_MinRelX; x <= a_MaxRelX; x++) + { + m_BlockLight[MakeIndex(x, y, z)] = a_BlockLight; + } // for x, z, y + } + if ((a_DataTypes & baSkyLight) != 0) + { + for (int y = a_MinRelY; y <= a_MaxRelY; y++) for (int z = a_MinRelZ; z <= a_MaxRelZ; z++) for (int x = a_MinRelX; x <= a_MaxRelX; x++) + { + m_BlockSkyLight[MakeIndex(x, y, z)] = a_BlockSkyLight; + } // for x, z, y + } +} + + + + + +void cBlockArea::RelLine(int a_RelX1, int a_RelY1, int a_RelZ1, int a_RelX2, int a_RelY2, int a_RelZ2, + int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, + NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight +) +{ + // Bresenham-3D algorithm for drawing lines: + int dx = abs(a_RelX2 - a_RelX1); + int dy = abs(a_RelY2 - a_RelY1); + int dz = abs(a_RelZ2 - a_RelZ1); + int sx = (a_RelX1 < a_RelX2) ? 1 : -1; + int sy = (a_RelY1 < a_RelY2) ? 1 : -1; + int sz = (a_RelZ1 < a_RelZ2) ? 1 : -1; + int err = dx - dz; + + if (dx >= std::max(dy, dz)) // x dominant + { + int yd = dy - dx / 2; + int zd = dz - dx / 2; + + while (true) + { + RelSetData(a_RelX1, a_RelY1, a_RelZ1, a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight); + + if (a_RelX1 == a_RelX2) + { + break; + } + + if (yd >= 0) // move along y + { + a_RelY1 += sy; + yd -= dx; + } + + if (zd >= 0) // move along z + { + a_RelZ1 += sz; + zd -= dx; + } + + // move along x + a_RelX1 += sx; + yd += dy; + zd += dz; + } + } + else if (dy >= std::max(dx, dz)) // y dominant + { + int xd = dx - dy / 2; + int zd = dz - dy / 2; + + while (true) + { + RelSetData(a_RelX1, a_RelY1, a_RelZ1, a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight); + + if (a_RelY1 == a_RelY2) + { + break; + } + + if (xd >= 0) // move along x + { + a_RelX1 += sx; + xd -= dy; + } + + if (zd >= 0) // move along z + { + a_RelZ1 += sz; + zd -= dy; + } + + // move along y + a_RelY1 += sy; + xd += dx; + zd += dz; + } + } + else + { + // z dominant + ASSERT(dz >= std::max(dx, dy)); + int xd = dx - dz / 2; + int yd = dy - dz / 2; + + while (true) + { + RelSetData(a_RelX1, a_RelY1, a_RelZ1, a_DataTypes, a_BlockType, a_BlockMeta, a_BlockLight, a_BlockSkyLight); + + if (a_RelZ1 == a_RelZ2) + { + break; + } + + if (xd >= 0) // move along x + { + a_RelX1 += sx; + xd -= dz; + } + + if (yd >= 0) // move along y + { + a_RelY1 += sy; + yd -= dz; + } + + // move along z + a_RelZ1 += sz; + xd += dx; + yd += dy; + } + } // if (which dimension is dominant) +} + + + + + +void cBlockArea::RotateCCW(void) +{ + if (!HasBlockTypes()) + { + LOGWARNING("cBlockArea: Cannot rotate blockmeta without blocktypes!"); + return; + } + + if (!HasBlockMetas()) + { + // There are no blockmetas to rotate, just use the NoMeta function + RotateCCWNoMeta(); + return; + } + + // We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time: + BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ]; + NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ]; + for (int x = 0; x < m_SizeX; x++) + { + int NewZ = m_SizeX - x - 1; + for (int z = 0; z < m_SizeZ; z++) + { + int NewX = z; + for (int y = 0; y < m_SizeY; y++) + { + int NewIdx = NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ; + int OldIdx = MakeIndex(x, y, z); + NewTypes[NewIdx] = m_BlockTypes[OldIdx]; + NewMetas[NewIdx] = BlockHandler(m_BlockTypes[OldIdx])->MetaRotateCCW(m_BlockMetas[OldIdx]); + } // for y + } // for z + } // for x + std::swap(m_BlockTypes, NewTypes); + std::swap(m_BlockMetas, NewMetas); + delete[] NewTypes; + delete[] NewMetas; + + std::swap(m_SizeX, m_SizeZ); +} + + + + + +void cBlockArea::RotateCW(void) +{ + if (!HasBlockTypes()) + { + LOGWARNING("cBlockArea: Cannot rotate blockmeta without blocktypes!"); + return; + } + + if (!HasBlockMetas()) + { + // There are no blockmetas to rotate, just use the NoMeta function + RotateCWNoMeta(); + return; + } + + // We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time: + BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ]; + NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ]; + for (int x = 0; x < m_SizeX; x++) + { + int NewZ = x; + for (int z = 0; z < m_SizeZ; z++) + { + int NewX = m_SizeZ - z - 1; + for (int y = 0; y < m_SizeY; y++) + { + int NewIdx = NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ; + int OldIdx = MakeIndex(x, y, z); + NewTypes[NewIdx] = m_BlockTypes[OldIdx]; + NewMetas[NewIdx] = BlockHandler(m_BlockTypes[OldIdx])->MetaRotateCW(m_BlockMetas[OldIdx]); + } // for y + } // for z + } // for x + std::swap(m_BlockTypes, NewTypes); + std::swap(m_BlockMetas, NewMetas); + delete[] NewTypes; + delete[] NewMetas; + + std::swap(m_SizeX, m_SizeZ); +} + + + + + +void cBlockArea::MirrorXY(void) +{ + if (!HasBlockTypes()) + { + LOGWARNING("cBlockArea: Cannot mirror meta without blocktypes!"); + return; + } + + if (!HasBlockMetas()) + { + // There are no blockmetas to mirror, just use the NoMeta function + MirrorXYNoMeta(); + return; + } + + // We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time: + int HalfZ = m_SizeZ / 2; + int MaxZ = m_SizeZ - 1; + for (int y = 0; y < m_SizeY; y++) + { + for (int z = 0; z < HalfZ; z++) + { + for (int x = 0; x < m_SizeX; x++) + { + int Idx1 = MakeIndex(x, y, z); + int Idx2 = MakeIndex(x, y, MaxZ - z); + std::swap(m_BlockTypes[Idx1], m_BlockTypes[Idx2]); + NIBBLETYPE Meta1 = BlockHandler(m_BlockTypes[Idx2])->MetaMirrorXY(m_BlockMetas[Idx1]); + NIBBLETYPE Meta2 = BlockHandler(m_BlockTypes[Idx1])->MetaMirrorXY(m_BlockMetas[Idx2]); + m_BlockMetas[Idx1] = Meta2; + m_BlockMetas[Idx2] = Meta1; + } // for x + } // for z + } // for y +} + + + + + +void cBlockArea::MirrorXZ(void) +{ + if (!HasBlockTypes()) + { + LOGWARNING("cBlockArea: Cannot mirror meta without blocktypes!"); + return; + } + + if (!HasBlockMetas()) + { + // There are no blockmetas to mirror, just use the NoMeta function + MirrorXZNoMeta(); + return; + } + + // We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time: + int HalfY = m_SizeY / 2; + int MaxY = m_SizeY - 1; + for (int y = 0; y < HalfY; y++) + { + for (int z = 0; z < m_SizeZ; z++) + { + for (int x = 0; x < m_SizeX; x++) + { + int Idx1 = MakeIndex(x, y, z); + int Idx2 = MakeIndex(x, MaxY - y, z); + std::swap(m_BlockTypes[Idx1], m_BlockTypes[Idx2]); + NIBBLETYPE Meta1 = BlockHandler(m_BlockTypes[Idx2])->MetaMirrorXZ(m_BlockMetas[Idx1]); + NIBBLETYPE Meta2 = BlockHandler(m_BlockTypes[Idx1])->MetaMirrorXZ(m_BlockMetas[Idx2]); + m_BlockMetas[Idx1] = Meta2; + m_BlockMetas[Idx2] = Meta1; + } // for x + } // for z + } // for y +} + + + + + +void cBlockArea::MirrorYZ(void) +{ + if (!HasBlockTypes()) + { + LOGWARNING("cBlockArea: Cannot mirror meta without blocktypes!"); + return; + } + + if (!HasBlockMetas()) + { + // There are no blockmetas to mirror, just use the NoMeta function + MirrorYZNoMeta(); + return; + } + + // We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time: + int HalfX = m_SizeX / 2; + int MaxX = m_SizeX - 1; + for (int y = 0; y < m_SizeY; y++) + { + for (int z = 0; z < m_SizeZ; z++) + { + for (int x = 0; x < HalfX; x++) + { + int Idx1 = MakeIndex(x, y, z); + int Idx2 = MakeIndex(MaxX - x, y, z); + std::swap(m_BlockTypes[Idx1], m_BlockTypes[Idx2]); + NIBBLETYPE Meta1 = BlockHandler(m_BlockTypes[Idx2])->MetaMirrorYZ(m_BlockMetas[Idx1]); + NIBBLETYPE Meta2 = BlockHandler(m_BlockTypes[Idx1])->MetaMirrorYZ(m_BlockMetas[Idx2]); + m_BlockMetas[Idx1] = Meta2; + m_BlockMetas[Idx2] = Meta1; + } // for x + } // for z + } // for y +} + + + + + +void cBlockArea::RotateCCWNoMeta(void) +{ + if (HasBlockTypes()) + { + BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ]; + for (int x = 0; x < m_SizeX; x++) + { + int NewZ = m_SizeX - x - 1; + for (int z = 0; z < m_SizeZ; z++) + { + int NewX = z; + for (int y = 0; y < m_SizeY; y++) + { + NewTypes[NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ] = m_BlockTypes[MakeIndex(x, y, z)]; + } // for y + } // for z + } // for x + std::swap(m_BlockTypes, NewTypes); + delete[] NewTypes; + } + if (HasBlockMetas()) + { + NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ]; + for (int x = 0; x < m_SizeX; x++) + { + int NewZ = m_SizeX - x - 1; + for (int z = 0; z < m_SizeZ; z++) + { + int NewX = z; + for (int y = 0; y < m_SizeY; y++) + { + NewMetas[NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ] = m_BlockMetas[MakeIndex(x, y, z)]; + } // for y + } // for z + } // for x + std::swap(m_BlockMetas, NewMetas); + delete[] NewMetas; + } + std::swap(m_SizeX, m_SizeZ); +} + + + + + +void cBlockArea::RotateCWNoMeta(void) +{ + if (HasBlockTypes()) + { + BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ]; + for (int z = 0; z < m_SizeZ; z++) + { + int NewX = m_SizeZ - z - 1; + for (int x = 0; x < m_SizeX; x++) + { + int NewZ = x; + for (int y = 0; y < m_SizeY; y++) + { + NewTypes[NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ] = m_BlockTypes[MakeIndex(x, y, z)]; + } // for y + } // for x + } // for z + std::swap(m_BlockTypes, NewTypes); + delete[] NewTypes; + } + if (HasBlockMetas()) + { + NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ]; + for (int z = 0; z < m_SizeZ; z++) + { + int NewX = m_SizeZ - z - 1; + for (int x = 0; x < m_SizeX; x++) + { + int NewZ = x; + for (int y = 0; y < m_SizeY; y++) + { + NewMetas[NewX + NewZ * m_SizeX + y * m_SizeX * m_SizeZ] = m_BlockMetas[MakeIndex(x, y, z)]; + } // for y + } // for x + } // for z + std::swap(m_BlockMetas, NewMetas); + delete[] NewMetas; + } + std::swap(m_SizeX, m_SizeZ); +} + + + + + +void cBlockArea::MirrorXYNoMeta(void) +{ + int HalfZ = m_SizeZ / 2; + int MaxZ = m_SizeZ - 1; + if (HasBlockTypes()) + { + for (int y = 0; y < m_SizeY; y++) + { + for (int z = 0; z < HalfZ; z++) + { + for (int x = 0; x < m_SizeX; x++) + { + std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(x, y, MaxZ - z)]); + } // for x + } // for z + } // for y + } // if (HasBlockTypes) + + if (HasBlockMetas()) + { + for (int y = 0; y < m_SizeY; y++) + { + for (int z = 0; z < HalfZ; z++) + { + for (int x = 0; x < m_SizeX; x++) + { + std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(x, y, MaxZ - z)]); + } // for x + } // for z + } // for y + } // if (HasBlockMetas) +} + + + + + +void cBlockArea::MirrorXZNoMeta(void) +{ + int HalfY = m_SizeY / 2; + int MaxY = m_SizeY - 1; + if (HasBlockTypes()) + { + for (int y = 0; y < HalfY; y++) + { + for (int z = 0; z < m_SizeZ; z++) + { + for (int x = 0; x < m_SizeX; x++) + { + std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(x, MaxY - y, z)]); + } // for x + } // for z + } // for y + } // if (HasBlockTypes) + + if (HasBlockMetas()) + { + for (int y = 0; y < HalfY; y++) + { + for (int z = 0; z < m_SizeZ; z++) + { + for (int x = 0; x < m_SizeX; x++) + { + std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(x, MaxY - y, z)]); + } // for x + } // for z + } // for y + } // if (HasBlockMetas) +} + + + + + +void cBlockArea::MirrorYZNoMeta(void) +{ + int HalfX = m_SizeX / 2; + int MaxX = m_SizeX - 1; + if (HasBlockTypes()) + { + for (int y = 0; y < m_SizeY; y++) + { + for (int z = 0; z < m_SizeZ; z++) + { + for (int x = 0; x < HalfX; x++) + { + std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(MaxX - x, y, z)]); + } // for x + } // for z + } // for y + } // if (HasBlockTypes) + + if (HasBlockMetas()) + { + for (int y = 0; y < m_SizeY; y++) + { + for (int z = 0; z < m_SizeZ; z++) + { + for (int x = 0; x < HalfX; x++) + { + std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(MaxX - x, y, z)]); + } // for x + } // for z + } // for y + } // if (HasBlockMetas) +} + + + + + +void cBlockArea::SetRelBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType) +{ + if (m_BlockTypes == NULL) + { + LOGWARNING("cBlockArea: BlockTypes have not been read!"); + return; + } + m_BlockTypes[MakeIndex(a_RelX, a_RelY, a_RelZ)] = a_BlockType; +} + + + + + +void cBlockArea::SetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType) +{ + SetRelBlockType(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType); +} + + + + + +void cBlockArea::SetRelBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockMeta) +{ + SetRelNibble(a_RelX, a_RelY, a_RelZ, a_BlockMeta, m_BlockMetas); +} + + + + + +void cBlockArea::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockMeta) +{ + SetNibble(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta, m_BlockMetas); +} + + + + + +void cBlockArea::SetRelBlockLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockLight) +{ + SetRelNibble(a_RelX, a_RelY, a_RelZ, a_BlockLight, m_BlockLight); +} + + + + + +void cBlockArea::SetBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockLight) +{ + SetNibble(a_BlockX, a_BlockY, a_BlockZ, a_BlockLight, m_BlockLight); +} + + + + + +void cBlockArea::SetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockSkyLight) +{ + SetRelNibble(a_RelX, a_RelY, a_RelZ, a_BlockSkyLight, m_BlockSkyLight); +} + + + + + +void cBlockArea::SetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockSkyLight) +{ + SetNibble(a_BlockX, a_BlockY, a_BlockZ, a_BlockSkyLight, m_BlockSkyLight); +} + + + + + +BLOCKTYPE cBlockArea::GetRelBlockType(int a_RelX, int a_RelY, int a_RelZ) const +{ + if (m_BlockTypes == NULL) + { + LOGWARNING("cBlockArea: BlockTypes have not been read!"); + return E_BLOCK_AIR; + } + return m_BlockTypes[MakeIndex(a_RelX, a_RelY, a_RelZ)]; +} + + + + + +BLOCKTYPE cBlockArea::GetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ) const +{ + return GetRelBlockType(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ); +} + + + + + +NIBBLETYPE cBlockArea::GetRelBlockMeta(int a_RelX, int a_RelY, int a_RelZ) const +{ + return GetRelNibble(a_RelX, a_RelY, a_RelZ, m_BlockMetas); +} + + + + + +NIBBLETYPE cBlockArea::GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ) const +{ + return GetNibble(a_BlockX, a_BlockY, a_BlockZ, m_BlockMetas); +} + + + + + +NIBBLETYPE cBlockArea::GetRelBlockLight(int a_RelX, int a_RelY, int a_RelZ) const +{ + return GetRelNibble(a_RelX, a_RelY, a_RelZ, m_BlockLight); +} + + + + + +NIBBLETYPE cBlockArea::GetBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ) const +{ + return GetNibble(a_BlockX, a_BlockY, a_BlockZ, m_BlockLight); +} + + + + + +NIBBLETYPE cBlockArea::GetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ) const +{ + return GetRelNibble(a_RelX, a_RelY, a_RelZ, m_BlockSkyLight); +} + + + + + +NIBBLETYPE cBlockArea::GetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ) const +{ + return GetNibble(a_BlockX, a_BlockY, a_BlockZ, m_BlockSkyLight); +} + + + + + +void cBlockArea::SetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +{ + SetRelBlockTypeMeta(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType, a_BlockMeta); +} + + + + + +void cBlockArea::SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) +{ + int idx = MakeIndex(a_RelX, a_RelY, a_RelZ); + if (m_BlockTypes == NULL) + { + LOGWARNING("%s: BlockTypes not available but requested to be written to.", __FUNCTION__); + } + else + { + m_BlockTypes[idx] = a_BlockType; + } + if (m_BlockMetas == NULL) + { + LOGWARNING("%s: BlockMetas not available but requested to be written to.", __FUNCTION__); + } + else + { + m_BlockMetas[idx] = a_BlockMeta; + } +} + + + + + +void cBlockArea::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const +{ + return GetRelBlockTypeMeta(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType, a_BlockMeta); +} + + + + + +void cBlockArea::GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const +{ + int idx = MakeIndex(a_RelX, a_RelY, a_RelZ); + if (m_BlockTypes == NULL) + { + LOGWARNING("cBlockArea: BlockTypes have not been read!"); + a_BlockType = E_BLOCK_AIR; + } + else + { + a_BlockType = m_BlockTypes[idx]; + } + + if (m_BlockMetas == NULL) + { + LOGWARNING("cBlockArea: BlockMetas have not been read!"); + a_BlockMeta = 0; + } + else + { + a_BlockMeta = m_BlockMetas[idx]; + } +} + + + + + +int cBlockArea::GetDataTypes(void) const +{ + int res = 0; + if (m_BlockTypes != NULL) + { + res |= baTypes; + } + if (m_BlockMetas != NULL) + { + res |= baMetas; + } + if (m_BlockLight != NULL) + { + res |= baLight; + } + if (m_BlockSkyLight != NULL) + { + res |= baSkyLight; + } + return res; +} + + + + + +bool cBlockArea::SetSize(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes) +{ + ASSERT(m_BlockTypes == NULL); // Has been cleared + + if (a_DataTypes & baTypes) + { + m_BlockTypes = new BLOCKTYPE[a_SizeX * a_SizeY * a_SizeZ]; + if (m_BlockTypes == NULL) + { + return false; + } + } + if (a_DataTypes & baMetas) + { + m_BlockMetas = new NIBBLETYPE[a_SizeX * a_SizeY * a_SizeZ]; + if (m_BlockMetas == NULL) + { + delete[] m_BlockTypes; + return false; + } + } + if (a_DataTypes & baLight) + { + m_BlockLight = new NIBBLETYPE[a_SizeX * a_SizeY * a_SizeZ]; + if (m_BlockLight == NULL) + { + delete[] m_BlockMetas; + delete[] m_BlockTypes; + return false; + } + } + if (a_DataTypes & baSkyLight) + { + m_BlockSkyLight = new NIBBLETYPE[a_SizeX * a_SizeY * a_SizeZ]; + if (m_BlockSkyLight == NULL) + { + delete[] m_BlockLight; + delete[] m_BlockMetas; + delete[] m_BlockTypes; + return false; + } + } + m_SizeX = a_SizeX; + m_SizeY = a_SizeY; + m_SizeZ = a_SizeZ; + return true; +} + + + + + +int cBlockArea::MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const +{ + ASSERT(a_RelX >= 0); + ASSERT(a_RelX < m_SizeX); + ASSERT(a_RelY >= 0); + ASSERT(a_RelY < m_SizeY); + ASSERT(a_RelZ >= 0); + ASSERT(a_RelZ < m_SizeZ); + + return a_RelX + a_RelZ * m_SizeX + a_RelY * m_SizeX * m_SizeZ; +} + + + + + +void cBlockArea::SetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Value, NIBBLETYPE * a_Array) +{ + if (a_Array == NULL) + { + LOGWARNING("cBlockArea: datatype has not been read!"); + return; + } + a_Array[MakeIndex(a_RelX, a_RelY, a_RelZ)] = a_Value; +} + + + + + +void cBlockArea::SetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Value, NIBBLETYPE * a_Array) +{ + SetRelNibble(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_Value, a_Array); +} + + + + + +NIBBLETYPE cBlockArea::GetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE * a_Array) const +{ + if (a_Array == NULL) + { + LOGWARNING("cBlockArea: datatype has not been read!"); + return 16; + } + return a_Array[MakeIndex(a_RelX, a_RelY, a_RelZ)]; +} + + + + + +NIBBLETYPE cBlockArea::GetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE * a_Array) const +{ + return GetRelNibble(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_Array); +} + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cBlockArea::cChunkReader: + +cBlockArea::cChunkReader::cChunkReader(cBlockArea & a_Area) : + m_Area(a_Area), + m_OriginX(a_Area.m_OriginX), + m_OriginY(a_Area.m_OriginY), + m_OriginZ(a_Area.m_OriginZ) +{ +} + + + + + +void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLETYPE * a_ChunkSrc) +{ + int SizeY = m_Area.m_SizeY; + int MinY = m_OriginY; + + // SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union) + // OffX, OffZ are the offsets of the current chunk data from the area origin + // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders + int SizeX = cChunkDef::Width; + int SizeZ = cChunkDef::Width; + int OffX, OffZ; + int BaseX, BaseZ; + OffX = m_CurrentChunkX * cChunkDef::Width - m_OriginX; + if (OffX < 0) + { + BaseX = -OffX; + SizeX += OffX; // SizeX is decreased, OffX is negative + OffX = 0; + } + else + { + BaseX = 0; + } + OffZ = m_CurrentChunkZ * cChunkDef::Width - m_OriginZ; + if (OffZ < 0) + { + BaseZ = -OffZ; + SizeZ += OffZ; // SizeZ is decreased, OffZ is negative + OffZ = 0; + } + else + { + BaseZ = 0; + } + // If the chunk extends beyond the area in the X or Z axis, cut off the Size: + if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_OriginX + m_Area.m_SizeX) + { + SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_OriginX + m_Area.m_SizeX); + } + if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_OriginZ + m_Area.m_SizeZ) + { + SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_OriginZ + m_Area.m_SizeZ); + } + + for (int y = 0; y < SizeY; y++) + { + int ChunkY = MinY + y; + int AreaY = y; + for (int z = 0; z < SizeZ; z++) + { + int ChunkZ = BaseZ + z; + int AreaZ = OffZ + z; + for (int x = 0; x < SizeX; x++) + { + int ChunkX = BaseX + x; + int AreaX = OffX + x; + a_AreaDst[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = cChunkDef::GetNibble(a_ChunkSrc, ChunkX, ChunkY, ChunkZ); + } // for x + } // for z + } // for y +} + + + + + +bool cBlockArea::cChunkReader::Coords(int a_ChunkX, int a_ChunkZ) +{ + m_CurrentChunkX = a_ChunkX; + m_CurrentChunkZ = a_ChunkZ; + return true; +} + + + + + +void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes) +{ + if (m_Area.m_BlockTypes == NULL) + { + // Don't want BlockTypes + return; + } + + int SizeY = m_Area.m_SizeY; + int MinY = m_OriginY; + + // SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union) + // OffX, OffZ are the offsets of the current chunk data from the area origin + // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders + int SizeX = cChunkDef::Width; + int SizeZ = cChunkDef::Width; + int OffX, OffZ; + int BaseX, BaseZ; + OffX = m_CurrentChunkX * cChunkDef::Width - m_OriginX; + if (OffX < 0) + { + BaseX = -OffX; + SizeX += OffX; // SizeX is decreased, OffX is negative + OffX = 0; + } + else + { + BaseX = 0; + } + OffZ = m_CurrentChunkZ * cChunkDef::Width - m_OriginZ; + if (OffZ < 0) + { + BaseZ = -OffZ; + SizeZ += OffZ; // SizeZ is decreased, OffZ is negative + OffZ = 0; + } + else + { + BaseZ = 0; + } + // If the chunk extends beyond the area in the X or Z axis, cut off the Size: + if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_OriginX + m_Area.m_SizeX) + { + SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_OriginX + m_Area.m_SizeX); + } + if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_OriginZ + m_Area.m_SizeZ) + { + SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_OriginZ + m_Area.m_SizeZ); + } + + for (int y = 0; y < SizeY; y++) + { + int ChunkY = MinY + y; + int AreaY = y; + for (int z = 0; z < SizeZ; z++) + { + int ChunkZ = BaseZ + z; + int AreaZ = OffZ + z; + for (int x = 0; x < SizeX; x++) + { + int ChunkX = BaseX + x; + int AreaX = OffX + x; + m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = cChunkDef::GetBlock(a_BlockTypes, ChunkX, ChunkY, ChunkZ); + } // for x + } // for z + } // for y +} + + + + + +void cBlockArea::cChunkReader::BlockMeta(const NIBBLETYPE * a_BlockMetas) +{ + if (m_Area.m_BlockMetas == NULL) + { + // Don't want metas + return; + } + CopyNibbles(m_Area.m_BlockMetas, a_BlockMetas); +} + + + + + +void cBlockArea::cChunkReader::BlockLight(const NIBBLETYPE * a_BlockLight) +{ + if (m_Area.m_BlockLight == NULL) + { + // Don't want light + return; + } + CopyNibbles(m_Area.m_BlockLight, a_BlockLight); +} + + + + + +void cBlockArea::cChunkReader::BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) +{ + if (m_Area.m_BlockSkyLight == NULL) + { + // Don't want skylight + return; + } + CopyNibbles(m_Area.m_BlockSkyLight, a_BlockSkyLight); +} + + + + + +void cBlockArea::CropBlockTypes(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ) +{ + int NewSizeX = GetSizeX() - a_AddMinX - a_SubMaxX; + int NewSizeY = GetSizeY() - a_AddMinY - a_SubMaxY; + int NewSizeZ = GetSizeZ() - a_AddMinZ - a_SubMaxZ; + BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[NewSizeX * NewSizeY * NewSizeZ]; + int idx = 0; + for (int y = 0; y < NewSizeY; y++) + { + for (int z = 0; z < NewSizeZ; z++) + { + for (int x = 0; x < NewSizeX; x++) + { + int OldIndex = MakeIndex(x + a_AddMinX, y + a_AddMinY, z + a_AddMinZ); + NewBlockTypes[idx++] = m_BlockTypes[OldIndex]; + } // for x + } // for z + } // for y + delete m_BlockTypes; + m_BlockTypes = NewBlockTypes; +} + + + + + +void cBlockArea::CropNibbles(NIBBLEARRAY & a_Array, int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ) +{ + int NewSizeX = GetSizeX() - a_AddMinX - a_SubMaxX; + int NewSizeY = GetSizeY() - a_AddMinY - a_SubMaxY; + int NewSizeZ = GetSizeZ() - a_AddMinZ - a_SubMaxZ; + NIBBLETYPE * NewNibbles = new NIBBLETYPE[NewSizeX * NewSizeY * NewSizeZ]; + int idx = 0; + for (int y = 0; y < NewSizeY; y++) + { + for (int z = 0; z < NewSizeZ; z++) + { + for (int x = 0; x < NewSizeX; x++) + { + NewNibbles[idx++] = a_Array[MakeIndex(x + a_AddMinX, y + a_AddMinY, z + a_AddMinZ)]; + } // for x + } // for z + } // for y + delete a_Array; + a_Array = NewNibbles; +} + + + + + +void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ) +{ + int NewSizeX = m_SizeX + a_SubMinX + a_AddMaxX; + int NewSizeY = m_SizeY + a_SubMinY + a_AddMaxY; + int NewSizeZ = m_SizeZ + a_SubMinZ + a_AddMaxZ; + int BlockCount = NewSizeX * NewSizeY * NewSizeZ; + BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[BlockCount]; + memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE)); + int OldIndex = 0; + for (int y = 0; y < m_SizeY; y++) + { + int IndexBaseY = (y + a_SubMinY) * m_SizeX * m_SizeZ; + for (int z = 0; z < m_SizeZ; z++) + { + int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_SizeX; + int idx = IndexBaseZ + a_SubMinX; + for (int x = 0; x < m_SizeX; x++) + { + NewBlockTypes[idx++] = m_BlockTypes[OldIndex++]; + } // for x + } // for z + } // for y + delete m_BlockTypes; + m_BlockTypes = NewBlockTypes; +} + + + + + +void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ) +{ + int NewSizeX = m_SizeX + a_SubMinX + a_AddMaxX; + int NewSizeY = m_SizeY + a_SubMinY + a_AddMaxY; + int NewSizeZ = m_SizeZ + a_SubMinZ + a_AddMaxZ; + int BlockCount = NewSizeX * NewSizeY * NewSizeZ; + NIBBLETYPE * NewNibbles = new NIBBLETYPE[BlockCount]; + memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE)); + int OldIndex = 0; + for (int y = 0; y < m_SizeY; y++) + { + int IndexBaseY = (y + a_SubMinY) * m_SizeX * m_SizeZ; + for (int z = 0; z < m_SizeZ; z++) + { + int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_SizeX; + int idx = IndexBaseZ + a_SubMinX; + for (int x = 0; x < m_SizeX; x++) + { + NewNibbles[idx++] = a_Array[OldIndex++]; + } // for x + } // for z + } // for y + delete a_Array; + a_Array = NewNibbles; +} + + + + + +bool cBlockArea::LoadFromSchematicNBT(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, + a_NBT.GetType(TSizeX), a_NBT.GetType(TSizeY), a_NBT.GetType(TSizeZ) + ); + return false; + } + + int SizeX = a_NBT.GetShort(TSizeX); + int SizeY = a_NBT.GetShort(TSizeY); + int SizeZ = a_NBT.GetShort(TSizeZ); + if ((SizeX < 1) || (SizeY < 1) || (SizeZ < 1)) + { + 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); + + Clear(); + SetSize(SizeX, SizeY, SizeZ, AreMetasPresent ? (baTypes | baMetas) : baTypes); + + // Copy the block types and metas: + int NumBytes = m_SizeX * m_SizeY * m_SizeZ; + if (a_NBT.GetDataLength(TBlockTypes) < NumBytes) + { + LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.", + NumBytes, a_NBT.GetDataLength(TBlockTypes) + ); + NumBytes = a_NBT.GetDataLength(TBlockTypes); + } + memcpy(m_BlockTypes, a_NBT.GetData(TBlockTypes), NumBytes); + + if (AreMetasPresent) + { + int NumBytes = m_SizeX * m_SizeY * m_SizeZ; + if (a_NBT.GetDataLength(TBlockMetas) < NumBytes) + { + LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.", + NumBytes, a_NBT.GetDataLength(TBlockMetas) + ); + NumBytes = a_NBT.GetDataLength(TBlockMetas); + } + memcpy(m_BlockMetas, a_NBT.GetData(TBlockMetas), NumBytes); + } + + return true; +} + + + + +void cBlockArea::RelSetData( + int a_RelX, int a_RelY, int a_RelZ, + int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, + NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight +) +{ + int Index = MakeIndex(a_RelX, a_RelY, a_RelZ); + if ((a_DataTypes & baTypes) != 0) + { + m_BlockTypes[Index] = a_BlockType; + } + if ((a_DataTypes & baMetas) != 0) + { + m_BlockMetas[Index] = a_BlockMeta; + } + if ((a_DataTypes & baLight) != 0) + { + m_BlockLight[Index] = a_BlockLight; + } + if ((a_DataTypes & baSkyLight) != 0) + { + m_BlockSkyLight[Index] = a_BlockSkyLight; + } +} + + + + -- cgit v1.2.3