#include "stdafx.h" #include "..\Minecraft.Client\Minecraft.h" #include "net.minecraft.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.storage.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.level.levelgen.h" #include "net.minecraft.world.level.levelgen.structure.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.level.dimension.h" #include "net.minecraft.world.entity.npc.h" #include "WeighedTreasure.h" #include "VillagePieces.h" #include "VillageFeature.h" #include "Direction.h" #include "JavaMath.h" #include "BiomeSource.h" WeighedTreasureArray VillagePieces::Smithy::treasureItems; void VillagePieces::loadStatic() { StructureFeatureIO::setPieceId(eStructurePiece_BookHouse, BookHouse::Create, L"ViBH"); StructureFeatureIO::setPieceId(eStructurePiece_DoubleFarmland, DoubleFarmland::Create, L"ViDF"); StructureFeatureIO::setPieceId(eStructurePiece_Farmland, Farmland::Create, L"ViF"); StructureFeatureIO::setPieceId(eStructurePiece_LightPost, LightPost::Create, L"ViL"); StructureFeatureIO::setPieceId(eStructurePiece_PigHouse, PigHouse::Create, L"ViPH"); StructureFeatureIO::setPieceId(eStructurePiece_SimpleHouse, SimpleHouse::Create, L"ViSH"); StructureFeatureIO::setPieceId(eStructurePiece_SmallHut, SmallHut::Create, L"ViSmH"); StructureFeatureIO::setPieceId(eStructurePiece_SmallTemple, SmallTemple::Create, L"ViST"); StructureFeatureIO::setPieceId(eStructurePiece_Smithy, Smithy::Create, L"ViS"); StructureFeatureIO::setPieceId(eStructurePiece_VillageStartPiece, StartPiece::Create, L"ViStart"); StructureFeatureIO::setPieceId(eStructurePiece_StraightRoad, StraightRoad::Create, L"ViSR"); StructureFeatureIO::setPieceId(eStructurePiece_TwoRoomHouse, TwoRoomHouse::Create, L"ViTRH"); StructureFeatureIO::setPieceId(eStructurePiece_Well, Well::Create, L"ViW"); } VillagePieces::PieceWeight::PieceWeight(VillagePieces::EPieceClass pieceClass, int weight, int maxPlaceCount) : weight(weight) { this->placeCount = 0; // 4J added initialiser this->pieceClass = pieceClass; this->maxPlaceCount = maxPlaceCount; } bool VillagePieces::PieceWeight::doPlace(int depth) { return maxPlaceCount == 0 || placeCount < maxPlaceCount; } bool VillagePieces::PieceWeight::isValid() { return maxPlaceCount == 0 || placeCount < maxPlaceCount; } list *VillagePieces::createPieceSet(Random *random, int villageSize) { list *newPieces = new list; StructureTable* table = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructureFeature* feature = table->getStructureFeature(eMinecraftStructureFeature_VillageFeature); int size = feature->options[0] + villageSize; newPieces->push_back(new PieceWeight(VillagePieces::EPieceClass_SimpleHouse, 4, Mth::nextInt(random, 2 + size, 4 + size * 2))); newPieces->push_back(new PieceWeight(VillagePieces::EPieceClass_SmallTemple, 20, Mth::nextInt(random, 0 + size, 1 + size))); newPieces->push_back(new PieceWeight(VillagePieces::EPieceClass_BookHouse, 20, Mth::nextInt(random, 0 + size, 2 + size))); newPieces->push_back(new PieceWeight(VillagePieces::EPieceClass_SmallHut, 3, Mth::nextInt(random, 2 + size, 5 + size * 3))); newPieces->push_back(new PieceWeight(VillagePieces::EPieceClass_PigHouse, 15, Mth::nextInt(random, 0 + size, 2 + size))); newPieces->push_back(new PieceWeight(VillagePieces::EPieceClass_DoubleFarmland, 3, Mth::nextInt(random, 1 + size, 4 + size))); newPieces->push_back(new PieceWeight(VillagePieces::EPieceClass_Farmland, 3, Mth::nextInt(random, 2 + size, 4 + size * 2))); newPieces->push_back(new PieceWeight(VillagePieces::EPieceClass_Smithy, 15, Mth::nextInt(random, 0, 1 + size))); newPieces->push_back(new PieceWeight(VillagePieces::EPieceClass_TwoRoomHouse, 8, Mth::nextInt(random, 0 + size, 3 + size * 2))); // silly way of filtering "infinite" buildings auto it = newPieces->begin(); while( it != newPieces->end() ) { if( (*it)->maxPlaceCount == 0 ) { delete (*it); it = newPieces->erase(it); } else { it++; } } return newPieces; } int VillagePieces::updatePieceWeight(list *currentPieces) { bool hasAnyPieces = false; int totalWeight = 0; for(auto& piece : *currentPieces) { if (piece->maxPlaceCount > 0 && piece->placeCount < piece->maxPlaceCount) { hasAnyPieces = true; } totalWeight += piece->weight; } return (hasAnyPieces ? totalWeight : -1); } VillagePieces::VillagePiece *VillagePieces::findAndCreatePieceFactory(StartPiece *startPiece, VillagePieces::PieceWeight *piece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth) { VillagePieces::EPieceClass pieceClass = piece->pieceClass; VillagePiece *villagePiece = nullptr; if (pieceClass == VillagePieces::EPieceClass_SimpleHouse) { villagePiece = SimpleHouse::createPiece(startPiece, pieces, random, footX, footY, footZ, direction, depth); } else if (pieceClass == VillagePieces::EPieceClass_SmallTemple) { villagePiece = SmallTemple::createPiece(startPiece, pieces, random, footX, footY, footZ, direction, depth); } else if (pieceClass == VillagePieces::EPieceClass_BookHouse) { villagePiece = BookHouse::createPiece(startPiece, pieces, random, footX, footY, footZ, direction, depth); } else if (pieceClass == VillagePieces::EPieceClass_SmallHut) { villagePiece = SmallHut::createPiece(startPiece, pieces, random, footX, footY, footZ, direction, depth); } else if (pieceClass == VillagePieces::EPieceClass_PigHouse) { villagePiece = PigHouse::createPiece(startPiece, pieces, random, footX, footY, footZ, direction, depth); } else if (pieceClass == VillagePieces::EPieceClass_DoubleFarmland) { villagePiece = DoubleFarmland::createPiece(startPiece, pieces, random, footX, footY, footZ, direction, depth); } else if (pieceClass == VillagePieces::EPieceClass_Farmland) { villagePiece = Farmland::createPiece(startPiece, pieces, random, footX, footY, footZ, direction, depth); } else if (pieceClass == VillagePieces::EPieceClass_Smithy) { villagePiece = Smithy::createPiece(startPiece, pieces, random, footX, footY, footZ, direction, depth); } else if (pieceClass == VillagePieces::EPieceClass_TwoRoomHouse) { villagePiece = TwoRoomHouse::createPiece(startPiece, pieces, random, footX, footY, footZ, direction, depth); } return villagePiece; } VillagePieces::VillagePiece *VillagePieces::generatePieceFromSmallDoor(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth) { int totalWeight = updatePieceWeight(startPiece->pieceSet); if (totalWeight <= 0) { return nullptr; } int numAttempts = 0; while (numAttempts < 5) { numAttempts++; int weightSelection = random->nextInt(totalWeight); for ( PieceWeight *piece : *startPiece->pieceSet ) { weightSelection -= piece->weight; if (weightSelection < 0) { if (!piece->doPlace(depth) || (piece == startPiece->previousPiece && startPiece->pieceSet->size() > 1)) { break; } VillagePiece *villagePiece = findAndCreatePieceFactory(startPiece, piece, pieces, random, footX, footY, footZ, direction, depth); if (villagePiece != nullptr) { piece->placeCount++; startPiece->previousPiece = piece; if (!piece->isValid()) { startPiece->pieceSet->remove(piece); } return villagePiece; } } } } // attempt to place a light post instead { BoundingBox *box = LightPost::findPieceBox(startPiece, pieces, random, footX, footY, footZ, direction); if (box != nullptr) { return new LightPost(startPiece, depth, random, box, direction); } delete box; } return nullptr; } StructurePiece *VillagePieces::generateAndAddPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth) { if (depth > MAX_DEPTH) { return nullptr; } if (abs(footX - startPiece->getBoundingBox()->x0) > 7 * 16 || abs(footZ - startPiece->getBoundingBox()->z0) > 7 * 16) { return nullptr; } StructurePiece *newPiece = generatePieceFromSmallDoor(startPiece, pieces, random, footX, footY, footZ, direction, depth + 1); if (newPiece != nullptr) { int x = (newPiece->boundingBox->x0 + newPiece->boundingBox->x1) / 2; int z = (newPiece->boundingBox->z0 + newPiece->boundingBox->z1) / 2; int xs = newPiece->boundingBox->x1 - newPiece->boundingBox->x0; int zs = newPiece->boundingBox->z1 - newPiece->boundingBox->z0; int r = xs > zs ? xs : zs; if (startPiece->getBiomeSource()->containsOnly(x, z, r / 2 + 4, VillageFeature::allowedBiomes)) { pieces->push_back(newPiece); startPiece->pendingHouses.push_back(newPiece); return newPiece; } delete newPiece; } return nullptr; } StructurePiece *VillagePieces::generateAndAddRoadPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth) { if (depth > BASE_ROAD_DEPTH + startPiece->villageSize) { return nullptr; } if (abs(footX - startPiece->getBoundingBox()->x0) > 7 * 16 || abs(footZ - startPiece->getBoundingBox()->z0) > 7 * 16) { return nullptr; } BoundingBox *box = StraightRoad::findPieceBox(startPiece, pieces, random, footX, footY, footZ, direction); if (box != nullptr && box->y0 > LOWEST_Y_POSITION) { StructurePiece *newPiece = new StraightRoad(startPiece, depth, random, box, direction); int x = (newPiece->boundingBox->x0 + newPiece->boundingBox->x1) / 2; int z = (newPiece->boundingBox->z0 + newPiece->boundingBox->z1) / 2; int xs = newPiece->boundingBox->x1 - newPiece->boundingBox->x0; int zs = newPiece->boundingBox->z1 - newPiece->boundingBox->z0; int r = xs > zs ? xs : zs; if (startPiece->getBiomeSource()->containsOnly(x, z, r / 2 + 4, VillageFeature::allowedBiomes)) { pieces->push_back(newPiece); startPiece->pendingRoads.push_back(newPiece); return newPiece; } // 4J Stu - The dtor for newPiece will destroy box delete newPiece; } else if(box != nullptr) { delete box; } return nullptr; } VillagePieces::VillagePiece::VillagePiece() { objectPlacedFlags.clear(); featureConditions.clear(); tileOptionRemap.clear(); entitySpawnCounts.clear(); heightPosition = -1; spawnedVillagerCount = 0; isDesertVillage = false; startPiece = nullptr; // for reflection } VillagePieces::VillagePiece::VillagePiece(StartPiece *startPiece, int genDepth) : StructurePiece(genDepth) { objectPlacedFlags.clear(); featureConditions.clear(); tileOptionRemap.clear(); entitySpawnCounts.clear(); heightPosition = -1; isDesertVillage = false; spawnedVillagerCount = 0; this->startPiece = startPiece; if (startPiece != nullptr) { this->isDesertVillage = startPiece->isDesertVillage; } } void VillagePieces::VillagePiece::addAdditionalSaveData(DataOutputStream *dos) { if (startPiece != nullptr) { this->isDesertVillage = startPiece->isDesertVillage; } dos->writeInt(heightPosition); addStructurePieceSaveData(dos, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); dos->writeInt(spawnedVillagerCount); dos->writeBoolean(isDesertVillage); } void VillagePieces::VillagePiece::readAdditonalSaveData(DataInputStream *dis) { heightPosition = dis->readInt(); readStructurePieceSaveData(dis, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); spawnedVillagerCount = dis->readInt(); bool isDesertVillageValue = dis->readBoolean(); isDesertVillage = startPiece != nullptr ? startPiece->isDesertVillage : isDesertVillageValue; } StructurePiece *VillagePieces::VillagePiece::generateHouseNorthernLeft(StartPiece *startPiece, list *pieces, Random *random, int yOff, int zOff) { switch (orientation) { case Direction::NORTH: return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 - 1, boundingBox->y0 + yOff, boundingBox->z0 + zOff, Direction::WEST, getGenDepth()); case Direction::SOUTH: return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 - 1, boundingBox->y0 + yOff, boundingBox->z0 + zOff, Direction::WEST, getGenDepth()); case Direction::WEST: return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + zOff, boundingBox->y0 + yOff, boundingBox->z0 - 1, Direction::NORTH, getGenDepth()); case Direction::EAST: return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + zOff, boundingBox->y0 + yOff, boundingBox->z0 - 1, Direction::NORTH, getGenDepth()); } return nullptr; } StructurePiece *VillagePieces::VillagePiece::generateHouseNorthernRight(StartPiece *startPiece, list *pieces, Random *random, int yOff, int zOff) { switch (orientation) { case Direction::NORTH: return generateAndAddPiece(startPiece, pieces, random, boundingBox->x1 + 1, boundingBox->y0 + yOff, boundingBox->z0 + zOff, Direction::EAST, getGenDepth()); case Direction::SOUTH: return generateAndAddPiece(startPiece, pieces, random, boundingBox->x1 + 1, boundingBox->y0 + yOff, boundingBox->z0 + zOff, Direction::EAST, getGenDepth()); case Direction::WEST: return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + zOff, boundingBox->y0 + yOff, boundingBox->z1 + 1, Direction::SOUTH, getGenDepth()); case Direction::EAST: return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + zOff, boundingBox->y0 + yOff, boundingBox->z1 + 1, Direction::SOUTH, getGenDepth()); } return nullptr; } int VillagePieces::VillagePiece::getAverageGroundHeight(Level *level, BoundingBox *chunkBB) { int total = 0; int count = 0; for (int z = boundingBox->z0; z <= boundingBox->z1; z++) { for (int x = boundingBox->x0; x <= boundingBox->x1; x++) { if (chunkBB->isInside(x, 64, z)) { total += Math::_max(level->getTopSolidBlock(x, z), level->dimension->getSpawnYPosition()); count++; } } } if (count == 0) { return -1; } return total / count; } bool VillagePieces::VillagePiece::isOkBox(BoundingBox *box, StartPiece *startRoom) { bool bIsOk = false; if(box != nullptr) { if( box->y0 > LOWEST_Y_POSITION ) bIsOk = true; int xzSize = startRoom->m_level->getLevelData()->getXZSize(); int blockMin = -( (xzSize << 4) / 2) + 1; int blockMax = ( (xzSize << 4) / 2 ) - 1; if(box->x0 <= blockMin) bIsOk = false; if(box->z0 <= blockMin) bIsOk = false; if(box->x1 >= blockMax) bIsOk = false; if(box->z1 >= blockMax) bIsOk = false; } return bIsOk; } void VillagePieces::VillagePiece::spawnVillagers(Level *level, BoundingBox *chunkBB, int x, int y, int z, int count) { if (spawnedVillagerCount >= count) { return; } for (int i = spawnedVillagerCount; i < count; i++) { int worldX = getWorldX(x + i, z); int worldY = getWorldY(y); int worldZ = getWorldZ(x + i, z); if (chunkBB->isInside(worldX, worldY, worldZ)) { spawnedVillagerCount++; shared_ptr villager = std::make_shared(level, getVillagerProfession(i)); villager->moveTo(worldX + 0.5, worldY, worldZ + 0.5, 0, 0); level->addEntity(villager); } else { // try again later break; } } } int VillagePieces::VillagePiece::getVillagerProfession(int villagerNumber) { return Villager::PROFESSION_FARMER; } int VillagePieces::VillagePiece::biomeBlock(int tile, int data) { if (startPiece != nullptr) this->isDesertVillage = startPiece->isDesertVillage; if (!isDesertVillage) return tile; StructureTable* table = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructureFeature* feature = table->getStructureFeature(eMinecraftStructureFeature_VillageFeature); auto it = feature->tiles.find(tile); if (it != feature->tiles.end()) { return it->second; } return tile; } int VillagePieces::VillagePiece::biomeData(int tile, int data) { if (startPiece != nullptr) this->isDesertVillage = startPiece->isDesertVillage; if (!isDesertVillage) return data; if (tile == Tile::treeTrunk_Id || tile == Tile::cobblestone_Id) return SandStoneTile::TYPE_DEFAULT; else if (tile == Tile::wood_Id) return SandStoneTile::TYPE_SMOOTHSIDE; return data; } void VillagePieces::VillagePiece::placeBlock(Level *level, int block, int data, int x, int y, int z, BoundingBox *chunkBB) { int bblock = biomeBlock(block, data); int bdata = biomeData(block, data); StructurePiece::placeBlock(level, bblock, bdata, x, y, z, chunkBB); } void VillagePieces::VillagePiece::generateBox(Level *level, BoundingBox *chunkBB, int x0, int y0, int z0, int x1, int y1, int z1, int edgeTile, int fillTile, bool skipAir) { int bEdge = biomeBlock(edgeTile, 0); int bEdgeData = biomeData(edgeTile, 0); int bFill = biomeBlock(fillTile, 0); int bFillData = biomeData(fillTile, 0); StructurePiece::generateBox(level, chunkBB, x0, y0, z0, x1, y1, z1, bEdge, bEdgeData, bFill, bFillData, skipAir); } void VillagePieces::VillagePiece::fillColumnDown(Level *level, int block, int data, int x, int startY, int z, BoundingBox *chunkBB) { int bblock = biomeBlock(block, data); int bdata = biomeData(block, data); StructurePiece::fillColumnDown(level, bblock, bdata, x, startY, z, chunkBB); } void VillagePieces::VillagePiece::fillBoxDown(Level* level, int x0, int y0, int z0, int x1, int y1, int z1, int tile, int tileData, BoundingBox* chunkBB) { int bblock = biomeBlock(x0, y0); int bdata = biomeData(x0, y0); StructurePiece::fillBoxDown(level, bblock, bdata, x0, y0, z0, x1, z1, chunkBB); } VillagePieces::Well::Well() { // for reflection } VillagePieces::Well::Well(StartPiece *startPiece, int genDepth, Random *random, int west, int north) : VillagePiece(startPiece, genDepth) { orientation = random->nextInt(4); StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_Well); switch (orientation) { case Direction::NORTH: case Direction::SOUTH: boundingBox = new BoundingBox(west, 64, north, west + piece->width - 1, 64 + piece->height - 1, north + piece->depth - 1); break; default: boundingBox = new BoundingBox(west, 64, north, west + piece->depth - 1, 64 + piece->height - 1, north + piece->width - 1); break; } } VillagePieces::Well::Well(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { orientation = direction; boundingBox = stairsBox; } void VillagePieces::Well::addChildren(StructurePiece *startPiece, list *pieces, Random *random) { generateAndAddRoadPiece(static_cast(startPiece), pieces, random, boundingBox->x0 - 1, boundingBox->y1 - 4, boundingBox->z0 + 1, Direction::WEST, getGenDepth()); generateAndAddRoadPiece(static_cast(startPiece), pieces, random, boundingBox->x1 + 1, boundingBox->y1 - 4, boundingBox->z0 + 1, Direction::EAST, getGenDepth()); generateAndAddRoadPiece(static_cast(startPiece), pieces, random, boundingBox->x0 + 1, boundingBox->y1 - 4, boundingBox->z0 - 1, Direction::NORTH, getGenDepth()); generateAndAddRoadPiece(static_cast(startPiece), pieces, random, boundingBox->x0 + 1, boundingBox->y1 - 4, boundingBox->z1 + 1, Direction::SOUTH, getGenDepth()); } bool VillagePieces::Well::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) { heightPosition = getAverageGroundHeight(level, chunkBB); if (heightPosition < 0) { return true; } boundingBox->move(0, heightPosition - boundingBox->y1 + 3, 0); } StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_Well); generateStructureFromData(level, chunkBB, random, piece, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); return true; } VillagePieces::StartPiece::StartPiece() { // for reflection } VillagePieces::StartPiece::StartPiece(BiomeSource *biomeSource, int genDepth, Random *random, int west, int north, list *pieceSet, int villageSize, Level *level) : Well(nullptr, 0, random, west, north) { isLibraryAdded = false; // 4J - added initialiser previousPiece = nullptr; // 4J - added initialiser this->biomeSource = biomeSource; this->pieceSet = pieceSet; this->villageSize = villageSize; m_level = level; Biome *biome = biomeSource->getBiome(west, north); isDesertVillage = biome == Biome::desert || biome == Biome::desertHills; } VillagePieces::StartPiece::~StartPiece() { for(auto& it : *pieceSet) { delete it; } delete pieceSet; } BiomeSource *VillagePieces::StartPiece::getBiomeSource() { return biomeSource; } VillagePieces::StraightRoad::StraightRoad() { // for reflection } VillagePieces::StraightRoad::StraightRoad(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillageRoadPiece(startPiece, genDepth) { orientation = direction; boundingBox = stairsBox; length = Math::_max(stairsBox->getXSpan(), stairsBox->getZSpan()); } void VillagePieces::StraightRoad::addAdditionalSaveData(DataOutputStream *dos) { VillageRoadPiece::addAdditionalSaveData(dos); dos->writeInt(length); } void VillagePieces::StraightRoad::readAdditonalSaveData(DataInputStream *dis) { VillageRoadPiece::readAdditonalSaveData(dis); length = dis->readInt(); } void VillagePieces::StraightRoad::addChildren(StructurePiece *startPiece, list *pieces, Random *random) { bool hasHouses = false; StructureTable* table = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructureFeature* feature = table->getStructureFeature(eMinecraftStructureFeature_VillageFeature); int roadExtensionChance = feature->options[1]; int endBuffer = feature->options[3]; int houseSpacing = feature->options[4]; // place left houses int depth = random->nextInt(houseSpacing); while (depth < length - endBuffer) { StructurePiece *piece = generateHouseNorthernLeft(static_cast(startPiece), pieces, random, 0, depth); if (piece != nullptr) { depth += Math::_max(piece->boundingBox->getXSpan(), piece->boundingBox->getZSpan()); hasHouses = true; } depth += 2 + random->nextInt(houseSpacing); } // place right houses depth = random->nextInt(houseSpacing); while (depth < length - endBuffer) { StructurePiece *piece = generateHouseNorthernRight(static_cast(startPiece), pieces, random, 0, depth); if (piece != nullptr) { depth += Math::_max(piece->boundingBox->getXSpan(), piece->boundingBox->getZSpan()); hasHouses = true; } depth += 2 + random->nextInt(houseSpacing); } if (hasHouses && random->nextInt(roadExtensionChance) > 0) { switch (orientation) { case Direction::NORTH: generateAndAddRoadPiece(static_cast(startPiece), pieces, random, boundingBox->x0 - 1, boundingBox->y0, boundingBox->z0, Direction::WEST, getGenDepth()); break; case Direction::SOUTH: generateAndAddRoadPiece(static_cast(startPiece), pieces, random, boundingBox->x0 - 1, boundingBox->y0, boundingBox->z1 - 2, Direction::WEST, getGenDepth()); break; case Direction::EAST: generateAndAddRoadPiece(static_cast(startPiece), pieces, random, boundingBox->x1 - 2, boundingBox->y0, boundingBox->z0 - 1, Direction::NORTH, getGenDepth()); break; case Direction::WEST: generateAndAddRoadPiece(static_cast(startPiece), pieces, random, boundingBox->x0, boundingBox->y0, boundingBox->z0 - 1, Direction::NORTH, getGenDepth()); break; } } if (hasHouses && random->nextInt(roadExtensionChance) > 0) { switch (orientation) { case Direction::NORTH: generateAndAddRoadPiece(static_cast(startPiece), pieces, random, boundingBox->x1 + 1, boundingBox->y0, boundingBox->z0, Direction::EAST, getGenDepth()); break; case Direction::SOUTH: generateAndAddRoadPiece(static_cast(startPiece), pieces, random, boundingBox->x1 + 1, boundingBox->y0, boundingBox->z1 - 2, Direction::EAST, getGenDepth()); break; case Direction::EAST: generateAndAddRoadPiece(static_cast(startPiece), pieces, random, boundingBox->x1 - 2, boundingBox->y0, boundingBox->z1 + 1, Direction::SOUTH, getGenDepth()); break; case Direction::WEST: generateAndAddRoadPiece(static_cast(startPiece), pieces, random, boundingBox->x0, boundingBox->y0, boundingBox->z1 + 1, Direction::SOUTH, getGenDepth()); break; } } } BoundingBox *VillagePieces::StraightRoad::findPieceBox(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction) { StructureTable *table = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructureFeature *feature = table->getStructureFeature(eMinecraftStructureFeature_VillageFeature); int size = feature->options[2]; int length = size * (Mth::nextInt(random, 3, 5)); while (length >= size) { BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, width, 3, length, direction); if (isOkBox(box, startPiece) && StructurePiece::findCollisionPiece(pieces, box) == nullptr) { return box; } delete box; length -= size; } return nullptr; } bool VillagePieces::StraightRoad::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructureFeature *feature = structureTable->getStructureFeature(eMinecraftStructureFeature_VillageFeature); int tileId = feature->options[5]; int tile = biomeBlock(tileId, 0); for (int x = boundingBox->x0; x <= boundingBox->x1; x++) { for (int z = boundingBox->z0; z <= boundingBox->z1; z++) { if (chunkBB->isInside(x, 64, z)) { int y = level->getTopSolidBlock(x, z) - 1; level->setTileAndData(x, y, z,tile, 0, Tile::UPDATE_CLIENTS); } } } return true; } VillagePieces::SimpleHouse::SimpleHouse() { // for reflection } VillagePieces::SimpleHouse::SimpleHouse(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { orientation = direction; boundingBox = stairsBox; } void VillagePieces::SimpleHouse::addAdditionalSaveData(DataOutputStream *dos) { VillagePiece::addAdditionalSaveData(dos); } void VillagePieces::SimpleHouse::readAdditonalSaveData(DataInputStream *dis) { VillagePiece::readAdditonalSaveData(dis); } VillagePieces::SimpleHouse *VillagePieces::SimpleHouse::createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_SimpleHouse); BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, piece->width, piece->height, piece->depth, direction); if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != nullptr) { delete box; return nullptr; } SimpleHouse *simpleHouse = new SimpleHouse(startPiece, genDepth, random, box, direction); simpleHouse->getRandomValuesFromDataSet(piece, random, simpleHouse->featureConditions, simpleHouse->tileOptionRemap); return simpleHouse; } bool VillagePieces::SimpleHouse::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) { heightPosition = getAverageGroundHeight(level, chunkBB); if (heightPosition < 0) { return true; } boundingBox->move(0, heightPosition - boundingBox->y1 + height - 1, 0); } StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_SimpleHouse); generateStructureFromData(level, chunkBB, random, piece, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); return true; } VillagePieces::SmallTemple::SmallTemple() { // for reflection } VillagePieces::SmallTemple::SmallTemple(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { heightPosition = -1; // 4J added initialiser orientation = direction; boundingBox = stairsBox; } VillagePieces::SmallTemple *VillagePieces::SmallTemple::createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_SmallTemple); BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, piece->width, piece->height, piece->depth, direction); if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != nullptr) { delete box; return nullptr; } SmallTemple *smallTemple = new SmallTemple(startPiece, genDepth, random, box, direction); smallTemple->getRandomValuesFromDataSet(piece, random, smallTemple->featureConditions, smallTemple->tileOptionRemap); return smallTemple; } bool VillagePieces::SmallTemple::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) { heightPosition = getAverageGroundHeight(level, chunkBB); if (heightPosition < 0) { return true; } boundingBox->move(0, heightPosition - boundingBox->y1 + height - 1, 0); } StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_SmallTemple); generateStructureFromData(level, chunkBB, random, piece, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); return true; } int VillagePieces::SmallTemple::getVillagerProfession(int villagerNumber) { return Villager::PROFESSION_PRIEST; } VillagePieces::BookHouse::BookHouse() { // for reflection } VillagePieces::BookHouse::BookHouse(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { heightPosition = -1; // 4J added initialiser orientation = direction; boundingBox = stairsBox; } VillagePieces::BookHouse *VillagePieces::BookHouse::createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_BookHouse); BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, piece->width, piece->height, piece->depth, direction); if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != nullptr) { delete box; return nullptr; } BookHouse *bookHouse = new BookHouse(startPiece, genDepth, random, box, direction); bookHouse->getRandomValuesFromDataSet(piece, random, bookHouse->featureConditions, bookHouse->tileOptionRemap); return bookHouse; } bool VillagePieces::BookHouse::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) { heightPosition = getAverageGroundHeight(level, chunkBB); if (heightPosition < 0) { return true; } boundingBox->move(0, heightPosition - boundingBox->y1 + height - 1, 0); } StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_BookHouse); generateStructureFromData(level, chunkBB, random, piece, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); return true; } int VillagePieces::BookHouse::getVillagerProfession(int villagerNumber) { return Villager::PROFESSION_LIBRARIAN; } VillagePieces::SmallHut::SmallHut() { // for reflection } VillagePieces::SmallHut::SmallHut(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { heightPosition = -1; // 4J added initialiser orientation = direction; boundingBox = stairsBox; } void VillagePieces::SmallHut::addAdditionalSaveData(DataOutputStream *dos) { VillagePiece::addAdditionalSaveData(dos); } void VillagePieces::SmallHut::readAdditonalSaveData(DataInputStream *dis) { VillagePiece::readAdditonalSaveData(dis); } VillagePieces::SmallHut *VillagePieces::SmallHut::createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_SmallHut); BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, piece->width, piece->height, piece->depth, direction); if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != nullptr) { delete box; return nullptr; } SmallHut *hut = new SmallHut(startPiece, genDepth, random, box, direction); hut->getRandomValuesFromDataSet(piece, random, hut->featureConditions, hut->tileOptionRemap); return hut; } bool VillagePieces::SmallHut::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) { heightPosition = getAverageGroundHeight(level, chunkBB); if (heightPosition < 0) { return true; } boundingBox->move(0, heightPosition - boundingBox->y1 + height - 1, 0); } StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_SmallHut); generateStructureFromData(level, chunkBB, random, piece, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); return true; } VillagePieces::PigHouse::PigHouse() { // for reflection } VillagePieces::PigHouse::PigHouse(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { orientation = direction; boundingBox = stairsBox; } VillagePieces::PigHouse *VillagePieces::PigHouse::createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_PigHouse); BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, piece->width, piece->height, piece->depth, direction); if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != nullptr) { delete box; return nullptr; } PigHouse *pigHouse = new PigHouse(startPiece, genDepth, random, box, direction); pigHouse->getRandomValuesFromDataSet(piece, random, pigHouse->featureConditions, pigHouse->tileOptionRemap); return pigHouse; } bool VillagePieces::PigHouse::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) { heightPosition = getAverageGroundHeight(level, chunkBB); if (heightPosition < 0) { return true; } boundingBox->move(0, heightPosition - boundingBox->y1 + height - 1, 0); } StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_PigHouse); generateStructureFromData(level, chunkBB, random, piece, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); return true; } int VillagePieces::PigHouse::getVillagerProfession(int villagerNumber) { if (villagerNumber == 0) { return Villager::PROFESSION_BUTCHER; } return Villager::PROFESSION_FARMER; } VillagePieces::TwoRoomHouse::TwoRoomHouse() { // for reflection } VillagePieces::TwoRoomHouse::TwoRoomHouse(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { heightPosition = -1; // 4J added initialiser orientation = direction; boundingBox = stairsBox; } VillagePieces::TwoRoomHouse *VillagePieces::TwoRoomHouse::createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_TwoRoomHouse); BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, piece->width, piece->height, piece->depth, direction); if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != nullptr) { delete box; return nullptr; } TwoRoomHouse *twoRoomHouse = new TwoRoomHouse(startPiece, genDepth, random, box, direction); twoRoomHouse->getRandomValuesFromDataSet(piece, random, twoRoomHouse->featureConditions, twoRoomHouse->tileOptionRemap); return twoRoomHouse; } bool VillagePieces::TwoRoomHouse::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) { heightPosition = getAverageGroundHeight(level, chunkBB); if (heightPosition < 0) { return true; } boundingBox->move(0, heightPosition - boundingBox->y1 + height - 1, 0); } StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_TwoRoomHouse); generateStructureFromData(level, chunkBB, random, piece, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); return true; } void VillagePieces::Smithy::staticCtor() { treasureItems = WeighedTreasureArray(17); treasureItems[0] = new WeighedTreasure(Item::diamond_Id, 0, 1, 3, 3); treasureItems[1] = new WeighedTreasure(Item::ironIngot_Id, 0, 1, 5, 10); treasureItems[2] = new WeighedTreasure(Item::goldIngot_Id, 0, 1, 3, 5); treasureItems[3] = new WeighedTreasure(Item::bread_Id, 0, 1, 3, 15); treasureItems[4] = new WeighedTreasure(Item::apple_Id, 0, 1, 3, 15); treasureItems[5] = new WeighedTreasure(Item::pickAxe_iron_Id, 0, 1, 1, 5); treasureItems[6] = new WeighedTreasure(Item::sword_iron_Id, 0, 1, 1, 5); treasureItems[7] = new WeighedTreasure(Item::chestplate_iron_Id, 0, 1, 1, 5); treasureItems[8] = new WeighedTreasure(Item::helmet_iron_Id, 0, 1, 1, 5); treasureItems[9] = new WeighedTreasure(Item::leggings_iron_Id, 0, 1, 1, 5); treasureItems[10] = new WeighedTreasure(Item::boots_iron_Id, 0, 1, 1, 5); treasureItems[11] = new WeighedTreasure(Tile::obsidian_Id, 0, 3, 7, 5); treasureItems[12] = new WeighedTreasure(Tile::sapling_Id, 0, 3, 7, 5); // very rare for villages ... treasureItems[13] = new WeighedTreasure(Item::saddle_Id, 0, 1, 1, 3); treasureItems[14] = new WeighedTreasure(Item::horseArmorMetal_Id, 0, 1, 1, 1); treasureItems[15] = new WeighedTreasure(Item::horseArmorGold_Id, 0, 1, 1, 1); treasureItems[16] = new WeighedTreasure(Item::horseArmorDiamond_Id, 0, 1, 1, 1); // ... } VillagePieces::Smithy::Smithy() { // for reflection } VillagePieces::Smithy::Smithy(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { orientation = direction; boundingBox = stairsBox; } VillagePieces::Smithy *VillagePieces::Smithy::createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_Smithy); BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, piece->width, piece->height, piece->depth, direction); if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != nullptr) { delete box; return nullptr; } Smithy *smithy = new Smithy(startPiece, genDepth, random, box, direction); smithy->getRandomValuesFromDataSet(piece, random, smithy->featureConditions, smithy->tileOptionRemap); return smithy; } void VillagePieces::Smithy::addAdditionalSaveData(DataOutputStream *dos) { VillagePiece::addAdditionalSaveData(dos); } void VillagePieces::Smithy::readAdditonalSaveData(DataInputStream *dis) { VillagePiece::readAdditonalSaveData(dis); } bool VillagePieces::Smithy::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) { heightPosition = getAverageGroundHeight(level, chunkBB); if (heightPosition < 0) { return true; } boundingBox->move(0, heightPosition - boundingBox->y1 + height - 1, 0); } StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_Smithy); generateStructureFromData(level, chunkBB, random, piece, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); return true; } int VillagePieces::Smithy::getVillagerProfession(int villagerNumber) { return Villager::PROFESSION_SMITH; } VillagePieces::Farmland::Farmland() { // for reflection } VillagePieces::Farmland::Farmland(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { orientation = direction; boundingBox = stairsBox; } void VillagePieces::Farmland::addAdditionalSaveData(DataOutputStream *dos) { VillagePiece::addAdditionalSaveData(dos); } void VillagePieces::Farmland::readAdditonalSaveData(DataInputStream *dis) { VillagePiece::readAdditonalSaveData(dis); } VillagePieces::Farmland *VillagePieces::Farmland::createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_Farmland); BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, piece->width, piece->height, piece->depth, direction); if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != nullptr) { delete box; return nullptr; } Farmland *farmland = new Farmland(startPiece, genDepth, random, box, direction); farmland->getRandomValuesFromDataSet(piece, random, farmland->featureConditions, farmland->tileOptionRemap); return farmland; } bool VillagePieces::Farmland::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) { heightPosition = getAverageGroundHeight(level, chunkBB); if (heightPosition < 0) { return true; } boundingBox->move(0, heightPosition - boundingBox->y1 + height - 1, 0); } StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_Farmland); generateStructureFromData(level, chunkBB, random, piece, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); return true; } VillagePieces::DoubleFarmland::DoubleFarmland() { // for reflection } VillagePieces::DoubleFarmland::DoubleFarmland(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { heightPosition = -1; // 4J added initialiser orientation = direction; boundingBox = stairsBox; } void VillagePieces::DoubleFarmland::addAdditionalSaveData(DataOutputStream *dos) { VillagePiece::addAdditionalSaveData(dos); } void VillagePieces::DoubleFarmland::readAdditonalSaveData(DataInputStream *dis) { VillagePiece::readAdditonalSaveData(dis); } VillagePieces::DoubleFarmland *VillagePieces::DoubleFarmland::createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_DoubleFarmland); BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, piece->width, piece->height, piece->depth, direction); if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != nullptr) { delete box; return nullptr; } DoubleFarmland *farmland = new DoubleFarmland(startPiece, genDepth, random, box, direction); farmland->getRandomValuesFromDataSet(piece, random, farmland->featureConditions, farmland->tileOptionRemap); return farmland; } bool VillagePieces::DoubleFarmland::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) { heightPosition = getAverageGroundHeight(level, chunkBB); if (heightPosition < 0) { return true; } boundingBox->move(0, heightPosition - boundingBox->y1 + height - 1, 0); } StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_DoubleFarmland); generateStructureFromData(level, chunkBB, random, piece, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); return true; } VillagePieces::LightPost::LightPost() { // for reflection } VillagePieces::LightPost::LightPost(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *box, int direction) : VillagePiece(startPiece, genDepth) { heightPosition = -1; // 4J - added initialiser orientation = direction; boundingBox = box; } BoundingBox *VillagePieces::LightPost::findPieceBox(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction) { StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_LightPost); BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, piece->width, piece->height, piece->depth, direction); if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != nullptr) { delete box; return nullptr; } return box; } bool VillagePieces::LightPost::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) { heightPosition = getAverageGroundHeight(level, chunkBB); if (heightPosition < 0) { return true; } boundingBox->move(0, heightPosition - boundingBox->y1 + height - 1, 0); } StructureTable *structureTable = Minecraft::GetInstance()->getStructureTable(); StructureTable::StructurePiece *piece = structureTable->getStructurePiece(eMinecraftStructurePiece_LightPost); generateStructureFromData(level, chunkBB, random, piece, objectPlacedFlags, featureConditions, tileOptionRemap, entitySpawnCounts); return true; }