1
0

Convert most calls to blocking GetHeight/GetBiomeAt to direct chunk accesses

* Hopefully fixes #5094
This commit is contained in:
Tiger Wang 2021-01-05 02:13:02 +00:00
parent eeb63b8901
commit 9328afe65c
14 changed files with 204 additions and 88 deletions

View File

@ -115,13 +115,14 @@ private:
/** Returns true if there's either a water source block close enough to hydrate the specified position, or it's raining there. */ /** Returns true if there's either a water source block close enough to hydrate the specified position, or it's raining there. */
static bool IsWaterInNear(const cChunk & a_Chunk, const Vector3i a_RelPos) static bool IsWaterInNear(const cChunk & a_Chunk, const Vector3i a_RelPos)
{ {
const auto WorldPos = a_Chunk.RelativeToAbsolute(a_RelPos); if (a_Chunk.IsWeatherWetAt(a_RelPos.addedY(1)))
if (a_Chunk.GetWorld()->IsWeatherWetAtXYZ(WorldPos))
{ {
// Rain hydrates farmland, too // Rain hydrates farmland, too
return true; return true;
} }
const auto WorldPos = a_Chunk.RelativeToAbsolute(a_RelPos);
// Search for water in a close proximity: // Search for water in a close proximity:
// Ref.: https://minecraft.gamepedia.com/Farmland#Hydration // Ref.: https://minecraft.gamepedia.com/Farmland#Hydration
// TODO: Rewrite this to use the chunk and its neighbors directly // TODO: Rewrite this to use the chunk and its neighbors directly

View File

@ -626,7 +626,6 @@ void cChunk::SpawnMobs(cMobSpawner & a_MobSpawner)
int WorldX, WorldY, WorldZ; int WorldX, WorldY, WorldZ;
PositionToWorldPosition(TryX, TryY, TryZ, WorldX, WorldY, WorldZ); PositionToWorldPosition(TryX, TryY, TryZ, WorldX, WorldY, WorldZ);
EMCSBiome Biome = m_ChunkMap->GetBiomeAt(WorldX, WorldZ);
// MG TODO : // MG TODO :
// Moon cycle (for slime) // Moon cycle (for slime)
// check player and playerspawn presence < 24 blocks // check player and playerspawn presence < 24 blocks
@ -641,12 +640,16 @@ void cChunk::SpawnMobs(cMobSpawner & a_MobSpawner)
*/ */
NumberOfTries++; NumberOfTries++;
if (!IsLightValid())
Vector3i Try(TryX, TryY, TryZ);
const auto Chunk = GetRelNeighborChunkAdjustCoords(Try);
if ((Chunk == nullptr) || !Chunk->IsValid() || !Chunk->IsLightValid())
{ {
continue; continue;
} }
auto newMob = a_MobSpawner.TryToSpawnHere(this, {TryX, TryY, TryZ}, Biome, MaxNbOfSuccess); auto newMob = a_MobSpawner.TryToSpawnHere(this, Try, GetBiomeAt(Try.x, Try.z), MaxNbOfSuccess);
if (newMob == nullptr) if (newMob == nullptr)
{ {
continue; continue;
@ -1190,15 +1193,56 @@ bool cChunk::UnboundedRelFastSetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType,
int cChunk::GetHeight(int a_X, int a_Z) int cChunk::GetHeight(int a_X, int a_Z) const
{ {
ASSERT((a_X >= 0) && (a_X < Width) && (a_Z >= 0) && (a_Z < Width)); ASSERT((a_X >= 0) && (a_X < Width) && (a_Z >= 0) && (a_Z < Width));
if ((a_X >= 0) && (a_X < Width) && (a_Z >= 0) && (a_Z < Width))
{
return m_HeightMap[a_X + a_Z * Width]; return m_HeightMap[a_X + a_Z * Width];
}
bool cChunk::IsWeatherSunnyAt(int a_RelX, int a_RelZ) const
{
return m_World->IsWeatherSunny() || IsBiomeNoDownfall(GetBiomeAt(a_RelX, a_RelZ));
}
bool cChunk::IsWeatherWetAt(const int a_RelX, const int a_RelZ) const
{
const auto Biome = GetBiomeAt(a_RelX, a_RelZ);
return m_World->IsWeatherWet() && !IsBiomeNoDownfall(Biome) && !IsBiomeCold(Biome);
}
bool cChunk::IsWeatherWetAt(const Vector3i a_Position) const
{
if ((a_Position.y < 0) || !IsWeatherWetAt(a_Position.x, a_Position.z))
{
return false;
} }
return 0;
if (a_Position.y >= cChunkDef::Height)
{
return true;
}
for (int y = GetHeight(a_Position.x, a_Position.z); y >= a_Position.y; y--)
{
if (cBlockInfo::IsRainBlocker(GetBlock({ a_Position.x, y, a_Position.z })))
{
return false;
}
}
return true;
} }

View File

@ -221,7 +221,17 @@ public:
/** Sets the sign text. Returns true if successful. Also sends update packets to all clients in the chunk */ /** Sets the sign text. Returns true if successful. Also sends update packets to all clients in the chunk */
bool SetSignLines(int a_RelX, int a_RelY, int a_RelZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); bool SetSignLines(int a_RelX, int a_RelY, int a_RelZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4);
int GetHeight( int a_X, int a_Z); int GetHeight( int a_X, int a_Z) const;
/** Returns true if it is sunny at the specified location. This takes into account biomes. */
bool IsWeatherSunnyAt(int a_RelX, int a_RelZ) const;
/** Returns true if it is raining or storming at the specified location, taking into account biomes. */
bool IsWeatherWetAt(int a_RelX, int a_RelZ) const;
/** Returns true if it is raining or storming at the specified location,
and the rain reaches (the bottom of) the specified block position. */
bool IsWeatherWetAt(Vector3i a_Position) const;
void SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client); void SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client);

View File

@ -337,6 +337,63 @@ bool cChunkMap::IsChunkQueued(int a_ChunkX, int a_ChunkZ) const
bool cChunkMap::IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) const
{
int ChunkX, ChunkZ, BlockY = 0;
cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSChunks);
const auto Chunk = FindChunk(ChunkX, ChunkZ);
if ((Chunk == nullptr) || !Chunk->IsValid())
{
return m_World->IsWeatherSunny();
}
return Chunk->IsWeatherSunnyAt(a_BlockX, a_BlockZ);
}
bool cChunkMap::IsWeatherWetAt(int a_BlockX, int a_BlockZ) const
{
int ChunkX, ChunkZ, BlockY = 0;
cChunkDef::AbsoluteToRelative(a_BlockX, BlockY, a_BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSChunks);
const auto Chunk = FindChunk(ChunkX, ChunkZ);
if ((Chunk == nullptr) || !Chunk->IsValid())
{
return m_World->IsWeatherWet();
}
return Chunk->IsWeatherWetAt(a_BlockX, a_BlockZ);
}
bool cChunkMap::IsWeatherWetAt(const Vector3i a_Position) const
{
const auto ChunkPosition = cChunkDef::BlockToChunk(a_Position);
const auto Position = cChunkDef::AbsoluteToRelative(a_Position, ChunkPosition);
cCSLock Lock(m_CSChunks);
const auto Chunk = FindChunk(ChunkPosition.m_ChunkX, ChunkPosition.m_ChunkZ);
if ((Chunk == nullptr) || !Chunk->IsValid())
{
return m_World->IsWeatherWet();
}
return Chunk->IsWeatherWetAt(Position);
}
bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkZ) const bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkZ) const
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
@ -647,10 +704,7 @@ EMCSBiome cChunkMap::GetBiomeAt(int a_BlockX, int a_BlockZ) const
{ {
return Chunk->GetBiomeAt(X, Z); return Chunk->GetBiomeAt(X, Z);
} }
else return EMCSBiome::biInvalidBiome;
{
return m_World->GetGenerator().GetBiomeAt(a_BlockX, a_BlockZ);
}
} }

