fix: guardians spawn in structure

This commit is contained in:
Lord_Cambion 2026-05-05 00:13:26 +02:00
parent f313489c97
commit 5c140a95b7
17 changed files with 324 additions and 134 deletions

View file

@ -28,6 +28,9 @@
#include "../Minecraft.World/ItemEntity.h"
#include "../Minecraft.World/Arrow.h"
#include "../Minecraft.World/PrimedTnt.h"
#include "../Minecraft.World/RandomLevelSource.h"
#include "../Minecraft.World/MobCategory.h"
#include "../Minecraft.World/OceanMonumentFeature.h"
#include "../Minecraft.World/FallingTile.h"
#include "../Minecraft.World/net.minecraft.network.packet.h"
#include "../Minecraft.World/Mth.h"
@ -377,6 +380,19 @@ void ServerLevel::tick()
#endif
}
bool ServerLevel::canMobSpawnAt(MobCategory *mobCategory, Biome::MobSpawnerData *data, const BlockPos& pos)
{
RandomLevelSource *rls = dynamic_cast<RandomLevelSource*>(getChunkSource());
if (rls)
{
if (mobCategory == MobCategory::monster && rls->oceanMonument->isInsideBoundingFeature(pos.getX(), pos.getY(), pos.getZ()))
{
return true;
}
}
return false;
}
Biome::MobSpawnerData *ServerLevel::getRandomMobSpawnAt(MobCategory *mobCategory, int x, int y, int z)
{
vector<Biome::MobSpawnerData *> *mobList = getChunkSource()->getMobsAt(mobCategory, x, y, z);

View file

@ -50,6 +50,7 @@ public:
~ServerLevel();
void tick();
Biome::MobSpawnerData *getRandomMobSpawnAt(MobCategory *mobCategory, int x, int y, int z);
bool canMobSpawnAt(MobCategory *mobCategory, Biome::MobSpawnerData *data, const BlockPos& pos);
void updateSleepingPlayerList();
protected:
void awakenAllPlayers();

View file

@ -37,7 +37,8 @@ public:
virtual ChunkStorage *createStorage(File dir);
virtual bool isValidSpawn(int x, int z) const;
virtual bool isHasCeiling() const { return hasCeiling; }
virtual float getTimeOfDay(int64_t time, float a) const;
virtual int getMoonPhase(int64_t time) const;
virtual bool isNaturalDimension();

View file

@ -1,5 +1,4 @@
#pragma once
class Direction
{
public:
@ -8,68 +7,71 @@ public:
static const int WEST = 1;
static const int NORTH = 2;
static const int EAST = 3;
static const int STEP_X[];
static const int STEP_Z[];
static const wstring NAMES[];;
// for [direction] it gives [tile-face]
static const wstring NAMES[];
static int DIRECTION_FACING[];
// for [facing] it gives [direction]
static int FACING_DIRECTION[];
// for [direction] it gives [opposite direction]
static int DIRECTION_OPPOSITE[];
// for [direction] it gives [90 degrees clockwise direction]
static int DIRECTION_CLOCKWISE[];
// for [direction] it gives [90 degrees counter-clockwise direction]
static int DIRECTION_COUNTER_CLOCKWISE[];
// for [direction][world-facing] it gives [tile-facing]
static int RELATIVE_DIRECTION_FACING[4][6];
static int getDirection(double xd, double zd);
static int getDirection(int x0, int z0, int x1, int z1);
static int getStepX(int direction) {
switch (direction) {
case WEST: return -1;
case EAST: return 1;
default: return 0;
}
}
static int getStepZ(int direction) {
switch (direction) {
case NORTH: return -1;
case SOUTH: return 1;
default: return 0;
}
}
static int getStepY(int direction) {
return 0;
}
static int getStepX(int direction)
{
switch (direction) {
case WEST: return -1;
case EAST: return 1;
default: return 0;
}
}
class Plane
{
public:
static int getStepZ(int direction)
{
switch (direction) {
case NORTH: return -1;
case SOUTH: return 1;
default: return 0;
}
}
static int getRandomFace(Random* random)
{
static const int horizontal[4] = {
Direction::SOUTH,
Direction::WEST,
Direction::NORTH,
Direction::EAST
};
return horizontal[random->nextInt(4)];
}
};
static int getStepY(int direction)
{
return 0;
}
};
static int get3DDataValue(int dir6)
{
return dir6;
}
static int from3DDataValue(int val)
{
return val;
}
static int getOpposite(int dir6)
{
static const int opp[6] = { 1, 0, 3, 2, 5, 4 };
if (dir6 >= 0 && dir6 < 6)
return opp[dir6];
return dir6;
}
class Plane
{
public:
static int getRandomFace(Random* random)
{
static const int horizontal[4] = {
Direction::SOUTH,
Direction::WEST,
Direction::NORTH,
Direction::EAST
};
return horizontal[random->nextInt(4)];
}
};
};

