4jcraft/Minecraft.World/WorldGen/Features/VillageFeature.cpp
MatthewBeshay a0fdc643d1 Merge branch 'upstream-dev' into cleanup/nullptr-replacement
# Conflicts:
#	Minecraft.Client/Network/PlayerChunkMap.cpp
#	Minecraft.Client/Network/PlayerList.cpp
#	Minecraft.Client/Network/ServerChunkCache.cpp
#	Minecraft.Client/Platform/Common/Consoles_App.cpp
#	Minecraft.Client/Platform/Common/DLC/DLCManager.cpp
#	Minecraft.Client/Platform/Common/GameRules/LevelGenerationOptions.cpp
#	Minecraft.Client/Platform/Common/GameRules/LevelRuleset.cpp
#	Minecraft.Client/Platform/Common/Tutorial/Tutorial.cpp
#	Minecraft.Client/Platform/Common/Tutorial/TutorialTask.cpp
#	Minecraft.Client/Platform/Common/UI/IUIScene_CreativeMenu.cpp
#	Minecraft.Client/Platform/Common/UI/UIComponent_Panorama.cpp
#	Minecraft.Client/Platform/Common/UI/UIController.cpp
#	Minecraft.Client/Platform/Common/UI/UIController.h
#	Minecraft.Client/Platform/Extrax64Stubs.cpp
#	Minecraft.Client/Platform/Windows64/4JLibs/inc/4J_Input.h
#	Minecraft.Client/Platform/Windows64/4JLibs/inc/4J_Storage.h
#	Minecraft.Client/Player/EntityTracker.cpp
#	Minecraft.Client/Player/ServerPlayer.cpp
#	Minecraft.Client/Rendering/EntityRenderers/PlayerRenderer.cpp
#	Minecraft.Client/Textures/Packs/DLCTexturePack.cpp
#	Minecraft.Client/Textures/Stitching/StitchedTexture.cpp
#	Minecraft.Client/Textures/Stitching/TextureMap.cpp
#	Minecraft.Client/Textures/Textures.cpp
#	Minecraft.World/Blocks/NotGateTile.cpp
#	Minecraft.World/Blocks/PressurePlateTile.cpp
#	Minecraft.World/Blocks/TileEntities/PotionBrewing.cpp
#	Minecraft.World/Enchantments/EnchantmentHelper.cpp
#	Minecraft.World/Entities/HangingEntity.cpp
#	Minecraft.World/Entities/LeashFenceKnotEntity.cpp
#	Minecraft.World/Entities/LivingEntity.cpp
#	Minecraft.World/Entities/Mobs/Boat.cpp
#	Minecraft.World/Entities/Mobs/Minecart.cpp
#	Minecraft.World/Entities/Mobs/Witch.cpp
#	Minecraft.World/Entities/SyncedEntityData.cpp
#	Minecraft.World/Items/LeashItem.cpp
#	Minecraft.World/Items/PotionItem.cpp
#	Minecraft.World/Level/BaseMobSpawner.cpp
#	Minecraft.World/Level/CustomLevelSource.cpp
#	Minecraft.World/Level/Level.cpp
#	Minecraft.World/Level/Storage/DirectoryLevelStorage.cpp
#	Minecraft.World/Level/Storage/McRegionLevelStorage.cpp
#	Minecraft.World/Level/Storage/RegionFileCache.cpp
#	Minecraft.World/Player/Player.cpp
#	Minecraft.World/WorldGen/Biomes/BiomeCache.cpp
#	Minecraft.World/WorldGen/Features/RandomScatteredLargeFeature.cpp
#	Minecraft.World/WorldGen/Layers/BiomeOverrideLayer.cpp
2026-03-30 16:28:40 +11:00

175 lines
5.8 KiB
C++