View File

@ -5,9 +5,6 @@
#pragma once #pragma once
#include <functional>
#include "ChunkDataCallback.h" #include "ChunkDataCallback.h"
#include "EffectID.h" #include "EffectID.h"
#include "FunctionRef.h" #include "FunctionRef.h"
@ -120,6 +117,10 @@ public:
/** Returns true iff the chunk is in the loader / generator queue. */ /** Returns true iff the chunk is in the loader / generator queue. */
bool IsChunkQueued(int a_ChunkX, int a_ChunkZ) const; bool IsChunkQueued(int a_ChunkX, int a_ChunkZ) const;
bool IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) const;
bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) const;
bool IsWeatherWetAt(Vector3i a_Position) const;
bool IsChunkValid (int a_ChunkX, int a_ChunkZ) const; bool IsChunkValid (int a_ChunkX, int a_ChunkZ) const;
bool HasChunkAnyClients (int a_ChunkX, int a_ChunkZ) const; bool HasChunkAnyClients (int a_ChunkX, int a_ChunkZ) const;
int GetHeight (int a_BlockX, int a_BlockZ); // Waits for the chunk to get loaded / generated int GetHeight (int a_BlockX, int a_BlockZ); // Waits for the chunk to get loaded / generated
@ -150,8 +151,8 @@ public:
/** Special function used for growing trees, replaces only blocks that tree may overwrite */ /** Special function used for growing trees, replaces only blocks that tree may overwrite */
void ReplaceTreeBlocks(const sSetBlockVector & a_Blocks); void ReplaceTreeBlocks(const sSetBlockVector & a_Blocks);
/** Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value */ /** Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, invalid otherwise. */
EMCSBiome GetBiomeAt (int a_BlockX, int a_BlockZ) const; EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ) const;
/** Sets the biome at the specified coords. Returns true if successful, false if not (chunk not loaded). /** Sets the biome at the specified coords. Returns true if successful, false if not (chunk not loaded).
Doesn't resend the chunk to clients. */ Doesn't resend the chunk to clients. */

