summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/BlockTypePalette.cpp80
-rw-r--r--src/BlockTypePalette.h44
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/Cuboid.h22
-rw-r--r--src/PalettedBlockArea.cpp261
-rw-r--r--src/PalettedBlockArea.h114
6 files changed, 525 insertions, 0 deletions
diff --git a/src/BlockTypePalette.cpp b/src/BlockTypePalette.cpp
new file mode 100644
index 000000000..fabf5698e
--- /dev/null
+++ b/src/BlockTypePalette.cpp
@@ -0,0 +1,80 @@
+#include "Globals.h"
+#include "BlockTypePalette.h"
+
+
+
+
+BlockTypePalette::BlockTypePalette()
+{
+ // Nothing needed yet
+}
+
+
+
+
+
+UInt32 BlockTypePalette::index(const AString & aBlockTypeName, const BlockState & aBlockState)
+{
+ auto idx = maybeIndex(aBlockTypeName, aBlockState);
+ if (idx.second)
+ {
+ return idx.first;
+ }
+
+ // Not found, append:
+ mPalette.push_back(std::make_pair(aBlockTypeName, aBlockState));
+ return static_cast<UInt32>(mPalette.size() - 1);
+}
+
+
+
+
+
+std::pair<UInt32, bool> BlockTypePalette::maybeIndex(const AString & aBlockTypeName, const BlockState & aBlockState) const
+{
+ auto count = mPalette.size();
+ for (size_t idx = 0; idx < count; ++idx)
+ {
+ const auto & entry = mPalette[idx];
+ if ((entry.first == aBlockTypeName) && (entry.second == aBlockState))
+ {
+ return std::make_pair(static_cast<UInt32>(idx), true);
+ }
+ }
+ return std::make_pair(0, false);
+}
+
+
+
+
+
+UInt32 BlockTypePalette::count() const
+{
+ return static_cast<UInt32>(mPalette.size());
+}
+
+
+
+
+
+const std::pair<AString, BlockState> & BlockTypePalette::entry(UInt32 aIndex) const
+{
+ ASSERT(aIndex < mPalette.size());
+ return mPalette[aIndex];
+}
+
+
+
+
+
+std::map<UInt32, UInt32> BlockTypePalette::createTransformMap(const BlockTypePalette & aOther)
+{
+ std::map<UInt32, UInt32> res;
+ auto numIndices = aOther.count();
+ for (UInt32 idx = 0; idx < numIndices; ++idx)
+ {
+ const auto & e = aOther.mPalette[idx];
+ res[idx] = index(e.first, e.second);
+ }
+ return res;
+}
diff --git a/src/BlockTypePalette.h b/src/BlockTypePalette.h
new file mode 100644
index 000000000..47318f171
--- /dev/null
+++ b/src/BlockTypePalette.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <utility>
+#include "BlockState.h"
+
+
+
+
+
+/** Holds a palette that maps block type + state into numbers.
+Used primarily by PalettedBlockArea to translate between numeric and stringular block representation.
+The object itself provides no thread safety, users of this class need to handle locking, if required. */
+class BlockTypePalette
+{
+public:
+
+ /** Create a new empty instance. */
+ BlockTypePalette();
+
+ /** Returns the index of the specified block type name and state.
+ If the combination is not found, it is added to the palette and the new index is returned. */
+ UInt32 index(const AString & aBlockTypeName, const BlockState & aBlockState);
+
+ /** Returns the <index, true> of the specified block type name and state, if it exists.
+ If the combination is not found, returns <undefined, false>. */
+ std::pair<UInt32, bool> maybeIndex(const AString & aBlockTypeName, const BlockState & aBlockState) const;
+
+ /** Returns the total number of entries in the palette. */
+ UInt32 count() const;
+
+ /** Returns the blockspec represented by the specified palette index.
+ The index must be valid (ASSERTed). */
+ const std::pair<AString, BlockState> & entry(UInt32 aIndex) const;
+
+ /** Adds missing entries from aOther to this, and returns an index-transform map from aOther to this.
+ Used when pasting two areas, to transform the src palette to dst palette. */
+ std::map<UInt32, UInt32> createTransformMap(const BlockTypePalette & aOther);
+
+
+protected:
+
+ /** The palette. Each item in the vector represents a single entry in the palette, the vector index is the palette index. */
+ std::vector<std::pair<AString, BlockState>> mPalette;
+};
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index dd92a969c..072eb6c97 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -18,6 +18,7 @@ SET (SRCS
BlockID.cpp
BlockInfo.cpp
BlockState.cpp
+ BlockTypePalette.cpp
BlockTypeRegistry.cpp
BrewingRecipes.cpp
Broadcaster.cpp
@@ -59,6 +60,7 @@ SET (SRCS
MonsterConfig.cpp
NetherPortalScanner.cpp
OverridesSettingsRepository.cpp
+ PalettedBlockArea.cpp
ProbabDistrib.cpp
RankManager.cpp
RCONServer.cpp
@@ -87,6 +89,7 @@ SET (HDRS
BlockInfo.h
BlockState.h
BlockTracer.h
+ BlockTypePalette.h
BlockTypeRegistry.h
BrewingRecipes.h
BoundingBox.h
@@ -140,6 +143,7 @@ SET (HDRS
NetherPortalScanner.h
OpaqueWorld.h
OverridesSettingsRepository.h
+ PalettedBlockArea.h
ProbabDistrib.h
RankManager.h
RCONServer.h
diff --git a/src/Cuboid.h b/src/Cuboid.h
index ed36a2298..4fefb8f57 100644
--- a/src/Cuboid.h
+++ b/src/Cuboid.h
@@ -117,6 +117,28 @@ public:
/** If needed, expands the cuboid so that it contains the specified point. Assumes sorted. Doesn't contract. */
void Engulf(Vector3i a_Point);
+ // tolua_end
+
+ /** Checks the two cuboids for equality. */
+ bool operator == (const cCuboid & aOther) const
+ {
+ return (
+ (p1.x == aOther.p1.x) &&
+ (p1.y == aOther.p1.y) &&
+ (p1.z == aOther.p1.z) &&
+ (p2.x == aOther.p2.x) &&
+ (p2.y == aOther.p2.y) &&
+ (p2.z == aOther.p2.z)
+ );
+ }
+
+ bool operator != (const cCuboid & aOther) const
+ {
+ return !operator ==(aOther);
+ }
+
+
+ // tolua_begin
private:
diff --git a/src/PalettedBlockArea.cpp b/src/PalettedBlockArea.cpp
new file mode 100644
index 000000000..e703adec0
--- /dev/null
+++ b/src/PalettedBlockArea.cpp
@@ -0,0 +1,261 @@
+#include "Globals.h"
+#include "PalettedBlockArea.h"
+
+
+
+
+
+PalettedBlockArea::PalettedBlockArea()
+{
+ // Nothing needed yet
+}
+
+
+
+
+
+PalettedBlockArea PalettedBlockArea::createFilled(Vector3i aSize, const AString & aBlockTypeName, const BlockState & aBlockState)
+{
+ ASSERT(aSize.x > 0);
+ ASSERT(aSize.y > 0);
+ ASSERT(aSize.z > 0);
+
+ PalettedBlockArea res;
+ auto numBlocks = static_cast<UInt64>(aSize.x) * static_cast<UInt64>(aSize.y) * static_cast<UInt64>(aSize.z);
+ if (numBlocks >= std::numeric_limits<UInt32>::max())
+ {
+ // We use 32-bit indices in some functions (for ARM speed), so we need the entire area to fit into UInt32
+ throw std::runtime_error("Size is too large");
+ }
+ res.mSize = aSize;
+ res.mBlocks.resize(static_cast<size_t>(numBlocks));
+ res.fill(aBlockTypeName, aBlockState);
+ return res;
+}
+
+
+
+
+
+cCuboid PalettedBlockArea::whole() const
+{
+ return cCuboid(Vector3i(), mSize);
+}
+
+
+
+
+
+void PalettedBlockArea::setBlock(Vector3i aPos, const AString & aBlockTypeName, const BlockState & aBlockState)
+{
+ setBlock(aPos, paletteIndex(aBlockTypeName, aBlockState));
+}
+
+
+
+
+
+void PalettedBlockArea::setBlock(Vector3i aPos, UInt32 aPaletteIndex)
+{
+ ASSERT(isPositionValid(aPos));
+ ASSERT(aPaletteIndex < mPalette.count());
+
+ auto idx = positionToIndex(aPos);
+ mBlocks[idx] = aPaletteIndex;
+}
+
+
+
+
+
+UInt32 PalettedBlockArea::paletteIndex(const AString & aBlockTypeName, const BlockState & aBlockState)
+{
+ return mPalette.index(aBlockTypeName, aBlockState);
+}
+
+
+
+
+
+std::pair<UInt32, bool> PalettedBlockArea::maybePaletteIndex(const AString & aBlockTypeName, const BlockState & aBlockState) const
+{
+ return mPalette.maybeIndex(aBlockTypeName, aBlockState);
+}
+
+
+
+
+
+UInt32 PalettedBlockArea::blockPaletteIndex(Vector3i aPos) const
+{
+ auto idx = positionToIndex(aPos);
+ return mBlocks[idx];
+}
+
+
+
+
+
+const std::pair<AString, BlockState> & PalettedBlockArea::block(Vector3i aPos) const
+{
+ return paletteEntry(blockPaletteIndex(aPos));
+}
+
+
+
+
+
+const std::pair<AString, BlockState> & PalettedBlockArea::paletteEntry(UInt32 aPaletteIndex) const
+{
+ return mPalette.entry(aPaletteIndex);
+}
+
+
+
+
+
+bool PalettedBlockArea::isPositionValid(Vector3i aPos) const
+{
+ return (
+ (aPos.x >= 0) && (aPos.y >= 0) && (aPos.z >= 0) && // Non-negative coords
+ (aPos.x < mSize.x) && (aPos.y < mSize.y) && (aPos.z < mSize.z) // Fit into size
+ );
+}
+
+
+
+
+
+void PalettedBlockArea::fill(const AString & aBlockTypeName, const BlockState & aBlockState)
+{
+ BlockTypePalette btp;
+ auto idx = btp.index(aBlockTypeName, aBlockState);
+ std::swap(mPalette, btp);
+ std::fill(mBlocks.begin(), mBlocks.end(), idx);
+}
+
+
+
+
+
+void PalettedBlockArea::paste(const PalettedBlockArea & aSrc, const cCuboid & aSrcCuboid, Vector3i aDstOrigin)
+{
+ // Clamp the src cuboid, first by src itself, then by this PBA's coord range:
+ cCuboid srcCuboid(aSrcCuboid);
+ srcCuboid.Sort();
+ srcCuboid.Clamp(aSrc.whole());
+ Vector3i maxSize = mSize - aDstOrigin;
+ srcCuboid.ClampSize(maxSize);
+ Vector3i dstOrigin(aDstOrigin);
+
+ // If any aDstOrigin coord is lower than 0, adjust the coord and src cuboid size:
+ if (dstOrigin.x < 0)
+ {
+ srcCuboid.p1.x -= dstOrigin.x;
+ if (srcCuboid.p1.x >= srcCuboid.p2.x)
+ {
+ return;
+ }
+ dstOrigin.x = 0;
+ }
+ if (dstOrigin.y < 0)
+ {
+ srcCuboid.p1.y -= dstOrigin.y;
+ if (srcCuboid.p1.y >= srcCuboid.p2.y)
+ {
+ return;
+ }
+ dstOrigin.y = 0;
+ }
+ if (dstOrigin.z < 0)
+ {
+ srcCuboid.p1.z -= dstOrigin.z;
+ if (srcCuboid.p1.z >= srcCuboid.p2.z)
+ {
+ return;
+ }
+ dstOrigin.z = 0;
+ }
+
+ // Create a transform map from aSrc's palette to our palette:
+ auto paletteTransform = mPalette.createTransformMap(aSrc.mPalette);
+
+ // Copy the data:
+ UInt32 srcStrideY = static_cast<UInt32>(aSrc.size().x * aSrc.size().z);
+ UInt32 srcStrideZ = static_cast<UInt32>(aSrc.size().x);
+ UInt32 dstStrideY = static_cast<UInt32>(mSize.x * mSize.z);
+ UInt32 dstStrideZ = static_cast<UInt32>(mSize.x);
+ UInt32 minX = static_cast<UInt32>(srcCuboid.p1.x);
+ UInt32 maxX = static_cast<UInt32>(srcCuboid.p2.x);
+ UInt32 minY = static_cast<UInt32>(srcCuboid.p1.y);
+ UInt32 maxY = static_cast<UInt32>(srcCuboid.p2.y);
+ UInt32 minZ = static_cast<UInt32>(srcCuboid.p1.z);
+ UInt32 maxZ = static_cast<UInt32>(srcCuboid.p2.z);
+ UInt32 dstX = static_cast<UInt32>(dstOrigin.x);
+ UInt32 dstY = static_cast<UInt32>(dstOrigin.y);
+ UInt32 dstZ = static_cast<UInt32>(dstOrigin.z);
+ for (UInt32 y = minY; y < maxY; ++y)
+ {
+ UInt32 srcOfsY = y * srcStrideY;
+ UInt32 dstOfsY = (y - minY + dstY) * dstStrideY;
+ for (UInt32 z = minZ; z < maxZ; ++z)
+ {
+ UInt32 srcOfs = srcOfsY + z * srcStrideZ + minX;
+ UInt32 dstOfs = dstOfsY + (z - minZ + dstZ) * dstStrideZ + dstX;
+ for (UInt32 x = minX; x < maxX; ++x)
+ {
+ mBlocks[dstOfs] = paletteTransform[aSrc.mBlocks[srcOfs]];
+ srcOfs += 1;
+ dstOfs += 1;
+ }
+ }
+ }
+}
+
+
+
+
+
+void PalettedBlockArea::crop(const cCuboid & aArea)
+{
+ cCuboid area(aArea);
+ area.Clamp(whole());
+
+ // Copy the data:
+ UInt32 srcStrideY = static_cast<UInt32>(size().x * size().z);
+ UInt32 srcStrideZ = static_cast<UInt32>(size().x);
+ UInt32 dstStrideY = static_cast<UInt32>(area.DifX() * area.DifZ());
+ UInt32 dstStrideZ = static_cast<UInt32>(area.DifZ());
+ UInt32 minX = static_cast<UInt32>(area.p1.x);
+ UInt32 maxX = static_cast<UInt32>(area.p2.x);
+ UInt32 minY = static_cast<UInt32>(area.p1.y);
+ UInt32 maxY = static_cast<UInt32>(area.p2.y);
+ UInt32 minZ = static_cast<UInt32>(area.p1.z);
+ UInt32 maxZ = static_cast<UInt32>(area.p2.z);
+ for (UInt32 y = minY; y < maxY; ++y)
+ {
+ UInt32 srcOfsY = (y - minY) * srcStrideY;
+ UInt32 dstOfsY = y * dstStrideY;
+ for (UInt32 z = minZ; z < maxZ; ++z)
+ {
+ UInt32 srcOfs = srcOfsY + (z - minZ) * srcStrideZ + minX;
+ UInt32 dstOfs = dstOfsY + z * dstStrideZ;
+ for (UInt32 x = minX; x < maxX; ++x)
+ {
+ mBlocks[dstOfs] = mBlocks[srcOfs];
+ srcOfs += 1;
+ dstOfs += 1;
+ }
+ }
+ }
+}
+
+
+
+
+
+UInt32 PalettedBlockArea::positionToIndex(Vector3i aPos) const
+{
+ ASSERT(isPositionValid(aPos));
+ return static_cast<UInt32>(aPos.x + aPos.z * mSize.x + aPos.y * mSize.x * mSize.z);
+}
diff --git a/src/PalettedBlockArea.h b/src/PalettedBlockArea.h
new file mode 100644
index 000000000..3866d405b
--- /dev/null
+++ b/src/PalettedBlockArea.h
@@ -0,0 +1,114 @@
+#pragma once
+
+
+
+
+
+#include <utility>
+
+#include "BlockTypePalette.h"
+#include "Cuboid.h"
+
+
+
+
+
+/** Represents an area of blocks that are represented using a palette.
+The object itself provides no thread safety, users of this class need to handle locking, if required.
+The PalettedBlockArea always contains Blocks and their associated BlockEntities, it may optionally contain Entities.
+There's no way to instantiate this class directly, you need to use either createFilled(), or read from cWorld. */
+class PalettedBlockArea
+{
+public:
+
+ /** Creates a new PBA of the specified size filled with the specified block.
+ Throws if there is an error (memory allocation etc.) */
+ static PalettedBlockArea createFilled(Vector3i aSize, const AString & aBlockTypeName, const BlockState & aBlockState);
+
+ /** Returns the actual size of the area in all 3 axes. */
+ const Vector3i & size() const { return mSize; }
+
+ /** Returns a cCuboid that encompasses the entire PBA.
+ Technically, {0, 0, 0} to mSize. */
+ cCuboid whole() const;
+
+ /** Sets a single block using its full blockspec.
+ The position must be valid (ASSERTed).
+ If the block is not already in palette, it is added. */
+ void setBlock(Vector3i aPos, const AString & aBlockTypeName, const BlockState & aBlockState);
+
+ /** Sets a single block using an index to the palette (retrieved earlier by paletteIndex()).
+ The position must be valid (ASSERTed).
+ The palette index must be valid (ASSERTed). */
+ void setBlock(Vector3i aPos, UInt32 aPaletteIndex);
+
+ /** Returns the index into the palette that is used by the specified full blockspec.
+ Adds the blockspec to palette if not already there. */
+ UInt32 paletteIndex(const AString & aBlockTypeName, const BlockState & aBlockState);
+
+ /** Returns the <index, true> into the palette that is used by the specified full blockspec.
+ Returns <undefined, false> if blockspec not in palette. */
+ std::pair<UInt32, bool> maybePaletteIndex(const AString & aBlockTypeName, const BlockState & aBlockState) const;
+
+ /** Returns the index into the palette for the block at the specified pos.
+ The position must be valid (ASSERTed). */
+ UInt32 blockPaletteIndex(Vector3i aPos) const;
+
+ /** Returns the full blockspec of the block at the specified position.
+ The position must be valid (ASSERTed). */
+ const std::pair<AString, BlockState> & block(Vector3i aPos) const;
+
+ /** Returns the blockspec represented by the specified palette index.
+ The index must be valid (ASSERTed). */
+ const std::pair<AString, BlockState> & paletteEntry(UInt32 aPaletteIndex) const;
+
+ /** Returns true if the specified position is within the size bounds of the area. */
+ bool isPositionValid(Vector3i aPos) const;
+
+ /** Fills the entire PBA with a single block of the specified type.
+ The palette is reset to one containing only the single block. */
+ void fill(const AString & aBlockTypeName, const BlockState & aBlockState);
+
+ /** Pastes (copies verbatim) a cCuboid out of the src PBA into this PBA.
+ aSrcCuboid is the coord range in aSrc that will be copied (min-coord is inclusive, max-coord is exclusive).
+ aDstOrigin is the coord relative to this PBA where the lowest coords of the copied area will be put.
+ aDstOrigin can be outside of this PBA's coord range (only part of the src is copied).
+ Automatically crops aSrcCuboid so that the copied part is entirely inside this PBA's coord range. */
+ void paste(const PalettedBlockArea & aSrc, const cCuboid & aSrcCuboid, Vector3i aDstOrigin = Vector3i());
+
+ /** Pastes (copies verbatim) the entire src PBA into this PBA.
+ aDstOrigin is the coord relative to this PBA where the lowest coords of the copied area will be put.
+ aDstOrigin can be outside of this PBA's coord range (only part of the src is copied).
+ Gracefully handles situations where the copied src PBA goes outside of this PBA's coord range. */
+ inline void paste(const PalettedBlockArea & aSrc, Vector3i aDstOrigin = Vector3i())
+ {
+ paste(aSrc, aSrc.whole(), aDstOrigin);
+ }
+
+ /** Crops this PBA by the specified coords.
+ aArea is first cropped to the size of this PBA (so it's only possible to shrink a PBA, not enlarge). */
+ void crop(const cCuboid & aArea);
+
+ /** Returns the (reqd-only) palette used internally by this object. */
+ const BlockTypePalette & palette() { return mPalette; }
+
+
+protected:
+
+ /** The palette used in the area. */
+ BlockTypePalette mPalette;
+
+ /** The blocks contained in the area, stored as indices into mPalette. */
+ std::vector<UInt32> mBlocks;
+
+ /** The size (dimensions) of the area. */
+ Vector3i mSize;
+
+
+ /** Creates a new uninitialized instance (all sizes zero). */
+ PalettedBlockArea();
+
+ /** Converts the position to index in mBlocks.
+ This may be removed later on when optimizing the RAM usage of this class by compressing low-palette-count PBAs. */
+ UInt32 positionToIndex(Vector3i aPos) const;
+};