#include "../../Platform/stdafx.h"
#include "VillageFeature.h"
#include "../Structures/VillagePieces.h"
#include "../../Headers/net.minecraft.world.level.h"
#include "../../Headers/net.minecraft.world.level.biome.h"
#include "../../Headers/net.minecraft.world.level.dimension.h"
const std::wstring VillageFeature::OPTION_SIZE_MODIFIER = L"size";
const std::wstring VillageFeature::OPTION_SPACING = L"distance";
std::vector<Biome*> VillageFeature::allowedBiomes;
void VillageFeature::staticCtor() {
allowedBiomes.push_back(Biome::plains);
allowedBiomes.push_back(Biome::desert);
}
void VillageFeature::_init(int iXZSize) {
villageSizeModifier = 0;
townSpacing = 32;
minTownSeparation = 8;
m_iXZSize = iXZSize;
}
VillageFeature::VillageFeature(int iXZSize) { _init(iXZSize); }
VillageFeature::VillageFeature(
std::unordered_map<std::wstring, std::wstring> options, int iXZSize) {
_init(iXZSize);
for (auto it = options.begin(); it != options.end(); ++it) {
if (it->first.compare(OPTION_SIZE_MODIFIER) == 0) {
villageSizeModifier =
Mth::getInt(it->second, villageSizeModifier, 0);
} else if (it->first.compare(OPTION_SPACING) == 0) {
townSpacing =
Mth::getInt(it->second, townSpacing, minTownSeparation + 1);
}
}
}
std::wstring VillageFeature::getFeatureName() { return L"Village"; }
bool VillageFeature::isFeatureChunk(int x, int z, bool bIsSuperflat) {
int townSpacing = this->townSpacing;
if (!bIsSuperflat
#ifdef _LARGE_WORLDS
&& level->dimension->getXZSize() < 128
#endif
) {
townSpacing = 16; // 4J change 32;
}
int xx = x;
int zz = z;
if (x < 0) x -= townSpacing - 1;
if (z < 0) z -= townSpacing - 1;
int xCenterTownChunk = x / townSpacing;
int zCenterTownChunk = z / townSpacing;
Random* r =
level->getRandomFor(xCenterTownChunk, zCenterTownChunk, 10387312);
xCenterTownChunk *= townSpacing;
zCenterTownChunk *= townSpacing;
xCenterTownChunk += r->nextInt(townSpacing - minTownSeparation);
zCenterTownChunk += r->nextInt(townSpacing - minTownSeparation);
x = xx;
z = zz;
bool forcePlacement = false;
LevelGenerationOptions* levelGenOptions = app.getLevelGenerationOptions();
if (levelGenOptions != nullptr) {
forcePlacement =
levelGenOptions->isFeatureChunk(x, z, eFeature_Village);
}
if (forcePlacement || (x == xCenterTownChunk && z == zCenterTownChunk)) {
bool biomeOk = level->getBiomeSource()->containsOnly(
x * 16 + 8, z * 16 + 8, 0, allowedBiomes);
if (biomeOk) {
// app.DebugPrintf("Biome ok for Village at %d, %d\n",(x * 16 +
// 8),(z * 16 + 8));
return true;
}
}
return false;
}
StructureStart* VillageFeature::createStructureStart(int x, int z) {
// 4J added
app.AddTerrainFeaturePosition(eTerrainFeature_Village, x, z);
return new VillageStart(level, random, x, z, villageSizeModifier,
m_iXZSize);
}
VillageFeature::VillageStart::VillageStart() {
valid = false; // 4J added initialiser
m_iXZSize = 0;
// for reflection
}
VillageFeature::VillageStart::VillageStart(Level* level, Random* random,
int chunkX, int chunkZ,
int villageSizeModifier,
int iXZSize) {
valid = false; // 4J added initialiser
m_iXZSize = iXZSize;
std::list<VillagePieces::PieceWeight*>* pieceSet =
VillagePieces::createPieceSet(random, villageSizeModifier);
// 4jcraft added casts to u
VillagePieces::StartPiece* startRoom = new VillagePieces::StartPiece(
level->getBiomeSource(), 0, random, ((unsigned)chunkX << 4) + 2,
((unsigned)chunkZ << 4) + 2, pieceSet, villageSizeModifier, level);
pieces.push_back(startRoom);
startRoom->addChildren(startRoom, &pieces, random);
std::vector<StructurePiece*>* pendingRoads = &startRoom->pendingRoads;
std::vector<StructurePiece*>* pendingHouses = &startRoom->pendingHouses;
while (!pendingRoads->empty() || !pendingHouses->empty()) {
// prioritize roads
if (pendingRoads->empty()) {
int pos = random->nextInt((int)pendingHouses->size());
auto it = pendingHouses->begin() + pos;
StructurePiece* structurePiece = *it;
pendingHouses->erase(it);
structurePiece->addChildren(startRoom, &pieces, random);
} else {
int pos = random->nextInt((int)pendingRoads->size());
auto it = pendingRoads->begin() + pos;
StructurePiece* structurePiece = *it;
pendingRoads->erase(it);
structurePiece->addChildren(startRoom, &pieces, random);
}
}
calculateBoundingBox();
int count = 0;
for (auto it = pieces.begin(); it != pieces.end(); it++) {
StructurePiece* piece = *it;
if (dynamic_cast<VillagePieces::VillageRoadPiece*>(piece) == nullptr) {
count++;
}
}
valid = count > 2;
}
bool VillageFeature::VillageStart::isValid() {
// 4J-PB - Adding a bounds check to ensure a village isn't over the edge of
// our world - we end up with half houses in that case
if ((boundingBox->x0 < (-m_iXZSize / 2)) ||
(boundingBox->x1 > (m_iXZSize / 2)) ||
(boundingBox->z0 < (-m_iXZSize / 2)) ||
(boundingBox->z1 > (m_iXZSize / 2))) {
valid = false;
}
return valid;
}
void VillageFeature::VillageStart::addAdditonalSaveData(CompoundTag* tag) {
StructureStart::addAdditonalSaveData(tag);
tag->putBoolean(L"Valid", valid);
}
void VillageFeature::VillageStart::readAdditonalSaveData(CompoundTag* tag) {
StructureStart::readAdditonalSaveData(tag);
valid = tag->getBoolean(L"Valid");
}