1
0
Fork 0

Merge pull request #2894 from LogicParrot/spider

Spiders now friendly at daylight, new cChunk functions
This commit is contained in:
LogicParrot 2016-01-22 20:53:34 +02:00
commit 30b95fcc4e
13 changed files with 221 additions and 163 deletions

View File

@ -123,9 +123,9 @@ cChunk::cChunk(
cChunk::~cChunk() cChunk::~cChunk()
{ {
cPluginManager::Get()->CallHookChunkUnloaded(*m_World, m_PosX, m_PosZ); cPluginManager::Get()->CallHookChunkUnloaded(*m_World, m_PosX, m_PosZ);
// LOGINFO("### delete cChunk() (%i, %i) from %p, thread 0x%x ###", m_PosX, m_PosZ, this, GetCurrentThreadId()); // LOGINFO("### delete cChunk() (%i, %i) from %p, thread 0x%x ###", m_PosX, m_PosZ, this, GetCurrentThreadId());
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr) for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
{ {
delete *itr; delete *itr;
@ -143,7 +143,7 @@ cChunk::~cChunk()
delete *itr; delete *itr;
} }
} }
if (m_NeighborXM != nullptr) if (m_NeighborXM != nullptr)
{ {
m_NeighborXM->m_NeighborXP = nullptr; m_NeighborXM->m_NeighborXP = nullptr;
@ -284,12 +284,12 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback)
a_Callback.LightIsValid(m_IsLightValid); a_Callback.LightIsValid(m_IsLightValid);
a_Callback.ChunkData(m_ChunkData); a_Callback.ChunkData(m_ChunkData);
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
{ {
a_Callback.Entity(*itr); a_Callback.Entity(*itr);
} }
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr) for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
{ {
a_Callback.BlockEntity(*itr); a_Callback.BlockEntity(*itr);
@ -305,7 +305,7 @@ void cChunk::SetAllData(cSetChunkData & a_SetChunkData)
ASSERT(a_SetChunkData.IsHeightMapValid()); ASSERT(a_SetChunkData.IsHeightMapValid());
ASSERT(a_SetChunkData.AreBiomesValid()); ASSERT(a_SetChunkData.AreBiomesValid());
ASSERT(IsQueued()); ASSERT(IsQueued());
memcpy(m_BiomeMap, a_SetChunkData.GetBiomes(), sizeof(m_BiomeMap)); memcpy(m_BiomeMap, a_SetChunkData.GetBiomes(), sizeof(m_BiomeMap));
memcpy(m_HeightMap, a_SetChunkData.GetHeightMap(), sizeof(m_HeightMap)); memcpy(m_HeightMap, a_SetChunkData.GetHeightMap(), sizeof(m_HeightMap));
@ -339,19 +339,19 @@ void cChunk::SetAllData(cSetChunkData & a_SetChunkData)
ASSERT(WorldBlockType == EntityBlockType); ASSERT(WorldBlockType == EntityBlockType);
} // for itr - m_BlockEntities } // for itr - m_BlockEntities
#endif // _DEBUG #endif // _DEBUG
// Set all block entities' World variable: // Set all block entities' World variable:
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr) for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
{ {
(*itr)->SetWorld(m_World); (*itr)->SetWorld(m_World);
} }
// Create block entities that the loader didn't load; fill them with defaults // Create block entities that the loader didn't load; fill them with defaults
CreateBlockEntities(); CreateBlockEntities();
// Set the chunk data as valid. This may be needed for some simulators that perform actions upon block adding (Vaporize) // Set the chunk data as valid. This may be needed for some simulators that perform actions upon block adding (Vaporize)
SetPresence(cpPresent); SetPresence(cpPresent);
// Wake up all simulators for their respective blocks: // Wake up all simulators for their respective blocks:
WakeUpSimulators(); WakeUpSimulators();
@ -399,7 +399,7 @@ void cChunk::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock
); );
return; return;
} }
// SizeX, SizeZ are the dimensions of the block data to copy to the chunk (size of the geometric union) // SizeX, SizeZ are the dimensions of the block data to copy to the chunk (size of the geometric union)
int BlockStartX = std::max(a_MinBlockX, m_PosX * cChunkDef::Width); int BlockStartX = std::max(a_MinBlockX, m_PosX * cChunkDef::Width);
@ -541,7 +541,7 @@ void cChunk::SpawnMobs(cMobSpawner & a_MobSpawner)
{ {
return; return;
} }
a_MobSpawner.NewPack(); a_MobSpawner.NewPack();
int NumberOfTries = 0; int NumberOfTries = 0;
int NumberOfSuccess = 0; int NumberOfSuccess = 0;
@ -561,7 +561,7 @@ void cChunk::SpawnMobs(cMobSpawner & a_MobSpawner)
ASSERT(TryY > 0); ASSERT(TryY > 0);
ASSERT(TryY < cChunkDef::Height - 1); ASSERT(TryY < cChunkDef::Height - 1);
EMCSBiome Biome = m_ChunkMap->GetBiomeAt(TryX, TryZ); EMCSBiome Biome = m_ChunkMap->GetBiomeAt(TryX, TryZ);
// MG TODO : // MG TODO :
// Moon cycle (for slime) // Moon cycle (for slime)
@ -569,7 +569,7 @@ void cChunk::SpawnMobs(cMobSpawner & a_MobSpawner)
// check mobs presence on the block // check mobs presence on the block
// MG TODO : check that "Level" really means Y // MG TODO : check that "Level" really means Y
/* /*
NIBBLETYPE SkyLight = 0; NIBBLETYPE SkyLight = 0;
@ -581,7 +581,7 @@ void cChunk::SpawnMobs(cMobSpawner & a_MobSpawner)
{ {
continue; continue;
} }
cEntity * newMob = a_MobSpawner.TryToSpawnHere(this, TryX, TryY, TryZ, Biome, MaxNbOfSuccess); cEntity * newMob = a_MobSpawner.TryToSpawnHere(this, TryX, TryY, TryZ, Biome, MaxNbOfSuccess);
if (newMob == nullptr) if (newMob == nullptr)
{ {
@ -606,10 +606,10 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt)
BroadcastPendingBlockChanges(); BroadcastPendingBlockChanges();
CheckBlocks(); CheckBlocks();
// Tick simulators: // Tick simulators:
m_World->GetSimulatorManager()->SimulateChunk(a_Dt, m_PosX, m_PosZ, this); m_World->GetSimulatorManager()->SimulateChunk(a_Dt, m_PosX, m_PosZ, this);
TickBlocks(); TickBlocks();
// Tick all block entities in this chunk: // Tick all block entities in this chunk:
@ -617,7 +617,7 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt)
{ {
m_IsDirty = (*itr)->Tick(a_Dt, *this) | m_IsDirty; m_IsDirty = (*itr)->Tick(a_Dt, *this) | m_IsDirty;
} }
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();)
{ {
if (!((*itr)->IsMob())) // Mobs are ticked inside cWorld::TickMobs() (as we don't have to tick them if they are far away from players) if (!((*itr)->IsMob())) // Mobs are ticked inside cWorld::TickMobs() (as we don't have to tick them if they are far away from players)
@ -657,7 +657,7 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt)
++itr; ++itr;
} }
} // for itr - m_Entitites[] } // for itr - m_Entitites[]
ApplyWeatherToTop(); ApplyWeatherToTop();
} }
@ -715,7 +715,7 @@ void cChunk::MoveEntityToNewChunk(cEntity * a_Entity)
m_Entity(a_CallbackEntity) m_Entity(a_CallbackEntity)
{} {}
} Mover(a_Entity); } Mover(a_Entity);
m_ChunkMap->CompareChunkClients(this, Neighbor, Mover); m_ChunkMap->CompareChunkClients(this, Neighbor, Mover);
} }
@ -761,10 +761,10 @@ void cChunk::CheckBlocks()
} }
std::vector<Vector3i> ToTickBlocks; std::vector<Vector3i> ToTickBlocks;
std::swap(m_ToTickBlocks, ToTickBlocks); std::swap(m_ToTickBlocks, ToTickBlocks);
cChunkInterface ChunkInterface(m_World->GetChunkMap()); cChunkInterface ChunkInterface(m_World->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*m_World); cBlockInServerPluginInterface PluginInterface(*m_World);
for (std::vector<Vector3i>::const_iterator itr = ToTickBlocks.begin(), end = ToTickBlocks.end(); itr != end; ++itr) for (std::vector<Vector3i>::const_iterator itr = ToTickBlocks.begin(), end = ToTickBlocks.end(); itr != end; ++itr)
{ {
Vector3i Pos = (*itr); Vector3i Pos = (*itr);
@ -788,17 +788,17 @@ void cChunk::TickBlocks(void)
int TickX = m_BlockTickX; int TickX = m_BlockTickX;
int TickY = m_BlockTickY; int TickY = m_BlockTickY;
int TickZ = m_BlockTickZ; int TickZ = m_BlockTickZ;
cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap()); cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*this->GetWorld()); cBlockInServerPluginInterface PluginInterface(*this->GetWorld());
// This for loop looks disgusting, but it actually does a simple thing - first processes m_BlockTick, then adds random to it // This for loop looks disgusting, but it actually does a simple thing - first processes m_BlockTick, then adds random to it
// This is so that SetNextBlockTick() works // This is so that SetNextBlockTick() works
for (int i = 0; i < 50; i++, for (int i = 0; i < 50; i++,
// This weird construct (*2, then /2) is needed, // This weird construct (*2, then /2) is needed,
// otherwise the blocktick distribution is too biased towards even coords! // otherwise the blocktick distribution is too biased towards even coords!
TickX = (TickX + RandomX) % (Width * 2), TickX = (TickX + RandomX) % (Width * 2),
TickY = (TickY + RandomY) % (Height * 2), TickY = (TickY + RandomY) % (Height * 2),
TickZ = (TickZ + RandomZ) % (Width * 2), TickZ = (TickZ + RandomZ) % (Width * 2),
@ -836,7 +836,7 @@ void cChunk::ApplyWeatherToTop()
// Not the right weather, or not at this tick; bail out // Not the right weather, or not at this tick; bail out
return; return;
} }
int X = m_World->GetTickRandomNumber(15); int X = m_World->GetTickRandomNumber(15);
int Z = m_World->GetTickRandomNumber(15); int Z = m_World->GetTickRandomNumber(15);
@ -944,7 +944,7 @@ void cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl
// Neighbors not valid or already taken by the same produce // Neighbors not valid or already taken by the same produce
return; return;
} }
// Pick a direction in which to place the produce: // Pick a direction in which to place the produce:
int x = 0, z = 0; int x = 0, z = 0;
int CheckType = a_TickRandom.randInt(3); // The index to the neighbors array which should be checked for emptiness int CheckType = a_TickRandom.randInt(3); // The index to the neighbors array which should be checked for emptiness
@ -955,7 +955,7 @@ void cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl
case 2: z = 1; break; case 2: z = 1; break;
case 3: z = -1; break; case 3: z = -1; break;
} }
// Check that the block in that direction is empty: // Check that the block in that direction is empty:
switch (BlockType[CheckType]) switch (BlockType[CheckType])
{ {
@ -968,7 +968,7 @@ void cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl
} }
default: return; default: return;
} }
// Check if there's soil under the neighbor. We already know the neighbors are valid. Place produce if ok // Check if there's soil under the neighbor. We already know the neighbors are valid. Place produce if ok
BLOCKTYPE Soil; BLOCKTYPE Soil;
VERIFY(UnboundedRelGetBlock(a_RelX + x, a_RelY - 1, a_RelZ + z, Soil, BlockMeta)); VERIFY(UnboundedRelGetBlock(a_RelX + x, a_RelY - 1, a_RelZ + z, Soil, BlockMeta));
@ -1019,7 +1019,7 @@ void cChunk::GrowSugarcane(int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks)
{ {
--Bottom; --Bottom;
} }
// Grow by at most a_NumBlocks, but no more than max height: // Grow by at most a_NumBlocks, but no more than max height:
int ToGrow = std::min(a_NumBlocks, m_World->GetMaxSugarcaneHeight() + 1 - (Top - Bottom)); int ToGrow = std::min(a_NumBlocks, m_World->GetMaxSugarcaneHeight() + 1 - (Top - Bottom));
for (int i = 0; i < ToGrow; i++) for (int i = 0; i < ToGrow; i++)
@ -1060,7 +1060,7 @@ void cChunk::GrowCactus(int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks)
{ {
--Bottom; --Bottom;
} }
// Grow by at most a_NumBlocks, but no more than max height: // Grow by at most a_NumBlocks, but no more than max height:
int ToGrow = std::min(a_NumBlocks, m_World->GetMaxCactusHeight() + 1 - (Top - Bottom)); int ToGrow = std::min(a_NumBlocks, m_World->GetMaxCactusHeight() + 1 - (Top - Bottom));
for (int i = 0; i < ToGrow; i++) for (int i = 0; i < ToGrow; i++)
@ -1273,7 +1273,7 @@ void cChunk::UnboundedQueueTickBlock(int a_RelX, int a_RelY, int a_RelZ)
int cChunk::GetHeight(int a_X, int a_Z) int cChunk::GetHeight(int a_X, int a_Z)
{ {
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)) 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];
@ -1410,7 +1410,7 @@ void cChunk::CalculateHeightmap(const BLOCKTYPE * a_BlockTypes)
void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients) void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
{ {
FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta, a_SendToClients); FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta, a_SendToClients);
// Tick this block and its neighbors: // Tick this block and its neighbors:
m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ)); m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ));
QueueTickBlockNeighbors(a_RelX, a_RelY, a_RelZ); QueueTickBlockNeighbors(a_RelX, a_RelY, a_RelZ);
@ -1425,7 +1425,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
delete BlockEntity; delete BlockEntity;
BlockEntity = nullptr; BlockEntity = nullptr;
} }
// If the new block is a block entity, create the entity object: // If the new block is a block entity, create the entity object:
switch (a_BlockType) switch (a_BlockType)
{ {
@ -1470,7 +1470,7 @@ void cChunk::QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ)
{ {
return; return;
} }
m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ)); m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ));
} }
@ -1508,7 +1508,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
ASSERT(!((a_RelX < 0) || (a_RelX >= Width) || (a_RelY < 0) || (a_RelY >= Height) || (a_RelZ < 0) || (a_RelZ >= Width))); ASSERT(!((a_RelX < 0) || (a_RelX >= Width) || (a_RelY < 0) || (a_RelY >= Height) || (a_RelZ < 0) || (a_RelZ >= Width)));
ASSERT(IsValid()); ASSERT(IsValid());
const BLOCKTYPE OldBlockType = GetBlock(a_RelX, a_RelY, a_RelZ); const BLOCKTYPE OldBlockType = GetBlock(a_RelX, a_RelY, a_RelZ);
const BLOCKTYPE OldBlockMeta = m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ); const BLOCKTYPE OldBlockMeta = m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ);
if ((OldBlockType == a_BlockType) && (OldBlockMeta == a_BlockMeta)) if ((OldBlockType == a_BlockType) && (OldBlockMeta == a_BlockMeta))
@ -1543,7 +1543,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT
{ {
m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta)); m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta));
} }
m_ChunkData.SetMeta(a_RelX, a_RelY, a_RelZ, a_BlockMeta); m_ChunkData.SetMeta(a_RelX, a_RelY, a_RelZ, a_BlockMeta);
// ONLY recalculate lighting if it's necessary! // ONLY recalculate lighting if it's necessary!
@ -1593,7 +1593,7 @@ void cChunk::SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_C
Vector3i wp = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ); Vector3i wp = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ);
a_Client->SendBlockChange(wp.x, wp.y, wp.z, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ)); a_Client->SendBlockChange(wp.x, wp.y, wp.z, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ));
// FS #268 - if a BlockEntity digging is cancelled by a plugin, the entire block entity must be re-sent to the client: // FS #268 - if a BlockEntity digging is cancelled by a plugin, the entire block entity must be re-sent to the client:
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), end = m_BlockEntities.end(); itr != end; ++itr) for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), end = m_BlockEntities.end(); itr != end; ++itr)
{ {
@ -1637,7 +1637,7 @@ cBlockEntity * cChunk::GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ)
return *itr; return *itr;
} }
} // for itr - m_BlockEntities[] } // for itr - m_BlockEntities[]
return nullptr; return nullptr;
} }
@ -1704,7 +1704,7 @@ void cChunk::SetAreaBiome(int a_MinRelX, int a_MaxRelX, int a_MinRelZ, int a_Max
} }
} }
MarkDirty(); MarkDirty();
// Re-send the chunk to all clients: // Re-send the chunk to all clients:
for (auto ClientHandle : m_LoadedByClient) for (auto ClientHandle : m_LoadedByClient)
{ {
@ -1721,7 +1721,7 @@ void cChunk::CollectPickupsByPlayer(cPlayer & a_Player)
double PosX = a_Player.GetPosX(); double PosX = a_Player.GetPosX();
double PosY = a_Player.GetPosY(); double PosY = a_Player.GetPosY();
double PosZ = a_Player.GetPosZ(); double PosZ = a_Player.GetPosZ();
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr)
{ {
if ((!(*itr)->IsPickup()) && (!(*itr)->IsProjectile())) if ((!(*itr)->IsPickup()) && (!(*itr)->IsProjectile()))
@ -2150,14 +2150,14 @@ bool cChunk::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBloc
{ {
continue; continue;
} }
if (a_Callback.Item(*itr)) if (a_Callback.Item(*itr))
{ {
return false; return false;
} }
return true; return true;
} // for itr - m_BlockEntitites[] } // for itr - m_BlockEntitites[]
// Not found: // Not found:
return false; return false;
} }
@ -2180,7 +2180,7 @@ bool cChunk::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCal
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false; return false;
} }
// The correct block entity is here // The correct block entity is here
if (a_Callback.Item(reinterpret_cast<cBeaconEntity *>(*itr))) if (a_Callback.Item(reinterpret_cast<cBeaconEntity *>(*itr)))
{ {
@ -2188,7 +2188,7 @@ bool cChunk::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCal
} }
return true; return true;
} // for itr - m_BlockEntitites[] } // for itr - m_BlockEntitites[]
// Not found: // Not found:
return false; return false;
} }
@ -2244,7 +2244,7 @@ bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallb
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false; return false;
} }
// The correct block entity is here // The correct block entity is here
if (a_Callback.Item(reinterpret_cast<cChestEntity *>(*itr))) if (a_Callback.Item(reinterpret_cast<cChestEntity *>(*itr)))
{ {
@ -2252,7 +2252,7 @@ bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallb
} }
return true; return true;
} // for itr - m_BlockEntitites[] } // for itr - m_BlockEntitites[]
// Not found: // Not found:
return false; return false;
} }
@ -2276,7 +2276,7 @@ bool cChunk::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispen
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false; return false;
} }
// The correct block entity is here // The correct block entity is here
if (a_Callback.Item(reinterpret_cast<cDispenserEntity *>(*itr))) if (a_Callback.Item(reinterpret_cast<cDispenserEntity *>(*itr)))
{ {
@ -2284,7 +2284,7 @@ bool cChunk::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispen
} }
return true; return true;
} // for itr - m_BlockEntitites[] } // for itr - m_BlockEntitites[]
// Not found: // Not found:
return false; return false;
} }
@ -2308,7 +2308,7 @@ bool cChunk::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperC
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false; return false;
} }
// The correct block entity is here // The correct block entity is here
if (a_Callback.Item(reinterpret_cast<cDropperEntity *>(*itr))) if (a_Callback.Item(reinterpret_cast<cDropperEntity *>(*itr)))
{ {
@ -2316,7 +2316,7 @@ bool cChunk::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperC
} }
return true; return true;
} // for itr - m_BlockEntitites[] } // for itr - m_BlockEntitites[]
// Not found: // Not found:
return false; return false;
} }
@ -2340,7 +2340,7 @@ bool cChunk::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDrop
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false; return false;
} }
// The correct block entity is here // The correct block entity is here
if (a_Callback.Item(reinterpret_cast<cDropSpenserEntity *>(*itr))) if (a_Callback.Item(reinterpret_cast<cDropSpenserEntity *>(*itr)))
{ {
@ -2348,7 +2348,7 @@ bool cChunk::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDrop
} }
return true; return true;
} // for itr - m_BlockEntitites[] } // for itr - m_BlockEntitites[]
// Not found: // Not found:
return false; return false;
} }
@ -2380,7 +2380,7 @@ bool cChunk::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceC
return false; return false;
} }
} // switch (BlockType) } // switch (BlockType)
// The correct block entity is here, // The correct block entity is here,
if (a_Callback.Item(reinterpret_cast<cFurnaceEntity *>(*itr))) if (a_Callback.Item(reinterpret_cast<cFurnaceEntity *>(*itr)))
{ {
@ -2388,7 +2388,7 @@ bool cChunk::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceC
} }
return true; return true;
} // for itr - m_BlockEntitites[] } // for itr - m_BlockEntitites[]
// Not found: // Not found:
return false; return false;
} }
@ -2412,7 +2412,7 @@ bool cChunk::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBl
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false; return false;
} }
// The correct block entity is here // The correct block entity is here
if (a_Callback.Item(reinterpret_cast<cNoteEntity *>(*itr))) if (a_Callback.Item(reinterpret_cast<cNoteEntity *>(*itr)))
{ {
@ -2420,7 +2420,7 @@ bool cChunk::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBl
} }
return true; return true;
} // for itr - m_BlockEntitites[] } // for itr - m_BlockEntitites[]
// Not found: // Not found:
return false; return false;
} }
@ -2444,7 +2444,7 @@ bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCom
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false; return false;
} }
// The correct block entity is here, // The correct block entity is here,
if (a_Callback.Item(reinterpret_cast<cCommandBlockEntity *>(*itr))) if (a_Callback.Item(reinterpret_cast<cCommandBlockEntity *>(*itr)))
{ {
@ -2452,7 +2452,7 @@ bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCom
} }
return true; return true;
} // for itr - m_BlockEntitites[] } // for itr - m_BlockEntitites[]
// Not found: // Not found:
return false; return false;
} }
@ -2476,7 +2476,7 @@ bool cChunk::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadC
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false; return false;
} }
// The correct block entity is here, // The correct block entity is here,
if (a_Callback.Item(reinterpret_cast<cMobHeadEntity *>(*itr))) if (a_Callback.Item(reinterpret_cast<cMobHeadEntity *>(*itr)))
{ {
@ -2484,7 +2484,7 @@ bool cChunk::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadC
} }
return true; return true;
} // for itr - m_BlockEntitites[] } // for itr - m_BlockEntitites[]
// Not found: // Not found:
return false; return false;
} }
@ -2508,7 +2508,7 @@ bool cChunk::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlower
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false; return false;
} }
// The correct block entity is here // The correct block entity is here
if (a_Callback.Item(reinterpret_cast<cFlowerPotEntity *>(*itr))) if (a_Callback.Item(reinterpret_cast<cFlowerPotEntity *>(*itr)))
{ {
@ -2516,7 +2516,7 @@ bool cChunk::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlower
} }
return true; return true;
} // for itr - m_BlockEntitites[] } // for itr - m_BlockEntitites[]
// Not found: // Not found:
return false; return false;
} }
@ -2546,11 +2546,11 @@ bool cChunk::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_
return true; return true;
} }
} // switch (BlockType) } // switch (BlockType)
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false; return false;
} // for itr - m_BlockEntitites[] } // for itr - m_BlockEntitites[]
// Not found: // Not found:
return false; return false;
} }
@ -2600,6 +2600,31 @@ void cChunk::GetBlockInfo(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_Bloc
bool cChunk::GetChunkAndRelByAbsolute(const Vector3d & a_Position, cChunk ** a_Chunk, Vector3i & a_Rel)
{
return GetChunkAndRelByAbsolute(Vector3i(FloorC(a_Position.x), FloorC(a_Position.y), FloorC(a_Position.z)), a_Chunk, a_Rel);
}
bool cChunk::GetChunkAndRelByAbsolute(const Vector3i & a_Position, cChunk ** a_Chunk, Vector3i & a_Rel)
{
*a_Chunk = this->GetNeighborChunk(a_Position.x, a_Position.z);
if ((*a_Chunk == nullptr) || !(*a_Chunk)->IsValid())
{
return false;
}
a_Rel.x = a_Position.x - (*a_Chunk)->GetPosX() * cChunkDef::Width;
a_Rel.y = a_Position.y;
a_Rel.z = a_Position.z - (*a_Chunk)->GetPosZ() * cChunkDef::Width;
return true;
}
cChunk * cChunk::GetNeighborChunk(int a_BlockX, int a_BlockZ) cChunk * cChunk::GetNeighborChunk(int a_BlockX, int a_BlockZ)
{ {
// Convert coords to relative, then call the relative version: // Convert coords to relative, then call the relative version:
@ -2652,7 +2677,7 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ)
// Going X first failed, but if the request is crossing Z as well, let's try the Z first later on. // Going X first failed, but if the request is crossing Z as well, let's try the Z first later on.
ReturnThis = false; ReturnThis = false;
} }
if (a_RelZ < 0) if (a_RelZ < 0)
{ {
if (m_NeighborZM != nullptr) if (m_NeighborZM != nullptr)
@ -2671,7 +2696,7 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ)
} }
return nullptr; return nullptr;
} }
return (ReturnThis ? this : nullptr); return (ReturnThis ? this : nullptr);
} }
@ -2691,7 +2716,7 @@ cChunk * cChunk::GetRelNeighborChunkAdjustCoords(int & a_RelX, int & a_RelZ) con
{ {
return ToReturn; return ToReturn;
} }
// Request for a different chunk, calculate chunk offset: // Request for a different chunk, calculate chunk offset:
int RelX = a_RelX; // Make a local copy of the coords (faster access) int RelX = a_RelX; // Make a local copy of the coords (faster access)
int RelZ = a_RelZ; int RelZ = a_RelZ;
@ -2721,7 +2746,7 @@ cChunk * cChunk::GetRelNeighborChunkAdjustCoords(int & a_RelX, int & a_RelZ) con
a_RelZ = RelZ; a_RelZ = RelZ;
return ToReturn; return ToReturn;
} }
// The chunk cannot be walked through neighbors, find it through the chunkmap: // The chunk cannot be walked through neighbors, find it through the chunkmap:
int AbsX = a_RelX + m_PosX * Width; int AbsX = a_RelX + m_PosX * Width;
int AbsZ = a_RelZ + m_PosZ * Width; int AbsZ = a_RelZ + m_PosZ * Width;

View File

@ -63,7 +63,9 @@ typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
typedef cItemCallback<cMobHeadEntity> cMobHeadCallback; typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback; typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
// A convenience macro for calling GetChunkAndRelByAbsolute.
#define PREPARE_REL_AND_CHUNK(Position, OriginalChunk) cChunk * Chunk; Vector3i Rel; bool RelSuccess = (OriginalChunk).GetChunkAndRelByAbsolute(Position, &Chunk, Rel);
#define PREPARE_BLOCKDATA BLOCKTYPE BlockType; NIBBLETYPE BlockMeta;
// This class is not to be used directly // This class is not to be used directly
@ -109,9 +111,9 @@ public:
bool IsDirty(void) const {return m_IsDirty; } bool IsDirty(void) const {return m_IsDirty; }
bool CanUnload(void); bool CanUnload(void);
bool IsLightValid(void) const {return m_IsLightValid; } bool IsLightValid(void) const {return m_IsLightValid; }
/* /*
To save a chunk, the WSSchema must: To save a chunk, the WSSchema must:
1. Mark the chunk as being saved (MarkSaving()) 1. Mark the chunk as being saved (MarkSaving())
@ -126,34 +128,34 @@ public:
/** Marks the chunk as failed to load. /** Marks the chunk as failed to load.
If m_ShouldGenerateIfLoadFailed is set, queues the chunk for generating. */ If m_ShouldGenerateIfLoadFailed is set, queues the chunk for generating. */
void MarkLoadFailed(void); void MarkLoadFailed(void);
/** Gets all chunk data, calls the a_Callback's methods for each data type */ /** Gets all chunk data, calls the a_Callback's methods for each data type */
void GetAllData(cChunkDataCallback & a_Callback); void GetAllData(cChunkDataCallback & a_Callback);
/** Sets all chunk data as either loaded from the storage or generated. /** Sets all chunk data as either loaded from the storage or generated.
BlockLight and BlockSkyLight are optional, if not present, chunk will be marked as unlighted. BlockLight and BlockSkyLight are optional, if not present, chunk will be marked as unlighted.
Modifies the BlockEntity list in a_SetChunkData - moves the block entities into the chunk. */ Modifies the BlockEntity list in a_SetChunkData - moves the block entities into the chunk. */
void SetAllData(cSetChunkData & a_SetChunkData); void SetAllData(cSetChunkData & a_SetChunkData);
void SetLight( void SetLight(
const cChunkDef::BlockNibbles & a_BlockLight, const cChunkDef::BlockNibbles & a_BlockLight,
const cChunkDef::BlockNibbles & a_SkyLight const cChunkDef::BlockNibbles & a_SkyLight
); );
/** Copies m_BlockData into a_BlockTypes, only the block types */ /** Copies m_BlockData into a_BlockTypes, only the block types */
void GetBlockTypes(BLOCKTYPE * a_BlockTypes); void GetBlockTypes(BLOCKTYPE * a_BlockTypes);
/** Writes the specified cBlockArea at the coords specified. Note that the coords may extend beyond the chunk! */ /** Writes the specified cBlockArea at the coords specified. Note that the coords may extend beyond the chunk! */
void WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes); void WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes);
/** Returns true if there is a block entity at the coords specified */ /** Returns true if there is a block entity at the coords specified */
bool HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ); bool HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ);
/** Sets or resets the internal flag that prevents chunk from being unloaded. /** Sets or resets the internal flag that prevents chunk from being unloaded.
The flag is cumulative - it can be set multiple times and then needs to be un-set that many times The flag is cumulative - it can be set multiple times and then needs to be un-set that many times
before the chunk is unloadable again. */ before the chunk is unloadable again. */
void Stay(bool a_Stay = true); void Stay(bool a_Stay = true);
/** Recence all mobs proximities to players in order to know what to do with them */ /** Recence all mobs proximities to players in order to know what to do with them */
void CollectMobCensus(cMobCensus & toFill); void CollectMobCensus(cMobCensus & toFill);
@ -161,22 +163,22 @@ public:
void SpawnMobs(cMobSpawner & a_MobSpawner); void SpawnMobs(cMobSpawner & a_MobSpawner);
void Tick(std::chrono::milliseconds a_Dt); void Tick(std::chrono::milliseconds a_Dt);
/** Ticks a single block. Used by cWorld::TickQueuedBlocks() to tick the queued blocks */ /** Ticks a single block. Used by cWorld::TickQueuedBlocks() to tick the queued blocks */
void TickBlock(int a_RelX, int a_RelY, int a_RelZ); void TickBlock(int a_RelX, int a_RelY, int a_RelZ);
int GetPosX(void) const { return m_PosX; } int GetPosX(void) const { return m_PosX; }
int GetPosZ(void) const { return m_PosZ; } int GetPosZ(void) const { return m_PosZ; }
cWorld * GetWorld(void) const { return m_World; } cWorld * GetWorld(void) const { return m_World; }
void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true); void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true);
// SetBlock() does a lot of work (heightmap, tickblocks, blockentities) so a BlockIdx version doesn't make sense // SetBlock() does a lot of work (heightmap, tickblocks, blockentities) so a BlockIdx version doesn't make sense
void SetBlock( const Vector3i & a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { SetBlock( a_RelBlockPos.x, a_RelBlockPos.y, a_RelBlockPos.z, a_BlockType, a_BlockMeta); } void SetBlock( const Vector3i & a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { SetBlock( a_RelBlockPos.x, a_RelBlockPos.y, a_RelBlockPos.z, a_BlockType, a_BlockMeta); }
/** Queues block for ticking (m_ToTickQueue) */ /** Queues block for ticking (m_ToTickQueue) */
void QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ); void QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ);
/** Queues all 6 neighbors of the specified block for ticking (m_ToTickQueue). If any are outside the chunk, relays the checking to the proper neighboring chunk */ /** Queues all 6 neighbors of the specified block for ticking (m_ToTickQueue). If any are outside the chunk, relays the checking to the proper neighboring chunk */
void QueueTickBlockNeighbors(int a_RelX, int a_RelY, int a_RelZ); void QueueTickBlockNeighbors(int a_RelX, int a_RelY, int a_RelZ);
@ -185,18 +187,38 @@ public:
BLOCKTYPE GetBlock(const Vector3i & a_RelCoords) const { return GetBlock(a_RelCoords.x, a_RelCoords.y, a_RelCoords.z); } BLOCKTYPE GetBlock(const Vector3i & a_RelCoords) const { return GetBlock(a_RelCoords.x, a_RelCoords.y, a_RelCoords.z); }
void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const; void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
void GetBlockInfo (int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); void GetBlockInfo (int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
/** Convert absolute coordinates into relative coordinates.
Returns false on failure to obtain a valid chunk. Returns true otherwise.
@param a_Position The position you'd like to convert, a_Position need not be in the calling chunk and can safely be out
of its bounds, but for best performance, it should not be too far from the calling chunk.
@param a_Chunk Returns the chunk in which a_Position is in. If a_Position is within the calling chunk's bounds,
returns the calling chunk. For best performance, a_Position shouldn't be too far from the calling chunk.
@param a_Rel Returns the converted relative position. Note that it is relative to the returned a_Chunk.
The vector will not be modified if the function returns false. */
bool GetChunkAndRelByAbsolute(const Vector3d & a_Position, cChunk ** a_Chunk, Vector3i & a_Rel);
/** Convert absolute coordinates into relative coordinates.
Returns false on failure to obtain a valid chunk. Returns true otherwise.
@param a_Position The position you'd like to convert, a_Position need not be in the calling chunk and can safely be out
of its bounds, but for best performance, it should not be too far from the calling chunk.
@param a_Chunk Returns the chunk in which a_Position is in. If a_Position is within the calling chunk's bounds,
returns the calling chunk. For best performance, a_Position shouldn't be too far from the calling chunk.
@param a_Rel Returns the converted relative position. Note that it is relative to the returned a_Chunk.
The vector will not be modified if the function returns false. */
bool GetChunkAndRelByAbsolute(const Vector3i & a_Position, cChunk ** a_Chunk, Vector3i & a_Rel);
/** Returns the chunk into which the specified block belongs, by walking the neighbors. /** Returns the chunk into which the specified block belongs, by walking the neighbors.
Will return self if appropriate. Returns nullptr if not reachable through neighbors. Will return self if appropriate. Returns nullptr if not reachable through neighbors.
*/ */
cChunk * GetNeighborChunk(int a_BlockX, int a_BlockZ); cChunk * GetNeighborChunk(int a_BlockX, int a_BlockZ);
/** /**
Returns the chunk into which the relatively-specified block belongs, by walking the neighbors. Returns the chunk into which the relatively-specified block belongs, by walking the neighbors.
Will return self if appropriate. Returns nullptr if not reachable through neighbors. Will return self if appropriate. Returns nullptr if not reachable through neighbors.
*/ */
cChunk * GetRelNeighborChunk(int a_RelX, int a_RelZ); cChunk * GetRelNeighborChunk(int a_RelX, int a_RelZ);
/** /**
Returns the chunk into which the relatively-specified block belongs. Returns the chunk into which the relatively-specified block belongs.
Also modifies the relative coords from this-relative to return-relative. Also modifies the relative coords from this-relative to return-relative.
@ -204,19 +226,19 @@ public:
Will try walking the neighbors first; if that fails, will query the chunkmap Will try walking the neighbors first; if that fails, will query the chunkmap
*/ */
cChunk * GetRelNeighborChunkAdjustCoords(int & a_RelX, int & a_RelZ) const; cChunk * GetRelNeighborChunkAdjustCoords(int & a_RelX, int & a_RelZ) const;
EMCSBiome GetBiomeAt(int a_RelX, int a_RelZ) const {return cChunkDef::GetBiome(m_BiomeMap, a_RelX, a_RelZ); } EMCSBiome GetBiomeAt(int a_RelX, int a_RelZ) const {return cChunkDef::GetBiome(m_BiomeMap, a_RelX, a_RelZ); }
/** Sets the biome at the specified relative coords. /** Sets the biome at the specified relative coords.
Doesn't resend the chunk to clients. */ Doesn't resend the chunk to clients. */
void SetBiomeAt(int a_RelX, int a_RelZ, EMCSBiome a_Biome); void SetBiomeAt(int a_RelX, int a_RelZ, EMCSBiome a_Biome);
/** Sets the biome in the specified relative coords area. All the coords are inclusive. /** Sets the biome in the specified relative coords area. All the coords are inclusive.
Sends the chunk to all relevant clients. */ Sends the chunk to all relevant clients. */
void SetAreaBiome(int a_MinRelX, int a_MaxRelX, int a_MinRelZ, int a_MaxRelZ, EMCSBiome a_Biome); void SetAreaBiome(int a_MinRelX, int a_MaxRelX, int a_MinRelZ, int a_MaxRelZ, EMCSBiome a_Biome);
void CollectPickupsByPlayer(cPlayer & a_Player); void CollectPickupsByPlayer(cPlayer & a_Player);
/** 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);
@ -226,20 +248,20 @@ public:
/** Adds a client to the chunk; returns true if added, false if already there */ /** Adds a client to the chunk; returns true if added, false if already there */
bool AddClient(cClientHandle * a_Client); bool AddClient(cClientHandle * a_Client);
/** Removes the specified client from the chunk; ignored if client not in chunk. */ /** Removes the specified client from the chunk; ignored if client not in chunk. */
void RemoveClient(cClientHandle * a_Client); void RemoveClient(cClientHandle * a_Client);
/** Returns true if the specified client is present in this chunk. */ /** Returns true if the specified client is present in this chunk. */
bool HasClient(cClientHandle * a_Client); bool HasClient(cClientHandle * a_Client);
/** Returns true if theres any client in the chunk; false otherwise */ /** Returns true if theres any client in the chunk; false otherwise */
bool HasAnyClients(void) const; bool HasAnyClients(void) const;
void AddEntity(cEntity * a_Entity); void AddEntity(cEntity * a_Entity);
void RemoveEntity(cEntity * a_Entity); void RemoveEntity(cEntity * a_Entity);
bool HasEntity(UInt32 a_EntityID); bool HasEntity(UInt32 a_EntityID);
/** Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true */ /** Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true */
bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible
@ -270,10 +292,10 @@ public:
/** Calls the callback for each furnace; returns true if all furnaces processed, false if the callback aborted by returning true */ /** Calls the callback for each furnace; returns true if all furnaces processed, false if the callback aborted by returning true */
bool ForEachFurnace(cFurnaceCallback & a_Callback); // Lua-accessible bool ForEachFurnace(cFurnaceCallback & a_Callback); // Lua-accessible
/** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible
/** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */
bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible
@ -300,7 +322,7 @@ public:
/** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */ /** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback);
/** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */ /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */
bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback); bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback);
@ -341,14 +363,14 @@ public:
void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr);
void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = nullptr); void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = nullptr);
void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ); void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ);
void SendBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client); void SendBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client);
Vector3i PositionToWorldPosition(const Vector3i & a_RelPos) Vector3i PositionToWorldPosition(const Vector3i & a_RelPos)
{ {
return PositionToWorldPosition(a_RelPos.x, a_RelPos.y, a_RelPos.z); return PositionToWorldPosition(a_RelPos.x, a_RelPos.y, a_RelPos.z);
} }
void PositionToWorldPosition(int a_RelX, int a_RelY, int a_RelZ, int & a_BlockX, int & a_BlockY, int & a_BlockZ); void PositionToWorldPosition(int a_RelX, int a_RelY, int a_RelZ, int & a_BlockX, int & a_BlockY, int & a_BlockZ);
Vector3i PositionToWorldPosition(int a_RelX, int a_RelY, int a_RelZ); Vector3i PositionToWorldPosition(int a_RelX, int a_RelY, int a_RelZ);
@ -357,7 +379,7 @@ public:
m_IsDirty = true; m_IsDirty = true;
m_IsSaving = false; m_IsSaving = false;
} }
/** Sets the blockticking to start at the specified block. Only one blocktick may be set, second call overwrites the first call */ /** Sets the blockticking to start at the specified block. Only one blocktick may be set, second call overwrites the first call */
inline void SetNextBlockTick(int a_RelX, int a_RelY, int a_RelZ) inline void SetNextBlockTick(int a_RelX, int a_RelY, int a_RelZ)
{ {
@ -365,7 +387,7 @@ public:
m_BlockTickY = a_RelY; m_BlockTickY = a_RelY;
m_BlockTickZ = a_RelZ; m_BlockTickZ = a_RelZ;
} }
inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
{ {
return m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ); return m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ);
@ -377,23 +399,32 @@ public:
{ {
MarkDirty(); MarkDirty();
m_IsRedstoneDirty = true; m_IsRedstoneDirty = true;
m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(a_RelX, a_RelY, a_RelZ), a_Meta)); m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(a_RelX, a_RelY, a_RelZ), a_Meta));
} }
} }
/** Light alterations based on time */
NIBBLETYPE GetTimeAlteredLight(NIBBLETYPE a_Skylight) const;
/** Get the level of artificial light illuminating the block (0 - 15) */
inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkData.GetBlockLight(a_RelX, a_RelY, a_RelZ); } inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkData.GetBlockLight(a_RelX, a_RelY, a_RelZ); }
/** Get the level of sky light illuminating the block (0 - 15) independent of daytime. */
inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkData.GetSkyLight(a_RelX, a_RelY, a_RelZ); } inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkData.GetSkyLight(a_RelX, a_RelY, a_RelZ); }
/** Get the level of sky light illuminating the block (0 - 15), taking daytime into a account. */
inline NIBBLETYPE GetSkyLightAltered (int a_RelX, int a_RelY, int a_RelZ) const {return GetTimeAlteredLight(m_ChunkData.GetSkyLight(a_RelX, a_RelY, a_RelZ)); }
/** Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */ /** Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */
bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const; bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
/** Same as GetBlockType(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */ /** Same as GetBlockType(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */
bool UnboundedRelGetBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType) const; bool UnboundedRelGetBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType) const;
/** Same as GetBlockMeta(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */ /** Same as GetBlockMeta(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */
bool UnboundedRelGetBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockMeta) const; bool UnboundedRelGetBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockMeta) const;
/** Same as GetBlockBlockLight(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */ /** Same as GetBlockBlockLight(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */
bool UnboundedRelGetBlockBlockLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockLight) const; bool UnboundedRelGetBlockBlockLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockLight) const;
@ -408,12 +439,10 @@ public:
/** Same as FastSetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */ /** Same as FastSetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */
bool UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); bool UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
/** Same as QueueTickBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s in such a case), ignores unsuccessful attempts */ /** Same as QueueTickBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s in such a case), ignores unsuccessful attempts */
void UnboundedQueueTickBlock(int a_RelX, int a_RelY, int a_RelZ); void UnboundedQueueTickBlock(int a_RelX, int a_RelY, int a_RelZ);
/** Light alterations based on time */
NIBBLETYPE GetTimeAlteredLight(NIBBLETYPE a_Skylight) const;
// Per-chunk simulator data: // Per-chunk simulator data:
@ -429,11 +458,11 @@ public:
cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * GetBlockEntity(const Vector3i & a_BlockPos) { return GetBlockEntity(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); } cBlockEntity * GetBlockEntity(const Vector3i & a_BlockPos) { return GetBlockEntity(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); }
/** Returns true if the chunk should be ticked in the tick-thread. /** Returns true if the chunk should be ticked in the tick-thread.
Checks if there are any clients and if the always-tick flag is set */ Checks if there are any clients and if the always-tick flag is set */
bool ShouldBeTicked(void) const; bool ShouldBeTicked(void) const;
/** Increments (a_AlwaysTicked == true) or decrements (false) the m_AlwaysTicked counter. /** Increments (a_AlwaysTicked == true) or decrements (false) the m_AlwaysTicked counter.
If the m_AlwaysTicked counter is greater than zero, the chunk is ticked in the tick-thread regardless of If the m_AlwaysTicked counter is greater than zero, the chunk is ticked in the tick-thread regardless of
whether it has any clients or not. whether it has any clients or not.
@ -450,7 +479,7 @@ public:
private: private:
friend class cChunkMap; friend class cChunkMap;
struct sSetBlockQueueItem struct sSetBlockQueueItem
{ {
Int64 m_Tick; Int64 m_Tick;
@ -458,7 +487,7 @@ private:
BLOCKTYPE m_BlockType; BLOCKTYPE m_BlockType;
NIBBLETYPE m_BlockMeta; NIBBLETYPE m_BlockMeta;
BLOCKTYPE m_PreviousType; BLOCKTYPE m_PreviousType;
sSetBlockQueueItem(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType) : sSetBlockQueueItem(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType) :
m_Tick(a_Tick), m_RelX(a_RelX), m_RelY(a_RelY), m_RelZ(a_RelZ), m_BlockType(a_BlockType), m_BlockMeta(a_BlockMeta), m_PreviousType(a_PreviousBlockType) m_Tick(a_Tick), m_RelX(a_RelX), m_RelY(a_RelY), m_RelZ(a_RelZ), m_BlockType(a_BlockType), m_BlockMeta(a_BlockMeta), m_PreviousType(a_PreviousBlockType)
{ {
@ -466,7 +495,7 @@ private:
} ; } ;
typedef std::vector<sSetBlockQueueItem> sSetBlockQueueVector; typedef std::vector<sSetBlockQueueItem> sSetBlockQueueVector;
/** Holds the presence status of the chunk - if it is present, or in the loader / generator queue, or unloaded */ /** Holds the presence status of the chunk - if it is present, or in the loader / generator queue, or unloaded */
ePresence m_Presence; ePresence m_Presence;
@ -478,15 +507,15 @@ private:
bool m_IsDirty; // True if the chunk has changed since it was last saved bool m_IsDirty; // True if the chunk has changed since it was last saved
bool m_IsSaving; // True if the chunk is being saved bool m_IsSaving; // True if the chunk is being saved
bool m_HasLoadFailed; // True if chunk failed to load and hasn't been generated yet since then bool m_HasLoadFailed; // True if chunk failed to load and hasn't been generated yet since then
std::vector<Vector3i> m_ToTickBlocks; std::vector<Vector3i> m_ToTickBlocks;
sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients
// A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers // A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers
std::vector<cClientHandle *> m_LoadedByClient; std::vector<cClientHandle *> m_LoadedByClient;
cEntityList m_Entities; cEntityList m_Entities;
cBlockEntityList m_BlockEntities; cBlockEntityList m_BlockEntities;
/** Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded */ /** Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded */
int m_StayCount; int m_StayCount;
@ -500,12 +529,12 @@ private:
cChunkDef::BiomeMap m_BiomeMap; cChunkDef::BiomeMap m_BiomeMap;
int m_BlockTickX, m_BlockTickY, m_BlockTickZ; int m_BlockTickX, m_BlockTickY, m_BlockTickZ;
cChunk * m_NeighborXM; // Neighbor at [X - 1, Z] cChunk * m_NeighborXM; // Neighbor at [X - 1, Z]
cChunk * m_NeighborXP; // Neighbor at [X + 1, Z] cChunk * m_NeighborXP; // Neighbor at [X + 1, Z]
cChunk * m_NeighborZM; // Neighbor at [X, Z - 1] cChunk * m_NeighborZM; // Neighbor at [X, Z - 1]
cChunk * m_NeighborZP; // Neighbor at [X, Z + 1] cChunk * m_NeighborZP; // Neighbor at [X, Z + 1]
// Per-chunk simulator data: // Per-chunk simulator data:
cFireSimulatorChunkData m_FireSimulatorData; cFireSimulatorChunkData m_FireSimulatorData;
cFluidSimulatorData * m_WaterSimulatorData; cFluidSimulatorData * m_WaterSimulatorData;
@ -517,12 +546,12 @@ private:
/** Indicates if simulate-once blocks should be updated by the redstone simulator */ /** Indicates if simulate-once blocks should be updated by the redstone simulator */
bool m_IsRedstoneDirty; bool m_IsRedstoneDirty;
/** If greater than zero, the chunk is ticked even if it has no clients. /** If greater than zero, the chunk is ticked even if it has no clients.
Manipulated by the SetAlwaysTicked() function, allows for nested calls of the function. Manipulated by the SetAlwaysTicked() function, allows for nested calls of the function.
This is the support for plugin-accessible chunk tick forcing. */ This is the support for plugin-accessible chunk tick forcing. */
int m_AlwaysTicked; int m_AlwaysTicked;
// Pick up a random block of this chunk // Pick up a random block of this chunk
void GetRandomBlockCoords(int & a_X, int & a_Y, int & a_Z); void GetRandomBlockCoords(int & a_X, int & a_Y, int & a_Z);
@ -533,31 +562,31 @@ private:
/** Creates a block entity for each block that needs a block entity and doesn't have one in the list */ /** Creates a block entity for each block that needs a block entity and doesn't have one in the list */
void CreateBlockEntities(void); void CreateBlockEntities(void);
/** Wakes up each simulator for its specific blocks; through all the blocks in the chunk */ /** Wakes up each simulator for its specific blocks; through all the blocks in the chunk */
void WakeUpSimulators(void); void WakeUpSimulators(void);
/** Sends m_PendingSendBlocks to all clients */ /** Sends m_PendingSendBlocks to all clients */
void BroadcastPendingBlockChanges(void); void BroadcastPendingBlockChanges(void);
/** Checks the block scheduled for checking in m_ToTickBlocks[] */ /** Checks the block scheduled for checking in m_ToTickBlocks[] */
void CheckBlocks(); void CheckBlocks();
/** Ticks several random blocks in the chunk */ /** Ticks several random blocks in the chunk */
void TickBlocks(void); void TickBlocks(void);
/** Adds snow to the top of snowy biomes and hydrates farmland / fills cauldrons in rainy biomes */ /** Adds snow to the top of snowy biomes and hydrates farmland / fills cauldrons in rainy biomes */
void ApplyWeatherToTop(void); void ApplyWeatherToTop(void);
/** Grows sugarcane by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking) */ /** Grows sugarcane by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking) */
void GrowSugarcane (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks); void GrowSugarcane (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks);
/** Grows cactus by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking) */ /** Grows cactus by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking) */
void GrowCactus (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks); void GrowCactus (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks);
/** Grows a melon or a pumpkin next to the block specified (assumed to be the stem) */ /** Grows a melon or a pumpkin next to the block specified (assumed to be the stem) */
void GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, MTRand & a_Random); void GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, MTRand & a_Random);
/** Called by Tick() when an entity moves out of this chunk into a neighbor; moves the entity and sends spawn / despawn packet to clients */ /** Called by Tick() when an entity moves out of this chunk into a neighbor; moves the entity and sends spawn / despawn packet to clients */
void MoveEntityToNewChunk(cEntity * a_Entity); void MoveEntityToNewChunk(cEntity * a_Entity);
}; };