View File

@ -1198,8 +1198,8 @@ void cEntity::TickBurning(cChunk & a_Chunk)
m_TicksLeftBurning = 0; m_TicksLeftBurning = 0;
} }
// Fire is extinguished by rain // Fire is extinguished by rain:
if (GetWorld()->IsWeatherWetAtXYZ(GetPosition().Floor())) if (a_Chunk.IsWeatherWetAt(cChunkDef::AbsoluteToRelative(GetPosition().Floor(), a_Chunk.GetPos())))
{ {
m_TicksLeftBurning = 0; m_TicksLeftBurning = 0;
} }

View File

@ -101,11 +101,16 @@ void cFloater::SpawnOn(cClientHandle & a_Client)
void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
auto & Random = GetRandomProvider();
HandlePhysics(a_Dt, a_Chunk); HandlePhysics(a_Dt, a_Chunk);
if (IsBlockWater(m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT))
&& (m_World->GetBlockMeta(POSX_TOINT, POSY_TOINT, POSZ_TOINT) == 0)) PREPARE_REL_AND_CHUNK(GetPosition().Floor(), a_Chunk);
if (!RelSuccess)
{
return;
}
auto & Random = GetRandomProvider();
if (IsBlockWater(Chunk->GetBlock(Rel)) && (Chunk->GetMeta(Rel) == 0))
{ {
if (!m_CanPickupItem && (m_AttachedMobID == cEntity::INVALID_ID)) // Check if you can't already pickup a fish and if the floater isn't attached to a mob. if (!m_CanPickupItem && (m_AttachedMobID == cEntity::INVALID_ID)) // Check if you can't already pickup a fish and if the floater isn't attached to a mob.
{ {
@ -113,7 +118,7 @@ void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
m_BitePos = GetPosition(); m_BitePos = GetPosition();
m_World->BroadcastSoundEffect("entity.bobber.splash", GetPosition(), 1, 1); m_World->BroadcastSoundEffect("entity.bobber.splash", GetPosition(), 1, 1);
SetPosY(GetPosY() - 1); AddSpeedY(-10);
m_CanPickupItem = true; m_CanPickupItem = true;
m_PickupCountDown = 20; m_PickupCountDown = 20;
m_CountDownTime = Random.RandInt(100, 900); m_CountDownTime = Random.RandInt(100, 900);
@ -132,9 +137,9 @@ void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
} }
m_CountDownTime--; m_CountDownTime--;
if (m_World->GetHeight(POSX_TOINT, POSZ_TOINT) == POSY_TOINT) if (Chunk->IsWeatherWetAt(Rel))
{ {
if (m_World->IsWeatherWet() && Random.RandBool(0.25)) // 25% chance of an extra countdown when being rained on. if (Random.RandBool(0.25)) // 25% chance of an extra countdown when being rained on.
{ {
m_CountDownTime--; m_CountDownTime--;
} }
@ -150,7 +155,10 @@ void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
} }
// Check water at the top of floater otherwise it floats into the air above the water // Check water at the top of floater otherwise it floats into the air above the water
if (IsBlockWater(m_World->GetBlock(POSX_TOINT, FloorC(GetPosY() + GetHeight()), POSZ_TOINT))) if (
const auto Above = Rel.addedY(FloorC(GetPosY() + GetHeight()));
(Above.y < cChunkDef::Height) && IsBlockWater(m_World->GetBlock(Above))
)
{ {
SetSpeedY(0.7); SetSpeedY(0.7);
} }

View File

@ -74,10 +74,6 @@ eMonsterType cMobSpawner::ChooseMobType(EMCSBiome a_Biome)
bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType a_MobType, EMCSBiome a_Biome, bool a_DisableSolidBelowCheck) bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType a_MobType, EMCSBiome a_Biome, bool a_DisableSolidBelowCheck)
{ {
if (a_Chunk == nullptr)
{
return false;
}
if ((a_RelPos.y >= cChunkDef::Height - 1) || (a_RelPos.y <= 0)) if ((a_RelPos.y >= cChunkDef::Height - 1) || (a_RelPos.y <= 0))
{ {
return false; return false;
@ -502,9 +498,6 @@ cMonster * cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, EMCS
m_NewPack = false; m_NewPack = false;
} }
// Make sure we are looking at the right chunk to spawn in
a_Chunk = a_Chunk->GetRelNeighborChunkAdjustCoords(a_RelPos);
if ((m_AllowedTypes.find(m_MobType) != m_AllowedTypes.end()) && CanSpawnHere(a_Chunk, a_RelPos, m_MobType, a_Biome)) 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 NewMob = cMonster::NewMonsterFromType(m_MobType);

View File

@ -1,6 +1,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Chunk.h"
#include "Enderman.h" #include "Enderman.h"
#include "../Entities/Player.h" #include "../Entities/Player.h"
#include "../LineBlockTracer.h" #include "../LineBlockTracer.h"
@ -148,11 +149,14 @@ void cEnderman::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
return; return;
} }
// Take damage when wet PREPARE_REL_AND_CHUNK(GetPosition().Floor(), a_Chunk);
if ( if (!RelSuccess)
cChunkDef::IsValidHeight(POSY_TOINT) && {
(GetWorld()->IsWeatherWetAtXYZ(GetPosition().Floor()) || IsInWater()) return;
) }
// Take damage when wet:
if (IsInWater() || Chunk->IsWeatherWetAt(Rel))
{ {
EventLosePlayer(); EventLosePlayer();
TakeDamage(dtEnvironment, nullptr, 1, 0); TakeDamage(dtEnvironment, nullptr, 1, 0);

View File

@ -1667,9 +1667,9 @@ bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk)
} }
if ( if (
(Chunk->GetBlock(Rel.x, Rel.y, Rel.z) != E_BLOCK_SOULSAND) && // Not on soulsand (Chunk->GetBlock(Rel) != E_BLOCK_SOULSAND) && // Not on soulsand
(GetWorld()->GetTimeOfDay() < 12000 + 1000) && // Daytime (GetWorld()->GetTimeOfDay() < 12000 + 1000) && // Daytime
GetWorld()->IsWeatherSunnyAt(POSX_TOINT, POSZ_TOINT) && // Not raining Chunk->IsWeatherSunnyAt(Rel.x, Rel.z) && // Not raining
!IsInWater() // Isn't swimming !IsInWater() // Isn't swimming
) )
{ {

View File

@ -1,6 +1,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Chunk.h"
#include "SnowGolem.h" #include "SnowGolem.h"
#include "../BlockInfo.h" #include "../BlockInfo.h"
#include "../World.h" #include "../World.h"
@ -36,17 +37,22 @@ void cSnowGolem::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
// The base class tick destroyed us // The base class tick destroyed us
return; return;
} }
if (IsBiomeNoDownfall(m_World->GetBiomeAt(POSX_TOINT, POSZ_TOINT)))
PREPARE_REL_AND_CHUNK(GetPosition().Floor(), a_Chunk);
if (!RelSuccess)
{
return;
}
if (IsBiomeNoDownfall(Chunk->GetBiomeAt(Rel.x, Rel.z)))
{ {
TakeDamage(dtEnvironment, nullptr, GetRawDamageAgainst(*this), GetKnockbackAmountAgainst(*this)); TakeDamage(dtEnvironment, nullptr, GetRawDamageAgainst(*this), GetKnockbackAmountAgainst(*this));
} }
else else if (const auto Below = Rel.addedY(-1); Below.y >= 0)
{ {
BLOCKTYPE BlockBelow = m_World->GetBlock(POSX_TOINT, POSY_TOINT - 1, POSZ_TOINT); if ((Chunk->GetBlock(Rel) == E_BLOCK_AIR) && cBlockInfo::IsSolid(Chunk->GetBlock(Below)))
BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT);
if ((Block == E_BLOCK_AIR) && cBlockInfo::IsSolid(BlockBelow))
{ {
m_World->SetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT, E_BLOCK_SNOW, 0); Chunk->SetBlock(Rel, E_BLOCK_SNOW, 0);
} }
} }
} }

