From 6309c6a97fdbabfde978358f5f9a0f61ab74f91f Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Tue, 26 Dec 2017 21:25:57 +0000 Subject: improve rain simulation (#4017) * Uses vanilla logic to decide which blocks rain falls through. * Rain falls infinitely above the world, and stops at y=0. * Entities will now be extinguished if they are under rain-blocking blocks, and fire will now be extinguished by rain similarly. * Create IsWeatherWetAtXYZ to identify wetness at a particular location. * Use new code for enderman rain detection. * Fixes issue #916 * Disable warnings for global constructors in the fire simulator. --- src/Simulator/FireSimulator.cpp | 67 +++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 22 deletions(-) (limited to 'src/Simulator/FireSimulator.cpp') diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index d5671c5c2..ac7456b0a 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -25,15 +25,22 @@ #define MAX_CHANCE_REPLACE_FUEL 100000 #define MAX_CHANCE_FLAMMABILITY 100000 +// The base chance that in a tick, rain will extinguish a fire block. +#define CHANCE_BASE_RAIN_EXTINGUISH 0.2 +// The additional chance, multiplied by the meta of the fire block, that rain +// will extinguish a fire block in a tick. +#define CHANCE_AGE_M_RAIN_EXTINGUISH 0.03 -static const struct -{ - int x, y, z; -} gCrossCoords[] = +#ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wglobal-constructors" +#endif + +static const Vector3i gCrossCoords[] = { { 1, 0, 0}, {-1, 0, 0}, @@ -45,10 +52,7 @@ static const struct -static const struct -{ - int x, y, z; -} gNeighborCoords[] = +static const Vector3i gNeighborCoords[] = { { 1, 0, 0}, {-1, 0, 0}, @@ -58,6 +62,10 @@ static const struct { 0, 0, -1}, } ; +#ifdef __clang__ + #pragma clang diagnostic pop +#endif + @@ -97,20 +105,39 @@ void cFireSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int x = itr->x; int y = itr->y; int z = itr->z; + auto AbsPos = cChunkDef::RelativeToAbsolute({x, y, z}, a_Chunk->GetPosX(), a_Chunk->GetPosZ()); BLOCKTYPE BlockType = a_Chunk->GetBlock(x, y, z); if (!IsAllowedBlock(BlockType)) { // The block is no longer eligible (not a fire block anymore; a player probably placed a block over the fire) FLOG("FS: Removing block {%d, %d, %d}", - itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width + AbsPos.x, AbsPos.y, AbsPos.z ); itr = Data.erase(itr); continue; } + auto BurnsForever = ((y > 0) && DoesBurnForever(a_Chunk->GetBlock(x, (y - 1), z))); + auto BlockMeta = a_Chunk->GetMeta(x, y, z); + + auto Raining = std::any_of(std::begin(gCrossCoords), std::end(gCrossCoords), + [this, AbsPos](Vector3i cc) + { + return (m_World.IsWeatherWetAtXYZ(AbsPos + cc)); + } + ); + + // Randomly burn out the fire if it is raining: + if (!BurnsForever && Raining && GetRandomProvider().RandBool(CHANCE_BASE_RAIN_EXTINGUISH + (BlockMeta * CHANCE_AGE_M_RAIN_EXTINGUISH))) + { + a_Chunk->SetBlock(x, y, z, E_BLOCK_AIR, 0); + itr = Data.erase(itr); + continue; + } + // Try to spread the fire: - TrySpreadFire(a_Chunk, itr->x, itr->y, itr->z); + TrySpreadFire(a_Chunk, x, y, z); itr->Data -= NumMSecs; if (itr->Data >= 0) @@ -120,30 +147,30 @@ void cFireSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, continue; } - // Burn out the fire one step by increasing the meta: /* FLOG("FS: Fire at {%d, %d, %d} is stepping", itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width ); */ - NIBBLETYPE BlockMeta = a_Chunk->GetMeta(x, y, z); + // Has the fire burnt out? if (BlockMeta == 0x0f) { - // The fire burnt out completely FLOG("FS: Fire at {%d, %d, %d} burnt out, removing the fire block", itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width ); - a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0); - RemoveFuelNeighbors(a_Chunk, itr->x, itr->y, itr->z); + a_Chunk->SetBlock(x, y, z, E_BLOCK_AIR, 0); + RemoveFuelNeighbors(a_Chunk, x, y, z); itr = Data.erase(itr); continue; } - if ((itr->y > 0) && (!DoesBurnForever(a_Chunk->GetBlock(itr->x, itr->y - 1, itr->z)))) + // Burn out the fire one step by increasing the meta: + if (!BurnsForever) { a_Chunk->SetMeta(x, y, z, BlockMeta + 1); } - itr->Data = GetBurnStepTime(a_Chunk, itr->x, itr->y, itr->z); // TODO: Add some randomness into this + + itr->Data = GetBurnStepTime(a_Chunk, x, y, z); // TODO: Add some randomness into this ++itr; } // for itr - Data[] } @@ -283,7 +310,7 @@ int cFireSimulator::GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, in } } // for i - gCrossCoords[] - if (!IsBlockBelowSolid && (a_RelY >= 0)) + if (!IsBlockBelowSolid) { // Checked through everything, nothing was flammable // If block below isn't solid, we can't have fire, it would be a non-fueled fire @@ -427,7 +454,3 @@ bool cFireSimulator::CanStartFireInBlock(cChunk * a_NearChunk, int a_RelX, int a } // for i - Coords[] return false; } - - - - -- cgit v1.2.3