2012-02-08 04:36:54 -08:00
2011-10-03 11:41:19 -07:00
# pragma once
2012-02-13 13:47:03 -08:00
# include "cEntity.h"
2012-03-14 13:56:09 -07:00
# include "ChunkDef.h"
2012-02-13 13:47:03 -08:00
2011-12-31 13:08:23 -08:00
# define C_CHUNK_USE_INLINE 1
// Do not touch
# if C_CHUNK_USE_INLINE
2012-02-13 13:47:03 -08:00
# define __C_CHUNK_INLINE__ inline
2011-12-31 13:08:23 -08:00
# else
2012-02-13 13:47:03 -08:00
# define __C_CHUNK_INLINE__
2011-12-31 13:08:23 -08:00
# endif
2012-02-13 13:47:03 -08:00
2011-10-03 11:41:19 -07:00
namespace Json
{
class Value ;
} ;
2012-02-08 04:36:54 -08:00
2011-10-30 17:52:20 -07:00
class cWorld ;
2011-10-03 11:41:19 -07:00
class cFurnaceEntity ;
class cPacket ;
class cClientHandle ;
class cServer ;
2012-02-08 04:36:54 -08:00
class MTRand ;
2012-02-13 13:47:03 -08:00
class cPlayer ;
2012-02-21 08:27:30 -08:00
class cChunkMap ;
2012-02-13 13:47:03 -08:00
typedef std : : list < cClientHandle * > cClientHandleList ;
2012-02-18 12:10:57 -08:00
2012-02-23 13:21:37 -08:00
// This class is not to be used directly
// Instead, call actions on cChunkMap (such as cChunkMap::SetBlock() etc.)
2012-03-14 13:56:09 -07:00
class cChunk :
public cChunkDef // The inheritance is "misused" here only to inherit the functions and constants defined in cChunkDef
2011-10-03 11:41:19 -07:00
{
public :
2012-02-21 08:27:30 -08:00
cChunk ( int a_X , int a_Y , int a_Z , cChunkMap * a_ChunkMap , cWorld * a_World ) ;
2011-10-03 11:41:19 -07:00
~ cChunk ( ) ;
2012-02-13 13:47:03 -08:00
bool IsValid ( void ) const { return m_IsValid ; } // Returns true if the chunk is valid (loaded / generated)
void SetValid ( bool a_SendToClients = true ) ; // Also wakes up all clients attached to this chunk to let them finish logging in
2012-02-16 05:42:35 -08:00
bool IsDirty ( void ) const { return m_IsDirty ; } // Returns true if the chunk has changed since it was last saved
2012-02-28 04:11:14 -08:00
bool HasLoadFailed ( void ) const { return m_HasLoadFailed ; } // Returns true if the chunk failed to load and hasn't been generated since then
2012-02-13 13:47:03 -08:00
bool CanUnload ( void ) ;
2012-02-16 05:42:35 -08:00
/*
To save a chunk , the WSSchema must :
1. Mark the chunk as being saved ( MarkSaving ( ) )
2. Get the chunk ' s data using GetAllData ( )
3. Mark the chunk as saved ( MarkSaved ( ) )
If anywhere inside this sequence another thread mmodifies the chunk , the chunk will not get marked as saved in MarkSaved ( )
*/
void MarkSaving ( void ) ; // Marks the chunk as being saved.
void MarkSaved ( void ) ; // Marks the chunk as saved, if it didn't change from the last call to MarkSaving()
void MarkLoaded ( void ) ; // Marks the chunk as freshly loaded. Fails if the chunk is already valid
2012-02-28 04:11:14 -08:00
void MarkLoadFailed ( void ) ; // Marks the chunk as failed to load. Ignored is the chunk is already valid
2012-02-16 05:42:35 -08:00
/// Gets all chunk data, calls the a_Callback's methods for each data type
2012-03-09 05:42:28 -08:00
void GetAllData ( cChunkDataCallback & a_Callback ) ;
2012-02-16 05:42:35 -08:00
/// Sets all chunk data
2012-03-14 13:56:09 -07:00
void SetAllData (
const BLOCKTYPE * a_BlockTypes ,
const BLOCKTYPE * a_BlockMeta ,
const BLOCKTYPE * a_BlockLight ,
const BLOCKTYPE * a_BlockSkyLight ,
const cChunkDef : : HeightMap * a_HeightMap ,
cEntityList & a_Entities ,
cBlockEntityList & a_BlockEntities
) ;
/// Copies m_BlockData into a_BlockTypes, only the block types
void GetBlockTypes ( BLOCKTYPE * a_BlockTypes ) ;
/// Copies entire block data into a_BlockData, the entire 4 arrays (Type, Meta, Light, SkyLight)
void GetBlockData ( BLOCKTYPE * a_BlockData ) ;
2012-02-18 11:18:16 -08:00
2012-02-16 05:42:35 -08:00
/// Returns true if there is a block entity at the coords specified
bool HasBlockEntityAt ( int a_BlockX , int a_BlockY , int a_BlockZ ) ;
2012-02-20 08:39:00 -08:00
2012-02-26 08:15:09 -08:00
/// Sets or resets the internal flag that prevents chunk from being unloaded
void Stay ( bool a_Stay = true ) ;
2012-02-08 04:36:54 -08:00
void Tick ( float a_Dt , MTRand & a_TickRandom ) ;
2011-10-03 11:41:19 -07:00
2011-10-30 17:52:20 -07:00
int GetPosX ( ) { return m_PosX ; }
int GetPosY ( ) { return m_PosY ; }
int GetPosZ ( ) { return m_PosZ ; }
2012-02-16 05:42:35 -08:00
cWorld * GetWorld ( ) { return m_World ; }
2011-10-03 11:41:19 -07:00
2012-03-05 08:41:57 -08:00
// OBSOLETE void SendTo( cClientHandle * a_Client );
2011-10-03 11:41:19 -07:00
2012-03-14 13:56:09 -07:00
void SetBlock ( int a_X , int a_Y , int a_Z , BLOCKTYPE a_BlockType , BLOCKTYPE a_BlockMeta ) ;
void SetBlock ( const Vector3i & a_BlockPos , BLOCKTYPE a_BlockType , BLOCKTYPE a_BlockMeta ) { SetBlock ( a_BlockPos . x , a_BlockPos . y , a_BlockPos . z , a_BlockType , a_BlockMeta ) ; }
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.
BLOCKTYPE GetBlock ( int a_X , int a_Y , int a_Z ) ;
BLOCKTYPE GetBlock ( int a_BlockIdx ) ;
2012-02-13 13:47:03 -08:00
void CollectPickupsByPlayer ( cPlayer * a_Player ) ;
void UpdateSign ( int a_PosX , int a_PosY , int a_PosZ , const AString & a_Line1 , const AString & a_Line2 , const AString & a_Line3 , const AString & a_Line4 ) ; // Also sends update packets to all clients in the chunk
2011-10-03 11:41:19 -07:00
2012-02-18 09:53:22 -08:00
int GetHeight ( int a_X , int a_Z ) ;
2011-10-03 11:41:19 -07:00
void SendBlockTo ( int a_X , int a_Y , int a_Z , cClientHandle * a_Client ) ;
2012-02-21 07:18:02 -08:00
/// Adds a client to the chunk; returns true if added, false if already there
bool AddClient ( cClientHandle * a_Client ) ;
2012-02-16 09:45:26 -08:00
void RemoveClient ( cClientHandle * a_Client ) ;
bool HasClient ( cClientHandle * a_Client ) ;
bool HasAnyClients ( void ) ; // Returns true if theres any client in the chunk; false otherwise
2011-10-03 11:41:19 -07:00
2012-02-20 08:39:00 -08:00
void AddEntity ( cEntity * a_Entity ) ;
2012-02-13 13:47:03 -08:00
void RemoveEntity ( cEntity * a_Entity ) ;
2012-02-15 06:22:44 -08:00
void UseBlockEntity ( cPlayer * a_Player , int a_X , int a_Y , int a_Z ) ; // [x, y, z] in world block coords
2011-10-03 11:41:19 -07:00
inline void RecalculateLighting ( ) { m_bCalculateLighting = true ; } // Recalculate lighting next tick
2012-03-14 13:56:09 -07:00
2012-02-13 13:47:03 -08:00
void CalculateLighting ( ) ; // Recalculate right now
void CalculateHeightmap ( ) ;
2011-10-03 11:41:19 -07:00
// Broadcasts to all clients that have loaded this chunk
2012-02-13 13:47:03 -08:00
void Broadcast ( const cPacket & a_Packet , cClientHandle * a_Exclude = NULL ) { Broadcast ( & a_Packet , a_Exclude ) ; }
void Broadcast ( const cPacket * a_Packet , cClientHandle * a_Exclude = NULL ) ;
2011-10-03 11:41:19 -07:00
2012-02-14 13:09:14 -08:00
// Loaded(blockdata, lightdata, blockentities, entities),
// Generated(blockdata, lightdata, blockentities, entities),
// GetBlockData(blockdatadest) etc.
2012-03-14 13:56:09 -07:00
/*
BLOCKTYPE * GetBlockTypes ( void ) { return m_BlockTypes ; }
BLOCKTYPE * GetBlockMeta ( void ) { return m_BlockMeta ; }
BLOCKTYPE * GetBlockLight ( void ) { return m_BlockLight ; }
BLOCKTYPE * GetBlockSkyLight ( void ) { return m_BlockSkyLight ; }
*/
2012-02-14 13:09:14 -08:00
2011-12-22 13:36:24 -08:00
void PositionToWorldPosition ( int a_ChunkX , int a_ChunkY , int a_ChunkZ , int & a_X , int & a_Y , int & a_Z ) ;
2012-03-09 16:25:05 -08:00
Vector3i PositionToWorldPosition ( const Vector3i & a_InChunkPos ) { return PositionToWorldPosition ( a_InChunkPos . x , a_InChunkPos . y , a_InChunkPos . z ) ; }
Vector3i PositionToWorldPosition ( int a_ChunkX , int a_ChunkY , int a_ChunkZ ) ;
2011-12-22 13:36:24 -08:00
2012-02-16 05:42:35 -08:00
inline void MarkDirty ( void )
{
m_IsDirty = true ;
m_IsSaving = false ;
}
2012-03-14 13:56:09 -07:00
inline void SpreadBlockSkyLight ( void ) { SpreadLight ( m_BlockSkyLight ) ; }
inline void SpreadBlockLight ( void ) { SpreadLight ( m_BlockLight ) ; }
inline BLOCKTYPE GetMeta ( int a_RelX , int a_RelY , int a_RelZ ) { return cChunkDef : : GetNibble ( m_BlockMeta , a_RelX , a_RelY , a_RelZ ) ; }
inline void SetMeta ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE a_Meta ) { cChunkDef : : SetNibble ( m_BlockMeta , a_RelX , a_RelY , a_RelZ , a_Meta ) ; }
2011-10-03 11:41:19 -07:00
2012-03-16 08:52:26 -07:00
inline BLOCKTYPE GetLight ( int a_RelX , int a_RelY , int a_RelZ ) { return cChunkDef : : GetNibble ( m_BlockLight , a_RelX , a_RelY , a_RelZ ) ; }
inline BLOCKTYPE GetSkyLight ( int a_RelX , int a_RelY , int a_RelZ ) { return cChunkDef : : GetNibble ( m_BlockSkyLight , a_RelX , a_RelY , a_RelZ ) ; }
2011-10-03 11:41:19 -07:00
private :
2012-02-20 08:39:00 -08:00
friend class cChunkMap ;
2012-02-13 13:47:03 -08:00
bool m_IsValid ; // True if the chunk is loaded / generated
2012-02-16 05:42:35 -08:00
bool m_IsDirty ; // True if the chunk has changed since it was last saved
bool m_IsSaving ; // True if the chunk is being saved
2012-02-28 04:11:14 -08:00
bool m_HasLoadFailed ; // True if chunk failed to load and hasn't been generated yet since then
2012-02-13 13:47:03 -08:00
2012-03-14 13:56:09 -07:00
cCriticalSection m_CSBlockLists ;
std : : deque < unsigned int > m_ToTickBlocks ;
std : : vector < unsigned int > m_PendingSendBlocks ;
2012-02-13 13:47:03 -08:00
2012-02-23 13:21:37 -08:00
// A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers
cClientHandleList m_LoadedByClient ;
cClientHandleList m_UnloadQuery ;
2012-02-13 13:47:03 -08:00
cEntityList m_Entities ;
cBlockEntityList m_BlockEntities ;
2012-02-26 08:15:09 -08:00
/// Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded
int m_StayCount ;
2011-10-03 11:41:19 -07:00
bool m_bCalculateLighting ;
int m_PosX , m_PosY , m_PosZ ;
2012-02-21 08:27:30 -08:00
cWorld * m_World ;
cChunkMap * m_ChunkMap ;
2011-10-03 11:41:19 -07:00
2012-03-14 13:56:09 -07:00
// TODO: Make these pointers and don't allocate what isn't needed
BLOCKTYPE m_BlockTypes [ cChunkDef : : NumBlocks ] ;
BLOCKTYPE m_BlockMeta [ cChunkDef : : NumBlocks / 2 ] ;
BLOCKTYPE m_BlockLight [ cChunkDef : : NumBlocks / 2 ] ;
BLOCKTYPE m_BlockSkyLight [ cChunkDef : : NumBlocks / 2 ] ;
2011-10-03 11:41:19 -07:00
2012-03-14 13:56:09 -07:00
cChunkDef : : HeightMap m_HeightMap ;
2011-10-03 11:41:19 -07:00
unsigned int m_BlockTickNum ;
unsigned int m_BlockTickX , m_BlockTickY , m_BlockTickZ ;
2012-02-13 13:47:03 -08:00
void RemoveBlockEntity ( cBlockEntity * a_BlockEntity ) ;
void AddBlockEntity ( cBlockEntity * a_BlockEntity ) ;
cBlockEntity * GetBlockEntity ( int a_X , int a_Y , int a_Z ) ;
2012-03-09 16:25:05 -08:00
cBlockEntity * GetBlockEntity ( const Vector3i & a_BlockPos ) { return GetBlockEntity ( a_BlockPos . x , a_BlockPos . y , a_BlockPos . z ) ; }
2012-02-13 13:47:03 -08:00
2012-03-14 14:21:03 -07:00
void SpreadLightOfBlock ( BLOCKTYPE * a_LightBuffer , int a_X , int a_Y , int a_Z , BLOCKTYPE a_Falloff ) ;
2012-02-13 13:47:03 -08:00
2012-02-16 05:42:35 -08:00
void CreateBlockEntities ( void ) ;
2012-02-20 08:39:00 -08:00
// Makes a copy of the list
cClientHandleList GetAllClients ( void ) const { return m_LoadedByClient ; }
2012-03-14 13:56:09 -07:00
void SpreadLight ( BLOCKTYPE * a_LightBuffer ) ;
2011-12-31 13:08:23 -08:00
} ;
2012-02-23 13:02:38 -08:00
typedef cChunk * cChunkPtr ;
2012-02-13 13:47:03 -08:00
typedef std : : list < cChunkPtr > cChunkPtrList ;
2011-12-31 13:08:23 -08:00
# if C_CHUNK_USE_INLINE
2012-02-13 13:47:03 -08:00
# include "cChunk.inl.h"
# endif