View File

@ -87,7 +87,6 @@ void cFireSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX,
for (cCoordWithIntList::iterator itr = Data.begin(); itr != Data.end();) for (cCoordWithIntList::iterator itr = Data.begin(); itr != Data.end();)
{ {
Vector3i relPos(itr->x, itr->y, itr->z); Vector3i relPos(itr->x, itr->y, itr->z);
auto absPos = a_Chunk->RelativeToAbsolute(relPos);
auto blockType = a_Chunk->GetBlock(relPos); auto blockType = a_Chunk->GetBlock(relPos);
if (!IsAllowedBlock(blockType)) if (!IsAllowedBlock(blockType))
@ -101,12 +100,16 @@ void cFireSimulator::SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX,
auto BurnsForever = ((relPos.y > 0) && DoesBurnForever(a_Chunk->GetBlock(relPos.addedY(-1)))); auto BurnsForever = ((relPos.y > 0) && DoesBurnForever(a_Chunk->GetBlock(relPos.addedY(-1))));
auto BlockMeta = a_Chunk->GetMeta(relPos); auto BlockMeta = a_Chunk->GetMeta(relPos);
auto Raining = std::any_of(std::begin(gCrossCoords), std::end(gCrossCoords), auto Raining = std::any_of(std::begin(gCrossCoords), std::end(gCrossCoords), [a_Chunk, relPos](Vector3i cc)
[this, absPos](Vector3i cc)
{ {
return (m_World.IsWeatherWetAtXYZ(absPos + cc)); auto Adjusted = relPos + cc;
const auto Chunk = a_Chunk->GetRelNeighborChunkAdjustCoords(Adjusted);
if ((Chunk != nullptr) && Chunk->IsValid())
{
return Chunk->IsWeatherWetAt(Adjusted);
} }
); return false;
});
// Randomly burn out the fire if it is raining: // Randomly burn out the fire if it is raining:
if (!BurnsForever && Raining && GetRandomProvider().RandBool(CHANCE_BASE_RAIN_EXTINGUISH + (BlockMeta * CHANCE_AGE_M_RAIN_EXTINGUISH))) if (!BurnsForever && Raining && GetRandomProvider().RandBool(CHANCE_BASE_RAIN_EXTINGUISH + (BlockMeta * CHANCE_AGE_M_RAIN_EXTINGUISH)))

View File

@ -548,28 +548,27 @@ void cWorld::ChangeWeather(void)
bool cWorld::IsWeatherWetAtXYZ(Vector3i a_Pos) bool cWorld::IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) const
{ {
if ((a_Pos.y < 0) || !IsWeatherWetAt(a_Pos.x, a_Pos.z)) return m_ChunkMap.IsWeatherSunnyAt(a_BlockX, a_BlockZ);
{ }
return false;
}
if (a_Pos.y >= cChunkDef::Height)
{
return true;
}
for (int y = GetHeight(a_Pos.x, a_Pos.z); y >= a_Pos.y; y--)
{
auto BlockType = GetBlock({a_Pos.x, y, a_Pos.z});
if (cBlockInfo::IsRainBlocker(BlockType))
{
return false;
}
}
return true;
bool cWorld::IsWeatherWetAt(int a_BlockX, int a_BlockZ)
{
return m_ChunkMap.IsWeatherWetAt(a_BlockX, a_BlockZ);
}
bool cWorld::IsWeatherWetAtXYZ(const Vector3i a_Position)
{
return m_ChunkMap.IsWeatherWetAt(a_Position);
} }

View File

@ -999,10 +999,7 @@ public:
bool IsWeatherSunny(void) const { return (m_Weather == wSunny); } bool IsWeatherSunny(void) const { return (m_Weather == wSunny); }
/** Returns true if it is sunny at the specified location. This takes into account biomes. */ /** Returns true if it is sunny at the specified location. This takes into account biomes. */
bool IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) bool IsWeatherSunnyAt(int a_BlockX, int a_BlockZ) const;
{
return (IsWeatherSunny() || IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ)));
}
/** Returns true if the current weather is rainy. */ /** Returns true if the current weather is rainy. */
bool IsWeatherRain(void) const { return (m_Weather == wRain); } bool IsWeatherRain(void) const { return (m_Weather == wRain); }
@ -1027,15 +1024,11 @@ public:
/** Returns true if it is raining or storming at the specified location. /** Returns true if it is raining or storming at the specified location.
This takes into account biomes. */ This takes into account biomes. */
virtual bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) override virtual bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) override;
{
auto Biome = GetBiomeAt(a_BlockX, a_BlockZ);
return (IsWeatherWet() && !IsBiomeNoDownfall(Biome) && !IsBiomeCold(Biome));
}
/** Returns true if it is raining or storming at the specified location, /** Returns true if it is raining or storming at the specified location,
and the rain reaches (the bottom of) the specified block position. */ and the rain reaches (the bottom of) the specified block position. */
virtual bool IsWeatherWetAtXYZ(Vector3i a_Pos) override; virtual bool IsWeatherWetAtXYZ(Vector3i a_Position) override;
/** Returns the seed of the world. */ /** Returns the seed of the world. */
int GetSeed(void) { return m_Generator.GetSeed(); } int GetSeed(void) { return m_Generator.GetSeed(); }