Initial ChunkStay code.
This commit is contained in:
parent
169b918222
commit
ea71bfa9b6
@ -422,7 +422,6 @@ bool cChunk::HasBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
|
||||
|
||||
|
||||
/// Sets or resets the internal flag that prevents chunk from being unloaded
|
||||
void cChunk::Stay(bool a_Stay)
|
||||
{
|
||||
m_StayCount += (a_Stay ? 1 : -1);
|
||||
|
110
src/Chunk.h
110
src/Chunk.h
@ -85,10 +85,10 @@ public:
|
||||
void MarkLoaded(void); // Marks the chunk as freshly loaded. Fails if the chunk is already valid
|
||||
void MarkLoadFailed(void); // Marks the chunk as failed to load. Ignored is the chunk is already valid
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Sets all chunk data
|
||||
/** Sets all chunk data */
|
||||
void SetAllData(
|
||||
const BLOCKTYPE * a_BlockTypes,
|
||||
const NIBBLETYPE * a_BlockMeta,
|
||||
@ -104,27 +104,29 @@ public:
|
||||
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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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
|
||||
before the chunk is unloadable again. */
|
||||
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);
|
||||
|
||||
/// Try to Spawn Monsters inside chunk
|
||||
/** Try to Spawn Monsters inside chunk */
|
||||
void SpawnMobs(cMobSpawner& a_MobSpawner);
|
||||
|
||||
void Tick(float 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);
|
||||
|
||||
int GetPosX(void) const { return m_PosX; }
|
||||
@ -137,13 +139,13 @@ public:
|
||||
// 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 ); }
|
||||
|
||||
/// Queues a block change till the specified world tick
|
||||
/** Queues a block change till the specified world tick */
|
||||
void QueueSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR);
|
||||
|
||||
/// Queues block for ticking (m_ToTickQueue)
|
||||
/** Queues block for ticking (m_ToTickQueue) */
|
||||
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 FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
|
||||
@ -175,14 +177,14 @@ public:
|
||||
|
||||
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);
|
||||
|
||||
int GetHeight( int a_X, int a_Z );
|
||||
|
||||
void SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client);
|
||||
|
||||
/// 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 );
|
||||
|
||||
void RemoveClient (cClientHandle* a_Client );
|
||||
@ -193,55 +195,55 @@ public:
|
||||
void RemoveEntity(cEntity * a_Entity);
|
||||
bool HasEntity(int 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
|
||||
|
||||
/// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found.
|
||||
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. */
|
||||
bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible
|
||||
|
||||
/// Calls the callback for each block entity; returns true if all block entities processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each block entity; returns true if all block entities processed, false if the callback aborted by returning true */
|
||||
bool ForEachBlockEntity(cBlockEntityCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Calls the callback for each chest; returns true if all chests processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each chest; returns true if all chests processed, false if the callback aborted by returning true */
|
||||
bool ForEachChest(cChestCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Calls the callback for each dispenser; returns true if all dispensers processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each dispenser; returns true if all dispensers processed, false if the callback aborted by returning true */
|
||||
bool ForEachDispenser(cDispenserCallback & a_Callback);
|
||||
|
||||
/// Calls the callback for each dropper; returns true if all droppers processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each dropper; returns true if all droppers processed, false if the callback aborted by returning true */
|
||||
bool ForEachDropper(cDropperCallback & a_Callback);
|
||||
|
||||
/// Calls the callback for each dropspenser; returns true if all dropspensers processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each dropspenser; returns true if all dropspensers processed, false if the callback aborted by returning true */
|
||||
bool ForEachDropSpenser(cDropSpenserCallback & a_Callback);
|
||||
|
||||
/// 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
|
||||
|
||||
/// 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
|
||||
|
||||
/// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found
|
||||
/** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */
|
||||
bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible
|
||||
|
||||
/// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found
|
||||
/** Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found */
|
||||
bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback);
|
||||
|
||||
/// Calls the callback for the dispenser at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found
|
||||
/** Calls the callback for the dispenser at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found */
|
||||
bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback);
|
||||
|
||||
/// Calls the callback for the dispenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found
|
||||
/** Calls the callback for the dispenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found */
|
||||
bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback);
|
||||
|
||||
/// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found
|
||||
/** Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found */
|
||||
bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found
|
||||
/** Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found */
|
||||
bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found
|
||||
/** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */
|
||||
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible
|
||||
|
||||
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // [x, y, z] in world block coords
|
||||
@ -292,7 +294,7 @@ public:
|
||||
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)
|
||||
{
|
||||
m_BlockTickX = a_RelX;
|
||||
@ -310,34 +312,34 @@ public:
|
||||
inline NIBBLETYPE GetBlockLight(int a_Idx) const {return cChunkDef::GetNibble(m_BlockLight, a_Idx); }
|
||||
inline NIBBLETYPE GetSkyLight (int a_Idx) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_Idx); }
|
||||
|
||||
/// 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;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Same as GetBlockSkyLight(), 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 GetBlockSkyLight(), 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 UnboundedRelGetBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_SkyLight) const;
|
||||
|
||||
/// Queries both BlockLight and SkyLight, relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success
|
||||
/** Queries both BlockLight and SkyLight, relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */
|
||||
bool UnboundedRelGetBlockLights(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockLight, NIBBLETYPE & a_SkyLight) const;
|
||||
|
||||
/// Same as SetBlock(), 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 SetBlock(), 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 UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Light alterations based on time
|
||||
/** Light alterations based on time */
|
||||
NIBBLETYPE GetTimeAlteredLight(NIBBLETYPE a_Skylight) const;
|
||||
|
||||
|
||||
@ -389,7 +391,7 @@ private:
|
||||
cEntityList m_Entities;
|
||||
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_PosX, m_PosY, m_PosZ;
|
||||
@ -427,40 +429,40 @@ private:
|
||||
void RemoveBlockEntity(cBlockEntity * a_BlockEntity);
|
||||
void AddBlockEntity (cBlockEntity * a_BlockEntity);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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);
|
||||
|
||||
// Makes a copy of the list
|
||||
cClientHandleList GetAllClients(void) const {return m_LoadedByClient; }
|
||||
|
||||
/// Sends m_PendingSendBlocks to all clients
|
||||
/** Sends m_PendingSendBlocks to all clients */
|
||||
void BroadcastPendingBlockChanges(void);
|
||||
|
||||
/// Checks the block scheduled for checking in m_ToTickBlocks[]
|
||||
/** Checks the block scheduled for checking in m_ToTickBlocks[] */
|
||||
void CheckBlocks();
|
||||
|
||||
/// Ticks several random blocks in the chunk
|
||||
/** Ticks several random blocks in the chunk */
|
||||
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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Processes all blocks that have been scheduled for replacement by the QueueSetBlock() function
|
||||
/** Processes all blocks that have been scheduled for replacement by the QueueSetBlock() function */
|
||||
void ProcessQueuedSetBlocks(void);
|
||||
};
|
||||
|
||||
|
@ -481,6 +481,7 @@ public:
|
||||
} ;
|
||||
|
||||
typedef std::list<cChunkCoords> cChunkCoordsList;
|
||||
typedef std::vector<cChunkCoords> cChunkCoordsVector;
|
||||
|
||||
|
||||
|
||||
|
171
src/ChunkMap.cpp
171
src/ChunkMap.cpp
@ -896,6 +896,7 @@ void cChunkMap::SetChunkData(
|
||||
cBlockEntityList & a_BlockEntities,
|
||||
bool a_MarkDirty
|
||||
)
|
||||
{
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
|
||||
@ -910,6 +911,13 @@ void cChunkMap::SetChunkData(
|
||||
Chunk->MarkDirty();
|
||||
}
|
||||
|
||||
// Notify relevant ChunkStays:
|
||||
for (cChunkStays::iterator itr = m_ChunkStays.begin(), end = m_ChunkStays.end(); itr != end; ++itr)
|
||||
{
|
||||
(*itr)->ChunkAvailable(a_ChunkX, a_ChunkZ);
|
||||
} // for itr - m_ChunkStays[]
|
||||
}
|
||||
|
||||
// Notify plugins of the chunk becoming available
|
||||
cPluginManager::Get()->CallHookChunkAvailable(m_World, a_ChunkX, a_ChunkZ);
|
||||
}
|
||||
@ -2206,24 +2214,6 @@ bool cChunkMap::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const ASt
|
||||
|
||||
|
||||
|
||||
void cChunkMap::ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
for (cChunkCoordsList::const_iterator itr = a_Chunks.begin(); itr != a_Chunks.end(); ++itr)
|
||||
{
|
||||
cChunkPtr Chunk = GetChunkNoLoad(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Chunk->Stay(a_Stay);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkMap::MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
@ -2810,12 +2800,16 @@ void cChunkMap::cChunkLayer::UnloadUnusedChunks(void)
|
||||
|
||||
|
||||
|
||||
void cChunkMap::FastSetBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
||||
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_X, a_Y, a_Z, a_BlockType, a_BlockMeta));
|
||||
m_FastSetBlockQueue.push_back(sSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkMap::FastSetQueuedBlocks()
|
||||
{
|
||||
// Asynchronously set blocks:
|
||||
@ -2834,110 +2828,75 @@ void cChunkMap::FastSetQueuedBlocks()
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cChunkStay:
|
||||
|
||||
cChunkStay::cChunkStay(cWorld * a_World) :
|
||||
m_World(a_World),
|
||||
m_IsEnabled(false)
|
||||
|
||||
|
||||
void cChunkMap::AddChunkStay(cChunkStay & a_ChunkStay)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
|
||||
// Add it to the list:
|
||||
ASSERT(std::find(m_ChunkStays.begin(), m_ChunkStays.end(), &a_ChunkStay) == m_ChunkStays.end()); // Has not yet been added
|
||||
m_ChunkStays.push_back(&a_ChunkStay);
|
||||
|
||||
// Schedule all chunks to be loaded / generated, and mark each as locked:
|
||||
const cChunkCoordsVector & WantedChunks = a_ChunkStay.GetChunks();
|
||||
for (cChunkCoordsVector::const_iterator itr = WantedChunks.begin(); itr != WantedChunks.end(); ++itr)
|
||||
{
|
||||
cChunkPtr Chunk = GetChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Chunk->Stay(true);
|
||||
if (Chunk->IsValid())
|
||||
{
|
||||
a_ChunkStay.ChunkAvailable(itr->m_ChunkX, itr->m_ChunkZ);
|
||||
}
|
||||
} // for itr - WantedChunks[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cChunkStay::~cChunkStay()
|
||||
/** Removes the specified cChunkStay descendant from the internal list of ChunkStays. */
|
||||
void cChunkMap::DelChunkStay(cChunkStay & a_ChunkStay)
|
||||
{
|
||||
Clear();
|
||||
cCSLock Lock(m_CSLayers);
|
||||
|
||||
// Remove from the list of active chunkstays:
|
||||
bool HasFound = false;
|
||||
for (cChunkStays::iterator itr = m_ChunkStays.begin(), end = m_ChunkStays.end(); itr != end; ++itr)
|
||||
{
|
||||
if (*itr == &a_ChunkStay)
|
||||
{
|
||||
m_ChunkStays.erase(itr);
|
||||
HasFound = true;
|
||||
break;
|
||||
}
|
||||
} // for itr - m_ChunkStays[]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Clear(void)
|
||||
if (!HasFound)
|
||||
{
|
||||
if (m_IsEnabled)
|
||||
{
|
||||
Disable();
|
||||
}
|
||||
m_Chunks.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Add(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
{
|
||||
ASSERT(!m_IsEnabled);
|
||||
|
||||
for (cChunkCoordsList::const_iterator itr = m_Chunks.begin(); itr != m_Chunks.end(); ++itr)
|
||||
{
|
||||
if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkY == a_ChunkY) && (itr->m_ChunkZ == a_ChunkZ))
|
||||
{
|
||||
// Already present
|
||||
ASSERT(!"Removing a cChunkStay that hasn't been added!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Unmark all contained chunks:
|
||||
const cChunkCoordsVector & Chunks = a_ChunkStay.GetChunks();
|
||||
for (cChunkCoordsVector::const_iterator itr = Chunks.begin(), end = Chunks.end(); itr != end; ++itr)
|
||||
{
|
||||
cChunkPtr Chunk = GetChunkNoLoad(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Chunk->Stay(false);
|
||||
} // for itr - Chunks[]
|
||||
m_Chunks.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Remove(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||
{
|
||||
ASSERT(!m_IsEnabled);
|
||||
|
||||
for (cChunkCoordsList::iterator itr = m_Chunks.begin(); itr != m_Chunks.end(); ++itr)
|
||||
{
|
||||
if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkY == a_ChunkY) && (itr->m_ChunkZ == a_ChunkZ))
|
||||
{
|
||||
// Found, un-"stay"
|
||||
m_Chunks.erase(itr);
|
||||
return;
|
||||
}
|
||||
} // for itr - m_Chunks[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Enable(void)
|
||||
{
|
||||
ASSERT(!m_IsEnabled);
|
||||
|
||||
m_World->ChunksStay(*this, true);
|
||||
m_IsEnabled = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Load(void)
|
||||
{
|
||||
for (cChunkCoordsList::iterator itr = m_Chunks.begin(); itr != m_Chunks.end(); ++itr)
|
||||
{
|
||||
m_World->TouchChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ);
|
||||
} // for itr - m_Chunks[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Disable(void)
|
||||
{
|
||||
ASSERT(m_IsEnabled);
|
||||
|
||||
m_World->ChunksStay(*this, false);
|
||||
m_IsEnabled = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
203
src/ChunkMap.h
203
src/ChunkMap.h
@ -85,19 +85,19 @@ public:
|
||||
void BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ );
|
||||
|
||||
/// Sends the block entity, if it is at the coords specified, to a_Client
|
||||
/** Sends the block entity, if it is at the coords specified, to a_Client */
|
||||
void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client);
|
||||
|
||||
/// a_Player rclked block entity at the coords specified, handle it
|
||||
/** a_Player rclked block entity at the coords specified, handle it */
|
||||
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z);
|
||||
|
||||
/// Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback
|
||||
/** Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback */
|
||||
bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback);
|
||||
|
||||
/// Wakes up simulators for the specified block
|
||||
/** Wakes up simulators for the specified block */
|
||||
void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
|
||||
/// Wakes up the simulators for the specified area of blocks
|
||||
/** Wakes up the simulators for the specified area of blocks */
|
||||
void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ);
|
||||
|
||||
void MarkChunkDirty (int a_ChunkX, int a_ChunkZ);
|
||||
@ -130,7 +130,7 @@ public:
|
||||
|
||||
bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback);
|
||||
|
||||
/// Copies the chunk's blocktypes into a_Blocks; returns true if successful
|
||||
/** Copies the chunk's blocktypes into a_Blocks; returns true if successful */
|
||||
bool GetChunkBlockTypes (int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_Blocks);
|
||||
|
||||
bool IsChunkValid (int a_ChunkX, int a_ChunkZ);
|
||||
@ -153,154 +153,151 @@ public:
|
||||
bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
|
||||
bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
|
||||
|
||||
/// Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType
|
||||
/** Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType */
|
||||
void ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType);
|
||||
|
||||
/// 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);
|
||||
|
||||
EMCSBiome GetBiomeAt (int a_BlockX, int a_BlockZ);
|
||||
|
||||
/// Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read.
|
||||
/** Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read. */
|
||||
bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure);
|
||||
|
||||
bool DigBlock (int a_X, int a_Y, int a_Z);
|
||||
void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player);
|
||||
|
||||
/// Compares clients of two chunks, calls the callback accordingly
|
||||
/** Compares clients of two chunks, calls the callback accordingly */
|
||||
void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback);
|
||||
|
||||
/// Compares clients of two chunks, calls the callback accordingly
|
||||
/** Compares clients of two chunks, calls the callback accordingly */
|
||||
void CompareChunkClients(cChunk * a_Chunk1, cChunk * a_Chunk2, cClientDiffCallback & a_Callback);
|
||||
|
||||
/// Adds client to a chunk, if not already present; returns true if added, false if present
|
||||
/** Adds client to a chunk, if not already present; returns true if added, false if present */
|
||||
bool AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
|
||||
|
||||
/// Removes the client from the chunk
|
||||
/** Removes the client from the chunk */
|
||||
void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
|
||||
|
||||
/// Removes the client from all chunks it is present in
|
||||
/** Removes the client from all chunks it is present in */
|
||||
void RemoveClientFromChunks(cClientHandle * a_Client);
|
||||
|
||||
/// Adds the entity to its appropriate chunk, takes ownership of the entity pointer
|
||||
/** Adds the entity to its appropriate chunk, takes ownership of the entity pointer */
|
||||
void AddEntity(cEntity * a_Entity);
|
||||
|
||||
/// Returns true if the entity with specified ID is present in the chunks
|
||||
/** Returns true if the entity with specified ID is present in the chunks */
|
||||
bool HasEntity(int a_EntityID);
|
||||
|
||||
/// Removes the entity from its appropriate chunk
|
||||
/** Removes the entity from its appropriate chunk */
|
||||
void RemoveEntity(cEntity * a_Entity);
|
||||
|
||||
/// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */
|
||||
bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */
|
||||
bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Destroys and returns a list of blocks destroyed in the explosion at the specified coordinates
|
||||
/** Destroys and returns a list of blocks destroyed in the explosion at the specified coordinates */
|
||||
void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlockAffected);
|
||||
|
||||
/// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false.
|
||||
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. */
|
||||
bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true */
|
||||
bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true */
|
||||
bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true */
|
||||
bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback);
|
||||
|
||||
/// Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true */
|
||||
bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback);
|
||||
|
||||
/// Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true */
|
||||
bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback);
|
||||
|
||||
/// Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true */
|
||||
bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, 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
|
||||
|
||||
/// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found
|
||||
/** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */
|
||||
bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible
|
||||
|
||||
/// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found
|
||||
/** Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found */
|
||||
bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found
|
||||
/** Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found */
|
||||
bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found
|
||||
/** Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found */
|
||||
bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found
|
||||
/** Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found */
|
||||
bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found
|
||||
/** Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found */
|
||||
bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// 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); // Lua-accessible
|
||||
|
||||
/// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found
|
||||
/** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */
|
||||
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible
|
||||
|
||||
/// Touches the chunk, causing it to be loaded or generated
|
||||
/** Touches the chunk, causing it to be loaded or generated */
|
||||
void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
|
||||
/// Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before)
|
||||
/** Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) */
|
||||
bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
|
||||
/// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid()
|
||||
/** Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() */
|
||||
void LoadChunks(const cChunkCoordsList & a_Chunks);
|
||||
|
||||
/// Marks the chunk as failed-to-load
|
||||
/** Marks the chunk as failed-to-load */
|
||||
void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
|
||||
/// Sets the sign text. Returns true if sign text changed.
|
||||
/** Sets the sign text. Returns true if sign text changed. */
|
||||
bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4);
|
||||
|
||||
/// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable; to be used only by cChunkStay!
|
||||
void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true);
|
||||
|
||||
/// Marks the chunk as being regenerated - all its clients want that chunk again (used by cWorld::RegenerateChunk() )
|
||||
/** Marks the chunk as being regenerated - all its clients want that chunk again (used by cWorld::RegenerateChunk() ) */
|
||||
void MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
bool IsChunkLighted(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
/// Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully
|
||||
/** Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully */
|
||||
bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback);
|
||||
|
||||
/// Writes the block area into the specified coords. Returns true if all chunks have been processed. Prefer cBlockArea::Write() instead.
|
||||
/** Writes the block area into the specified coords. Returns true if all chunks have been processed. Prefer cBlockArea::Write() instead. */
|
||||
bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes);
|
||||
|
||||
/// Returns the number of valid chunks and the number of dirty chunks
|
||||
/** Returns the number of valid chunks and the number of dirty chunks */
|
||||
void GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty);
|
||||
|
||||
/// 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_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, MTRand & a_Rand);
|
||||
|
||||
/// Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config
|
||||
/** Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config */
|
||||
void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
|
||||
|
||||
/// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config
|
||||
/** Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config */
|
||||
void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
|
||||
|
||||
/// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call
|
||||
/** Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call */
|
||||
void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
|
||||
/// Make a Mob census, of all mobs, their family, their chunk and theyr distance to closest player
|
||||
/** Make a Mob census, of all mobs, their family, their chunk and theyr distance to closest player */
|
||||
void CollectMobCensus(cMobCensus& a_ToFill);
|
||||
|
||||
/// Try to Spawn Monsters inside all Chunks
|
||||
/** Try to Spawn Monsters inside all Chunks */
|
||||
void SpawnMobs(cMobSpawner& a_MobSpawner);
|
||||
|
||||
void Tick(float 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_BlockX, int a_BlockY, int a_BlockZ);
|
||||
|
||||
void UnloadUnusedChunks(void);
|
||||
@ -312,15 +309,20 @@ public:
|
||||
|
||||
void ChunkValidated(void); // Called by chunks that have become valid
|
||||
|
||||
/// Queues the specified block for ticking (block update)
|
||||
/** Queues the specified block for ticking (block update) */
|
||||
void QueueTickBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
|
||||
/// Returns the CS for locking the chunkmap; only cWorld::cLock may use this function!
|
||||
/** Returns the CS for locking the chunkmap; only cWorld::cLock may use this function! */
|
||||
cCriticalSection & GetCS(void) { return m_CSLayers; }
|
||||
|
||||
private:
|
||||
|
||||
friend class cChunk; // The chunks can manipulate neighbors while in their Tick() method, using LockedGetBlock() and LockedSetBlock()
|
||||
// The chunks can manipulate neighbors while in their Tick() method, using LockedGetBlock() and LockedSetBlock()
|
||||
friend class cChunk;
|
||||
|
||||
// The chunkstay can (de-)register itself using AddChunkStay() and DelChunkStay()
|
||||
friend class cChunkStay;
|
||||
|
||||
|
||||
class cChunkLayer
|
||||
{
|
||||
@ -328,10 +330,10 @@ private:
|
||||
cChunkLayer(int a_LayerX, int a_LayerZ, cChunkMap * a_Parent);
|
||||
~cChunkLayer();
|
||||
|
||||
/// Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check
|
||||
/** Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check */
|
||||
cChunkPtr GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ );
|
||||
|
||||
/// Returns the specified chunk, or NULL if not created yet
|
||||
/** Returns the specified chunk, or NULL if not created yet */
|
||||
cChunk * FindChunk(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
int GetX(void) const {return m_LayerX; }
|
||||
@ -344,22 +346,22 @@ private:
|
||||
void Save(void);
|
||||
void UnloadUnusedChunks(void);
|
||||
|
||||
/// Collect a mob census, of all mobs, their megatype, their chunk and their distance o closest player
|
||||
/** Collect a mob census, of all mobs, their megatype, their chunk and their distance o closest player */
|
||||
void CollectMobCensus(cMobCensus& a_ToFill);
|
||||
/// Try to Spawn Monsters inside all Chunks
|
||||
/** Try to Spawn Monsters inside all Chunks */
|
||||
void SpawnMobs(cMobSpawner& a_MobSpawner);
|
||||
|
||||
void Tick(float a_Dt);
|
||||
|
||||
void RemoveClient(cClientHandle * a_Client);
|
||||
|
||||
/// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true
|
||||
/** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */
|
||||
bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found.
|
||||
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. */
|
||||
bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackReturn); // Lua-accessible
|
||||
|
||||
/// Returns true if there is an entity with the specified ID within this layer's chunks
|
||||
/** Returns true if there is an entity with the specified ID within this layer's chunks */
|
||||
bool HasEntity(int a_EntityID);
|
||||
|
||||
protected:
|
||||
@ -373,16 +375,18 @@ private:
|
||||
|
||||
typedef std::list<cChunkLayer *> cChunkLayerList;
|
||||
|
||||
/// Finds the cChunkLayer object responsible for the specified chunk; returns NULL if not found. Assumes m_CSLayers is locked.
|
||||
typedef std::list<cChunkStay *> cChunkStays;
|
||||
|
||||
/** Finds the cChunkLayer object responsible for the specified chunk; returns NULL if not found. Assumes m_CSLayers is locked. */
|
||||
cChunkLayer * FindLayerForChunk(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
/// Returns the specified cChunkLayer object; returns NULL if not found. Assumes m_CSLayers is locked.
|
||||
/** Returns the specified cChunkLayer object; returns NULL if not found. Assumes m_CSLayers is locked. */
|
||||
cChunkLayer * FindLayer(int a_LayerX, int a_LayerZ);
|
||||
|
||||
/// Returns the cChunkLayer object responsible for the specified chunk; creates it if not found.
|
||||
/** Returns the cChunkLayer object responsible for the specified chunk; creates it if not found. */
|
||||
cChunkLayer * GetLayerForChunk (int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
/// Returns the specified cChunkLayer object; creates it if not found.
|
||||
/** Returns the specified cChunkLayer object; creates it if not found. */
|
||||
cChunkLayer * GetLayer(int a_LayerX, int a_LayerZ);
|
||||
|
||||
void RemoveLayer(cChunkLayer * a_Layer);
|
||||
@ -396,67 +400,42 @@ private:
|
||||
cCriticalSection m_CSFastSetBlock;
|
||||
sSetBlockList m_FastSetBlockQueue;
|
||||
|
||||
/** The cChunkStay descendants that are currently enabled in this chunkmap */
|
||||
cChunkStays m_ChunkStays;
|
||||
|
||||
cChunkPtr GetChunk (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading / generating if not valid
|
||||
cChunkPtr GetChunkNoGen (int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Also queues the chunk for loading if not valid; doesn't generate
|
||||
cChunkPtr GetChunkNoLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Doesn't load, doesn't generate
|
||||
|
||||
/// Gets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load)
|
||||
/** Gets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */
|
||||
bool LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
|
||||
|
||||
/// Gets a block type in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load)
|
||||
/** Gets a block type in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */
|
||||
bool LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType);
|
||||
|
||||
/// Gets a block meta in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load)
|
||||
/** Gets a block meta in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */
|
||||
bool LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE & a_BlockMeta);
|
||||
|
||||
/// Sets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load)
|
||||
/** Sets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */
|
||||
bool LockedSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||
|
||||
/// Fast-sets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load)
|
||||
/** Fast-sets a block in any chunk while in the cChunk's Tick() method; returns true if successful, false if chunk not loaded (doesn't queue load) */
|
||||
bool LockedFastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||
|
||||
/// Locates a chunk ptr in the chunkmap; doesn't create it when not found; assumes m_CSLayers is locked. To be called only from cChunkMap.
|
||||
/** Locates a chunk ptr in the chunkmap; doesn't create it when not found; assumes m_CSLayers is locked. To be called only from cChunkMap. */
|
||||
cChunk * FindChunk(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
/** Adds a new cChunkStay descendant to the internal list of ChunkStays; loads its chunks.
|
||||
To be used only by cChunkStay; others should use cChunkStay::Enable() instead */
|
||||
void AddChunkStay(cChunkStay & a_ChunkStay);
|
||||
|
||||
/** Removes the specified cChunkStay descendant from the internal list of ChunkStays.
|
||||
To be used only by cChunkStay; others should use cChunkStay::Disable() instead */
|
||||
void DelChunkStay(cChunkStay & a_ChunkStay);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Makes chunks stay loaded until this object is cleared or destroyed
|
||||
Works by setting internal flags in the cChunk that it should not be unloaded.
|
||||
To optimize for speed, cChunkStay has an Enabled flag, it will "stay" the chunks only when enabled and it will refuse manipulations when enabled
|
||||
The object itself is not made thread-safe, it's supposed to be used from a single thread only.
|
||||
*/
|
||||
class cChunkStay
|
||||
{
|
||||
public:
|
||||
cChunkStay(cWorld * a_World);
|
||||
~cChunkStay();
|
||||
|
||||
void Clear(void);
|
||||
|
||||
void Add(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
void Remove(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||
|
||||
void Enable(void);
|
||||
void Disable(void);
|
||||
|
||||
/// Queues each chunk in m_Chunks[] for loading / generating
|
||||
void Load(void);
|
||||
|
||||
// Allow cChunkStay be passed to functions expecting a const cChunkCoordsList &
|
||||
operator const cChunkCoordsList(void) const {return m_Chunks; }
|
||||
|
||||
protected:
|
||||
|
||||
cWorld * m_World;
|
||||
|
||||
bool m_IsEnabled;
|
||||
|
||||
cChunkCoordsList m_Chunks;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
136
src/ChunkStay.cpp
Normal file
136
src/ChunkStay.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
|
||||
// ChunkStay.cpp
|
||||
|
||||
// Implements the cChunkStay class representing a base for classes that keep chunks loaded
|
||||
|
||||
#include "Globals.h"
|
||||
#include "ChunkStay.h"
|
||||
#include "ChunkMap.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cChunkStay::cChunkStay(void) :
|
||||
m_ChunkMap(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cChunkStay::~cChunkStay()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Clear(void)
|
||||
{
|
||||
if (m_ChunkMap != NULL)
|
||||
{
|
||||
Disable();
|
||||
}
|
||||
m_Chunks.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Add(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
ASSERT(m_ChunkMap == NULL);
|
||||
|
||||
for (cChunkCoordsVector::const_iterator itr = m_Chunks.begin(); itr != m_Chunks.end(); ++itr)
|
||||
{
|
||||
if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ))
|
||||
{
|
||||
// Already present
|
||||
return;
|
||||
}
|
||||
} // for itr - Chunks[]
|
||||
m_Chunks.push_back(cChunkCoords(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Remove(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
ASSERT(m_ChunkMap == NULL);
|
||||
|
||||
for (cChunkCoordsVector::iterator itr = m_Chunks.begin(); itr != m_Chunks.end(); ++itr)
|
||||
{
|
||||
if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ))
|
||||
{
|
||||
// Found, un-"stay"
|
||||
m_Chunks.erase(itr);
|
||||
return;
|
||||
}
|
||||
} // for itr - m_Chunks[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Enable(cChunkMap & a_ChunkMap)
|
||||
{
|
||||
ASSERT(m_ChunkMap == NULL);
|
||||
|
||||
m_ChunkMap = &a_ChunkMap;
|
||||
a_ChunkMap.AddChunkStay(*this);
|
||||
m_OutstandingChunks = m_Chunks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::Disable(void)
|
||||
{
|
||||
ASSERT(m_ChunkMap != NULL);
|
||||
|
||||
m_ChunkMap->DelChunkStay(*this);
|
||||
m_ChunkMap = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkStay::ChunkAvailable(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
// Check if this is a chunk that we want:
|
||||
bool IsMine = false;
|
||||
for (cChunkCoordsVector::const_iterator itr = m_OutstandingChunks.begin(), end = m_OutstandingChunks.end(); itr != end; ++itr)
|
||||
{
|
||||
if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ))
|
||||
{
|
||||
m_OutstandingChunks.erase(itr);
|
||||
IsMine = true;
|
||||
break;
|
||||
}
|
||||
} // for itr - m_OutstandingChunks[]
|
||||
if (!IsMine)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Call the appropriate callbacks:
|
||||
OnChunkAvailable(a_ChunkX, a_ChunkZ);
|
||||
if (m_OutstandingChunks.empty())
|
||||
{
|
||||
OnAllChunksAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
92
src/ChunkStay.h
Normal file
92
src/ChunkStay.h
Normal file
@ -0,0 +1,92 @@
|
||||
|
||||
// ChunkStay.h
|
||||
|
||||
/* Declares the cChunkStay class representing a base for classes that want to wait for certain chunks to load,
|
||||
then do some action on them. While the object is enabled, the chunks contained within are locked and will
|
||||
not unload
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// fwd
|
||||
class cChunkMap;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Makes chunks stay loaded until this object is cleared or destroyed
|
||||
Works by setting internal flags in the cChunk that it should not be unloaded.
|
||||
To optimize for speed, cChunkStay has an Enabled flag, it will "stay" the chunks only when enabled
|
||||
and it will refuse chunk-list manipulations when enabled.
|
||||
The object itself is not made thread-safe, it's supposed to be used from a single thread only.
|
||||
This class is abstract, the descendants are expected to provide the OnChunkAvailable() and
|
||||
the OnAllChunksAvailable() callback implementations. Note that those are called from the contexts of
|
||||
different threads' - the caller, the Loader or the Generator thread.
|
||||
*/
|
||||
class cChunkStay
|
||||
{
|
||||
public:
|
||||
cChunkStay(void);
|
||||
~cChunkStay();
|
||||
|
||||
void Clear(void);
|
||||
|
||||
/** Adds a chunk to be locked from unloading.
|
||||
To be used only while the ChunkStay object is not enabled. */
|
||||
void Add (int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
/** Releases the chunk so that it's no longer locked from unloading.
|
||||
To be used only while the ChunkStay object is not enabled. */
|
||||
void Remove(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
/** Enables the ChunkStay on the specified chunkmap, causing it to load and generate chunks.
|
||||
All the contained chunks are queued for loading / generating. */
|
||||
void Enable (cChunkMap & a_ChunkMap);
|
||||
|
||||
/** Disables the ChunkStay, the chunks are released and the ChunkStay
|
||||
object can be edited with Add() and Remove() again*/
|
||||
void Disable(void);
|
||||
|
||||
/** Returns all the chunks that should be kept */
|
||||
const cChunkCoordsVector & GetChunks(void) const { return m_Chunks; }
|
||||
|
||||
/** Called when a specific chunk become available. */
|
||||
virtual void OnChunkAvailable(int a_ChunkX, int a_ChunkZ) = 0;
|
||||
|
||||
/** Caled once all of the contained chunks are available. */
|
||||
virtual void OnAllChunksAvailable(void) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
friend class cChunkMap;
|
||||
|
||||
|
||||
/** The chunkmap where the object is enabled.
|
||||
Valid only after call to Enable() and before Disable(). */
|
||||
cChunkMap * m_ChunkMap;
|
||||
|
||||
/** The list of chunks to lock from unloading. */
|
||||
cChunkCoordsVector m_Chunks;
|
||||
|
||||
/** The chunks that still need loading */
|
||||
cChunkCoordsVector m_OutstandingChunks;
|
||||
|
||||
|
||||
/** Called by cChunkMap when a chunk is available, checks m_NumLoaded and triggers the appropriate callbacks.
|
||||
May be called for chunks outside this ChunkStay. */
|
||||
void ChunkAvailable(int a_ChunkX, int a_ChunkZ);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "Globals.h"
|
||||
#include "LightingThread.h"
|
||||
#include "ChunkMap.h"
|
||||
#include "ChunkStay.h"
|
||||
#include "World.h"
|
||||
|
||||
|
||||
@ -109,9 +110,14 @@ void cLightingThread::Stop(void)
|
||||
{
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
for (sItems::iterator itr = m_Queue.begin(), end = m_Queue.end(); itr != end; ++itr)
|
||||
for (cChunkStays::iterator itr = m_PendingQueue.begin(), end = m_PendingQueue.end(); itr != end; ++itr)
|
||||
{
|
||||
delete itr->m_ChunkStay;
|
||||
delete *itr;
|
||||
}
|
||||
m_PendingQueue.clear();
|
||||
for (cChunkStays::iterator itr = m_Queue.begin(), end = m_Queue.end(); itr != end; ++itr)
|
||||
{
|
||||
delete *itr;
|
||||
}
|
||||
m_Queue.clear();
|
||||
}
|
||||
@ -129,25 +135,12 @@ void cLightingThread::QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback
|
||||
{
|
||||
ASSERT(m_World != NULL); // Did you call Start() properly?
|
||||
|
||||
cChunkStay * ChunkStay = new cChunkStay(m_World);
|
||||
ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ + 1);
|
||||
ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ);
|
||||
ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ - 1);
|
||||
ChunkStay->Add(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ + 1);
|
||||
ChunkStay->Add(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
|
||||
ChunkStay->Add(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ - 1);
|
||||
ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ + 1);
|
||||
ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ);
|
||||
ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ - 1);
|
||||
ChunkStay->Enable();
|
||||
ChunkStay->Load();
|
||||
cChunkStay * ChunkStay = new cLightingChunkStay(*this, a_ChunkX, a_ChunkZ, a_CallbackAfter);
|
||||
ChunkStay->Enable(*m_World->GetChunkMap());
|
||||
// The ChunkStay will enqueue itself using the QueueChunkStay() once it is fully loaded
|
||||
// In the meantime, put it into the PendingQueue so that it can be removed when stopping the thread
|
||||
cCSLock Lock(m_CS);
|
||||
m_Queue.push_back(sItem(a_ChunkX, a_ChunkZ, ChunkStay, a_CallbackAfter));
|
||||
if (m_Queue.size() > WARN_ON_QUEUE_SIZE)
|
||||
{
|
||||
LOGINFO("Lighting thread overloaded, %d items in queue", m_Queue.size());
|
||||
}
|
||||
m_evtItemAdded.Set();
|
||||
m_PendingQueue.push_back(ChunkStay);
|
||||
}
|
||||
|
||||
|
||||
@ -157,7 +150,7 @@ void cLightingThread::QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback
|
||||
void cLightingThread::WaitForQueueEmpty(void)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
while (!m_ShouldTerminate && (!m_Queue.empty() || !m_PostponedQueue.empty()))
|
||||
while (!m_ShouldTerminate && (!m_Queue.empty() || !m_PendingQueue.empty()))
|
||||
{
|
||||
cCSUnlock Unlock(Lock);
|
||||
m_evtQueueEmpty.Wait();
|
||||
@ -171,43 +164,7 @@ void cLightingThread::WaitForQueueEmpty(void)
|
||||
size_t cLightingThread::GetQueueLength(void)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
return m_Queue.size() + m_PostponedQueue.size();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cLightingThread::ChunkReady(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
// Check all the items in the m_PostponedQueue, if the chunk is their neighbor, move the item to m_Queue
|
||||
|
||||
bool NewlyAdded = false;
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
for (sItems::iterator itr = m_PostponedQueue.begin(); itr != m_PostponedQueue.end(); )
|
||||
{
|
||||
if (
|
||||
(itr->x - a_ChunkX >= -1) && (itr->x - a_ChunkX <= 1) &&
|
||||
(itr->z - a_ChunkZ >= -1) && (itr->z - a_ChunkZ <= 1)
|
||||
)
|
||||
{
|
||||
// It is a neighbor
|
||||
m_Queue.push_back(*itr);
|
||||
itr = m_PostponedQueue.erase(itr);
|
||||
NewlyAdded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++itr;
|
||||
}
|
||||
} // for itr - m_PostponedQueue[]
|
||||
} // Lock(m_CS)
|
||||
|
||||
if (NewlyAdded)
|
||||
{
|
||||
m_evtItemAdded.Set(); // Notify the thread it has some work to do
|
||||
}
|
||||
return m_Queue.size() + m_PendingQueue.size();
|
||||
}
|
||||
|
||||
|
||||
@ -233,14 +190,14 @@ void cLightingThread::Execute(void)
|
||||
}
|
||||
|
||||
// Process one items from the queue:
|
||||
sItem Item;
|
||||
cLightingChunkStay * Item;
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
if (m_Queue.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Item = m_Queue.front();
|
||||
Item = (cLightingChunkStay *)m_Queue.front();
|
||||
m_Queue.pop_front();
|
||||
if (m_Queue.empty())
|
||||
{
|
||||
@ -248,7 +205,7 @@ void cLightingThread::Execute(void)
|
||||
}
|
||||
} // CSLock(m_CS)
|
||||
|
||||
LightChunk(Item);
|
||||
LightChunk(*Item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -257,23 +214,11 @@ void cLightingThread::Execute(void)
|
||||
|
||||
|
||||
|
||||
void cLightingThread::LightChunk(cLightingThread::sItem & a_Item)
|
||||
void cLightingThread::LightChunk(cLightingChunkStay & a_Item)
|
||||
{
|
||||
cChunkDef::BlockNibbles BlockLight, SkyLight;
|
||||
|
||||
if (!ReadChunks(a_Item.x, a_Item.z))
|
||||
{
|
||||
// Neighbors not available. Re-queue in the postponed queue
|
||||
cCSLock Lock(m_CS);
|
||||
m_PostponedQueue.push_back(a_Item);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
// DEBUG: torch somewhere:
|
||||
m_BlockTypes[19 + 24 * cChunkDef::Width * 3 + (m_HeightMap[24 + 24 * cChunkDef::Width * 3] / 2) * BlocksPerYLayer] = E_BLOCK_TORCH;
|
||||
// m_HeightMap[24 + 24 * cChunkDef::Width * 3]++;
|
||||
*/
|
||||
ReadChunks(a_Item.m_ChunkX, a_Item.m_ChunkZ);
|
||||
|
||||
PrepareBlockLight();
|
||||
CalcLight(m_BlockLight);
|
||||
@ -339,13 +284,13 @@ void cLightingThread::LightChunk(cLightingThread::sItem & a_Item)
|
||||
CompressLight(m_BlockLight, BlockLight);
|
||||
CompressLight(m_SkyLight, SkyLight);
|
||||
|
||||
m_World->ChunkLighted(a_Item.x, a_Item.z, BlockLight, SkyLight);
|
||||
m_World->ChunkLighted(a_Item.m_ChunkX, a_Item.m_ChunkZ, BlockLight, SkyLight);
|
||||
|
||||
if (a_Item.m_Callback != NULL)
|
||||
if (a_Item.m_CallbackAfter != NULL)
|
||||
{
|
||||
a_Item.m_Callback->Call(a_Item.x, a_Item.z);
|
||||
a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ);
|
||||
}
|
||||
delete a_Item.m_ChunkStay;
|
||||
delete &a_Item;
|
||||
}
|
||||
|
||||
|
||||
@ -561,3 +506,51 @@ void cLightingThread::CompressLight(NIBBLETYPE * a_LightArray, NIBBLETYPE * a_Ch
|
||||
|
||||
|
||||
|
||||
|
||||
void cLightingThread::QueueChunkStay(cLightingChunkStay & a_ChunkStay)
|
||||
{
|
||||
// Move the ChunkStay from the Pending queue to the lighting queue.
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
m_PendingQueue.remove(&a_ChunkStay);
|
||||
m_Queue.push_back(&a_ChunkStay);
|
||||
}
|
||||
m_evtItemAdded.Set();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cLightingThread::cLightingChunkStay:
|
||||
|
||||
cLightingThread::cLightingChunkStay::cLightingChunkStay(cLightingThread & a_LightingThread, int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter) :
|
||||
m_LightingThread(a_LightingThread),
|
||||
m_ChunkX(a_ChunkX),
|
||||
m_ChunkZ(a_ChunkZ),
|
||||
m_CallbackAfter(a_CallbackAfter)
|
||||
{
|
||||
Add(a_ChunkX + 1, a_ChunkZ + 1);
|
||||
Add(a_ChunkX + 1, a_ChunkZ);
|
||||
Add(a_ChunkX + 1, a_ChunkZ - 1);
|
||||
Add(a_ChunkX, a_ChunkZ + 1);
|
||||
Add(a_ChunkX, a_ChunkZ);
|
||||
Add(a_ChunkX, a_ChunkZ - 1);
|
||||
Add(a_ChunkX - 1, a_ChunkZ + 1);
|
||||
Add(a_ChunkX - 1, a_ChunkZ);
|
||||
Add(a_ChunkX - 1, a_ChunkZ - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cLightingThread::cLightingChunkStay::OnAllChunksAvailable(void)
|
||||
{
|
||||
m_LightingThread.QueueChunkStay(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -33,6 +33,7 @@ Chunks from m_PostponedQueue are moved back into m_Queue when their neighbors ge
|
||||
|
||||
#include "OSSupport/IsThread.h"
|
||||
#include "ChunkDef.h"
|
||||
#include "ChunkStay.h"
|
||||
|
||||
|
||||
|
||||
@ -41,9 +42,6 @@ Chunks from m_PostponedQueue are moved back into m_Queue when their neighbors ge
|
||||
// fwd: "cWorld.h"
|
||||
class cWorld;
|
||||
|
||||
// fwd: "cChunkMap.h"
|
||||
class cChunkStay;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -62,44 +60,50 @@ public:
|
||||
|
||||
void Stop(void);
|
||||
|
||||
/// Queues the entire chunk for lighting
|
||||
/** Queues the entire chunk for lighting */
|
||||
void QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter = NULL);
|
||||
|
||||
/// Blocks until the queue is empty or the thread is terminated
|
||||
/** Blocks until the queue is empty or the thread is terminated */
|
||||
void WaitForQueueEmpty(void);
|
||||
|
||||
size_t GetQueueLength(void);
|
||||
|
||||
/// Called from cWorld when a chunk gets valid. Chunks in m_PostponedQueue may need moving into m_Queue
|
||||
void ChunkReady(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
protected:
|
||||
|
||||
struct sItem
|
||||
class cLightingChunkStay :
|
||||
public cChunkStay
|
||||
{
|
||||
int x, z;
|
||||
cChunkStay * m_ChunkStay;
|
||||
cChunkCoordCallback * m_Callback;
|
||||
public:
|
||||
cLightingThread & m_LightingThread;
|
||||
int m_ChunkX;
|
||||
int m_ChunkZ;
|
||||
cChunkCoordCallback * m_CallbackAfter;
|
||||
|
||||
sItem(void) {} // empty default constructor needed
|
||||
sItem(int a_X, int a_Z, cChunkStay * a_ChunkStay, cChunkCoordCallback * a_Callback) :
|
||||
x(a_X),
|
||||
z(a_Z),
|
||||
m_ChunkStay(a_ChunkStay),
|
||||
m_Callback(a_Callback)
|
||||
{
|
||||
}
|
||||
cLightingChunkStay(cLightingThread & a_LightingThread, int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter);
|
||||
|
||||
protected:
|
||||
virtual void OnChunkAvailable(int a_ChunkX, int a_ChunkZ) override {}
|
||||
virtual void OnAllChunksAvailable(void) override;
|
||||
} ;
|
||||
|
||||
typedef std::list<sItem> sItems;
|
||||
typedef std::list<cChunkStay *> cChunkStays;
|
||||
|
||||
|
||||
cWorld * m_World;
|
||||
|
||||
/** The mutex to protect m_Queue and m_PendingQueue */
|
||||
cCriticalSection m_CS;
|
||||
sItems m_Queue;
|
||||
sItems m_PostponedQueue; // Chunks that have been postponed due to missing neighbors
|
||||
|
||||
/** The ChunkStays that are loaded and are waiting to be lit. */
|
||||
cChunkStays m_Queue;
|
||||
|
||||
/** The ChunkStays that are waiting for load. Used for stopping the thread. */
|
||||
cChunkStays m_PendingQueue;
|
||||
|
||||
cEvent m_evtItemAdded; // Set when queue is appended, or to stop the thread
|
||||
cEvent m_evtQueueEmpty; // Set when the queue gets empty
|
||||
|
||||
|
||||
// Buffers for the 3x3 chunk data
|
||||
// These buffers alone are 1.7 MiB in size, therefore they cannot be located on the stack safely - some architectures may have only 1 MiB for stack, or even less
|
||||
// Placing the buffers into the object means that this object can light chunks only in one thread!
|
||||
@ -124,29 +128,29 @@ protected:
|
||||
|
||||
virtual void Execute(void) override;
|
||||
|
||||
/// Lights the entire chunk. If neighbor chunks don't exist, touches them and re-queues the chunk
|
||||
void LightChunk(sItem & a_Item);
|
||||
/** Lights the entire chunk. If neighbor chunks don't exist, touches them and re-queues the chunk */
|
||||
void LightChunk(cLightingChunkStay & a_Item);
|
||||
|
||||
/// Prepares m_BlockTypes and m_HeightMap data; returns false if any of the chunks fail. Zeroes out the light arrays
|
||||
/** Prepares m_BlockTypes and m_HeightMap data; returns false if any of the chunks fail. Zeroes out the light arrays */
|
||||
bool ReadChunks(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
/// Uses m_HeightMap to initialize the m_SkyLight[] data; fills in seeds for the skylight
|
||||
/** Uses m_HeightMap to initialize the m_SkyLight[] data; fills in seeds for the skylight */
|
||||
void PrepareSkyLight(void);
|
||||
|
||||
/// Uses m_BlockTypes to initialize the m_BlockLight[] data; fills in seeds for the blocklight
|
||||
/** Uses m_BlockTypes to initialize the m_BlockLight[] data; fills in seeds for the blocklight */
|
||||
void PrepareBlockLight(void);
|
||||
|
||||
/// Calculates light in the light array specified, using stored seeds
|
||||
/** Calculates light in the light array specified, using stored seeds */
|
||||
void CalcLight(NIBBLETYPE * a_Light);
|
||||
|
||||
/// Does one step in the light calculation - one seed propagation and seed recalculation
|
||||
/** Does one step in the light calculation - one seed propagation and seed recalculation */
|
||||
void CalcLightStep(
|
||||
NIBBLETYPE * a_Light,
|
||||
int a_NumSeedsIn, unsigned char * a_IsSeedIn, unsigned int * a_SeedIdxIn,
|
||||
int & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut
|
||||
);
|
||||
|
||||
/// Compresses from 1-block-per-byte (faster calc) into 2-blocks-per-byte (MC storage):
|
||||
/** Compresses from 1-block-per-byte (faster calc) into 2-blocks-per-byte (MC storage): */
|
||||
void CompressLight(NIBBLETYPE * a_LightArray, NIBBLETYPE * a_ChunkLight);
|
||||
|
||||
inline void PropagateLight(
|
||||
@ -174,6 +178,10 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
/** Queues a chunkstay that has all of its chunks loaded.
|
||||
Called by cLightingChunkStay when all of its chunks are loaded. */
|
||||
void QueueChunkStay(cLightingChunkStay & a_ChunkStay);
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -2145,9 +2145,6 @@ void cWorld::SetChunkData(
|
||||
{
|
||||
m_ChunkSender.ChunkReady(a_ChunkX, a_ChunkZ);
|
||||
}
|
||||
|
||||
// Notify the lighting thread that the chunk has become valid (in case it is a neighbor of a postponed chunk):
|
||||
m_Lighting.ChunkReady(a_ChunkX, a_ChunkZ);
|
||||
}
|
||||
|
||||
|
||||
@ -2561,15 +2558,6 @@ bool cWorld::SetCommandBlockCommand(int a_BlockX, int a_BlockY, int a_BlockZ, co
|
||||
|
||||
|
||||
|
||||
void cWorld::ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay)
|
||||
{
|
||||
m_ChunkMap->ChunksStay(a_Chunks, a_Stay);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
m_ChunkMap->MarkChunkRegenerating(a_ChunkX, a_ChunkZ);
|
||||
|
@ -308,9 +308,6 @@ public:
|
||||
/** Sets the command block command. Returns true if command changed. */
|
||||
bool SetCommandBlockCommand(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Command); // tolua_export
|
||||
|
||||
/** Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay! */
|
||||
void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true);
|
||||
|
||||
/** Regenerate the given chunk: */
|
||||
void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user