9 #include "../Bindings/LuaState.h"
10 #include "../WorldStorage/SchematicFileSerializer.h"
11 #include "../StringCompression.h"
17 static std::map<AString, cBlockArea::eMergeStrategy> msmap;
50 const cPrefab::sDef * a_StartingPieceDefs,
size_t a_NumStartingPieceDefs,
51 int a_DefaultStartingPieceHeight
55 if (a_StartingPieceDefs !=
nullptr)
95 ASSERT(a_PieceDefs !=
nullptr);
96 for (
size_t i = 0; i < a_NumPieceDefs; i++)
110 size_t a_NumStartingPieceDefs,
111 int a_DefaultPieceHeight
114 ASSERT(a_StartingPieceDefs !=
nullptr);
116 for (
size_t i = 0; i < a_NumStartingPieceDefs; i++)
119 if (a_DefaultPieceHeight >= 0)
135 if (contents.empty())
137 CONDWARNING(a_LogWarnings,
"Cannot read data from file %s", a_FileName.c_str());
150 if (a_Contents.substr(0, 3) ==
"\x1f\x8b\x08")
156 reinterpret_cast<const std::byte *
>(a_Contents.data()), a_Contents.size()
163 return LoadFromString(std::string(Extracted.GetStringView()), a_FileName, a_LogWarnings);
165 catch (
const std::exception & Oops)
167 CONDWARNING(a_LogWarnings,
"Failed to decompress Gzip data in file %s. %s", a_FileName.c_str(), Oops.what());
173 const auto Header = a_Contents.substr(0, 8
KiB);
174 if (Header.find(
"CubesetFormatVersion =") != AString::npos)
178 CONDWARNING(a_LogWarnings,
"Cannot load prefabs from file %s, unknown file format", a_FileName.c_str());
189 cLuaState Lua(fmt::format(FMT_STRING(
"LoadablePiecePool {}"), a_FileName));
192 if (!Lua.
LoadString(a_Contents, a_FileName, a_LogWarnings))
200 if (!Lua.
GetNamedGlobal(
"Cubeset.Metadata.CubesetFormatVersion", Version))
202 CONDWARNING(a_LogWarnings,
"Cannot load cubeset %s, it doesn't contain version information.", a_FileName);
213 CONDWARNING(a_LogWarnings,
"Cannot load cubeset %s, version (%d) not supported.", a_FileName, Version);
224 for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
242 if (!pieces.IsValid() || !lua_istable(a_LuaState, -1))
244 CONDWARNING(a_LogWarnings,
"The cubeset file %s doesn't contain any pieces", a_FileName.c_str());
253 lua_pushinteger(a_LuaState, idx);
254 lua_gettable(a_LuaState, -2);
255 if (!lua_istable(a_LuaState, -1))
258 lua_pop(a_LuaState, 1);
265 lua_pop(a_LuaState, 1);
277 ASSERT(lua_istable(a_LuaState, -1));
281 if (!a_LuaState.
GetNamedValue(
"OriginData.ExportName", PieceName))
283 PieceName = fmt::format(FMT_STRING(
"Piece #{}"), a_PieceIndex);
297 CONDWARNING(a_LogWarnings,
"Cannot load piece %s from file %s, it's missing hitbox information", PieceName, a_FileName);
303 if (prefab ==
nullptr)
307 prefab->SetHitBox(Hitbox);
316 int AllowedRotations = 0;
317 a_LuaState.
GetNamedValue(
"Metadata.AllowedRotations", AllowedRotations);
318 prefab->SetAllowedRotations(AllowedRotations);
327 int IsStartingPiece = 0;
328 a_LuaState.
GetNamedValue(
"Metadata.IsStarting", IsStartingPiece);
329 if (IsStartingPiece != 0)
331 if (prefab->GetVerticalStrategy() ==
nullptr)
333 CONDWARNING(a_LogWarnings,
"Starting prefab %s in file %s doesn't have its VerticalStrategy set. Setting to Fixed|150.",
334 PieceName, a_FileName
336 VERIFY(prefab->SetVerticalStrategyFromString(
"Fixed|150",
false));
341 if (IsStartingPiece != 0)
347 auto p = prefab.release();
368 if (a_LuaState.
GetNamedValue(
"SchematicFileName", SchematicFileName))
370 auto PathEnd = a_FileName.find_last_of(
"/\\");
371 if (PathEnd != AString::npos)
373 SchematicFileName = a_FileName.substr(0, PathEnd) + SchematicFileName;
380 catch (
const std::exception & Oops)
382 CONDWARNING(a_LogWarnings,
"Cannot load schematic file \"%s\" for piece %s in cubeset %s. %s",
383 SchematicFileName.c_str(), a_PieceName.c_str(), a_FileName.c_str(), Oops.what()
387 return std::make_unique<cPrefab>(area);
395 !a_LuaState.
GetNamedValue(
"BlockDefinitions", BlockDefinitions) ||
399 CONDWARNING(a_LogWarnings,
"Cannot parse block data for piece %s in cubeset %s", a_PieceName.c_str(), a_FileName.c_str());
407 CONDWARNING(a_LogWarnings,
"Cannot concat block definitions for piece %s in cubeset %s", a_PieceName.c_str(), a_FileName.c_str());
415 CONDWARNING(a_LogWarnings,
"Cannot concat block data for piece %s in cubeset %s", a_PieceName.c_str(), a_FileName.c_str());
420 int SizeX = 0, SizeY = 0, SizeZ = 0;
427 CONDWARNING(a_LogWarnings,
"Cannot load piece %s from file %s, its size information is missing", a_PieceName.c_str(), a_FileName.c_str());
432 if (
static_cast<size_t>(SizeX * SizeY * SizeZ) != BlockDataStr.size())
434 CONDWARNING(a_LogWarnings,
"Cannot create piece %s from file %s, its size (%d) doesn't match the blockdata length (%u)",
435 a_PieceName.c_str(), a_FileName.c_str(),
436 SizeX * SizeY * SizeZ,
static_cast<unsigned>(BlockDataStr.size())
441 return std::make_unique<cPrefab>(BlockDefStr, BlockDataStr, SizeX, SizeY, SizeZ);
458 if (!conns.IsValid())
460 CONDWARNING(a_LogWarnings,
"Cannot load piece %s from file %s, it has no connectors definition.", a_PieceName.c_str(), a_FileName.c_str());
469 lua_pushinteger(a_LuaState, idx);
470 lua_gettable(a_LuaState, -2);
471 if (!lua_istable(a_LuaState, -1))
474 lua_pop(a_LuaState, 1);
477 int Type = 0, RelX = 0, RelY = 0, RelZ = 0;
491 FLOGWARNING(
"Piece {0} in file {1} has a malformed Connector at index {2} ({3}, type {4}, direction {5}). Skipping the connector.",
492 a_PieceName, a_FileName, idx,
Vector3i{RelX, RelY, RelZ},
Type, DirectionStr
496 lua_pop(a_LuaState, 1);
501 lua_pop(a_LuaState, 1);
527 int AddWeightIfSame = 0, DefaultWeight = 100, MoveToGround = 0;
529 a_LuaState.
GetNamedValue(
"AddWeightIfSame", AddWeightIfSame);
542 auto strategy = msmap.find(MergeStrategy);
543 if (strategy == msmap.end())
545 CONDWARNING(a_LogWarnings,
"Unknown merge strategy (\"%s\") specified for piece %s in file %s. Using msSpongePrint instead.",
546 MergeStrategy.c_str(), a_PieceName.c_str(), a_FileName.c_str()
556 AString ExpandFloorStrategyStr;
557 if (!a_LuaState.
GetNamedValue(
"ExpandFloorStrategy", ExpandFloorStrategyStr))
560 int ShouldExpandFloor;
561 if (a_LuaState.
GetNamedValue(
"ShouldExpandFloor", ShouldExpandFloor))
563 LOG(
"Piece \"%s\" in file \"%s\" is using the old \"ShouldExpandFloor\" attribute. Use the new \"ExpandFloorStrategy\" attribute instead for more options.",
564 a_PieceName.c_str(), a_FileName.c_str()
571 auto lcExpandFloorStrategyStr =
StrToLower(ExpandFloorStrategyStr);
572 if (lcExpandFloorStrategyStr ==
"repeatbottomtillnonair")
576 else if (lcExpandFloorStrategyStr ==
"repeatbottomtillsolid")
582 if (lcExpandFloorStrategyStr !=
"none")
584 LOGWARNING(
"Piece \"%s\" in file \"%s\" is using an unknown \"ExpandFloorStrategy\" attribute value: \"%s\"",
585 a_PieceName.c_str(), a_FileName.c_str(), ExpandFloorStrategyStr.c_str()
595 CONDWARNING(a_LogWarnings,
"Unknown VerticalLimit (\"%s\") specified for piece %s in file %s. Using no limit instead.",
596 VerticalLimit.c_str(), a_PieceName.c_str(), a_FileName.c_str()
639 if (allowedBiomes.empty())
654 for (
const auto & biome: biomes)
659 CONDWARNING(a_LogWarnings,
"Invalid biome (\"%s\") specified in AllowedBiomes in cubeset file %s. Skipping the biome.",
660 biome.c_str(), a_FileName.c_str()
687 lua_pushnil(a_LuaState);
688 while (lua_next(a_LuaState, -2) != 0)
694 lua_pop(a_LuaState, 1);
722 auto verticalStrategy = piece->GetVerticalStrategy();
723 if (verticalStrategy !=
nullptr)
725 verticalStrategy->AssignGens(a_Seed, a_BiomeGen, a_HeightGen, a_SeaLevel);
732 auto verticalLimit = piece->GetVerticalLimit();
733 if (verticalLimit !=
nullptr)
735 verticalLimit->AssignGens(a_Seed, a_BiomeGen, a_HeightGen, a_SeaLevel);
737 auto modifiers = piece->GetModifiers();
738 if (modifiers.size() > 0)
740 for (
size_t i = 0; i < modifiers.size(); i++)
742 modifiers[i]->AssignSeed(a_Seed);
779 return (
static_cast<const cPrefab &
>(a_NewPiece)).GetPieceWeight(a_PlacedPiece, a_ExistingConnector);
788 return (
static_cast<const cPrefab &
>(a_NewPiece)).GetDefaultWeight();
EMCSBiome StringToBiome(const AString &a_BiomeString)
Translates a biome string to biome enum.
EMCSBiome
Biome IDs The first batch corresponds to the clientside biomes, used by MineCraft.
std::vector< cPiece * > cPieces
static std::map< AString, cBlockArea::eMergeStrategy > & GetMergeStrategyMap(void)
Returns the map of string => eMergeStrategy used when translating cubeset file merge strategies.
cPiece::cVerticalStrategyPtr CreateVerticalStrategyFromString(const AString &a_StrategyDesc, bool a_LogWarnings)
Returns a new cPiece::cVerticalStrategy descendant based on the specified description.
#define KiB
Allows arithmetic expressions like "32 KiB" (but consider using parenthesis around it,...
void LOGWARNING(std::string_view a_Format, const Args &... args)
void LOG(std::string_view a_Format, const Args &... args)
void FLOGWARNING(std::string_view a_Format, const Args &... args)
#define CONDWARNING(ShouldLog,...)
AStringVector StringSplitAndTrim(const AString &str, const AString &delim)
Split the string at any of the listed delimiters and trim each value.
AString StrToLower(const AString &s)
Returns a lower-cased copy of the string.
T GetStringMapInteger(const AStringMap &a_Map, const AString &a_Key, T a_Default)
Returns a number (of any integer type T) from a key-value string map.
Parses a string containing a range in which both values are optional ("<MinHeight>|<MaxHeight>") into...
Parses a string containing a range in which both values are optional ("<MinHeight>|<MaxHeight>") into...
Encapsulates a Lua state and provides some syntactic sugar for common operations.
bool Call(const FnT &a_Function, Args &&... args)
Call the specified Lua function.
bool GetNamedValue(const AString &a_Name, T &a_Value)
Retrieves the named value in the table at the top of the Lua stack.
cStackValue WalkToNamedGlobal(const AString &a_Name)
Pushes the named value in the global table to the top of the stack.
bool GetNamedGlobal(const AString &a_Name, T &a_Value)
Retrieves the named global value.
cStackValue WalkToValue(const AString &a_Name)
Pushes the named value in the table at the top of the stack.
bool LoadString(const AString &a_StringToLoad, const AString &a_FileName, bool a_LogWarnings=true)
Loads the specified string.
bool GetStackValues(int a_StartStackPos, Arg1 &&a_Arg1, Args &&... args)
Retrieves a list of values from the Lua stack, starting at the specified index.
void Create(void)
Creates the m_LuaState, if not created already.
Provides a RAII-style locking for the LuaState.
Used for storing references to object in the global registry.
The interface that a biome generator must implement A biome generator takes chunk coords on input and...
The interface that is used to query terrain height from the shape generator.
Represents a single piece.
void SetVerticalStrategy(cVerticalStrategyPtr a_VerticalStrategy)
bool SetVerticalStrategyFromString(const AString &a_StrategyDesc, bool a_LogWarnings)
Sets the vertical strategy based on the description in the string.
bool SetVerticalLimitFromString(const AString &a_LimitDesc, bool a_LogWarnings)
Sets the vertical limit based on the description string.
bool SetPieceModifiersFromString(const AString &a_Definition, bool a_LogWarnings)
Sets the modifiers with their params in the string.
std::vector< cConnector > cConnectors
static bool StringToDirection(const AString &a_Value, eDirection &a_Out)
Converts the string representation of a direction into the eDirection enum value.
Represents a single piece that has been placed to specific coords in the world.
void SetMergeStrategy(cBlockArea::eMergeStrategy a_MergeStrategy)
Sets the merge strategy to be used when drawing the piece.
void SetMoveToGround(bool a_MoveToGround)
Sets the flag whether the prefab should be moved to ground level before being drawn.
void SetExtendFloorStrategy(eExtendFloorStrategy a_Strategy)
Sets the strategy to use between the bottom of the prefab and the terrain top.
void ParseDepthWeight(const char *a_DepthWeightDef)
Parses the per-depth weight into m_DepthWeight member.
void AddConnector(int a_RelX, int a_RelY, int a_RelZ, cPiece::cConnector::eDirection a_Direction, int a_Type)
Adds the specified connector to the list of connectors this piece supports.
void SetAddWeightIfSame(int a_AddWeightIfSame)
Sets the AddWeightIfSame member, that is used to modify the weight when the previous piece is the sam...
@ efsRepeatBottomTillSolid
Repeat the bottom-most block down until the first solid block; non-solids are overwritten.
@ efsRepeatBottomTillNonAir
Repeat the bottom-most block down until the first non-air block.
@ efsNone
No processing, the prefab is left "floating in the air".
void SetDefaultWeight(int a_DefaultWeight)
Sets the (unmodified) DefaultWeight property for this piece.
void ApplyBaseMetadataCubesetVer1(const AString &a_FileName, bool a_LogWarnings)
Applies the base known metadata from the m_Metadata map into this pool.
BLOCKTYPE m_VillageWaterRoadBlockType
The block type used for the village roads if the road is on water.
cPrefabPiecePool(void)
Creates an empty instance.
int m_MaxDensity
The maximum density, as read from the metadata.
void Clear(void)
Removes and frees all pieces from this pool.
int m_MinDensity
The minimum density, as read from the metadata.
cPiecesMap m_PiecesByConnector
The map that has all pieces by their connector types The pieces are copies out of m_AllPieces and sho...
virtual int GetStartingPieceWeight(const cPiece &a_NewPiece) override
Returns the relative weight with which the a_NewPiece is to be selected for placing as the first piec...
BLOCKTYPE m_VillageRoadBlockType
The block type to use for the village roads.
bool ReadPoolMetadataCubesetVer1(const AString &a_FileName, cLuaState &a_LuaState, bool a_LogWarnings)
Reads the metadata for the entire pool from the cubeset file, stores it in the m_Metadata map.
bool LoadFromCubeset(const AString &a_Contents, const AString &a_FileName, bool a_LogWarnings)
Loads the pieces from the specified string containing Cubeset file data.
virtual ~cPrefabPiecePool() override
Destroys the pool, freeing all pieces.
std::unique_ptr< cPrefab > LoadPrefabFromCubesetVer1(const AString &a_FileName, cLuaState &a_LuaState, const AString &a_PieceName, bool a_LogWarnings)
Loads a single piece's prefab from the cubeset file parsed into the specified Lua state.
cPieces m_StartingPieces
The pieces that are used as starting pieces.
void AddPieceDefs(const cPrefab::sDef *a_PieceDefs, size_t a_NumPieceDefs)
Adds pieces from the specified definitions into m_AllPieces.
virtual int GetPieceWeight(const cPlacedPiece &a_PlacedPiece, const cPiece::cConnector &a_ExistingConnector, const cPiece &a_NewPiece) override
Returns the relative weight with which the a_NewPiece is to be selected for placing under a_PlacedPie...
virtual cPieces GetStartingPieces(void) override
Returns the pieces that should be used as the starting point.
AString m_IntendedUse
The intended use of this piece pool, as specified by the pool's metadata.
bool LoadFromFile(const AString &a_FileName, bool a_LogWarnings)
Loads the pieces from the specified file.
NIBBLETYPE m_VillageRoadBlockMeta
The block meta to use for the village roads.
cPieces m_AllPieces
All the pieces that are allowed for building.
void AddToPerConnectorMap(cPrefab *a_Prefab)
Adds the prefab to the m_PiecesByConnector map for all its connectors.
std::unordered_set< EMCSBiome, BiomeHasher > m_AllowedBiomes
A set of allowed biomes for the pool.
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override
Returns a list of pieces that contain the specified connector type.
virtual void Reset(void) override
Called when the pool has finished the current structure and should reset any piece-counters it has fo...
void AddStartingPieceDefs(const cPrefab::sDef *a_StartingPieceDefs, size_t a_NumStartingPieceDefs, int a_DefaultPieceHeight=-1)
Adds pieces from the specified definitions into m_StartingPieces.
void AssignGens(int a_Seed, cBiomeGen &a_BiomeGen, cTerrainHeightGen &a_HeightGen, int a_SeaLevel)
Called when the piece pool is assigned to a generator, so that the individual starting pieces' vertic...
bool LoadCubesetPieceVer1(const AString &a_FileName, cLuaState &a_LuaState, int a_PieceIndex, bool a_LogWarnings)
Loads a single piece from the cubeset file parsed into the specified Lua state.
bool ReadConnectorsCubesetVer1(const AString &a_FileName, cLuaState &a_LuaState, const AString &a_PieceName, cPrefab *a_Prefab, bool a_LogWarnings)
Reads a single piece's connectors from the cubeset file parsed into the specified Lua state.
AString GetMetadata(const AString &a_ParamName) const
Returns the specified value from the metadata map.
bool ReadPieceMetadataCubesetVer1(const AString &a_FileName, cLuaState &a_LuaState, const AString &a_PieceName, cPrefab *a_Prefab, bool a_LogWarnings)
Reads a single piece's metadata from the cubeset file parsed into the specified Lua state.
bool LoadFromString(const AString &a_Contents, const AString &a_FileName, bool a_LogWarnings)
Loads the pieces from the specified string.
AStringMap m_Metadata
A dictionary of pool-wide metadata, as read from the cubeset file.
bool LoadFromCubesetVer1(const AString &a_FileName, cLuaState &a_LuaState, bool a_LogWarnings)
Loads the pieces from the cubeset file parsed into the specified Lua state.
NIBBLETYPE m_VillageWaterRoadBlockMeta
The block meta used for the village roads if the road is on water.
virtual void PiecePlaced(const cPiece &a_Piece) override
Called after a piece is placed, to notify the pool that it has been used.
static AString ReadWholeFile(const AString &a_FileName)
Returns the entire contents of the specified file as a string.
Contains routines for data extraction.
Result ExtractGZip(ContiguousByteBufferView Input)
static void LoadFromSchematicFile(cBlockArea &a_BlockArea, const std::string &a_FileName)
Loads an area from a .schematic file.