View file

@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "com.mojang.nbt.h"
#include "net.minecraft.world.level.tile.h"
#include "net.minecraft.world.phys.h"
@ -16,6 +16,7 @@
#include "../Minecraft.World/net.minecraft.world.entity.animal.h"
#include "MobEffect.h"
#include "MobEffectInstance.h"
#include <Difficulty.h>
void Guardian::_init()
@ -34,7 +35,7 @@ void Guardian::_init()
attackTimer = 0;
}
Guardian::Guardian(Level *level) : WaterAnimal(level)
Guardian::Guardian(Level *level) : Monster(level)
{
this->defineSynchedData();
registerAttributes();
@ -52,7 +53,7 @@ Guardian::Guardian(Level *level) : WaterAnimal(level)
void Guardian::registerAttributes()
{
WaterAnimal::registerAttributes();
Monster::registerAttributes();
getAttributes()->registerAttribute(SharedMonsterAttributes::ATTACK_DAMAGE);
getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(6.0);
getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.5);
@ -64,7 +65,7 @@ void Guardian::registerAttributes()
void Guardian::defineSynchedData()
{
WaterAnimal::defineSynchedData();
Monster::defineSynchedData();
entityData->define(16, (byte)0);
entityData->define(17, 0);
}
@ -75,13 +76,13 @@ void Guardian::defineSynchedData()
void Guardian::readAdditionalSaveData(CompoundTag *tag)
{
WaterAnimal::readAdditionalSaveData(tag);
Monster::readAdditionalSaveData(tag);
setElder(tag->getBoolean(L"Elder"));
}
void Guardian::addAdditonalSaveData(CompoundTag *tag)
{
WaterAnimal::addAdditonalSaveData(tag);
Monster::addAdditonalSaveData(tag);
tag->putBoolean(L"Elder", isElder());
}
@ -202,13 +203,6 @@ float Guardian::getSpikesAnimation(float partialTicks)
void Guardian::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel)
{
//loot (prismarine, sponge)
}
float Guardian::getEyeHeight()
{
return bbHeight * 0.5f;
@ -254,7 +248,7 @@ void Guardian::lookAt(shared_ptr<Entity> e, float yMax, float xMax)
void Guardian::serverAiStep()
{
WaterAnimal::serverAiStep();
Monster::serverAiStep();
if (isElder() && !level->isClientSide)
{
@ -348,7 +342,16 @@ void Guardian::serverAiStep()
{
float angle = random->nextFloat() * (float)PI * 2.0f;
tx = Mth::cos(angle) * 0.2f;
ty = -0.1f + random->nextFloat() * 0.2f;
if (isElder()) {
ty = -0.15f + random->nextFloat() * 0.15f;
} else {
ty = -0.1f + random->nextFloat() * 0.2f;
}
tz = Mth::sin(angle) * 0.2f;
noActionTime = 0;
}
@ -437,7 +440,7 @@ void Guardian::aiStep()
xBodyRotO = xBodyRot;
zBodyRotO = zBodyRot;
WaterAnimal::aiStep();
Monster::aiStep();
}
void Guardian::updateSize(bool elder)
@ -458,10 +461,11 @@ void Guardian::travel(float xa, float ya)
xd *= 0.9f;
yd *= 0.9f;
zd *= 0.9f;
yd -= 0.02f;
}
else
{
WaterAnimal::travel(xa, ya);
Monster::travel(xa, ya);
}
}
else
@ -473,10 +477,11 @@ void Guardian::travel(float xa, float ya)
xd *= 0.9f;
yd *= 0.9f;
zd *= 0.9f;
yd -= 0.02f;
}
else
{
WaterAnimal::travel(xa, ya);
Monster::travel(xa, ya);
}
}
@ -484,7 +489,7 @@ void Guardian::travel(float xa, float ya)
MobGroupData *Guardian::finalizeMobSpawn(MobGroupData *groupData, int extraData)
{
WaterAnimal::finalizeMobSpawn(groupData, extraData);
Monster::finalizeMobSpawn(groupData, extraData);
if (extraData == 1)
setElder(true);
return groupData;
@ -508,7 +513,7 @@ void Guardian::handleEntityEvent(byte eventId)
}
}
WaterAnimal::handleEntityEvent(eventId);
Monster::handleEntityEvent(eventId);
}
int Guardian::getAmbientSound()
@ -621,7 +626,60 @@ float Guardian::getSoundVolume()
return 1.0f;
}
int Guardian::getDeathLoot()
bool Guardian::removeWhenFarAway()
{
return 0;
return !isElder();
}
void Guardian::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel)
{
int shards = 2 + random->nextInt(2);
spawnAtLocation(Item::prismarine_shard_Id, shards, 0.5f);
int crystals = random->nextInt(2);
if (crystals > 0)
spawnAtLocation(Item::prismarine_cystal_Id, crystals, 0.5f);
spawnAtLocation(Item::fish_raw_Id, 1, 0.5f);
if (isElder())
{
spawnAtLocation(Tile::sponge_Id, 1, 0.5f);
}
if (wasKilledByPlayer)
{
level->addEntity(std::make_shared<ExperienceOrb>(
level, x, y, z,
isElder() ? 10 : 5));
}
}
bool Guardian::canSpawn()
{
if (level->difficulty == Difficulty::PEACEFUL)
return false;
bool bypassSky = random->nextInt(20) == 0;
if (!bypassSky)
{
int bx = Mth::floor(x);
int by = Mth::floor(y);
int bz = Mth::floor(z);
if (level->canSeeSkyFromBelowWater(bx, by, bz))
return false;
}
if (!isInWater())
return false;
return level->isUnobstructed(bb) && level->getCubes(shared_from_this(), bb)->empty();
}

