From 61904af626b036b6e4e045ca219b2a361aa45a6e Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 11 Oct 2019 11:02:53 +0200 Subject: Moved growing from cWorld / cChunk to cBlockHandler descendants. --- src/Simulator/FireSimulator.cpp | 120 ++++++++++++++------------------- src/Simulator/FireSimulator.h | 8 +-- src/Simulator/FloodyFluidSimulator.cpp | 47 ++++++------- src/Simulator/FloodyFluidSimulator.h | 2 +- 4 files changed, 80 insertions(+), 97 deletions(-) (limited to 'src/Simulator') diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index 7862ed335..2b603315e 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -102,40 +102,38 @@ void cFireSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int NumMSecs = static_cast(a_Dt.count()); for (cCoordWithIntList::iterator itr = Data.begin(); itr != Data.end();) { - 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); + Vector3i relPos(itr->x, itr->y, itr->z); + auto absPos = a_Chunk->RelativeToAbsolute(relPos); + auto blockType = a_Chunk->GetBlock(relPos); - if (!IsAllowedBlock(BlockType)) + if (!IsAllowedBlock(blockType)) { // The block is no longer eligible (not a fire block anymore; a player probably placed a block over the fire) - FIRE_FLOG("FS: Removing block {0}", AbsPos); + FIRE_FLOG("FS: Removing block {0}", absPos); 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 BurnsForever = ((relPos.y > 0) && DoesBurnForever(a_Chunk->GetBlock(relPos.addedY(-1)))); + auto BlockMeta = a_Chunk->GetMeta(relPos); auto Raining = std::any_of(std::begin(gCrossCoords), std::end(gCrossCoords), - [this, AbsPos](Vector3i cc) + [this, absPos](Vector3i cc) { - return (m_World.IsWeatherWetAtXYZ(AbsPos + 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); + a_Chunk->SetBlock(relPos, E_BLOCK_AIR, 0); itr = Data.erase(itr); continue; } // Try to spread the fire: - TrySpreadFire(a_Chunk, x, y, z); + TrySpreadFire(a_Chunk, relPos); itr->Data -= NumMSecs; if (itr->Data >= 0) @@ -145,20 +143,15 @@ void cFireSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, continue; } - /* - FIRE_FLOG("FS: Fire at {0} is stepping", - a_Chunk->PositionToWorldPosition(itr->x, itr->y, itr->z) - ); - */ + // FIRE_FLOG("FS: Fire at {0} is stepping", absPos); + // Has the fire burnt out? if (BlockMeta == 0x0f) { // The fire burnt out completely - FIRE_FLOG("FS: Fire at {0} burnt out, removing the fire block", - a_Chunk->PositionToWorldPosition({itr->x, itr->y, itr->z}) - ); - a_Chunk->SetBlock({x, y, z}, E_BLOCK_AIR, 0); - RemoveFuelNeighbors(a_Chunk, x, y, z); + FIRE_FLOG("FS: Fire at {0} burnt out, removing the fire block", absPos); + a_Chunk->SetBlock(relPos, E_BLOCK_AIR, 0); + RemoveFuelNeighbors(a_Chunk, relPos); itr = Data.erase(itr); continue; } @@ -166,10 +159,10 @@ void cFireSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, // Burn out the fire one step by increasing the meta: if (!BurnsForever) { - a_Chunk->SetMeta(x, y, z, BlockMeta + 1); + a_Chunk->SetMeta(relPos, BlockMeta + 1); } - itr->Data = GetBurnStepTime(a_Chunk, x, y, z); // TODO: Add some randomness into this + itr->Data = GetBurnStepTime(a_Chunk, relPos); // TODO: Add some randomness into this ++itr; } // for itr - Data[] } @@ -278,12 +271,12 @@ void cFireSimulator::AddBlock(Vector3i a_Block, cChunk * a_Chunk) -int cFireSimulator::GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ) +int cFireSimulator::GetBurnStepTime(cChunk * a_Chunk, Vector3i a_RelPos) { bool IsBlockBelowSolid = false; - if (a_RelY > 0) + if (a_RelPos.y > 0) { - BLOCKTYPE BlockBelow = a_Chunk->GetBlock(a_RelX, a_RelY - 1, a_RelZ); + BLOCKTYPE BlockBelow = a_Chunk->GetBlock(a_RelPos.addedY(-1)); if (DoesBurnForever(BlockBelow)) { // Is burning atop of netherrack, burn forever (re-check in 10 sec) @@ -296,11 +289,11 @@ int cFireSimulator::GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, in IsBlockBelowSolid = cBlockInfo::IsSolid(BlockBelow); } - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + for (const auto & cross: gCrossCoords) { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - if (a_Chunk->UnboundedRelGetBlock(a_RelX + gCrossCoords[i].x, a_RelY, a_RelZ + gCrossCoords[i].z, BlockType, BlockMeta)) + if (a_Chunk->UnboundedRelGetBlock(a_RelPos + cross, BlockType, BlockMeta)) { if (IsFuel(BlockType)) { @@ -314,7 +307,7 @@ int cFireSimulator::GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, in // Checked through everything, nothing was flammable // If block below isn't solid, we can't have fire, it would be a non-fueled fire // SetBlock just to make sure fire doesn't spawn - a_Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, E_BLOCK_AIR, 0); + a_Chunk->SetBlock(a_RelPos, E_BLOCK_AIR, 0); return 0; } return static_cast(m_BurnStepTimeNonfuel); @@ -324,7 +317,7 @@ int cFireSimulator::GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, in -void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ) +void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, Vector3i a_RelPos) { /* if (GetRandomProvider().RandBool(0.99)) @@ -334,11 +327,11 @@ void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int } */ - for (int x = a_RelX - 1; x <= a_RelX + 1; x++) + for (int x = -1; x <= 1; x++) { - for (int z = a_RelZ - 1; z <= a_RelZ + 1; z++) + for (int z = -1; z <= 1; z++) { - for (int y = a_RelY - 1; y <= a_RelY + 2; y++) // flames spread up one more block than around + for (int y = 1; y <= 2; y++) // flames spread up one more block than around { // No need to check the coords for equality with the parent block, // it cannot catch fire anyway (because it's not an air block) @@ -348,24 +341,18 @@ void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int continue; } - // Start the fire in the neighbor {x, y, z} - /* - FIRE_LOG("FS: Trying to start fire at {0}.", - a_Chunk->PositionToWorldPosition(x, y, z) - ); - */ - if (CanStartFireInBlock(a_Chunk, x, y, z)) + // Start the fire in the neighbor a_RelPos + {x, y, z} + auto dstRelPos = a_RelPos + Vector3i{x, y, z}; + if (CanStartFireInBlock(a_Chunk, dstRelPos)) { - int a_PosX = x + a_Chunk->GetPosX() * cChunkDef::Width; - int a_PosZ = z + a_Chunk->GetPosZ() * cChunkDef::Width; - - if (cRoot::Get()->GetPluginManager()->CallHookBlockSpread(m_World, a_PosX, y, a_PosZ, ssFireSpread)) + auto dstAbsPos = a_Chunk->RelativeToAbsolute(dstRelPos); + if (cRoot::Get()->GetPluginManager()->CallHookBlockSpread(m_World, dstAbsPos.x, dstAbsPos.y, dstAbsPos.z, ssFireSpread)) { return; } - FIRE_FLOG("FS: Starting new fire at {0}.", Vector3i{a_PosX, y, a_PosZ}); - a_Chunk->UnboundedRelSetBlock(x, y, z, E_BLOCK_FIRE, 0); + FIRE_FLOG("FS: Starting new fire at {0}.", dstAbsPos); + a_Chunk->UnboundedRelSetBlock(dstRelPos, E_BLOCK_FIRE, 0); } } // for y } // for z @@ -376,45 +363,40 @@ void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int -void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ) +void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, Vector3i a_RelPos) { - for (auto & Coord : gNeighborCoords) + for (auto & coord : gNeighborCoords) { BLOCKTYPE BlockType; - int X = a_RelX + Coord.x; - int Z = a_RelZ + Coord.z; - - cChunkPtr Neighbour = a_Chunk->GetRelNeighborChunkAdjustCoords(X, Z); - if (Neighbour == nullptr) + auto relPos = a_RelPos + coord; + auto neighbor = a_Chunk->GetRelNeighborChunkAdjustCoords(relPos); + if (neighbor == nullptr) { continue; } - BlockType = Neighbour->GetBlock(X, a_RelY + Coord.y, Z); + BlockType = neighbor->GetBlock(relPos); if (!IsFuel(BlockType)) { continue; } - int AbsX = (Neighbour->GetPosX() * cChunkDef::Width) + X; - int Y = a_RelY + Coord.y; - int AbsZ = (Neighbour->GetPosZ() * cChunkDef::Width) + Z; - + auto absPos = neighbor->RelativeToAbsolute(relPos); if (BlockType == E_BLOCK_TNT) { - m_World.SpawnPrimedTNT({static_cast(AbsX), static_cast(Y), static_cast(AbsZ)}, 0); - Neighbour->SetBlock({X, Y, Z}, E_BLOCK_AIR, 0); + neighbor->SetBlock(relPos, E_BLOCK_AIR, 0); + m_World.SpawnPrimedTNT(absPos, 0); return; } bool ShouldReplaceFuel = (GetRandomProvider().RandBool(m_ReplaceFuelChance * (1.0 / MAX_CHANCE_REPLACE_FUEL))); - if (ShouldReplaceFuel && !cRoot::Get()->GetPluginManager()->CallHookBlockSpread(m_World, AbsX, Y, AbsZ, ssFireSpread)) + if (ShouldReplaceFuel && !cRoot::Get()->GetPluginManager()->CallHookBlockSpread(m_World, absPos.x, absPos.y, absPos.z, ssFireSpread)) { - Neighbour->SetBlock({X, Y, Z}, E_BLOCK_FIRE, 0); + neighbor->SetBlock(relPos, E_BLOCK_FIRE, 0); } else { - Neighbour->SetBlock({X, Y, Z}, E_BLOCK_AIR, 0); + neighbor->SetBlock(relPos, E_BLOCK_AIR, 0); } } // for i - Coords[] } @@ -423,11 +405,11 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel -bool cFireSimulator::CanStartFireInBlock(cChunk * a_NearChunk, int a_RelX, int a_RelY, int a_RelZ) +bool cFireSimulator::CanStartFireInBlock(cChunk * a_NearChunk, Vector3i a_RelPos) { BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - if (!a_NearChunk->UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta)) + if (!a_NearChunk->UnboundedRelGetBlock(a_RelPos, BlockType, BlockMeta)) { // The chunk is not accessible return false; @@ -439,9 +421,9 @@ bool cFireSimulator::CanStartFireInBlock(cChunk * a_NearChunk, int a_RelX, int a return false; } - for (size_t i = 0; i < ARRAYCOUNT(gNeighborCoords); i++) + for (const auto & neighbor: gNeighborCoords) { - if (!a_NearChunk->UnboundedRelGetBlock(a_RelX + gNeighborCoords[i].x, a_RelY + gNeighborCoords[i].y, a_RelZ + gNeighborCoords[i].z, BlockType, BlockMeta)) + if (!a_NearChunk->UnboundedRelGetBlock(a_RelPos + neighbor, BlockType, BlockMeta)) { // Neighbor inaccessible, skip it while evaluating continue; diff --git a/src/Simulator/FireSimulator.h b/src/Simulator/FireSimulator.h index bbfeb045e..236be5686 100644 --- a/src/Simulator/FireSimulator.h +++ b/src/Simulator/FireSimulator.h @@ -46,19 +46,19 @@ protected: virtual void AddBlock(Vector3i a_Block, cChunk * a_Chunk) override; /** Returns the time [msec] after which the specified fire block is stepped again; based on surrounding fuels */ - int GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ); + int GetBurnStepTime(cChunk * a_Chunk, Vector3i a_RelPos); /** Tries to spread fire to a neighborhood of the specified block */ - void TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ); + void TrySpreadFire(cChunk * a_Chunk, Vector3i a_RelPos); /** Removes all burnable blocks neighboring the specified block */ - void RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ); + void RemoveFuelNeighbors(cChunk * a_Chunk, Vector3i a_RelPos); /** Returns true if a fire can be started in the specified block, that is, it is an air block and has fuel next to it. Note that a_NearChunk may be a chunk neighbor to the block specified! The coords are relative to a_NearChunk but not necessarily in it. */ - bool CanStartFireInBlock(cChunk * a_NearChunk, int a_RelX, int a_RelY, int a_RelZ); + bool CanStartFireInBlock(cChunk * a_NearChunk, Vector3i a_RelPos); } ; diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp index f00dd3bfd..b620dddce 100644 --- a/src/Simulator/FloodyFluidSimulator.cpp +++ b/src/Simulator/FloodyFluidSimulator.cpp @@ -66,7 +66,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re } // When in contact with water, lava should harden - if (HardenBlock(a_Chunk, a_RelX, a_RelY, a_RelZ, MyBlock, MyMeta)) + if (HardenBlock(a_Chunk, {a_RelX, a_RelY, a_RelZ}, MyBlock, MyMeta)) { // Block was changed, bail out return; @@ -221,19 +221,18 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i ASSERT(a_NewMeta <= 8); // Invalid meta values ASSERT(a_NewMeta > 0); // Source blocks aren't spread - a_NearChunk = a_NearChunk->GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + Vector3i relPos(a_RelX, a_RelY, a_RelZ); + a_NearChunk = a_NearChunk->GetRelNeighborChunkAdjustCoords(relPos); if ((a_NearChunk == nullptr) || (!a_NearChunk->IsValid())) { // Chunk not available return; } - const int BlockX = a_NearChunk->GetPosX() * cChunkDef::Width + a_RelX; - const int BlockZ = a_NearChunk->GetPosZ() * cChunkDef::Width + a_RelZ; - + const auto absPos = a_NearChunk->RelativeToAbsolute(relPos); BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - a_NearChunk->GetBlockTypeMeta(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta); + a_NearChunk->GetBlockTypeMeta(relPos, BlockType, BlockMeta); if (IsAllowedBlock(BlockType)) { @@ -252,13 +251,13 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i // Lava flowing into water, change to stone / cobblestone based on direction: BLOCKTYPE NewBlock = (a_NewMeta == 8) ? E_BLOCK_STONE : E_BLOCK_COBBLESTONE; FLUID_FLOG(" Lava flowing into water, turning water at rel {0} into {1}", - Vector3i{a_RelX, a_RelY, a_RelZ}, ItemTypeToString(NewBlock) + relPos, ItemTypeToString(NewBlock) ); - a_NearChunk->SetBlock({a_RelX, a_RelY, a_RelZ}, NewBlock, 0); + a_NearChunk->SetBlock(relPos, NewBlock, 0); m_World.BroadcastSoundEffect( "block.lava.extinguish", - Vector3d(BlockX, a_RelY, BlockZ), + absPos, 0.5f, 1.5f ); @@ -272,13 +271,13 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i // Water flowing into lava, change to cobblestone / obsidian based on dest block: BLOCKTYPE NewBlock = (BlockMeta == 0) ? E_BLOCK_OBSIDIAN : E_BLOCK_COBBLESTONE; FLUID_FLOG(" Water flowing into lava, turning lava at rel {0} into {1}", - Vector3i{a_RelX, a_RelY, a_RelZ}, ItemTypeToString(NewBlock) + relPos, ItemTypeToString(NewBlock) ); - a_NearChunk->SetBlock({a_RelX, a_RelY, a_RelZ}, NewBlock, 0); + a_NearChunk->SetBlock(relPos, NewBlock, 0); m_World.BroadcastSoundEffect( "block.lava.extinguish", - Vector3d(BlockX, a_RelY, BlockZ), + absPos, 0.5f, 1.5f ); @@ -302,16 +301,16 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i cBlockHandler * Handler = BlockHandler(BlockType); if (Handler->DoesDropOnUnsuitable()) { - m_World.DropBlockAsPickups({BlockX, a_RelY, BlockZ}, nullptr, nullptr); + m_World.DropBlockAsPickups(absPos, nullptr, nullptr); } } // if (CanWashAway) // Spread: - FLUID_FLOG(" Spreading to {0} with meta {1}", Vector3i{BlockX, a_RelY, BlockZ}, a_NewMeta); - a_NearChunk->SetBlock({a_RelX, a_RelY, a_RelZ}, m_FluidBlock, a_NewMeta); - m_World.GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, a_NearChunk); + FLUID_FLOG(" Spreading to {0} with meta {1}", absPos, a_NewMeta); + a_NearChunk->SetBlock(relPos, m_FluidBlock, a_NewMeta); + m_World.GetSimulatorManager()->WakeUp(absPos, a_NearChunk); - HardenBlock(a_NearChunk, a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta); + HardenBlock(a_NearChunk, relPos, m_FluidBlock, a_NewMeta); } @@ -365,8 +364,10 @@ bool cFloodyFluidSimulator::CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX -bool cFloodyFluidSimulator::HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) +bool cFloodyFluidSimulator::HardenBlock(cChunk * a_Chunk, Vector3i a_RelPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) { + ASSERT(cChunkDef::IsValidRelPos(a_RelPos)); + // Only lava blocks can harden if (!IsBlockLava(a_BlockType)) { @@ -377,16 +378,16 @@ bool cFloodyFluidSimulator::HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - static const Vector3i Coords[] = + static const Vector3i neighborOffsets[] = { Vector3i( 1, 0, 0), Vector3i(-1, 0, 0), Vector3i( 0, 0, 1), Vector3i( 0, 0, -1), }; - for (size_t i = 0; i < ARRAYCOUNT(Coords); i++) + for (const auto & ofs: neighborOffsets) { - if (!a_Chunk->UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta)) + if (!a_Chunk->UnboundedRelGetBlock(a_RelPos + ofs, BlockType, BlockMeta)) { continue; } @@ -401,13 +402,13 @@ bool cFloodyFluidSimulator::HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY if (a_Meta == 0) { // Source lava block - a_Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, E_BLOCK_OBSIDIAN, 0); + a_Chunk->SetBlock(a_RelPos, E_BLOCK_OBSIDIAN, 0); return true; } // Ignore last lava level else if (a_Meta <= 4) { - a_Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, E_BLOCK_COBBLESTONE, 0); + a_Chunk->SetBlock(a_RelPos, E_BLOCK_COBBLESTONE, 0); return true; } } diff --git a/src/Simulator/FloodyFluidSimulator.h b/src/Simulator/FloodyFluidSimulator.h index d193b0f90..1139da1fc 100644 --- a/src/Simulator/FloodyFluidSimulator.h +++ b/src/Simulator/FloodyFluidSimulator.h @@ -42,7 +42,7 @@ protected: /** Checks if the specified block should harden (Water / Lava interaction) and if so, converts it to a suitable block. Returns whether the block was changed or not. */ - bool HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta); + bool HardenBlock(cChunk * a_Chunk, Vector3i a_RelPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta); /** Spread fluid to XZ neighbors. The coords are of the block currently being processed; a_NewMeta is the new meta for the new fluid block. -- cgit v1.2.3