View File

@ -37,7 +37,6 @@
class cWorld; class cWorld;
class cClientHandle; class cClientHandle;
class cPlayer; class cPlayer;

View File

@ -36,11 +36,11 @@ void cAggressiveMonster::InStateChasing(std::chrono::milliseconds a_Dt, cChunk &
void cAggressiveMonster::EventSeePlayer(cEntity * a_Entity) void cAggressiveMonster::EventSeePlayer(cEntity * a_Entity, cChunk & a_Chunk)
{ {
if (!static_cast<cPlayer *>(a_Entity)->IsGameModeCreative()) if (!static_cast<cPlayer *>(a_Entity)->IsGameModeCreative())
{ {
super::EventSeePlayer(a_Entity); super::EventSeePlayer(a_Entity, a_Chunk);
m_EMState = CHASING; m_EMState = CHASING;
} }
} }
@ -59,7 +59,7 @@ void cAggressiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
} }
else else
{ {
CheckEventSeePlayer(); CheckEventSeePlayer(a_Chunk);
} }
if (m_Target == nullptr) if (m_Target == nullptr)

View File

@ -19,7 +19,7 @@ public:
virtual void Tick (std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual void Tick (std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void InStateChasing(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual void InStateChasing(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void EventSeePlayer(cEntity *) override; virtual void EventSeePlayer(cEntity * a_Player, cChunk & a_Chunk) override;
/** Try to perform attack /** Try to perform attack
returns true if attack was deemed successful (hit player, fired projectile, creeper exploded, etc.) even if it didn't actually do damage returns true if attack was deemed successful (hit player, fired projectile, creeper exploded, etc.) even if it didn't actually do damage

View File

@ -28,32 +28,32 @@ public:
{ {
return false; return false;
} }
Vector3d Direction = m_EndermanPos - a_Player->GetPosition(); Vector3d Direction = m_EndermanPos - a_Player->GetPosition();
// Don't check players who are more then SightDistance (64) blocks away // Don't check players who are more then SightDistance (64) blocks away
if (Direction.Length() > m_SightDistance) if (Direction.Length() > m_SightDistance)
{ {
return false; return false;
} }
// Don't check if the player has a pumpkin on his head // Don't check if the player has a pumpkin on his head
if (a_Player->GetEquippedHelmet().m_ItemType == E_BLOCK_PUMPKIN) if (a_Player->GetEquippedHelmet().m_ItemType == E_BLOCK_PUMPKIN)
{ {
return false; return false;
} }
Vector3d LookVector = a_Player->GetLookVector(); Vector3d LookVector = a_Player->GetLookVector();
double dot = Direction.Dot(LookVector); double dot = Direction.Dot(LookVector);
// 0.09 rad ~ 5 degrees // 0.09 rad ~ 5 degrees
// If the player's crosshair is within 5 degrees of the enderman, it counts as looking // If the player's crosshair is within 5 degrees of the enderman, it counts as looking
if (dot <= cos(0.09)) if (dot <= cos(0.09))
{ {
return false; return false;
} }
cTracer LineOfSight(a_Player->GetWorld()); cTracer LineOfSight(a_Player->GetWorld());
if (LineOfSight.Trace(m_EndermanPos, Direction, static_cast<int>(Direction.Length()))) if (LineOfSight.Trace(m_EndermanPos, Direction, static_cast<int>(Direction.Length())))
{ {
@ -64,7 +64,7 @@ public:
m_Player = a_Player; m_Player = a_Player;
return true; return true;
} }
cPlayer * GetPlayer(void) const { return m_Player; } cPlayer * GetPlayer(void) const { return m_Player; }
protected: protected:
@ -102,7 +102,7 @@ void cEnderman::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cEnderman::CheckEventSeePlayer() void cEnderman::CheckEventSeePlayer(cChunk & a_Chunk)
{ {
if (m_Target != nullptr) if (m_Target != nullptr)
{ {
@ -114,7 +114,7 @@ void cEnderman::CheckEventSeePlayer()
{ {
return; return;
} }
ASSERT(Callback.GetPlayer() != nullptr); ASSERT(Callback.GetPlayer() != nullptr);
if (!CheckLight()) if (!CheckLight())
@ -126,7 +126,7 @@ void cEnderman::CheckEventSeePlayer()
if (!Callback.GetPlayer()->IsGameModeCreative()) if (!Callback.GetPlayer()->IsGameModeCreative())
{ {
cMonster::EventSeePlayer(Callback.GetPlayer()); cMonster::EventSeePlayer(Callback.GetPlayer(), a_Chunk);
m_EMState = CHASING; m_EMState = CHASING;
m_bIsScreaming = true; m_bIsScreaming = true;
GetWorld()->BroadcastEntityMetadata(*this); GetWorld()->BroadcastEntityMetadata(*this);
@ -145,7 +145,7 @@ void cEnderman::CheckEventLostPlayer(void)
EventLosePlayer(); EventLosePlayer();
} }
} }

View File

@ -11,14 +11,14 @@ class cEnderman :
public cPassiveAggressiveMonster public cPassiveAggressiveMonster
{ {
typedef cPassiveAggressiveMonster super; typedef cPassiveAggressiveMonster super;
public: public:
cEnderman(void); cEnderman(void);
CLASS_PROTODEF(cEnderman) CLASS_PROTODEF(cEnderman)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
virtual void CheckEventSeePlayer(void) override; virtual void CheckEventSeePlayer(cChunk & a_Chunk) override;
virtual void CheckEventLostPlayer(void) override; virtual void CheckEventLostPlayer(void) override;
virtual void EventLosePlayer(void) override; virtual void EventLosePlayer(void) override;
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;

View File

@ -560,14 +560,14 @@ void cMonster::OnRightClicked(cPlayer & a_Player)
// Checks to see if EventSeePlayer should be fired // Checks to see if EventSeePlayer should be fired
// monster sez: Do I see the player // monster sez: Do I see the player
void cMonster::CheckEventSeePlayer(void) void cMonster::CheckEventSeePlayer(cChunk & a_Chunk)
{ {
// TODO: Rewrite this to use cWorld's DoWithPlayers() // TODO: Rewrite this to use cWorld's DoWithPlayers()
cPlayer * Closest = m_World->FindClosestPlayer(GetPosition(), static_cast<float>(m_SightDistance), false); cPlayer * Closest = m_World->FindClosestPlayer(GetPosition(), static_cast<float>(m_SightDistance), false);
if (Closest != nullptr) if (Closest != nullptr)
{ {
EventSeePlayer(Closest); EventSeePlayer(Closest, a_Chunk);
} }
} }
@ -596,7 +596,7 @@ void cMonster::CheckEventLostPlayer(void)
// What to do if player is seen // What to do if player is seen
// default to change state to chasing // default to change state to chasing
void cMonster::EventSeePlayer(cEntity * a_SeenPlayer) void cMonster::EventSeePlayer(cEntity * a_SeenPlayer, cChunk & a_Chunk)
{ {
m_Target = a_SeenPlayer; m_Target = a_SeenPlayer;
} }

View File

@ -67,8 +67,8 @@ public:
eFamily GetMobFamily(void) const; eFamily GetMobFamily(void) const;
// tolua_end // tolua_end
virtual void CheckEventSeePlayer(void); virtual void CheckEventSeePlayer(cChunk & a_Chunk);
virtual void EventSeePlayer(cEntity * a_Player); virtual void EventSeePlayer(cEntity * a_Entity, cChunk & a_Chunk);
/** Reads the monster configuration for the specified monster name and assigns it to this object. */ /** Reads the monster configuration for the specified monster name and assigns it to this object. */
void GetMonsterConfig(const AString & a_Name); void GetMonsterConfig(const AString & a_Name);

View File

@ -25,7 +25,7 @@ bool cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
{ {
return false; return false;
} }
if ((m_Target != nullptr) && (m_Target->IsPlayer())) if ((m_Target != nullptr) && (m_Target->IsPlayer()))
{ {
if (!static_cast<cPlayer *>(m_Target)->IsGameModeCreative()) if (!static_cast<cPlayer *>(m_Target)->IsGameModeCreative())
@ -39,7 +39,7 @@ bool cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
void cPassiveAggressiveMonster::EventSeePlayer(cEntity *) void cPassiveAggressiveMonster::EventSeePlayer(cEntity *, cChunk & a_Chunk)
{ {
// don't do anything, neutral mobs don't react to just seeing the player // don't do anything, neutral mobs don't react to just seeing the player
} }

View File

@ -11,12 +11,12 @@ class cPassiveAggressiveMonster :
public cAggressiveMonster public cAggressiveMonster
{ {
typedef cAggressiveMonster super; typedef cAggressiveMonster super;
public: public:
cPassiveAggressiveMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height); cPassiveAggressiveMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void EventSeePlayer(cEntity *) override; virtual void EventSeePlayer(cEntity *, cChunk & a_Chunk) override;
} ; } ;

View File

@ -5,7 +5,7 @@
#include "../World.h" #include "../World.h"
#include "../Entities/Player.h" #include "../Entities/Player.h"
#include "../Chunk.h"
cSpider::cSpider(void) : cSpider::cSpider(void) :
@ -35,17 +35,22 @@ void cSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cSpider::EventSeePlayer(cEntity * a_Entity) void cSpider::EventSeePlayer(cEntity * a_Entity, cChunk & a_Chunk)
{ {
if (!GetWorld()->IsChunkLighted(GetChunkX(), GetChunkZ())) if (!GetWorld()->IsChunkLighted(GetChunkX(), GetChunkZ()))
{ {
GetWorld()->QueueLightChunk(GetChunkX(), GetChunkZ());
return; return;
} }
if (!static_cast<cPlayer *>(a_Entity)->IsGameModeCreative() && (GetWorld()->GetBlockBlockLight(this->GetPosition()) <= 9)) PREPARE_REL_AND_CHUNK(GetPosition(), a_Chunk);
if (!RelSuccess)
{ {
super::EventSeePlayer(a_Entity); return;
}
if (!static_cast<cPlayer *>(a_Entity)->IsGameModeCreative() && (Chunk->GetSkyLightAltered(Rel.x, Rel.y, Rel.z) <= 9))
{
super::EventSeePlayer(a_Entity, a_Chunk);
} }
} }

View File

@ -11,14 +11,14 @@ class cSpider :
public cAggressiveMonster public cAggressiveMonster
{ {
typedef cAggressiveMonster super; typedef cAggressiveMonster super;
public: public:
cSpider(void); cSpider(void);
CLASS_PROTODEF(cSpider) CLASS_PROTODEF(cSpider)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
virtual void EventSeePlayer(cEntity *) override; virtual void EventSeePlayer(cEntity *, cChunk & a_Chunk) override;
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
} ; } ;