From 410d6c00453f2207ddb7a184590251b62b4769fa Mon Sep 17 00:00:00 2001 From: 12xx12 <44411062+12xx12@users.noreply.github.com> Date: Sun, 27 Sep 2020 19:02:16 +0200 Subject: [PATCH] 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 --- src/BlockEntities/BlockEntity.h | 2 +- src/BlockEntities/MobSpawnerEntity.cpp | 33 ++-- src/MobSpawner.cpp | 217 +++++++++++++----------- src/MobSpawner.h | 2 +- src/WorldStorage/NBTChunkSerializer.cpp | 1 - src/WorldStorage/WSSAnvil.cpp | 25 +-- 6 files changed, 137 insertions(+), 143 deletions(-) diff --git a/src/BlockEntities/BlockEntity.h b/src/BlockEntities/BlockEntity.h index 1933ed891..c133c186c 100644 --- a/src/BlockEntities/BlockEntity.h +++ b/src/BlockEntities/BlockEntity.h @@ -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; } diff --git a/src/BlockEntities/MobSpawnerEntity.cpp b/src/BlockEntities/MobSpawnerEntity.cpp index d7b72714d..f5fb5c3ff 100644 --- a/src/BlockEntities/MobSpawnerEntity.cpp +++ b/src/BlockEntities/MobSpawnerEntity.cpp @@ -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((Random.RandReal() - Random.RandReal()) * 4.0), Random.RandInt(-1, 1), static_cast((Random.RandReal() - Random.RandReal()) * 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++; } } diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp index 4d18b7358..b83cd247d 100644 --- a/src/MobSpawner.cpp +++ b/src/MobSpawner.cpp @@ -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 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; } diff --git a/src/MobSpawner.h b/src/MobSpawner.h index 7d5ce5274..6625114a1 100644 --- a/src/MobSpawner.h +++ b/src/MobSpawner.h @@ -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 GetAllowedMobTypes(EMCSBiome a_Biome); diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index c78b04c66..70f07557f 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -546,7 +546,6 @@ public: { mWriter.BeginCompound(""); AddBasicTileEntity(a_MobSpawner, "MobSpawner"); - mWriter.AddShort("Entity", static_cast(a_MobSpawner->GetEntity())); mWriter.AddString("EntityId", cMonster::MobTypeToVanillaName(a_MobSpawner->GetEntity())); mWriter.AddShort("Delay", a_MobSpawner->GetSpawnDelay()); mWriter.EndCompound(); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index b01bb7fd5..03decbea3 100755 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -1338,27 +1338,14 @@ OwnedBlockEntity cWSSAnvil::LoadMobSpawnerFromNBT(const cParsedNBT & a_NBT, int auto MobSpawner = std::make_unique(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(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); } }