From 4af1f3ac35f6a7fe7ac2bfe625bad9abaf2e868d Mon Sep 17 00:00:00 2001 From: Niels Breuker Date: Thu, 30 Mar 2023 17:18:18 +0200 Subject: PieceGenerator: Added functionality to end a structure with a custom prefab. --- Server/Prefabs/PieceStructures/NetherFort.cubeset | 119 +++++++++++++++++++++- src/Generating/PieceGeneratorBFSTree.cpp | 112 ++++++++++++-------- src/Generating/PieceGeneratorBFSTree.h | 6 +- src/Generating/PiecePool.h | 3 + src/Generating/PrefabPiecePool.cpp | 41 +++++++- src/Generating/PrefabPiecePool.h | 4 + src/Generating/VillageGen.cpp | 7 ++ 7 files changed, 246 insertions(+), 46 deletions(-) diff --git a/Server/Prefabs/PieceStructures/NetherFort.cubeset b/Server/Prefabs/PieceStructures/NetherFort.cubeset index 2fad9d773..ec8496fac 100644 --- a/Server/Prefabs/PieceStructures/NetherFort.cubeset +++ b/Server/Prefabs/PieceStructures/NetherFort.cubeset @@ -1773,7 +1773,124 @@ Cubeset = }, }, -- BlazePlatformOverhang - + { + OriginData = + { + ExportName = "ClosurePiece", + }, + Size = + { + x = 5, + y = 2, + z = 1 + }, + Hitbox = + { + MinX = 0, + MinY = 0, + MinZ = 0, + MaxX = 4, + MaxY = 2, + MaxZ = 0, + }, + Connectors = + { + { + Type = 0, + RelX = 2, + RelY = 1, + RelZ = 0, + Direction = 2, + } + }, + Metadata = + { + ["AddWeightIfSame"] = "0", + ["AllowedRotations"] = "7", + ["DefaultWeight"] = "100", + ["DepthWeight"] = "", + ["ExpandFloorStrategy"] = "none", + ["IsClosurePiece"] = "1", + ["MergeStrategy"] = "msSpongePrint", + ["MoveToGround"] = "0", + ["VerticalStrategy"] = "Range|40|100", + }, + BlockDefinitions = + { + ".:112:0", + "a:113:0", + }, + BlockData = + { + ".....", + ".aaa.", + } + }, -- End Piece Connector + + { + OriginData = + { + ExportName = "ClosurePiece", + }, + Size = + { + x = 5, + y = 6, + z = 1 + }, + Hitbox = + { + MinX = 0, + MinY = 0, + MinZ = 0, + MaxX = 4, + MaxY = 4, + MaxZ = 0, + }, + Connectors = + { + { + Type = 1, + RelX = 2, + RelY = 1, + RelZ = 0, + Direction = 2, + }, + { + Type = -1, + RelX = 2, + RelY = 1, + RelZ = 0, + Direction = 2, + } + }, + Metadata = + { + ["AddWeightIfSame"] = "0", + ["AllowedRotations"] = "7", + ["DefaultWeight"] = "100", + ["DepthWeight"] = "", + ["ExpandFloorStrategy"] = "RepeatBottomTillSolid", + ["IsClosurePiece"] = "1", + ["MergeStrategy"] = "msSpongePrint", + ["MoveToGround"] = "0", + ["VerticalStrategy"] = "Range|40|100", + }, + BlockDefinitions = + { + ".:112:0", + "a:113:0", + }, + BlockData = + { + ".....", + ".aaa.", + ".aaa.", + ".aaa.", + ".aaa.", + ".....", + } + }, -- End Piece Connector { OriginData = diff --git a/src/Generating/PieceGeneratorBFSTree.cpp b/src/Generating/PieceGeneratorBFSTree.cpp index 2e26463f2..cf6e82ca3 100644 --- a/src/Generating/PieceGeneratorBFSTree.cpp +++ b/src/Generating/PieceGeneratorBFSTree.cpp @@ -101,16 +101,80 @@ bool cPieceGeneratorBFSTree::TryPlacePieceAtConnector( const cPlacedPiece & a_ParentPiece, const cPiece::cConnector & a_Connector, cPlacedPieces & a_OutPieces, - cPieceGeneratorBFSTree::cFreeConnectors & a_OutConnectors + cPieceGeneratorBFSTree::cFreeConnectors & a_OutConnectors, + bool a_OnlyClosurePieces ) { // Get a list of available connections: cConnections Connections; int WantedConnectorType = -a_Connector.m_Type; - cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(WantedConnectorType); + cPieces AvailablePieces; + if (a_OnlyClosurePieces) + { + AvailablePieces = m_PiecePool.GetClosurePiecesWithConnector(WantedConnectorType); + } + else + { + AvailablePieces = m_PiecePool.GetPiecesWithConnector(WantedConnectorType); + } Connections.reserve(AvailablePieces.size()); Vector3i ConnPos = cPiece::cConnector::AddDirection(a_Connector.m_Pos, a_Connector.m_Direction); // The position at which the new connector should be placed - 1 block away from the current connector int WeightTotal = 0; + FindPieceForConnector(AvailablePieces, a_ParentPiece, a_Connector, WantedConnectorType, ConnPos, a_OutPieces, Connections, WeightTotal); + if (Connections.empty()) + { + // If there are no available connections try to place a closure connector. + AvailablePieces = m_PiecePool.GetClosurePiecesWithConnector(WantedConnectorType); + FindPieceForConnector(AvailablePieces, a_ParentPiece, a_Connector, WantedConnectorType, ConnPos, a_OutPieces, Connections, WeightTotal); + if (Connections.empty()) + { + // No available connections, bail out + return false; + } + } + ASSERT(WeightTotal > 0); + + // Choose a random connection from the list, based on the weights: + int rnd = (m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7) % WeightTotal; + size_t ChosenIndex = 0; + for (cConnections::const_iterator itr = Connections.begin(), end = Connections.end(); itr != end; ++itr, ++ChosenIndex) + { + rnd -= itr->m_Weight; + if (rnd <= 0) + { + // This is the piece to choose + break; + } + } + cConnection & Conn = Connections[ChosenIndex]; + + // Place the piece: + Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations); + ConnPos -= NewPos; + auto PlacedPiece = std::make_unique(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations); + + // Add the new piece's connectors to the list of free connectors: + cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors(); + for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr) + { + if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos)) + { + // This is the connector through which we have been connected to the parent, don't add + continue; + } + a_OutConnectors.emplace_back(PlacedPiece.get(), Conn.m_Piece->RotateMoveConnector(*itr, Conn.m_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z)); + } + a_OutPieces.push_back(std::move(PlacedPiece)); + + return true; +} + + + + + +void cPieceGeneratorBFSTree::FindPieceForConnector(cPieces& AvailablePieces, const cPlacedPiece& a_ParentPiece, const cPiece::cConnector& a_Connector, int WantedConnectorType, Vector3i& ConnPos, cPlacedPieces& a_OutPieces, cPieceGeneratorBFSTree::cConnections& Connections, int& WeightTotal) +{ for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP) { // Get the relative chance of this piece being generated in this path: @@ -153,46 +217,6 @@ bool cPieceGeneratorBFSTree::TryPlacePieceAtConnector( WeightTotal += Weight; } // for itrC - Connectors[] } // for itrP - AvailablePieces[] - if (Connections.empty()) - { - // No available connections, bail out - return false; - } - ASSERT(WeightTotal > 0); - - // Choose a random connection from the list, based on the weights: - int rnd = (m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7) % WeightTotal; - size_t ChosenIndex = 0; - for (cConnections::const_iterator itr = Connections.begin(), end = Connections.end(); itr != end; ++itr, ++ChosenIndex) - { - rnd -= itr->m_Weight; - if (rnd <= 0) - { - // This is the piece to choose - break; - } - } - cConnection & Conn = Connections[ChosenIndex]; - - // Place the piece: - Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations); - ConnPos -= NewPos; - auto PlacedPiece = std::make_unique(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations); - - // Add the new piece's connectors to the list of free connectors: - cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors(); - for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr) - { - if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos)) - { - // This is the connector through which we have been connected to the parent, don't add - continue; - } - a_OutConnectors.emplace_back(PlacedPiece.get(), Conn.m_Piece->RotateMoveConnector(*itr, Conn.m_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z)); - } - a_OutPieces.push_back(std::move(PlacedPiece)); - - return true; } @@ -274,6 +298,10 @@ void cPieceGeneratorBFSTree::PlacePieces(int a_BlockX, int a_BlockZ, int a_MaxDe //*/ } } + else + { + TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces, ConnectorPool, true); + } NumProcessed++; if (NumProcessed > 1000) { diff --git a/src/Generating/PieceGeneratorBFSTree.h b/src/Generating/PieceGeneratorBFSTree.h index 33d2e5350..c7d85c44a 100644 --- a/src/Generating/PieceGeneratorBFSTree.h +++ b/src/Generating/PieceGeneratorBFSTree.h @@ -73,9 +73,13 @@ protected: const cPlacedPiece & a_ParentPiece, // The existing piece to a new piece should be placed const cPiece::cConnector & a_Connector, // The existing connector (world-coords) to which a new piece should be placed cPlacedPieces & a_OutPieces, // Already placed pieces, to be checked for intersections - cFreeConnectors & a_OutConnectors // List of free connectors to which the new connectors will be placed + cFreeConnectors & a_OutConnectors, // List of free connectors to which the new connectors will be placed + bool a_OnlyClosurePieces = false ); + /** Searches through the provided list for pieces that will fit the parent piece */ + void FindPieceForConnector(cPieces & AvailablePieces, const cPlacedPiece & a_ParentPiece, const cPiece::cConnector & a_Connector, int WantedConnectorType, Vector3i & ConnPos, cPlacedPieces & a_OutPieces, cPieceGeneratorBFSTree::cConnections & Connections, int & WeightTotal); + /** Checks if the specified piece would fit with the already-placed pieces, using the specified connector and number of CCW rotations. a_ExistingConnector is in world-coords and is already rotated properly diff --git a/src/Generating/PiecePool.h b/src/Generating/PiecePool.h index 5897f32c7..2e027e354 100644 --- a/src/Generating/PiecePool.h +++ b/src/Generating/PiecePool.h @@ -284,6 +284,9 @@ public: The cPiece pointers returned are managed by the pool and the caller doesn't free them. */ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) = 0; + /** Returns a list of closure pieces that contain the specified connector type. */ + virtual cPieces GetClosurePiecesWithConnector(int a_ConnectorType) = 0; + /** Returns the pieces that should be used as the starting point. Multiple starting points are supported, one of the returned piece will be chosen. */ virtual cPieces GetStartingPieces(void) = 0; diff --git a/src/Generating/PrefabPiecePool.cpp b/src/Generating/PrefabPiecePool.cpp index 4deee38ef..b78251d78 100644 --- a/src/Generating/PrefabPiecePool.cpp +++ b/src/Generating/PrefabPiecePool.cpp @@ -84,6 +84,11 @@ void cPrefabPiecePool::Clear(void) delete *itr; } m_StartingPieces.clear(); + for (cPieces::iterator itr = m_ClosurePieces.begin(), end = m_ClosurePieces.end(); itr != end; ++itr) + { + delete* itr; + } + m_ClosurePieces.clear(); } @@ -345,8 +350,18 @@ bool cPrefabPiecePool::LoadCubesetPieceVer1(const AString & a_FileName, cLuaStat else { auto p = prefab.release(); - m_AllPieces.push_back(p); - AddToPerConnectorMap(p); + + int IsClosurePiece = 0; + a_LuaState.GetNamedValue("Metadata.IsClosurePiece", IsClosurePiece); + if (IsClosurePiece != 0) + { + m_ClosurePieces.push_back(p); + } + else + { + m_AllPieces.push_back(p); + AddToPerConnectorMap(p); + } } return true; @@ -758,6 +773,28 @@ cPieces cPrefabPiecePool::GetPiecesWithConnector(int a_ConnectorType) +cPieces cPrefabPiecePool::GetClosurePiecesWithConnector(int a_ConnectorType) +{ + cPieces pieces; + for (auto& piece : m_ClosurePieces) + { + auto connectors = piece->GetConnectors(); + for (auto& connector : connectors) + { + if (connector.m_Type == a_ConnectorType) + { + pieces.push_back(piece); + break; + } + } + } + return pieces; +} + + + + + cPieces cPrefabPiecePool::GetStartingPieces(void) { if (m_StartingPieces.empty()) diff --git a/src/Generating/PrefabPiecePool.h b/src/Generating/PrefabPiecePool.h index 708b9be57..36aaf8bae 100644 --- a/src/Generating/PrefabPiecePool.h +++ b/src/Generating/PrefabPiecePool.h @@ -112,6 +112,7 @@ public: // cPiecePool overrides: virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override; + virtual cPieces GetClosurePiecesWithConnector(int a_ConnectorType) override; virtual cPieces GetStartingPieces(void) override; virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override; virtual int GetStartingPieceWeight(const cPiece & a_NewPiece) override; @@ -132,6 +133,9 @@ protected: This list is not shared and the pieces need deallocation. */ cPieces m_StartingPieces; + /** The pieces that can be used when no other piece will be placed. */ + cPieces m_ClosurePieces; + /** The map that has all pieces by their connector types The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */ cPiecesMap m_PiecesByConnector; diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp index 6575b2f3a..281d49541 100644 --- a/src/Generating/VillageGen.cpp +++ b/src/Generating/VillageGen.cpp @@ -258,6 +258,13 @@ protected: } + virtual cPieces GetClosurePiecesWithConnector(int a_ConnectorType) override + { + cPieces pieces; + return pieces; + } + + virtual cPieces GetStartingPieces(void) override { return m_Prefabs.GetStartingPieces(); -- cgit v1.2.3