View file

@ -1,11 +1,11 @@
#pragma once
using namespace std;
#include "WaterAnimal.h"
#include "Monster.h"
class Level;
class Player;
class Guardian : public WaterAnimal
class Guardian : public Monster
{
public:
eINSTANCEOF GetType() { return eTYPE_GUARDIAN; }
@ -34,12 +34,12 @@ protected:
virtual int getHurtSound();
virtual int getDeathSound();
virtual float getSoundVolume();
virtual int getDeathLoot();
virtual bool makeStepSound();
void playFlopSound();
void playAttackSound();
void playCurseSound();
virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel);
virtual bool removeWhenFarAway();
virtual void serverAiStep();
public:
@ -57,6 +57,8 @@ public:
bool isMoving();
void setMoving(bool moving);
virtual bool canSpawn();
virtual bool isWaterMob() { return true; }
int getTargetedEntityId();

View file

@ -1168,6 +1168,20 @@ int Level::getDaytimeRawBrightness(int x, int y, int z)
return getChunk(x >> 4, z >> 4)->getRawBrightness(x & 15, y, z & 15, 0);
}
int Level::getDaytimeRawBrightness(const BlockPos& pos)
{
int x = pos.getX();
int y = pos.getY();
int z = pos.getZ();
if (y < 0)
return 0;
if (y >= maxBuildHeight)
y = maxBuildHeight - 1;
return getChunk(x >> 4, z >> 4)->getRawBrightness(x & 15, y, z & 15, 0);
}
int Level::getRawBrightness(int x, int y, int z)
{
@ -4810,4 +4824,42 @@ BlockPos Level::getHeightmapPos(int x, int z)
}
return BlockPos(x, 0, z);
}
bool Level::canSeeSkyFromBelowWater(int x, int y, int z)
{
if (y < 63)
{
int cx = x;
int cy = 63;
int cz = z;
if (dimension->isHasCeiling())
return false;
while (true)
{
cy--;
if (cy <= y)
break;
int tileId = getTile(cx, cy, cz);
if (Tile::lightBlock[tileId] > 0)
{
Material *mat = nullptr;
if (Tile::tiles[tileId] != nullptr)
mat = Tile::tiles[tileId]->material;
if (mat == nullptr || !mat->isLiquid())
return false;
}
}
return true;
}
else
{
return !dimension->isHasCeiling();
}
}

View file

