summaryrefslogtreecommitdiffstats
path: root/src/Generating
diff options
context:
space:
mode:
Diffstat (limited to 'src/Generating')
-rw-r--r--src/Generating/ChunkDesc.cpp6
-rw-r--r--src/Generating/Prefab.cpp312
-rw-r--r--src/Generating/Prefab.h105
3 files changed, 420 insertions, 3 deletions
diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp
index 308fbe423..7711723fc 100644
--- a/src/Generating/ChunkDesc.cpp
+++ b/src/Generating/ChunkDesc.cpp
@@ -343,9 +343,9 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
int SizeY = a_MaxRelY - a_MinRelY;
int SizeZ = a_MaxRelZ - a_MinRelZ;
a_Dest.Clear();
- a_Dest.m_OriginX = m_ChunkX * cChunkDef::Width + a_MinRelX;
- a_Dest.m_OriginY = a_MinRelY;
- a_Dest.m_OriginZ = m_ChunkZ * cChunkDef::Width + a_MinRelZ;
+ a_Dest.m_Origin.x = m_ChunkX * cChunkDef::Width + a_MinRelX;
+ a_Dest.m_Origin.y = a_MinRelY;
+ a_Dest.m_Origin.z = m_ChunkZ * cChunkDef::Width + a_MinRelZ;
a_Dest.SetSize(SizeX, SizeY, SizeZ, cBlockArea::baTypes | cBlockArea::baMetas);
for (int y = 0; y < SizeY; y++)
diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp
new file mode 100644
index 000000000..a9e0a839d
--- /dev/null
+++ b/src/Generating/Prefab.cpp
@@ -0,0 +1,312 @@
+
+// Prefab.cpp
+
+/*
+Implements the cPrefab class, representing a cPiece descendant for the cPieceGenerator that
+uses a prefabricate in a cBlockArea for drawing itself.
+*/
+
+#include "Globals.h"
+#include "Prefab.h"
+#include "../WorldStorage/SchematicFileSerializer.h"
+#include "ChunkDesc.h"
+
+
+
+
+
+#ifdef SELF_TEST
+
+// Create one static prefab to test the parser:
+static const cPrefab::sDef g_TestPrefabDef =
+{
+ // Size:
+ 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* 0 */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "b.....b"
+ "b.....b"
+ "a.....a"
+ "aabbbaa"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa",
+
+ // Connections:
+ "0: 0, 3, 2: 4\n"
+ "0: 2, 3, 0: 2\n",
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msImprint
+};
+
+static cPrefab g_TestPrefab(g_TestPrefabDef);
+#endif
+
+
+
+
+
+cPrefab::cPrefab(const cPrefab::sDef & a_Def) :
+ m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ),
+ m_HitBox(0, 0, 0, a_Def.m_SizeX - 1, a_Def.m_SizeY - 1, a_Def.m_SizeZ - 1),
+ m_AllowedRotations(a_Def.m_AllowedRotations),
+ m_MergeStrategy(a_Def.m_MergeStrategy)
+{
+ m_BlockArea[0].Create(m_Size);
+ CharMap cm;
+ ParseCharMap(cm, a_Def.m_CharMap);
+ ParseBlockImage(cm, a_Def.m_Image);
+ ParseConnectors(a_Def.m_Connectors);
+
+ // 1 CCW rotation:
+ if ((m_AllowedRotations & 0x01) != 0)
+ {
+ m_BlockArea[1].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[1].RotateCCW();
+ }
+
+ // 2 rotations are the same as mirroring twice; mirroring is faster because it has no reallocations
+ if ((m_AllowedRotations & 0x02) != 0)
+ {
+ m_BlockArea[2].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[2].MirrorXY();
+ m_BlockArea[2].MirrorYZ();
+ }
+
+ // 3 CCW rotations = 1 CW rotation:
+ if ((m_AllowedRotations & 0x04) != 0)
+ {
+ m_BlockArea[3].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[3].RotateCW();
+ }
+}
+
+
+
+
+
+void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const
+{
+ Vector3i Placement = a_Placement->GetCoords();
+ int ChunkStartX = a_Dest.GetChunkX() * cChunkDef::Width;
+ int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width;
+ Placement.Move(-ChunkStartX, 0, -ChunkStartZ);
+ a_Dest.WriteBlockArea(m_BlockArea[a_Placement->GetNumCCWRotations()], Placement.x, Placement.y, Placement.z, m_MergeStrategy);
+
+}
+
+
+
+
+
+bool cPrefab::HasConnectorType(int a_ConnectorType) const
+{
+ for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr)
+ {
+ if (itr->m_Type == a_ConnectorType)
+ {
+ return true;
+ }
+ } // for itr - m_Connectors[]
+ return false;
+}
+
+
+
+
+
+void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
+{
+ // Initialize the charmap to all-invalid values:
+ for (size_t i = 0; i < ARRAYCOUNT(a_CharMapOut); i++)
+ {
+ a_CharMapOut[i].m_BlockType = 0;
+ a_CharMapOut[i].m_BlockMeta = 16; // Mark unassigned entries with a meta that is impossible otherwise
+ }
+
+ // Process the lines in the definition:
+ AStringVector Lines = StringSplitAndTrim(a_CharMapDef, "\n");
+ for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
+ {
+ AStringVector CharDef = StringSplitAndTrim(*itr, ":");
+ size_t NumElements = CharDef.size();
+ if ((NumElements < 2) || CharDef[0].empty() || CharDef[1].empty())
+ {
+ LOGWARNING("Bad prefab CharMap definition line: \"%s\", skipping.", itr->c_str());
+ continue;
+ }
+ unsigned char Src = (unsigned char)CharDef[0][0];
+ ASSERT(a_CharMapOut[Src].m_BlockMeta == 16); // This letter has not been assigned yet?
+ a_CharMapOut[Src].m_BlockType = (BLOCKTYPE)atoi(CharDef[1].c_str());
+ NIBBLETYPE BlockMeta = 0;
+ if ((NumElements >= 3) && !CharDef[2].empty())
+ {
+ BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str());
+ ASSERT((BlockMeta >= 0) && (BlockMeta <= 15));
+ }
+ a_CharMapOut[Src].m_BlockMeta = BlockMeta;
+ } // for itr - Lines[]
+}
+
+
+
+
+
+void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockImage)
+{
+ // Map each letter in the a_BlockImage (from the in-source definition) to real blocktype / blockmeta:
+ for (int y = 0; y < m_Size.y; y++)
+ {
+ for (int z = 0; z < m_Size.z; z++)
+ {
+ const unsigned char * BlockImage = (const unsigned char *)a_BlockImage + y * m_Size.x * m_Size.z + z * m_Size.x;
+ for (int x = 0; x < m_Size.x; x++)
+ {
+ const sBlockTypeDef & MappedValue = a_CharMap[BlockImage[x]];
+ ASSERT(MappedValue.m_BlockMeta != 16); // Using a letter not defined in the CharMap?
+ m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, MappedValue.m_BlockType, MappedValue.m_BlockMeta);
+ }
+ }
+ }
+}
+
+
+
+
+
+void cPrefab::ParseConnectors(const char * a_ConnectorsDef)
+{
+ AStringVector Lines = StringSplitAndTrim(a_ConnectorsDef, "\n");
+ for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
+ {
+ if (itr->empty())
+ {
+ continue;
+ }
+ // Split into components: "Type: X, Y, Z: Face":
+ AStringVector Defs = StringSplitAndTrim(*itr, ":");
+ if (Defs.size() != 3)
+ {
+ LOGWARNING("Bad prefab Connector definition line: \"%s\", skipping.", itr->c_str());
+ continue;
+ }
+ AStringVector Coords = StringSplitAndTrim(Defs[1], ",");
+ if (Coords.size() != 3)
+ {
+ LOGWARNING("Bad prefab Connector coords definition: \"%s\", skipping.", Defs[1].c_str());
+ continue;
+ }
+
+ // Check that the BlockFace is within range:
+ int BlockFace = atoi(Defs[2].c_str());
+ if ((BlockFace < 0) || (BlockFace >= 6))
+ {
+ LOGWARNING("Bad prefab Connector Blockface: \"%s\", skipping.", Defs[2].c_str());
+ continue;
+ }
+
+ // Add the connector:
+ m_Connectors.push_back(cPiece::cConnector(
+ atoi(Coords[0].c_str()), atoi(Coords[1].c_str()), atoi(Coords[2].c_str()), // Connector pos
+ atoi(Defs[0].c_str()), // Connector type
+ (eBlockFace)BlockFace
+ ));
+ } // for itr - Lines[]
+}
+
+
+
+
+
+cPiece::cConnectors cPrefab::GetConnectors(void) const
+{
+ return m_Connectors;
+}
+
+
+
+
+
+Vector3i cPrefab::GetSize(void) const
+{
+ return m_Size;
+}
+
+
+
+
+
+cCuboid cPrefab::GetHitBox(void) const
+{
+ return m_HitBox;
+}
+
+
+
+
+
+bool cPrefab::CanRotateCCW(int a_NumRotations) const
+{
+ // Either zero rotations
+ // Or the proper bit in m_AllowedRotations is set
+ return (a_NumRotations == 0) || ((m_AllowedRotations & (1 << ((a_NumRotations + 3) % 4))) != 0);
+}
+
+
+
+
diff --git a/src/Generating/Prefab.h b/src/Generating/Prefab.h
new file mode 100644
index 000000000..04c4f09da
--- /dev/null
+++ b/src/Generating/Prefab.h
@@ -0,0 +1,105 @@
+
+// Prefab.h
+
+/*
+Declares the cPrefab class, representing a cPiece descendant for the cPieceGenerator that
+uses a prefabricate in a cBlockArea for drawing itself.
+The class can be constructed from data that is stored directly in the executable, in a sPrefabDef structure
+declared in this file as well; the Gallery server exports areas in this format.
+*/
+
+
+
+
+
+#pragma once
+
+#include "PieceGenerator.h"
+#include "../BlockArea.h"
+
+
+
+
+
+// fwd:
+class cChunkDesc;
+
+
+
+
+
+class cPrefab :
+ public cPiece
+{
+public:
+ struct sDef
+ {
+ int m_SizeX;
+ int m_SizeY;
+ int m_SizeZ;
+ const char * m_CharMap;
+ const char * m_Image;
+ const char * m_Connectors;
+ int m_AllowedRotations;
+ cBlockArea::eMergeStrategy m_MergeStrategy;
+ };
+
+ cPrefab(const sDef & a_Def);
+
+ /** Draws the prefab into the specified chunk, according to the placement stored in the PlacedPiece. */
+ void Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const;
+
+ /** Returns true if the prefab has any connector of the specified type. */
+ bool HasConnectorType(int a_ConnectorType) const;
+
+protected:
+ /** Packs complete definition of a single block, for per-letter assignment. */
+ struct sBlockTypeDef
+ {
+ BLOCKTYPE m_BlockType;
+ NIBBLETYPE m_BlockMeta;
+ };
+
+ /** Maps letters in the sDef::m_Image onto a number, BlockType * 16 | BlockMeta */
+ typedef sBlockTypeDef CharMap[256];
+
+
+ /** The cBlockArea that contains the block definitions for the prefab.
+ The index identifies the number of CCW rotations applied (0 = no rotation, 1 = 1 CCW rotation, ...). */
+ cBlockArea m_BlockArea[4];
+
+ /** The size of the prefab */
+ Vector3i m_Size;
+
+ /** The hitbox of the prefab. In first version is the same as the m_BlockArea dimensions */
+ cCuboid m_HitBox;
+
+ /** The connectors through which the piece connects to other pieces */
+ cConnectors m_Connectors;
+
+ /** Bitmask, bit N set -> N rotations CCW supported */
+ int m_AllowedRotations;
+
+ /** The merge strategy to use when drawing the prefab into a block area */
+ cBlockArea::eMergeStrategy m_MergeStrategy;
+
+
+ // cPiece overrides:
+ virtual cConnectors GetConnectors(void) const override;
+ virtual Vector3i GetSize(void) const override;
+ virtual cCuboid GetHitBox(void) const override;
+ virtual bool CanRotateCCW(int a_NumRotations) const override;
+
+ /** Parses the CharMap in the definition into a CharMap binary data used for translating the definition into BlockArea. */
+ void ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef);
+
+ /** Parses the Image in the definition into m_BlockArea[0]'s block types and metas, using the specified CharMap. */
+ void ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockImage);
+
+ /** Parses the connectors definition text into m_Connectors member. */
+ void ParseConnectors(const char * a_ConnectorsDef);
+};
+
+
+
+