A working POCPiece generator.

master
madmaxoft 2014-03-09 22:04:29 +01:00
parent dacb6cef1d
commit 0e985293b5
5 changed files with 359 additions and 6 deletions

View File

@ -22,6 +22,7 @@
#include "EndGen.h"
#include "MineShafts.h"
#include "Noise3DGenerator.h"
#include "POCPieceGenerator.h"
#include "Ravines.h"
@ -364,6 +365,10 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
m_FinishGens.push_back(new cStructGenOreNests(Seed));
}
else if (NoCaseCompare(*itr, "POCPieces") == 0)
{
m_FinishGens.push_back(new cPOCPieceGenerator(Seed));
}
else if (NoCaseCompare(*itr, "PreSimulator") == 0)
{
m_FinishGens.push_back(new cFinishGenPreSimulator);

View File

@ -0,0 +1,265 @@
// POCPieceGenerator.cpp
// Implements the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique
// The generator generates a maze of rooms at {0, 100, 0}
#include "Globals.h"
#include "POCPieceGenerator.h"
#include "ChunkDesc.h"
/** POC pieces are simple boxes that have connectors in the middle of their walls.
Each wall has one connector, there are 3 connector types that get assigned semi-randomly.
The piece also knows how to imprint itself in a cChunkDesc, each piece has a different color glass
and each connector is uses a different color wool frame. */
class cPOCPiece :
public cPiece
{
public:
cPOCPiece(int a_Size) :
m_Size(a_Size)
{
m_Connectors.push_back(cConnector(m_Size / 2, 1, 0, 0, BLOCK_FACE_ZM));
m_Connectors.push_back(cConnector(m_Size / 2, 1, m_Size - 1, 1, BLOCK_FACE_ZP));
m_Connectors.push_back(cConnector(0, 1, m_Size / 2, 2, BLOCK_FACE_XM));
m_Connectors.push_back(cConnector(m_Size - 1, 1, m_Size / 2, m_Size % 3, BLOCK_FACE_XP));
}
/** Imprints the piece in the specified chunk. Assumes they intersect. */
void ImprintInChunk(cChunkDesc & a_ChunkDesc, const Vector3i & a_Pos, int a_NumCCWRotations)
{
int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
Vector3i Min = a_Pos;
Min.Move(-BlockX, 0, -BlockZ);
Vector3i Max = Min;
Max.Move(m_Size - 1, 2, m_Size - 1);
ASSERT(Min.x < cChunkDef::Width);
ASSERT(Min.z < cChunkDef::Width);
ASSERT(Max.x >= 0);
ASSERT(Max.z >= 0);
if (Min.x >= 0)
{
// Draw the XM wall:
a_ChunkDesc.FillRelCuboid(Min.x, Min.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_Size % 16);
}
if (Min.z >= 0)
{
// Draw the ZM wall:
a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Min.z, Min.z, E_BLOCK_STAINED_GLASS, m_Size % 16);
}
if (Max.x < cChunkDef::Width)
{
// Draw the XP wall:
a_ChunkDesc.FillRelCuboid(Max.x, Max.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_Size % 16);
}
if (Max.z < cChunkDef::Width)
{
// Draw the ZP wall:
a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Max.z, Max.z, E_BLOCK_STAINED_GLASS, m_Size % 16);
}
// Draw all the connectors:
for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr)
{
cConnector Conn = cPiece::RotateMoveConnector(*itr, a_NumCCWRotations, a_Pos.x, a_Pos.y, a_Pos.z);
Conn.m_Pos.Move(-BlockX, 0, -BlockZ);
if (
(Conn.m_Pos.x >= 0) && (Conn.m_Pos.x < cChunkDef::Width) &&
(Conn.m_Pos.z >= 0) && (Conn.m_Pos.z < cChunkDef::Width)
)
{
a_ChunkDesc.SetBlockTypeMeta(Conn.m_Pos.x, Conn.m_Pos.y, Conn.m_Pos.z, E_BLOCK_WOOL, itr->m_Type % 16);
}
/*
// TODO: Frame the connectors
switch (itr->m_Direction)
{
case BLOCK_FACE_XM:
case BLOCK_FACE_XP:
{
// TODO
break;
}
case BLOCK_FACE_ZM:
case BLOCK_FACE_ZP:
{
// TODO
break;
}
}
*/
} // for itr - m_Connectors[]
}
protected:
int m_Size;
cConnectors m_Connectors;
// cPiece overrides:
virtual cConnectors GetConnectors(void) const override
{
return m_Connectors;
}
virtual Vector3i GetSize(void) const override
{
return Vector3i(m_Size, 3, m_Size);
}
virtual cCuboid GetHitBox(void) const override
{
return cCuboid(0, 0, 0, m_Size - 1, 2, m_Size - 1);
}
virtual bool CanRotateCCW(int a_NumRotations) const override
{
return true;
}
};
static void DebugPieces(const cPlacedPieces & a_Pieces)
{
size_t idx = 0;
for (cPlacedPieces::const_iterator itr = a_Pieces.begin(), end = a_Pieces.end(); itr != end; ++itr, ++idx)
{
const cCuboid & HitBox = (*itr)->GetHitBox();
printf(" %u: %d rotations, {%d - %d, %d - %d}\n",
idx, (*itr)->GetNumCCWRotations(),
HitBox.p1.x, HitBox.p2.x, HitBox.p1.z, HitBox.p2.z
);
} // for itr - a_Pieces[]
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cPOCPieceGenerator:
cPOCPieceGenerator::cPOCPieceGenerator(int a_Seed) :
m_Seed(a_Seed)
{
// Prepare a vector of available pieces:
m_AvailPieces.push_back(new cPOCPiece(5));
m_AvailPieces.push_back(new cPOCPiece(7));
m_AvailPieces.push_back(new cPOCPiece(9));
// Generate the structure:
cBFSPieceGenerator Gen(*this, a_Seed);
Gen.PlacePieces(0, 50, 0, 6, m_Pieces);
// DebugPieces(m_Pieces);
// Get the smallest cuboid encompassing the entire generated structure:
cCuboid Bounds(0, 50, 0, 0, 50, 0);
for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
{
Vector3i MinCoords = (*itr)->GetCoords();
Bounds.Engulf(MinCoords);
Bounds.Engulf(MinCoords + (*itr)->GetPiece().GetSize());
} // for itr - m_Pieces[]
m_Bounds = Bounds;
}
cPOCPieceGenerator::~cPOCPieceGenerator()
{
cPieceGenerator::FreePieces(m_Pieces);
}
void cPOCPieceGenerator::GenFinish(cChunkDesc & a_ChunkDesc)
{
int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
if (
(BlockX + 16 < m_Bounds.p1.x) || (BlockX > m_Bounds.p2.x) || // X coords out of bounds of the generated structure
(BlockZ + 16 < m_Bounds.p1.z) || (BlockZ > m_Bounds.p2.z) // Z coords out of bounds of the generated structure
)
{
return;
}
// Imprint each piece in the chunk:
for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
{
const Vector3i & Pos = (*itr)->GetCoords();
Vector3i Size = (*itr)->GetPiece().GetSize();
if (((*itr)->GetNumCCWRotations() % 2) == 1)
{
std::swap(Size.x, Size.z);
}
if (
(Pos.x >= BlockX + 16) || (Pos.x + Size.x - 1 < BlockX) ||
(Pos.z >= BlockZ + 16) || (Pos.z + Size.z - 1 < BlockZ)
)
{
// This piece doesn't intersect the chunk
continue;
}
((cPOCPiece &)(*itr)->GetPiece()).ImprintInChunk(a_ChunkDesc, Pos, (*itr)->GetNumCCWRotations());
} // for itr - m_Pieces[]
a_ChunkDesc.UpdateHeightmap();
}
cPieces cPOCPieceGenerator::GetPiecesWithConnector(int a_ConnectorType)
{
// Each piece has each connector
return m_AvailPieces;
}
cPieces cPOCPieceGenerator::GetStartingPieces(void)
{
// Any piece can be a starting piece
return m_AvailPieces;
}
void cPOCPieceGenerator::PiecePlaced(const cPiece & a_Piece)
{
UNUSED(a_Piece);
}
void cPOCPieceGenerator::Reset(void)
{
// Nothing needed
}

View File

@ -0,0 +1,54 @@
// POCPieceGenerator.h
// Declares the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique
// The generator generates a maze of rooms at {0, 100, 0}
#pragma once
#include "PieceGenerator.h"
#include "ComposableGenerator.h"
class cPOCPieceGenerator :
public cFinishGen,
protected cPiecePool
{
public:
cPOCPieceGenerator(int a_Seed);
~cPOCPieceGenerator();
protected:
int m_Seed;
/** The pieces from which the generated structure is built. */
cPieces m_AvailPieces;
/** The placed pieces of the generated structure. */
cPlacedPieces m_Pieces;
/** Bounds of the complete structure, to save on processing outside chunks. */
cCuboid m_Bounds;
// cFinishGen overrides:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
// cPiecePool overrides:
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
virtual cPieces GetStartingPieces(void) override;
virtual void PiecePlaced(const cPiece & a_Piece) override;
virtual void Reset(void) override;
} ;

View File

@ -11,6 +11,8 @@
#ifdef SELF_TEST
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Self-test:
@ -132,6 +134,8 @@ protected:
}
} g_Test;
#endif // SELF_TEST
@ -287,6 +291,7 @@ cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece
{
m_Depth = (m_Parent == NULL) ? 0 : (m_Parent->GetDepth() + 1);
m_HitBox = a_Piece.RotateMoveHitBox(a_NumCCWRotations, a_Coords.x, a_Coords.y, a_Coords.z);
m_HitBox.Sort();
}
@ -375,10 +380,10 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
/* YM, YP, ZM, ZP, XM, XP
/* YM */ { 0, 0, 0, 0, 0, 0},
/* YP */ { 0, 0, 0, 0, 0, 0},
/* ZM */ { 0, 0, 0, 2, 1, 3},
/* ZP */ { 0, 0, 2, 0, 3, 1},
/* XM */ { 0, 0, 3, 1, 0, 2},
/* XP */ { 0, 0, 1, 3, 2, 0},
/* ZM */ { 0, 0, 2, 0, 1, 3},
/* ZP */ { 0, 0, 0, 2, 3, 1},
/* XM */ { 0, 0, 3, 1, 2, 0},
/* XP */ { 0, 0, 1, 3, 0, 2},
};
// Get a list of available connections:
@ -389,8 +394,10 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
Vector3i ConnPos = a_Connector.m_Pos; // The position at which the new connector should be placed - 1 block away from the connector
AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction);
/*
// DEBUG:
printf("Placing piece at pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str());
printf("Placing piece at connector pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str());
//*/
for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP)
{
@ -427,11 +434,15 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
cConnection & Conn = Connections[rnd % Connections.size()];
// Place the piece:
/*
// DEBUG
printf("Chosen connector at {%d, %d, %d}, direction %s, needs %d rotations\n",
Conn.m_Connector.m_Pos.x, Conn.m_Connector.m_Pos.y, Conn.m_Connector.m_Pos.z,
BlockFaceToString(Conn.m_Connector.m_Direction).c_str(),
Conn.m_NumCCWRotations
);
//*/
Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations);
ConnPos -= NewPos;
cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations);
@ -440,8 +451,10 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
// Add the new piece's connectors to the list of free connectors:
cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors();
/*
// DEBUG:
printf("Adding %u connectors to the pool\n", Connectors.size() - 1);
//*/
for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
{
@ -471,6 +484,7 @@ bool cPieceGenerator::CheckConnection(
{
// For each placed piece, test the hitbox against the new piece:
cCuboid RotatedHitBox = a_Piece.RotateHitBoxToConnector(a_NewConnector, a_ToPos, a_NumCCWRotations);
RotatedHitBox.Sort();
for (cPlacedPieces::const_iterator itr = a_OutPieces.begin(), end = a_OutPieces.end(); itr != end; ++itr)
{
if ((*itr)->GetHitBox().DoesIntersect(RotatedHitBox))
@ -485,6 +499,7 @@ bool cPieceGenerator::CheckConnection(
//*
// DEBUG:
void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed)
{
@ -501,6 +516,7 @@ void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors
);
} // for itr - a_ConnectorPool[]
}
//*/
@ -553,6 +569,7 @@ void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, i
// Place the starting piece:
a_OutPieces.push_back(PlaceStartingPiece(a_BlockX, a_BlockY, a_BlockZ, ConnectorPool));
/*
// DEBUG:
printf("Placed the starting piece at {%d, %d, %d}\n", a_BlockX, a_BlockY, a_BlockZ);
cCuboid Hitbox = a_OutPieces[0]->GetHitBox();
@ -563,6 +580,7 @@ void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, i
Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
);
DebugConnectorPool(ConnectorPool, 0);
//*/
// Place pieces at the available connectors:
/*
@ -578,6 +596,8 @@ void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, i
{
if (TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces, ConnectorPool))
{
/*
// DEBUG:
const cPlacedPiece * NewPiece = a_OutPieces.back();
const Vector3i & Coords = NewPiece->GetCoords();
printf("Placed a new piece at {%d, %d, %d}, rotation %d\n", Coords.x, Coords.y, Coords.z, NewPiece->GetNumCCWRotations());
@ -589,6 +609,7 @@ void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, i
Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
);
DebugConnectorPool(ConnectorPool, NumProcessed + 1);
//*/
}
}
NumProcessed++;

View File

@ -30,6 +30,9 @@ Each uses a slightly different approach to generating:
class cPiece
{
public:
// Force a virtual destructor in all descendants
virtual ~cPiece() {}
struct cConnector
{
/** Position relative to the piece */
@ -82,9 +85,14 @@ typedef std::vector<cPiece *> cPieces;
/** This class is an interface that provides pieces for the generator. It can keep track of what pieces were
placed and adjust the returned piece vectors. */
class cPiecePool
{
public:
// Force a virtual destructor in all descendants:
virtual ~cPiecePool() {}
/** Returns a list of pieces that contain the specified connector type.
The cPiece pointers returned are managed by the pool and the caller doesn't free them. */
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) = 0;
@ -140,7 +148,7 @@ public:
/** Cleans up all the memory used by the placed pieces.
Call this utility function instead of freeing the items on your own. */
void FreePieces(cPlacedPieces & a_PlacedPieces);
static void FreePieces(cPlacedPieces & a_PlacedPieces);
protected:
/** The type used for storing a connection from one piece to another, while building the piece tree. */