@ -8,6 +8,7 @@ using namespace std;
#include "Definitions.h"
#include "ParticleTypes.h"
#include "Biome.h"
#include "BlockPos.h"
#include "C4JThread.h"
#ifdef __PSVITA__
@ -51,6 +52,7 @@ class Minecart;
class EntitySelector;
class Scoreboard;
class GameRules;
class BlockPos;
class Level : public LevelSource
{
@ -210,6 +212,7 @@ public:
bool reallyHasChunksAt(int x, int y, int z, int r); // 4J added
bool reallyHasChunksAt(int x0, int y0, int z0, int x1, int y1, int z1); // 4J added
BlockPos getHeightmapPos(int x, int z);
bool canSeeSkyFromBelowWater(int x, int y, int z);
public:
bool hasChunk(int x, int z);
bool reallyHasChunk(int x, int z ); // 4J added
@ -237,6 +240,7 @@ public:
virtual bool isTileToBeTickedAt(int x, int y, int z, int tileId);
bool canSeeSky(int x, int y, int z);
int getDaytimeRawBrightness(int x, int y, int z);
int getDaytimeRawBrightness(const BlockPos& pos);
int getRawBrightness(int x, int y, int z);
int getRawBrightness(int x, int y, int z, bool propagate);
bool isSkyLit(int x, int y, int z);
@ -560,4 +564,5 @@ public:
};
bool canCreateMore(eINSTANCEOF type, ESPAWN_TYPE spawnType);
};

View file

