diff --git a/src/Blocks/BlockGrass.h b/src/Blocks/BlockGrass.h index 51a321b35..8792a51f9 100644 --- a/src/Blocks/BlockGrass.h +++ b/src/Blocks/BlockGrass.h @@ -52,71 +52,21 @@ public: a_Chunk.GetWorld()->QueueLightChunk(a_Chunk.GetPosX(), a_Chunk.GetPosZ()); return; } - auto AbovePos = a_RelPos.addedY(1); - if (cChunkDef::IsValidHeight(AbovePos.y)) - { - // Grass turns back to dirt when the block Above it is not transparent or water. - // It does not turn to dirt when a snow layer is Above. - auto Above = a_Chunk.GetBlock(AbovePos); - if ( - (Above != E_BLOCK_SNOW) && - (!cBlockInfo::IsTransparent(Above) || IsBlockWater(Above))) - { - a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_DIRT, E_META_DIRT_NORMAL); - return; - } - // Make sure that there is enough light at the source block to spread - auto light = std::max(a_Chunk.GetBlockLight(AbovePos), a_Chunk.GetTimeAlteredLight(a_Chunk.GetSkyLight(AbovePos))); - if (light < 9) - { - return; - } + if (!cBlockGrassHandler::TrySurvive(a_Chunk, a_RelPos)) + { + return; } // Grass spreads to adjacent dirt blocks: - auto & rand = GetRandomProvider(); - for (int i = 0; i < 2; i++) // Pick two blocks to grow to + for (unsigned i = 0; i < 2; i++) // Pick two blocks to grow to { - int OfsX = rand.RandInt(-1, 1); - int OfsY = rand.RandInt(-3, 1); - int OfsZ = rand.RandInt(-1, 1); + auto & Random = GetRandomProvider(); + int OfsX = Random.RandInt(-1, 1); + int OfsY = Random.RandInt(-3, 1); + int OfsZ = Random.RandInt(-1, 1); - BLOCKTYPE DestBlock; - NIBBLETYPE DestMeta; - auto Pos = a_RelPos + Vector3i(OfsX, OfsY, OfsZ); - if (!cChunkDef::IsValidHeight(Pos.y)) - { - // Y Coord out of range - continue; - } - auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(Pos); - if (Chunk == nullptr) - { - // Unloaded chunk - continue; - } - Chunk->GetBlockTypeMeta(Pos, DestBlock, DestMeta); - if ((DestBlock != E_BLOCK_DIRT) || (DestMeta != E_META_DIRT_NORMAL)) - { - // Not a regular dirt block - continue; - } - auto AboveDestPos = Pos.addedY(1); - auto AboveBlockType = Chunk->GetBlock(AboveDestPos); - auto Light = std::max(Chunk->GetBlockLight(AboveDestPos), Chunk->GetTimeAlteredLight(Chunk->GetSkyLight(AboveDestPos))); - if ((Light > 4) && - cBlockInfo::IsTransparent(AboveBlockType) && - (!IsBlockLava(AboveBlockType)) && - (!IsBlockWaterOrIce(AboveBlockType)) - ) - { - auto AbsPos = Chunk->RelativeToAbsolute(Pos); - if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(*Chunk->GetWorld(), AbsPos.x, AbsPos.y, AbsPos.z, ssGrassSpread)) - { - Chunk->FastSetBlock(Pos, E_BLOCK_GRASS, 0); - } - } + cBlockGrassHandler::TryThrive(a_Chunk, a_RelPos + Vector3i(OfsX, OfsY, OfsZ)); } // for i - repeat twice } @@ -124,13 +74,89 @@ public: + /** Check if conditions are favourable to a grass block at the given position. + If they are not, the grass dies and is turned to dirt. + Returns whether conditions are so good that the grass can try to spread to neighbours. */ + static bool TrySurvive(cChunk & a_Chunk, const Vector3i a_RelPos) + { + const auto AbovePos = a_RelPos.addedY(1); + if (!cChunkDef::IsValidHeight(AbovePos.y)) + { + return true; + } + + // Grass turns back to dirt when the block Above it is not transparent or water. + // It does not turn to dirt when a snow layer is Above. + const auto Above = a_Chunk.GetBlock(AbovePos); + if ( + (Above != E_BLOCK_SNOW) && + (!cBlockInfo::IsTransparent(Above) || IsBlockWater(Above))) + { + a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_DIRT, E_META_DIRT_NORMAL); + return false; + } + + // Make sure that there is enough light at the source block to spread + const auto Light = std::max(a_Chunk.GetBlockLight(AbovePos), a_Chunk.GetSkyLightAltered(AbovePos)); + return (Light >= 9); + } + + + + + + /** Attempt to spread grass to a block at the given position. */ + static void TryThrive(cChunk & a_Chunk, Vector3i a_RelPos) + { + if (!cChunkDef::IsValidHeight(a_RelPos.y)) + { + // Y Coord out of range + return; + } + + auto Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(a_RelPos); + if (Chunk == nullptr) + { + // Unloaded chunk + return; + } + + BLOCKTYPE DestBlock; + NIBBLETYPE DestMeta; + Chunk->GetBlockTypeMeta(a_RelPos, DestBlock, DestMeta); + + if ((DestBlock != E_BLOCK_DIRT) || (DestMeta != E_META_DIRT_NORMAL)) + { + // Not a regular dirt block + return; + } + + const auto AbovePos = a_RelPos.addedY(1); + const auto Above = Chunk->GetBlock(AbovePos); + const auto Light = std::max(Chunk->GetBlockLight(AbovePos), Chunk->GetSkyLightAltered(AbovePos)); + + if ( + (Light > 4) && + cBlockInfo::IsTransparent(Above) && + !IsBlockLava(Above) && + !IsBlockWaterOrIce(Above) + ) + { + const auto AbsPos = Chunk->RelativeToAbsolute(a_RelPos); + if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread(*Chunk->GetWorld(), AbsPos.x, AbsPos.y, AbsPos.z, ssGrassSpread)) + { + Chunk->FastSetBlock(a_RelPos, E_BLOCK_GRASS, 0); + } + } + } + + + + + virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override { UNUSED(a_Meta); return 1; } } ; - - - - diff --git a/src/Protocol/Protocol_1_11.cpp b/src/Protocol/Protocol_1_11.cpp index e8381c70b..204371e90 100644 --- a/src/Protocol/Protocol_1_11.cpp +++ b/src/Protocol/Protocol_1_11.cpp @@ -394,8 +394,8 @@ void cProtocol_1_11_0::SendSpawnMob(const cMonster & a_Mob) Pkt.WriteBEDouble(LastSentPos.x); Pkt.WriteBEDouble(LastSentPos.y); Pkt.WriteBEDouble(LastSentPos.z); + Pkt.WriteByteAngle(a_Mob.GetHeadYaw()); // Doesn't seem to be used Pkt.WriteByteAngle(a_Mob.GetPitch()); - Pkt.WriteByteAngle(a_Mob.GetHeadYaw()); Pkt.WriteByteAngle(a_Mob.GetYaw()); Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedX() * 400)); Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedY() * 400)); diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp index a9fa8f23a..b5d78e457 100644 --- a/src/Protocol/Protocol_1_8.cpp +++ b/src/Protocol/Protocol_1_8.cpp @@ -1409,8 +1409,8 @@ void cProtocol_1_8_0::SendSpawnMob(const cMonster & a_Mob) Pkt.WriteFPInt(LastSentPos.x); Pkt.WriteFPInt(LastSentPos.y); Pkt.WriteFPInt(LastSentPos.z); + Pkt.WriteByteAngle(a_Mob.GetHeadYaw()); // Doesn't seem to be used Pkt.WriteByteAngle(a_Mob.GetPitch()); - Pkt.WriteByteAngle(a_Mob.GetHeadYaw()); Pkt.WriteByteAngle(a_Mob.GetYaw()); Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedX() * 400)); Pkt.WriteBEInt16(static_cast(a_Mob.GetSpeedY() * 400));