2012-06-14 06:06:06 -07:00
// cChunkMap.h
// Interfaces to the cChunkMap class representing the chunk storage for a single world
# pragma once
# include "ChunkDef.h"
class cWorld ;
class cItem ;
class MTRand ;
class cChunkStay ;
class cChunk ;
class cPlayer ;
2012-06-17 12:58:39 -07:00
class cChestEntity ;
2012-12-19 13:19:36 -08:00
class cDispenserEntity ;
2012-06-17 12:58:39 -07:00
class cFurnaceEntity ;
2012-08-19 14:14:45 -07:00
class cPawn ;
2012-08-24 02:49:00 -07:00
class cPickup ;
2012-08-26 14:01:07 -07:00
class cChunkDataSerializer ;
2012-10-06 09:58:31 -07:00
class cBlockArea ;
2012-06-14 06:06:06 -07:00
typedef std : : list < cClientHandle * > cClientHandleList ;
typedef cChunk * cChunkPtr ;
2012-12-19 13:19:36 -08:00
typedef cItemCallback < cEntity > cEntityCallback ;
typedef cItemCallback < cChestEntity > cChestCallback ;
typedef cItemCallback < cDispenserEntity > cDispenserCallback ;
typedef cItemCallback < cFurnaceEntity > cFurnaceCallback ;
2012-06-14 06:06:06 -07:00
class cChunkMap
{
public :
static const int LAYER_SIZE = 32 ;
cChunkMap ( cWorld * a_World ) ;
~ cChunkMap ( ) ;
2012-08-19 04:51:17 -07:00
/// Broadcasts an a_Player's animation to all clients in the chunk where a_Player is
void BroadcastPlayerAnimation ( const cPlayer & a_Player , char a_Animation , const cClientHandle * a_Exclude = NULL ) ;
/// Broadcasts an entity equipment change to all clients in the chunk where a_Entity is
void BroadcastEntityEquipment ( const cEntity & a_Entity , short a_SlotNum , const cItem & a_Item , const cClientHandle * a_Exclude = NULL ) ;
2012-08-19 12:42:32 -07:00
/// Broadcasts a RelEntMoveLook packet to all clients in the chunk where a_Entity is
2012-08-29 14:02:39 -07:00
void BroadcastEntRelMoveLook ( const cEntity & a_Entity , char a_RelX , char a_RelY , char a_RelZ , const cClientHandle * a_Exclude = NULL ) ;
2012-08-19 12:42:32 -07:00
/// Broadcasts a RelEntMove packet to all clients in the chunk where a_Entity is
2012-08-29 14:02:39 -07:00
void BroadcastEntRelMove ( const cEntity & a_Entity , char a_RelX , char a_RelY , char a_RelZ , const cClientHandle * a_Exclude = NULL ) ;
2012-08-19 12:42:32 -07:00
/// Broadcasts a EntLook packet to all clients in the chunk where a_Entity is
void BroadcastEntLook ( const cEntity & a_Entity , const cClientHandle * a_Exclude = NULL ) ;
/// Broadcasts a EntHeadLook packet to all clients in the chunk where a_Entity is
void BroadcastEntHeadLook ( const cEntity & a_Entity , const cClientHandle * a_Exclude = NULL ) ;
/// Broadcasts a BlockAction packet to all clients who are in the specified chunk
2012-08-31 14:59:57 -07:00
void BroadcastBlockAction ( int a_BlockX , int a_BlockY , int a_BlockZ , char a_Byte1 , char a_Byte2 , BLOCKTYPE a_BlockType , const cClientHandle * a_Exclude = NULL ) ;
2012-08-19 12:42:32 -07:00
void BroadcastDestroyEntity ( const cEntity & a_Entity , const cClientHandle * a_Exclude = NULL ) ;
2012-08-19 14:14:45 -07:00
void BroadcastEntityStatus ( const cEntity & a_Entity , char a_Status , const cClientHandle * a_Exclude = NULL ) ;
void BroadcastMetadata ( const cPawn & a_Pawn , const cClientHandle * a_Exclude = NULL ) ;
2012-08-24 00:58:26 -07:00
void BroadcastSpawn ( cEntity & a_Entity , const cClientHandle * a_Exclude = NULL ) ;
2012-08-24 02:49:00 -07:00
void BroadcastCollectPickup ( const cPickup & a_Pickup , const cPlayer & a_Player , const cClientHandle * a_Exclude = NULL ) ;
2012-08-25 14:46:18 -07:00
void BroadcastThunderbolt ( int a_BlockX , int a_BlockY , int a_BlockZ , const cClientHandle * a_Exclude = NULL ) ;
2012-08-26 14:01:07 -07:00
2012-09-11 05:01:34 -07:00
void BroadcastSoundEffect ( const AString & a_SoundName , int a_SrcX , int a_SrcY , int a_SrcZ , float a_Volume , float a_Pitch , const cClientHandle * a_Exclude = NULL ) ; // a_Src coords are Block * 8
2012-09-25 02:54:36 -07:00
2012-10-21 00:46:28 -07:00
void BroadcastSoundParticleEffect ( int a_EffectID , int a_SrcX , int a_SrcY , int a_SrcZ , int a_Data , const cClientHandle * a_Exclude = NULL ) ;
2012-09-25 02:54:36 -07:00
void BroadcastBlockBreakAnimation ( int a_entityID , int a_blockX , int a_blockY , int a_blockZ , char a_stage , const cClientHandle * a_Exclude = NULL ) ;
2012-09-11 05:01:34 -07:00
2012-09-29 13:43:42 -07:00
void BroadcastUseBed ( const cEntity & a_Entity , int a_BlockX , int a_BlockY , int a_BlockZ ) ;
2012-08-26 14:01:07 -07:00
void BroadcastChunkData ( int a_ChunkX , int a_ChunkZ , cChunkDataSerializer & a_Serializer , const cClientHandle * a_Exclude = NULL ) ;
2012-08-25 14:46:18 -07:00
2012-08-24 00:58:26 -07:00
/// Broadcasts the block entity, if it is at the coords specified, to all clients except a_Exclude
void BroadcastBlockEntity ( int a_BlockX , int a_BlockY , int a_BlockZ , const cClientHandle * a_Exclude ) ;
/// 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 ) ;
2012-06-14 06:06:06 -07:00
/// 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 ) ;
void MarkChunkDirty ( int a_ChunkX , int a_ChunkY , int a_ChunkZ ) ;
void MarkChunkSaving ( int a_ChunkX , int a_ChunkY , int a_ChunkZ ) ;
void MarkChunkSaved ( int a_ChunkX , int a_ChunkY , int a_ChunkZ ) ;
/** Sets the chunk data as either loaded from the storage or generated.
a_BlockLight and a_BlockSkyLight are optional , if not present , chunk will be marked as unlighted .
a_BiomeMap is optional , if not present , biomes will be calculated by the generator
a_HeightMap is optional , if not present , will be calculated .
If a_MarkDirty is set , the chunk is set as dirty ( used after generating )
*/
void SetChunkData (
int a_ChunkX , int a_ChunkY , int a_ChunkZ ,
const BLOCKTYPE * a_BlockTypes ,
const NIBBLETYPE * a_BlockMeta ,
const NIBBLETYPE * a_BlockLight ,
const NIBBLETYPE * a_BlockSkyLight ,
const cChunkDef : : HeightMap * a_HeightMap ,
const cChunkDef : : BiomeMap & a_BiomeMap ,
cEntityList & a_Entities ,
cBlockEntityList & a_BlockEntities ,
bool a_MarkDirty
) ;
void ChunkLighted (
int a_ChunkX , int a_ChunkZ ,
const cChunkDef : : BlockNibbles & a_BlockLight ,
const cChunkDef : : BlockNibbles & a_SkyLight
) ;
bool GetChunkData ( int a_ChunkX , int a_ChunkY , int a_ChunkZ , cChunkDataCallback & a_Callback ) ;
2012-11-11 07:06:31 -08:00
/// Copies the chunk's blocktypes into a_Blocks; returns true if successful
2012-06-14 06:06:06 -07:00
bool GetChunkBlockTypes ( int a_ChunkX , int a_ChunkY , int a_ChunkZ , BLOCKTYPE * a_Blocks ) ;
bool IsChunkValid ( int a_ChunkX , int a_ChunkY , int a_ChunkZ ) ;
bool HasChunkAnyClients ( int a_ChunkX , int a_ChunkY , int a_ChunkZ ) ;
int GetHeight ( int a_BlockX , int a_BlockZ ) ;
void FastSetBlocks ( sSetBlockList & a_BlockList ) ;
void CollectPickupsByPlayer ( cPlayer * a_Player ) ;
2012-10-20 04:40:34 -07:00
BLOCKTYPE GetBlock ( int a_BlockX , int a_BlockY , int a_BlockZ ) ;
NIBBLETYPE GetBlockMeta ( int a_BlockX , int a_BlockY , int a_BlockZ ) ;
NIBBLETYPE GetBlockSkyLight ( int a_BlockX , int a_BlockY , int a_BlockZ ) ;
NIBBLETYPE GetBlockBlockLight ( int a_BlockX , int a_BlockY , int a_BlockZ ) ;
void SetBlockMeta ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockMeta ) ;
void SetBlock ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType , BLOCKTYPE a_BlockMeta ) ;
2012-10-26 01:47:30 -07:00
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 ) ;
2012-06-14 06:06:06 -07:00
/// 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
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.
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
void CompareChunkClients ( int a_ChunkX1 , int a_ChunkY1 , int a_ChunkZ1 , int a_ChunkX2 , int a_ChunkY2 , int a_ChunkZ2 , cClientDiffCallback & a_Callback ) ;
/// Adds client to a chunk, if not already present; returns true if added, false if present
bool AddChunkClient ( int a_ChunkX , int a_ChunkY , int a_ChunkZ , cClientHandle * a_Client ) ;
/// Removes the client from the chunk
void RemoveChunkClient ( int a_ChunkX , int a_ChunkY , int a_ChunkZ , cClientHandle * a_Client ) ;
/// Removes the client from all chunks it is present in
void RemoveClientFromChunks ( cClientHandle * a_Client ) ;
/// Moves the entity from its current chunk to the new chunk specified
void MoveEntityToChunk ( cEntity * a_Entity , int a_ChunkX , int a_ChunkY , int a_ChunkZ ) ;
/// Removes the entity from the chunk specified
void RemoveEntityFromChunk ( cEntity * a_Entity , int a_ChunkX , int a_ChunkY , int a_ChunkZ ) ;
2012-06-16 01:35:07 -07:00
/// 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
2012-06-17 12:58:39 -07:00
/// 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
2012-12-26 09:16:33 -08:00
/// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true
2012-12-27 07:07:12 -08:00
bool ForEachDispenserInChunk ( int a_ChunkX , int a_ChunkZ , cDispenserCallback & a_Callback ) ;
2012-12-26 09:16:33 -08:00
2012-06-17 12:58:39 -07:00
/// 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 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
2012-12-26 09:16:33 -08:00
/// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords, true if found
2012-12-27 07:07:12 -08:00
bool DoWithDispenserAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cDispenserCallback & a_Callback ) ;
2012-12-26 09:16:33 -08:00
2012-06-17 12:58:39 -07:00
/// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords, true if found
bool DoWithFurnaceAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cFurnaceCallback & 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
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
2012-06-14 06:06:06 -07:00
/// 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)
bool LoadChunk ( int a_ChunkX , int a_ChunkY , int a_ChunkZ ) ;
/// 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:
void ChunkLoadFailed ( int a_ChunkX , int a_ChunkY , int a_ChunkZ ) ;
void UpdateSign ( int a_X , int a_Y , int a_Z , 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() )
void MarkChunkRegenerating ( int a_ChunkX , int a_ChunkZ ) ;
bool IsChunkLighted ( int a_ChunkX , int a_ChunkZ ) ;
2012-07-02 09:30:17 -07:00
/// 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 ) ;
2012-10-06 09:58:31 -07:00
/// 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 ) ;
2012-06-14 06:06:06 -07:00
/// 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)
void GrowMelonPumpkin ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType , MTRand & a_Rand ) ;
2012-10-03 01:52:11 -07:00
/// Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config
2012-06-14 06:06:06 -07:00
void GrowSugarcane ( int a_BlockX , int a_BlockY , int a_BlockZ , int a_NumBlocksToGrow ) ;
2012-10-03 01:52:11 -07:00
/// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config
2012-06-14 06:06:06 -07:00
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
void SetNextBlockTick ( int a_BlockX , int a_BlockY , int a_BlockZ ) ;
void Tick ( float a_Dt , MTRand & a_TickRand ) ;
void UnloadUnusedChunks ( ) ;
void SaveAllChunks ( ) ;
cWorld * GetWorld ( ) { return m_World ; }
int GetNumChunks ( void ) ;
void ChunkValidated ( void ) ; // Called by chunks that have become valid
2012-10-14 11:30:16 -07:00
/// Schedules the specified block for checking (block update)
void CheckBlock ( int a_BlockX , int a_BlockY , int a_BlockZ ) ;
2012-06-14 06:06:06 -07:00
private :
friend class cChunk ; // The chunks can manipulate neighbors while in their Tick() method, using LockedGetBlock() and LockedSetBlock()
class cChunkLayer
{
public :
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
cChunkPtr GetChunk ( int a_ChunkX , int a_ChunkY , int a_ChunkZ ) ;
2012-12-14 14:38:30 -08:00
/// Returns the specified chunk, or NULL if not created yet
cChunk * FindChunk ( int a_ChunkX , int a_ChunkZ ) ;
2012-06-14 06:06:06 -07:00
int GetX ( void ) const { return m_LayerX ; }
int GetZ ( void ) const { return m_LayerZ ; }
int GetNumChunksLoaded ( void ) const ;
void GetChunkStats ( int & a_NumChunksValid , int & a_NumChunksDirty ) const ;
void Save ( void ) ;
void UnloadUnusedChunks ( void ) ;
void Tick ( float a_Dt , MTRand & a_TickRand ) ;
void RemoveClient ( cClientHandle * a_Client ) ;
protected :
cChunkPtr m_Chunks [ LAYER_SIZE * LAYER_SIZE ] ;
int m_LayerX ;
int m_LayerZ ;
cChunkMap * m_Parent ;
int m_NumChunksLoaded ;
} ;
typedef std : : list < cChunkLayer * > cChunkLayerList ;
2012-12-14 14:38:30 -08:00
/// 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.
cChunkLayer * FindLayer ( int a_LayerX , int a_LayerZ ) ;
/// 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.
cChunkLayer * GetLayer ( int a_LayerX , int a_LayerZ ) ;
void RemoveLayer ( cChunkLayer * a_Layer ) ;
2012-06-14 06:06:06 -07:00
cCriticalSection m_CSLayers ;
cChunkLayerList m_Layers ;
cEvent m_evtChunkValid ; // Set whenever any chunk becomes valid, via ChunkValidated()
cWorld * m_World ;
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)
bool LockedGetBlock ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE & a_BlockType , 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)
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)
bool LockedFastSetBlock ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta ) ;
2012-12-14 14:38:30 -08:00
/// 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 ) ;
2012-06-14 06:06:06 -07:00
} ;
/** 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 ;
} ;