@ -14,9 +14,13 @@
#include "Level.h"
#include "ChunkPos.h"
#include "TilePos.h"
#include "BlockPos.h"
#include "net.minecraft.world.level.chunk.h"
#include "../Minecraft.Client/ServerLevel.h"
#include "MobSpawner.h"
#include "Dimension.h"
#include "OceanMonumentFeature.h"
#include "RandomLevelSource.h"
const int MobSpawner::MIN_SPAWN_DISTANCE = 24;
@ -195,6 +199,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
for (unsigned int i = 0; i < MobCategory::values.length; i++)
{
MobCategory *mobCategory = MobCategory::values[i];
if ((mobCategory->isFriendly() && !spawnFriendlies) || (!mobCategory->isFriendly() && !spawnEnemies) || (mobCategory->isPersistent() && !spawnPersistent))
{
continue;
@ -212,7 +217,8 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
// 4J - this is now quite different to the java version. We just have global max counts for the level whereas the original has a max per chunk that
// scales with the number of chunks to be polled.
int categoryCount = level->countInstanceOf( mobCategory->getEnumBaseClass(), mobCategory->isSingleType());
if( categoryCount >= mobCategory->getMaxInstancesPerLevel())
if( categoryCount >= mobCategory->getMaxInstancesPerLevel() && mobCategory != MobCategory::monster)
{
continue;
}
@ -235,13 +241,18 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
// 4J - don't let this actually create/load a chunk that isn't here already - we'll let the normal updateDirtyChunks etc. processes do that, so it can happen on another thread
if( !level->hasChunk(cp->x,cp->z) ) continue;
TilePos start = getRandomPosWithin(level, cp->x, cp->z);
int xStart = start.x;
int yStart = start.y;
int zStart = start.z;
int xStart = cp->x * 16 + level->random->nextInt(16);
int zStart = cp->z * 16 + level->random->nextInt(16);
int height = level->getChunk(cp->x, cp->z)->getHeightmap(xStart & 15, zStart & 15);
int yMax = (height + 1 + 15) & ~15;
if (yMax <= 0) yMax = 256;
int yStart = level->random->nextInt(yMax);
if (level->isSolidBlockingTile(xStart, yStart, zStart)) continue;
if (level->getMaterial(xStart, yStart, zStart) != mobCategory->getSpawnPositionMaterial()) continue;
if (level->getMaterial(xStart, yStart, zStart) != mobCategory->getSpawnPositionMaterial() &&
!(mobCategory == MobCategory::monster && level->getMaterial(xStart, yStart, zStart) == Material::water)) continue;
int clusterSize = 0;
for (int dd = 0; dd < 3; dd++)
@ -264,11 +275,18 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
// 4J - don't let this actually create/load a chunk that isn't here already - we'll let the normal updateDirtyChunks etc. processes do that, so it can happen on another thread
if( !level->hasChunkAt( x, y, z ) ) continue;
if (isSpawnPositionOk(mobCategory, level, x, y, z))
BlockPos pos(x, y, z);
if (currentMobType == nullptr)
{
currentMobType = level->getRandomMobSpawnAt(mobCategory, x, y, z);
}
if (currentMobType != nullptr && (level->canMobSpawnAt(mobCategory, currentMobType, pos) || isSpawnPositionOk(mobCategory, level, x, y, z)))
{
float xx = x + 0.5f;
float yy = static_cast<float>(y);
float zz = z + 0.5f;
if (level->getNearestPlayer(xx, yy, zz, MIN_SPAWN_DISTANCE) != nullptr)
{
continue;
@ -285,15 +303,6 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
}
}
if (currentMobType == nullptr)
{
currentMobType = level->getRandomMobSpawnAt(mobCategory, x, y, z);
if (currentMobType == nullptr)
{
break;
}
}
shared_ptr<Mob> mob;
// 4J - removed try/catch
// try
@ -316,18 +325,13 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
if( ( mobType & eTYPE_ANIMALS_SPAWN_LIMIT_CHECK ) || ( mobType & eTYPE_MONSTER ) )
{
// even more special rule for ghasts, because filling up the nether with 25 of them is a bit unpleasant. In the java version they are
// only limited by the fact that the world fills up with pig zombies (the only other type of enemy mob in the nether) before them - they
// aren't actually even counted properly themselves
if( mobType == eTYPE_GHAST )
{
if( level->countInstanceOf(mobType, true) >= 4 ) continue;
}
else if( mobType == eTYPE_ENDERMAN && level->dimension->id == 1 )
{
// Special rule for the end, as we only have Endermen (plus the dragon). Increase the spawnable counts based on level difficulty
int maxEndermen = mobCategory->getMaxInstancesPerLevel();
if( level->difficulty == Difficulty::NORMAL )
{
maxEndermen -= mobCategory->getMaxInstancesPerLevel()/4;
@ -336,7 +340,6 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie
{
maxEndermen -= mobCategory->getMaxInstancesPerLevel()/2;
}
if( level->countInstanceOf(mobType, true) >= maxEndermen ) continue;
}
else if( level->countInstanceOf(mobType, true) >= ( mobCategory->getMaxInstancesPerLevel() / 2 ) ) continue;
@ -391,6 +394,16 @@ bool MobSpawner::isSpawnPositionOk(MobCategory *category, Level *level, int x, i
}
#endif
if (category == MobCategory::monster && level->getMaterial(x, y, z) == Material::water)
{
if (level->getMaterial(x, y - 1, z)->isLiquid())
{
return !level->isSolidBlockingTile(x, y + 1, z);
}
return false;
}
if (category->getSpawnPositionMaterial() == Material::water)
{
// 4J - changed to spawn water things only in deep water
@ -403,7 +416,6 @@ bool MobSpawner::isSpawnPositionOk(MobCategory *category, Level *level, int x, i
yo++;
}
// 4J - Sometimes deep water could be just a waterfall, so check that it's wide as well
bool inEnoughWater = false;
if( liquidCount == 5 )
{
@ -425,7 +437,7 @@ bool MobSpawner::isSpawnPositionOk(MobCategory *category, Level *level, int x, i
int tt = level->getTile(x, y - 1, z);
return tt != Tile::unbreakable_Id && !level->isSolidBlockingTile(x, y, z) && !level->getMaterial(x, y, z)->isLiquid() && !level->isSolidBlockingTile(x, y + 1, z);
}
}
}
void MobSpawner::postProcessSpawnMobs(Level *level, Biome *biome, int xo, int zo, int cellWidth, int cellHeight, Random *random)
{

View file

@ -32,6 +32,7 @@ void OceanMonumentFeature::prescanNearby(int scanRadiusInGridCells)
int validated = 0;
int halfSizeChunks = this->level->getLevelData()->getXZSize() / 2;
int halfSizeBlocks = (this->level->getLevelData()->getXZSize() * 16) / 2;
app.DebugPrintf("Ocean Monument pre-scan (HalfSize: %d chunks / %d blocks)\n", halfSizeChunks, halfSizeBlocks);
for (int gz = -scanRadiusInGridCells; gz <= scanRadiusInGridCells; gz++)
@ -54,18 +55,28 @@ void OceanMonumentFeature::prescanNearby(int scanRadiusInGridCells)
int blockZ = cz * 16 + 8;
if (Mth::abs(blockX) > halfSizeBlocks || Mth::abs(blockZ) > halfSizeBlocks)
{
continue;
}
continue;
if (this->isFeatureChunk(cx, cz))
{
validated++;
int64_t key = ChunkPos::hashCode(cx, cz);
if (cachedStructures.find(key) == cachedStructures.end())
{
StructureStart *start = createStructureStart(cx, cz);
if (start != nullptr)
{
cachedStructures[key] = start;
app.DebugPrintf("prescanNearby: cached MonumentStart at chunk (%d,%d)\n", cx, cz);
}
}
}
}
}
app.DebugPrintf(" Pre-scan done: %d grid slots checked, %d validated monuments found. \n", candidates, validated);
app.DebugPrintf(" Pre-scan done: %d grid slots checked, %d validated monuments found.\n", candidates, validated);
}
bool OceanMonumentFeature::isFeatureChunk(int x, int z, bool bIsSuperflat)
@ -120,7 +131,22 @@ bool OceanMonumentFeature::isFeatureChunk(int x, int z, bool bIsSuperflat)
StructureStart* OceanMonumentFeature::createStructureStart(int x, int z)
{
if (this->level == nullptr) return nullptr;
return new MonumentStart(level, random, x, z);
MonumentStart* start = new MonumentStart(level, random, x, z);
BoundingBox* bb = start->getBoundingBox();
if (bb != nullptr)
{
app.DebugPrintf("MonumentStart BB: x0=%d y0=%d z0=%d x1=%d y1=%d z1=%d\n",
bb->x0, bb->y0, bb->z0,
bb->x1, bb->y1, bb->z1);
}
else
{
app.DebugPrintf("MonumentStart BB: NULL!\n");
}
return start;
}
OceanMonumentFeature::MonumentStart::MonumentStart() {}
@ -137,7 +163,6 @@ OceanMonumentFeature::MonumentStart::MonumentStart(Level* level, Random* random,
int startX = chunkX * 16 + 8 - 29;
int startZ = chunkZ * 16 + 8 - 29;
int facing = random->nextInt(4) + 2;
OceanMonumentPieces::MonumentBuilding* building =
@ -145,4 +170,5 @@ OceanMonumentFeature::MonumentStart::MonumentStart(Level* level, Random* random,
pieces.push_back(building);
calculateBoundingBox();
}
}

View file

@ -33,7 +33,8 @@ public:
void prescanNearby(int scanRadiusInGridCells = 8);
protected:
public:
virtual bool isFeatureChunk(int x, int z, bool bIsSuperflat = false) override;
virtual StructureStart* createStructureStart(int x, int z) override;

View file

@ -326,13 +326,13 @@ OceanMonumentPieces::MonumentBuilding::MonumentBuilding(Random* random, int x, i
p->getBoundingBox()->move(baseX, minY, baseZ);
BoundingBox* wing1BB = new BoundingBox(
BoundingBox* wing1BB = BoundingBox::fromCorners(
getWorldX(1, 1), getWorldY(1), getWorldZ(1, 1),
getWorldX(23, 21), getWorldY(8), getWorldZ(23, 21));
BoundingBox* wing2BB = new BoundingBox(
BoundingBox* wing2BB = BoundingBox::fromCorners(
getWorldX(34, 1), getWorldY(1), getWorldZ(34, 1),
getWorldX(56, 21), getWorldY(8), getWorldZ(56, 21));
BoundingBox* penthouseBB = new BoundingBox(
BoundingBox* penthouseBB = BoundingBox::fromCorners(
getWorldX(22, 22), getWorldY(13), getWorldZ(22, 22),
getWorldX(35, 35), getWorldY(17), getWorldZ(35, 35));
@ -1612,7 +1612,7 @@ bool OceanMonumentPieces::WingRoom::postProcess(Level* level, Random* random, Bo
generateBox(level, chunkBB, 6, 0, 21, 7, 4, 21, Tile::prismarine_Id, blockPrismarineBricks(),Tile::prismarine_Id, blockPrismarineBricks(), false);
generateBox(level, chunkBB, 15, 0, 21, 16, 4, 21, Tile::prismarine_Id, blockPrismarineBricks(),Tile::prismarine_Id, blockPrismarineBricks(), false);
spawnElderGuardian(level, chunkBB, 11, 2, 16);
spawnElderGuardian(level, chunkBB, 11, 5, 16);
}
else // wingType == 1
{

View file

@ -144,7 +144,7 @@ public:
class MonumentBuilding : public Piece
{
private:
public:
static const int ARRAY_SIZE = 75; // 5*5*3
RoomDefinition* entryRoom; // field_175845_o
RoomDefinition* coreRoom; // field_175844_p

View file

@ -20,4 +20,7 @@ public:
float nextFloat();
int64_t nextLong();
bool nextBoolean();
static int nextInt(Random* r, int n) { return r->nextInt(n); }
static bool nextBoolean(Random* r) { return r->nextBoolean(); }
static long long nextLong(Random* r) { return r->nextLong(); }
};

View file

@ -15,6 +15,8 @@
#ifdef __PS3__
#include "../Minecraft.Client/PS3/SPU_Tasks/PerlinNoise/PerlinNoiseJob.h"
#include "C4JSpursJob.h"
#include <OceanMonumentFeature.cpp>
#include <OceanMonumentFeature.cpp>
static PerlinNoise_DataIn g_lperlinNoise1_SPU __attribute__((__aligned__(16)));
static PerlinNoise_DataIn g_lperlinNoise2_SPU __attribute__((__aligned__(16)));
static PerlinNoise_DataIn g_perlinNoise1_SPU __attribute__((__aligned__(16)));
@ -841,23 +843,21 @@ wstring RandomLevelSource::gatherStats()
vector<Biome::MobSpawnerData *> *RandomLevelSource::getMobsAt(MobCategory *mobCategory, int x, int y, int z)
{
Biome *biome = level->getBiome(x, z);
if (biome == nullptr)
{
return nullptr;
}
if (mobCategory == MobCategory::monster)
{
if (scatteredFeature->isSwamphut(x, y, z))
{
return scatteredFeature->getSwamphutEnemies();
}
if (oceanMonument->isInsideFeature(x, y, z))
{
Biome *biome = level->getBiome(x, z);
if (biome == nullptr)
return nullptr;
if (mobCategory == MobCategory::monster)
{
if (scatteredFeature->isSwamphut(x, y, z))
return scatteredFeature->getSwamphutEnemies();
if (oceanMonument->isInsideBoundingFeature(x, y, z))
return oceanMonument->getMonumentEnemies();
}
}
return biome->getMobs(mobCategory);
}
return biome->getMobs(mobCategory);
}
TilePos *RandomLevelSource::findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z)
@ -878,4 +878,4 @@ void RandomLevelSource::recreateLogicStructuresForChunk(int chunkX, int chunkZ)
strongholdFeature->apply(this, level, chunkX, chunkZ, byteArray());
scatteredFeature->apply(this, level, chunkX, chunkZ, byteArray());
}
}
}

View file

@ -2,6 +2,7 @@
using namespace std;
#include "ChunkSource.h"
#include "OceanMonumentFeature.h"
class ProgressListener;
class LargeFeature;
@ -62,7 +63,7 @@ public:
public:
void buildSurfaces(int xOffs, int zOffs, byteArray blocks, byteArray blockData, BiomeArray biomes);
private:
public:
LargeFeature *caveFeature;
StrongholdFeature *strongholdFeature;
VillageFeature *villageFeature;
@ -97,4 +98,5 @@ public:
virtual vector<Biome::MobSpawnerData *> *getMobsAt(MobCategory *mobCategory, int x, int y, int z);
virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z);
virtual void recreateLogicStructuresForChunk(int chunkX, int chunkZ);
};

View file

@ -132,6 +132,9 @@ StructureStart *StructureFeature::getStructureAt(int cellX, int cellY, int cellZ
*/
list<StructurePiece *> *pieces=pStructureStart->getPieces();
for (auto& piece : *pieces)
{
if ( piece->getBoundingBox()->isInside(cellX, cellY, cellZ) )
@ -154,7 +157,13 @@ bool StructureFeature::isInsideBoundingFeature(int cellX, int cellY, int cellZ)
StructureStart *structureStart = it.second;
if (structureStart->isValid())
{
return (structureStart->getBoundingBox()->intersects(cellX, cellZ, cellX, cellZ));
BoundingBox* bb = structureStart->getBoundingBox();
if (cellX >= bb->x0 && cellX <= bb->x1 &&
cellY >= bb->y0 && cellY <= bb->y1 &&
cellZ >= bb->z0 && cellZ <= bb->z1)
{
return true;
}
}
}
return false;