1
0

Fixing Mob spawner behaviour (#4930)

* fixed mob spawner failure (whoopsie in the BlockEntity.GetChunkZ())
Style

* fixed spawning behaviour

* fixed saving entity type saving

* checkstyle

* removed debug log

* removed short saving

* Style

Co-authored-by: 12xx12 <12xx12100@gmail.com>
Co-authored-by: Tiger Wang <ziwei.tiger@outlook.com>
This commit is contained in:
12xx12 2020-09-27 19:02:16 +02:00 committed by GitHub
parent c158569af3
commit 410d6c0045
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 137 additions and 143 deletions

View File

@ -122,7 +122,7 @@ public:
cWorld * GetWorld() const { return m_World; }
int GetChunkX() const { return FAST_FLOOR_DIV(m_Pos.x, cChunkDef::Width); }
int GetChunkZ() const { return FAST_FLOOR_DIV(m_Pos.y, cChunkDef::Width); }
int GetChunkZ() const { return FAST_FLOOR_DIV(m_Pos.z, cChunkDef::Width); }
int GetRelX() const { return m_RelX; }
int GetRelZ() const { return m_RelZ; }

View File

@ -124,14 +124,13 @@ void cMobSpawnerEntity::ResetTimer(void)
void cMobSpawnerEntity::SpawnEntity(void)
{
int NearbyEntities = GetNearbyMonsterNum(m_Entity);
auto NearbyEntities = GetNearbyMonsterNum(m_Entity);
if (NearbyEntities >= 6)
{
ResetTimer();
return;
}
auto MobType = m_Entity;
bool EntitiesSpawned = m_World->DoWithChunk(GetChunkX(), GetChunkZ(), [&](cChunk & a_Chunk)
{
auto & Random = GetRandomProvider();
@ -144,38 +143,34 @@ void cMobSpawnerEntity::SpawnEntity(void)
break;
}
Vector3i spawnRelPos(GetRelPos());
spawnRelPos += Vector3i(
auto SpawnRelPos(GetRelPos());
SpawnRelPos += Vector3i(
static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * 4.0),
Random.RandInt(-1, 1),
static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * 4.0)
);
auto chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(spawnRelPos);
if ((chunk == nullptr) || !chunk->IsValid())
auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(SpawnRelPos);
if ((Chunk == nullptr) || !Chunk->IsValid())
{
continue;
}
EMCSBiome Biome = chunk->GetBiomeAt(spawnRelPos.x, spawnRelPos.z);
EMCSBiome Biome = Chunk->GetBiomeAt(SpawnRelPos.x, SpawnRelPos.z);
if (cMobSpawner::CanSpawnHere(chunk, spawnRelPos, MobType, Biome))
if (cMobSpawner::CanSpawnHere(Chunk, SpawnRelPos, m_Entity, Biome, true))
{
auto absPos = chunk->RelativeToAbsolute(spawnRelPos);
auto monster = cMonster::NewMonsterFromType(MobType);
if (monster == nullptr)
auto AbsPos = Chunk->RelativeToAbsolute(SpawnRelPos);
auto Monster = cMonster::NewMonsterFromType(m_Entity);
if (Monster == nullptr)
{
continue;
}
monster->SetPosition(absPos);
monster->SetYaw(Random.RandReal(360.0f));
if (chunk->GetWorld()->SpawnMobFinalize(std::move(monster)) != cEntity::INVALID_ID)
Monster->SetPosition(AbsPos);
Monster->SetYaw(Random.RandReal(360.0f));
if (Chunk->GetWorld()->SpawnMobFinalize(std::move(Monster)) != cEntity::INVALID_ID)
{
HaveSpawnedEntity = true;
m_World->BroadcastSoundParticleEffect(
EffectID::PARTICLE_MOBSPAWN,
absPos,
0
);
m_World->BroadcastSoundParticleEffect(EffectID::PARTICLE_MOBSPAWN, AbsPos, 0);
NearbyEntities++;
}
}

View File

@ -72,7 +72,7 @@ eMonsterType cMobSpawner::ChooseMobType(EMCSBiome a_Biome)
bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType a_MobType, EMCSBiome a_Biome)
bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType a_MobType, EMCSBiome a_Biome, bool a_DisableSolidBelowCheck)
{
if (a_Chunk == nullptr)
{
@ -88,59 +88,50 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType
return false; // Make sure mobs do not spawn on bedrock.
}
auto & random = GetRandomProvider();
auto targetBlock = a_Chunk->GetBlock(a_RelPos);
auto & Random = GetRandomProvider();
auto TargetBlock = a_Chunk->GetBlock(a_RelPos);
// If too close to any player, don't spawn anything
auto absPos = a_Chunk->RelativeToAbsolute(a_RelPos);
static const double rangeLimit = 24;
if (a_Chunk->GetWorld()->DoWithNearestPlayer(absPos, rangeLimit, [](cPlayer & a_Player) -> bool
{
return true;
})
)
{
return false;
}
auto BlockLight = a_Chunk->GetBlockLight(a_RelPos);
auto SkyLight = a_Chunk->GetSkyLight(a_RelPos);
auto BlockAbove = a_Chunk->GetBlock(a_RelPos.addedY(1));
auto BlockBelow = a_Chunk->GetBlock(a_RelPos.addedY(-1));
auto blockLight = a_Chunk->GetBlockLight(a_RelPos);
auto skyLight = a_Chunk->GetSkyLight(a_RelPos);
auto blockAbove = a_Chunk->GetBlock(a_RelPos.addedY(1));
auto blockBelow = a_Chunk->GetBlock(a_RelPos.addedY(-1));
skyLight = a_Chunk->GetTimeAlteredLight(skyLight);
SkyLight = a_Chunk->GetTimeAlteredLight(SkyLight);
switch (a_MobType)
{
case mtBat:
{
return (
return
(
(a_RelPos.y <= 63) &&
(blockLight <= 4) &&
(skyLight <= 4) &&
(targetBlock == E_BLOCK_AIR) &&
(!cBlockInfo::IsTransparent(blockAbove))
(BlockLight <= 4) &&
(SkyLight <= 4) &&
(TargetBlock == E_BLOCK_AIR) &&
(!cBlockInfo::IsTransparent(BlockAbove))
);
}
case mtBlaze:
{
return (
(targetBlock == E_BLOCK_AIR) &&
(blockAbove == E_BLOCK_AIR) &&
(!cBlockInfo::IsTransparent(blockBelow)) &&
(random.RandBool())
return
(
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
((!cBlockInfo::IsTransparent(BlockBelow)) || (a_DisableSolidBelowCheck)) &&
(Random.RandBool())
);
}
case mtCaveSpider:
{
return (
(targetBlock == E_BLOCK_AIR) &&
(!cBlockInfo::IsTransparent(blockBelow)) &&
(skyLight <= 7) &&
(blockLight <= 7) &&
(random.RandBool())
return
(
(TargetBlock == E_BLOCK_AIR) &&
((!cBlockInfo::IsTransparent(BlockBelow)) || (a_DisableSolidBelowCheck)) &&
(SkyLight <= 7) &&
(BlockLight <= 7) &&
(Random.RandBool())
);
}
@ -151,11 +142,12 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType
case mtRabbit:
case mtSheep:
{
return (
(targetBlock == E_BLOCK_AIR) &&
(blockAbove == E_BLOCK_AIR) &&
(blockBelow == E_BLOCK_GRASS) &&
(skyLight >= 9)
return
(
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
(BlockBelow == E_BLOCK_GRASS) &&
(SkyLight >= 9)
);
}
@ -163,13 +155,14 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType
case mtSkeleton:
case mtZombie:
{
return (
(targetBlock == E_BLOCK_AIR) &&
(blockAbove == E_BLOCK_AIR) &&
(!cBlockInfo::IsTransparent(blockBelow)) &&
(skyLight <= 7) &&
(blockLight <= 7) &&
(random.RandBool())
return
(
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
((!cBlockInfo::IsTransparent(BlockBelow)) || (a_DisableSolidBelowCheck)) &&
(SkyLight <= 7) &&
(BlockLight <= 7) &&
(Random.RandBool())
);
}
@ -181,13 +174,14 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType
if (blockTop == E_BLOCK_AIR)
{
blockTop = a_Chunk->GetBlock(a_RelPos.addedY(3));
return (
(targetBlock == E_BLOCK_AIR) &&
(blockAbove == E_BLOCK_AIR) &&
return
(
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
(blockTop == E_BLOCK_AIR) &&
(!cBlockInfo::IsTransparent(blockBelow)) &&
(skyLight <= 7) &&
(blockLight <= 7)
((!cBlockInfo::IsTransparent(BlockBelow)) || (a_DisableSolidBelowCheck)) &&
(SkyLight <= 7) &&
(BlockLight <= 7)
);
}
}
@ -196,18 +190,20 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType
case mtGhast:
{
return (
(targetBlock == E_BLOCK_AIR) &&
(blockAbove == E_BLOCK_AIR) &&
(random.RandBool(0.01))
return
(
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
(Random.RandBool(0.01))
);
}
case mtGuardian:
{
return (
IsBlockWater(targetBlock) &&
IsBlockWater(blockBelow) &&
return
(
IsBlockWater(TargetBlock) &&
IsBlockWater(BlockBelow) &&
(a_RelPos.y >= 45) &&
(a_RelPos.y <= 62)
);
@ -216,22 +212,22 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType
case mtMagmaCube:
case mtSlime:
{
return (
(targetBlock == E_BLOCK_AIR) &&
(blockAbove == E_BLOCK_AIR) &&
(!cBlockInfo::IsTransparent(blockBelow)) &&
(
(a_RelPos.y <= 40) || (a_Biome == biSwampland)
)
return
(
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
((!cBlockInfo::IsTransparent(BlockBelow)) || (a_DisableSolidBelowCheck)) &&
((a_RelPos.y <= 40) || (a_Biome == biSwampland))
);
}
case mtMooshroom:
{
return (
(targetBlock == E_BLOCK_AIR) &&
(blockAbove == E_BLOCK_AIR) &&
(blockBelow == E_BLOCK_MYCELIUM) &&
return
(
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
(BlockBelow == E_BLOCK_MYCELIUM) &&
(
(a_Biome == biMushroomShore) ||
(a_Biome == biMushroomIsland)
@ -242,46 +238,46 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType
case mtOcelot:
{
return (
(targetBlock == E_BLOCK_AIR) &&
(blockAbove == E_BLOCK_AIR) &&
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
(
(blockBelow == E_BLOCK_GRASS) || (blockBelow == E_BLOCK_LEAVES) || (blockBelow == E_BLOCK_NEW_LEAVES)
(BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES) || (BlockBelow == E_BLOCK_NEW_LEAVES)
) &&
(a_RelPos.y >= 62) &&
(random.RandBool(2.0 / 3.0))
(Random.RandBool(2.0 / 3.0))
);
}
case mtSpider:
{
bool canSpawn = true;
bool hasFloor = false;
bool CanSpawn = true;
bool HasFloor = false;
for (int x = 0; x < 2; ++x)
{
for (int z = 0; z < 2; ++z)
{
canSpawn = a_Chunk->UnboundedRelGetBlockType(a_RelPos.addedXZ(x, z), targetBlock);
canSpawn = canSpawn && (targetBlock == E_BLOCK_AIR);
if (!canSpawn)
CanSpawn = a_Chunk->UnboundedRelGetBlockType(a_RelPos.addedXZ(x, z), TargetBlock);
CanSpawn = CanSpawn && (TargetBlock == E_BLOCK_AIR);
if (!CanSpawn)
{
return false;
}
hasFloor = (
hasFloor ||
HasFloor = (
HasFloor ||
(
a_Chunk->UnboundedRelGetBlockType(a_RelPos + Vector3i(x, -1, z), targetBlock) &&
!cBlockInfo::IsTransparent(targetBlock)
a_Chunk->UnboundedRelGetBlockType(a_RelPos + Vector3i(x, -1, z), TargetBlock) &&
!cBlockInfo::IsTransparent(TargetBlock)
)
);
}
}
return canSpawn && hasFloor && (skyLight <= 7) && (blockLight <= 7);
return CanSpawn && HasFloor && (SkyLight <= 7) && (BlockLight <= 7);
}
case mtSquid:
{
return (
IsBlockWater(targetBlock) &&
IsBlockWater(TargetBlock) &&
(a_RelPos.y >= 45) &&
(a_RelPos.y <= 62)
);
@ -290,20 +286,20 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType
case mtWitherSkeleton:
{
return (
(targetBlock == E_BLOCK_AIR) &&
(blockAbove == E_BLOCK_AIR) &&
(!cBlockInfo::IsTransparent(blockBelow)) &&
(skyLight <= 7) &&
(blockLight <= 7) &&
(random.RandBool(0.6))
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
((!cBlockInfo::IsTransparent(BlockBelow)) || (a_DisableSolidBelowCheck)) &&
(SkyLight <= 7) &&
(BlockLight <= 7) &&
(Random.RandBool(0.6))
);
}
case mtWolf:
{
return (
(targetBlock == E_BLOCK_GRASS) &&
(blockAbove == E_BLOCK_AIR) &&
(TargetBlock == E_BLOCK_GRASS) &&
(BlockAbove == E_BLOCK_AIR) &&
(
(a_Biome == biColdTaiga) ||
(a_Biome == biColdTaigaHills) ||
@ -321,9 +317,9 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType
case mtZombiePigman:
{
return (
(targetBlock == E_BLOCK_AIR) &&
(blockAbove == E_BLOCK_AIR) &&
(!cBlockInfo::IsTransparent(blockBelow))
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
((!cBlockInfo::IsTransparent(BlockBelow)) || (a_DisableSolidBelowCheck))
);
}
@ -467,6 +463,23 @@ std::set<eMonsterType> cMobSpawner::GetAllowedMobTypes(EMCSBiome a_Biome)
cMonster * cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, EMCSBiome a_Biome, int & a_MaxPackSize)
{
// If too close to any player, don't spawn anything
auto AbsPos = a_Chunk->RelativeToAbsolute(a_RelPos);
static const double RangeLimit = 24;
if (
a_Chunk->GetWorld()->DoWithNearestPlayer(
AbsPos,
RangeLimit,
[](cPlayer & a_Player)
{
return true;
}
)
)
{
return nullptr;
}
if (m_NewPack)
{
m_MobType = ChooseMobType(a_Biome);
@ -494,11 +507,11 @@ cMonster * cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, EMCS
if ((m_AllowedTypes.find(m_MobType) != m_AllowedTypes.end()) && CanSpawnHere(a_Chunk, a_RelPos, m_MobType, a_Biome))
{
auto newMob = cMonster::NewMonsterFromType(m_MobType);
auto NewMobPtr = newMob.get();
if (newMob)
auto NewMob = cMonster::NewMonsterFromType(m_MobType);
auto NewMobPtr = NewMob.get();
if (NewMob)
{
m_Spawned.push_back(std::move(newMob));
m_Spawned.push_back(std::move(NewMob));
}
return NewMobPtr;
}

View File

@ -43,7 +43,7 @@ public :
}
/** Returns true if specified type of mob can spawn on specified block */
static bool CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType a_MobType, EMCSBiome a_Biome);
static bool CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType a_MobType, EMCSBiome a_Biome, bool a_DisableSolidBelowCheck = false);
/** Returns all mob types that can spawn that biome */
static std::set<eMonsterType> GetAllowedMobTypes(EMCSBiome a_Biome);

View File

@ -546,7 +546,6 @@ public:
{
mWriter.BeginCompound("");
AddBasicTileEntity(a_MobSpawner, "MobSpawner");
mWriter.AddShort("Entity", static_cast<short>(a_MobSpawner->GetEntity()));
mWriter.AddString("EntityId", cMonster::MobTypeToVanillaName(a_MobSpawner->GetEntity()));
mWriter.AddShort("Delay", a_MobSpawner->GetSpawnDelay());
mWriter.EndCompound();

View File

@ -1338,27 +1338,14 @@ OwnedBlockEntity cWSSAnvil::LoadMobSpawnerFromNBT(const cParsedNBT & a_NBT, int
auto MobSpawner = std::make_unique<cMobSpawnerEntity>(a_BlockType, a_BlockMeta, a_Pos, m_World);
// Load entity (Cuberite worlds):
int Type = a_NBT.FindChildByName(a_TagIdx, "Entity");
if ((Type >= 0) && (a_NBT.GetType(Type) == TAG_Short))
// Load entity type
int Type = a_NBT.FindChildByName(a_TagIdx, "EntityId");
if ((Type >= 0) && (a_NBT.GetType(Type) == TAG_String))
{
short MonsterType = a_NBT.GetShort(Type);
if ((MonsterType >= 50) && (MonsterType <= 120))
eMonsterType MonsterType = cMonster::StringToMobType(a_NBT.GetString(Type));
if (MonsterType != eMonsterType::mtInvalidType)
{
MobSpawner->SetEntity(static_cast<eMonsterType>(MonsterType));
}
}
else
{
// Load entity (vanilla worlds):
Type = a_NBT.FindChildByName(a_TagIdx, "EntityId");
if ((Type >= 0) && (a_NBT.GetType(Type) == TAG_String))
{
eMonsterType MonsterType = cMonster::StringToMobType(a_NBT.GetString(Type));
if (MonsterType != eMonsterType::mtInvalidType)
{
MobSpawner->SetEntity(MonsterType);
}
MobSpawner->SetEntity(MonsterType);
}
}