diff options
Diffstat (limited to 'src/ChunkMap.cpp')
-rw-r--r-- | src/ChunkMap.cpp | 100 |
1 files changed, 69 insertions, 31 deletions
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 40ccecad8..3cfa5c3f5 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -20,7 +20,7 @@ #include "Entities/Pickup.h" #ifndef _WIN32 - #include <cstdlib> // abs + #include <cstdlib> // abs #endif #include "zlib/zlib.h" @@ -33,14 +33,15 @@ //////////////////////////////////////////////////////////////////////////////// // cChunkMap: -cChunkMap::cChunkMap(cWorld * a_World ) - : m_World( a_World ), +cChunkMap::cChunkMap(cWorld * a_World) : + m_World(a_World), m_Pool( new cListAllocationPool<cChunkData::sChunkSection, 1600>( std::auto_ptr<cAllocationPool<cChunkData::sChunkSection>::cStarvationCallbacks>( - new cStarvationCallbacks()) + new cStarvationCallbacks() ) ) + ) { } @@ -419,16 +420,16 @@ void cChunkMap::BroadcastChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSeriali -void cChunkMap::BroadcastCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude) +void cChunkMap::BroadcastCollectEntity(const cEntity & a_Entity, const cPlayer & a_Player, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - cChunkPtr Chunk = GetChunkNoGen(a_Pickup.GetChunkX(), ZERO_CHUNK_Y, a_Pickup.GetChunkZ()); + cChunkPtr Chunk = GetChunkNoGen(a_Entity.GetChunkX(), ZERO_CHUNK_Y, a_Entity.GetChunkZ()); if (Chunk == NULL) { return; } // It's perfectly legal to broadcast packets even to invalid chunks! - Chunk->BroadcastCollectPickup(a_Pickup, a_Player, a_Exclude); + Chunk->BroadcastCollectEntity(a_Entity, a_Player, a_Exclude); } @@ -647,19 +648,19 @@ void cChunkMap::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_Effe -void cChunkMap::BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude) +void cChunkMap::BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_SrcX / 8, a_SrcZ / 8, ChunkX, ChunkZ); + cChunkDef::BlockToChunk((int)std::floor(a_X), (int)std::floor(a_Z), ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); if (Chunk == NULL) { return; } // It's perfectly legal to broadcast packets even to invalid chunks! - Chunk->BroadcastSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch, a_Exclude); + Chunk->BroadcastSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch, a_Exclude); } @@ -847,7 +848,22 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M -void cChunkMap::MarkChunkDirty (int a_ChunkX, int a_ChunkZ) +void cChunkMap::MarkRedstoneDirty(int a_ChunkX, int a_ChunkZ) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + if ((Chunk == NULL) || !Chunk->IsValid()) + { + return; + } + Chunk->SetIsRedstoneDirty(true); +} + + + + + +void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDirty) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); @@ -856,6 +872,10 @@ void cChunkMap::MarkChunkDirty (int a_ChunkX, int a_ChunkZ) return; } Chunk->MarkDirty(); + if (a_MarkRedstoneDirty) + { + Chunk->SetIsRedstoneDirty(true); + } } @@ -1259,7 +1279,7 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP -void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients) +void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients) { cChunkInterface ChunkInterface(this); if (a_BlockType == E_BLOCK_AIR) @@ -1284,7 +1304,7 @@ void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a -void cChunkMap::QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType) +void cChunkMap::QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType) { int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); @@ -1530,7 +1550,7 @@ void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if (Chunk->IsValid()) + if ((Chunk != NULL) && (Chunk->IsValid())) { Chunk->SendBlockTo(a_X, a_Y, a_Z, a_Player->GetClientHandle()); } @@ -1717,7 +1737,9 @@ void cChunkMap::RemoveEntity(cEntity * a_Entity) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); - if ((Chunk == NULL) || !Chunk->IsValid()) + + // Even if a chunk is not valid, it may still contain entities such as players; make sure to remove them (#1190) + if (Chunk == NULL) { return; } @@ -1818,7 +1840,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ // Activate the TNT, with a random fuse between 10 to 30 game ticks int FuseTime = 10 + m_World->GetTickRandomNumber(20); m_World->SpawnPrimedTNT(a_BlockX + x + 0.5, a_BlockY + y + 0.5, a_BlockZ + z + 0.5, FuseTime); - area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR); + area.SetBlockTypeMeta(bx + x, by + y, bz + z, E_BLOCK_AIR, 0); a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z)); break; } @@ -1854,15 +1876,15 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ default: { - if (m_World->GetTickRandomNumber(100) <= 25) // 25% chance of pickups + if (m_World->GetTickRandomNumber(100) <= 25) // 25% chance of pickups { cItems Drops; cBlockHandler * Handler = BlockHandler(Block); - Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z)); // Stone becomes cobblestone, coal ore becomes coal, etc. + Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z)); // Stone becomes cobblestone, coal ore becomes coal, etc. m_World->SpawnItemPickups(Drops, bx + x, by + y, bz + z); } - else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around + else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around { if (!cBlockInfo::FullyOccupiesVoxel(Block)) { @@ -1875,7 +1897,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z)); } - area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR); + area.SetBlockTypeMeta(bx + x, by + y, bz + z, E_BLOCK_AIR, 0); a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z)); break; @@ -1902,7 +1924,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ { if (a_Entity->IsPickup()) { - if (((cPickup *)a_Entity)->GetAge() < 20) // If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned) + if (((cPickup *)a_Entity)->GetAge() < 20) // If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned) { return false; } @@ -1911,7 +1933,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ Vector3d EntityPos = a_Entity->GetPosition(); cBoundingBox bbEntity(EntityPos, a_Entity->GetWidth() / 2, a_Entity->GetHeight()); - if (!m_bbTNT.IsInside(bbEntity)) // IsInside actually acts like DoesSurround + if (!m_bbTNT.IsInside(bbEntity)) // IsInside actually acts like DoesSurround { return false; } @@ -1934,7 +1956,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ else if (FinalDamage < 0) FinalDamage = 0; - if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible + if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible { a_Entity->TakeDamage(dtExplosion, NULL, (int)FinalDamage, 0); } @@ -2675,11 +2697,25 @@ void cChunkMap::QueueTickBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +void cChunkMap::SetChunkAlwaysTicked(int a_ChunkX, int a_ChunkZ, bool a_AlwaysTicked) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + if (Chunk != NULL) + { + Chunk->SetAlwaysTicked(a_AlwaysTicked); + } +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cChunkMap::cChunkLayer: cChunkMap::cChunkLayer::cChunkLayer( - int a_LayerX, int a_LayerZ, + int a_LayerX, int a_LayerZ, cChunkMap * a_Parent, cAllocationPool<cChunkData::sChunkSection> & a_Pool ) @@ -2701,7 +2737,7 @@ cChunkMap::cChunkLayer::~cChunkLayer() for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); ++i) { delete m_Chunks[i]; - m_Chunks[i] = NULL; // // Must zero out, because further chunk deletions query the chunkmap for entities and that would touch deleted data + m_Chunks[i] = NULL; // Must zero out, because further chunk deletions query the chunkmap for entities and that would touch deleted data } // for i - m_Chunks[] } @@ -2727,8 +2763,8 @@ cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkY, int a_Ch { cChunk * neixm = (LocalX > 0) ? m_Chunks[Index - 1] : m_Parent->FindChunk(a_ChunkX - 1, a_ChunkZ); cChunk * neixp = (LocalX < LAYER_SIZE - 1) ? m_Chunks[Index + 1] : m_Parent->FindChunk(a_ChunkX + 1, a_ChunkZ); - cChunk * neizm = (LocalZ > 0) ? m_Chunks[Index - LAYER_SIZE] : m_Parent->FindChunk(a_ChunkX , a_ChunkZ - 1); - cChunk * neizp = (LocalZ < LAYER_SIZE - 1) ? m_Chunks[Index + LAYER_SIZE] : m_Parent->FindChunk(a_ChunkX , a_ChunkZ + 1); + cChunk * neizm = (LocalZ > 0) ? m_Chunks[Index - LAYER_SIZE] : m_Parent->FindChunk(a_ChunkX, a_ChunkZ - 1); + cChunk * neizp = (LocalZ < LAYER_SIZE - 1) ? m_Chunks[Index + LAYER_SIZE] : m_Parent->FindChunk(a_ChunkX, a_ChunkZ + 1); m_Chunks[Index] = new cChunk(a_ChunkX, 0, a_ChunkZ, m_Parent, m_Parent->GetWorld(), neixm, neixp, neizm, neizp, m_Pool); } return m_Chunks[Index]; @@ -2789,12 +2825,14 @@ void cChunkMap::cChunkLayer::SpawnMobs(cMobSpawner& a_MobSpawner) + + void cChunkMap::cChunkLayer::Tick(float a_Dt) { for (size_t i = 0; i < ARRAYCOUNT(m_Chunks); i++) { - // Only tick chunks that are valid and have clients: - if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) + // Only tick chunks that are valid and should be ticked: + if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->ShouldBeTicked()) { m_Chunks[i]->Tick(a_Dt); } @@ -2889,7 +2927,7 @@ int cChunkMap::cChunkLayer::GetNumChunksLoaded(void) const NumChunks++; } } // for i - m_Chunks[] - return NumChunks; + return NumChunks; } @@ -2960,7 +2998,7 @@ void cChunkMap::cChunkLayer::UnloadUnusedChunks(void) void cChunkMap::FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { cCSLock Lock(m_CSFastSetBlock); - m_FastSetBlockQueue.push_back(sSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta)); + m_FastSetBlockQueue.push_back(sSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta)); } |