2012-06-14 09:06:06 -04:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
# ifndef _WIN32
# include <cstdlib>
# endif
2012-09-23 18:09:57 -04:00
# include "Chunk.h"
# include "World.h"
# include "ClientHandle.h"
# include "Server.h"
2013-11-26 12:14:46 -05:00
# include "zlib/zlib.h"
2012-06-14 09:06:06 -04:00
# include "Defines.h"
2013-05-28 15:12:47 -04:00
# include "BlockEntities/ChestEntity.h"
# include "BlockEntities/DispenserEntity.h"
# include "BlockEntities/DropperEntity.h"
# include "BlockEntities/FurnaceEntity.h"
2013-06-13 03:36:43 -04:00
# include "BlockEntities/HopperEntity.h"
2013-05-28 15:12:47 -04:00
# include "BlockEntities/JukeboxEntity.h"
# include "BlockEntities/NoteEntity.h"
# include "BlockEntities/SignEntity.h"
2014-02-19 08:45:09 -05:00
# include "BlockEntities/MobHeadEntity.h"
2014-03-06 19:30:34 -05:00
# include "BlockEntities/FlowerPotEntity.h"
2013-08-19 05:39:13 -04:00
# include "Entities/Pickup.h"
2012-09-23 18:09:57 -04:00
# include "Item.h"
# include "Noise.h"
# include "Root.h"
2012-06-14 09:06:06 -04:00
# include "MersenneTwister.h"
2013-08-19 05:39:13 -04:00
# include "Entities/Player.h"
2012-07-09 03:00:28 -04:00
# include "BlockArea.h"
2013-12-08 06:17:54 -05:00
# include "Bindings/PluginManager.h"
2012-09-29 09:59:32 -04:00
# include "Blocks/BlockHandler.h"
2013-03-02 10:44:31 -05:00
# include "Simulator/FluidSimulator.h"
2013-09-07 16:19:56 -04:00
# include "MobCensus.h"
2013-09-07 18:11:38 -04:00
# include "MobSpawner.h"
2014-02-02 09:49:37 -05:00
# include "BlockInServerPluginInterface.h"
2012-06-14 09:06:06 -04:00
2013-11-27 03:17:25 -05:00
# include "json/json.h"
2012-06-14 09:06:06 -04:00
2012-07-02 15:22:05 -04:00
2012-06-14 09:06:06 -04:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// sSetBlock:
sSetBlock : : sSetBlock ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta ) // absolute block position
: x ( a_BlockX )
, y ( a_BlockY )
, z ( a_BlockZ )
, BlockType ( a_BlockType )
, BlockMeta ( a_BlockMeta )
{
cChunkDef : : AbsoluteToRelative ( x , y , z , ChunkX , ChunkZ ) ;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cChunk:
2012-12-14 17:38:30 -05:00
cChunk : : cChunk (
int a_ChunkX , int a_ChunkY , int a_ChunkZ ,
cChunkMap * a_ChunkMap , cWorld * a_World ,
cChunk * a_NeighborXM , cChunk * a_NeighborXP , cChunk * a_NeighborZM , cChunk * a_NeighborZP
2013-12-20 13:10:07 -05:00
) :
m_IsValid ( false ) ,
m_IsLightValid ( false ) ,
m_IsDirty ( false ) ,
m_IsSaving ( false ) ,
m_HasLoadFailed ( false ) ,
m_StayCount ( 0 ) ,
m_PosX ( a_ChunkX ) ,
m_PosY ( a_ChunkY ) ,
m_PosZ ( a_ChunkZ ) ,
m_World ( a_World ) ,
m_ChunkMap ( a_ChunkMap ) ,
m_BlockTickX ( 0 ) ,
m_BlockTickY ( 0 ) ,
m_BlockTickZ ( 0 ) ,
m_NeighborXM ( a_NeighborXM ) ,
m_NeighborXP ( a_NeighborXP ) ,
m_NeighborZM ( a_NeighborZM ) ,
m_NeighborZP ( a_NeighborZP ) ,
m_WaterSimulatorData ( a_World - > GetWaterSimulator ( ) - > CreateChunkData ( ) ) ,
2014-06-12 10:21:07 -04:00
m_LavaSimulatorData ( a_World - > GetLavaSimulator ( ) - > CreateChunkData ( ) ) ,
m_EntityTickIteratorData ( std : : make_pair ( false , & m_Entities . end ( ) ) )
2012-06-14 09:06:06 -04:00
{
2012-12-14 17:38:30 -05:00
if ( a_NeighborXM ! = NULL )
{
a_NeighborXM - > m_NeighborXP = this ;
}
if ( a_NeighborXP ! = NULL )
{
a_NeighborXP - > m_NeighborXM = this ;
}
if ( a_NeighborZM ! = NULL )
{
a_NeighborZM - > m_NeighborZP = this ;
}
if ( a_NeighborZP ! = NULL )
{
a_NeighborZP - > m_NeighborZM = this ;
}
2012-06-14 09:06:06 -04:00
}
cChunk : : ~ cChunk ( )
{
2013-02-05 14:57:22 -05:00
cPluginManager : : Get ( ) - > CallHookChunkUnloaded ( m_World , m_PosX , m_PosZ ) ;
2012-06-14 09:06:06 -04:00
// LOGINFO("### delete cChunk() (%i, %i) from %p, thread 0x%x ###", m_PosX, m_PosZ, this, GetCurrentThreadId() );
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) ; itr ! = m_BlockEntities . end ( ) ; + + itr )
{
delete * itr ;
}
m_BlockEntities . clear ( ) ;
// Remove and destroy all entities that are not players:
cEntityList Entities ;
2013-04-13 17:02:10 -04:00
std : : swap ( Entities , m_Entities ) ; // Need another list because cEntity destructors check if they've been removed from chunk
for ( cEntityList : : const_iterator itr = Entities . begin ( ) ; itr ! = Entities . end ( ) ; + + itr )
2012-06-14 09:06:06 -04:00
{
2012-12-21 07:52:14 -05:00
if ( ! ( * itr ) - > IsPlayer ( ) )
2012-06-14 09:06:06 -04:00
{
2013-06-25 02:36:59 -04:00
( * itr ) - > Destroy ( false ) ;
2013-04-13 17:02:10 -04:00
delete * itr ;
2012-06-14 09:06:06 -04:00
}
}
2012-12-14 17:38:30 -05:00
if ( m_NeighborXM ! = NULL )
{
m_NeighborXM - > m_NeighborXP = NULL ;
}
if ( m_NeighborXP ! = NULL )
{
m_NeighborXP - > m_NeighborXM = NULL ;
}
if ( m_NeighborZM ! = NULL )
{
m_NeighborZM - > m_NeighborZP = NULL ;
}
if ( m_NeighborZP ! = NULL )
{
m_NeighborZP - > m_NeighborZM = NULL ;
}
2013-03-02 10:44:31 -05:00
delete m_WaterSimulatorData ;
delete m_LavaSimulatorData ;
2012-06-14 09:06:06 -04:00
}
void cChunk : : SetValid ( void )
{
m_IsValid = true ;
m_World - > GetChunkMap ( ) - > ChunkValidated ( ) ;
}
void cChunk : : MarkRegenerating ( void )
{
// Tell all clients attached to this chunk that they want this chunk:
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
( * itr ) - > AddWantedChunk ( m_PosX , m_PosZ ) ;
} // for itr - m_LoadedByClient[]
}
bool cChunk : : CanUnload ( void )
{
return m_LoadedByClient . empty ( ) & & ! m_IsDirty & & ( m_StayCount = = 0 ) ;
}
void cChunk : : MarkSaving ( void )
{
m_IsSaving = true ;
}
void cChunk : : MarkSaved ( void )
{
if ( ! m_IsSaving )
{
return ;
}
m_IsDirty = false ;
}
void cChunk : : MarkLoaded ( void )
{
m_IsDirty = false ;
SetValid ( ) ;
}
void cChunk : : MarkLoadFailed ( void )
{
if ( m_IsValid )
{
return ;
}
m_HasLoadFailed = true ;
}
void cChunk : : GetAllData ( cChunkDataCallback & a_Callback )
{
2014-05-21 14:58:48 -04:00
a_Callback . HeightMap ( & m_HeightMap ) ;
a_Callback . BiomeData ( & m_BiomeMap ) ;
2014-03-23 10:34:19 -04:00
2014-05-21 14:58:48 -04:00
a_Callback . LightIsValid ( m_IsLightValid ) ;
2014-04-04 18:16:52 -04:00
2014-05-21 14:58:48 -04:00
a_Callback . ChunkData ( m_ChunkData ) ;
2012-06-14 09:06:06 -04:00
for ( cEntityList : : iterator itr = m_Entities . begin ( ) ; itr ! = m_Entities . end ( ) ; + + itr )
{
a_Callback . Entity ( * itr ) ;
}
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) ; itr ! = m_BlockEntities . end ( ) ; + + itr )
{
a_Callback . BlockEntity ( * itr ) ;
}
}
void cChunk : : SetAllData (
2014-04-02 17:53:03 -04:00
const BLOCKTYPE * a_BlockTypes ,
2012-06-14 09:06:06 -04:00
const NIBBLETYPE * a_BlockMeta ,
const NIBBLETYPE * a_BlockLight ,
const NIBBLETYPE * a_BlockSkyLight ,
const HeightMap * a_HeightMap ,
const BiomeMap & a_BiomeMap ,
cBlockEntityList & a_BlockEntities
)
{
memcpy ( m_BiomeMap , a_BiomeMap , sizeof ( m_BiomeMap ) ) ;
2014-04-02 17:53:03 -04:00
2012-06-14 09:06:06 -04:00
if ( a_HeightMap ! = NULL )
{
memcpy ( m_HeightMap , a_HeightMap , sizeof ( m_HeightMap ) ) ;
}
2014-03-23 10:34:19 -04:00
2014-04-07 15:57:14 -04:00
if ( a_HeightMap = = NULL )
2014-04-06 18:30:21 -04:00
{
2014-04-07 15:57:14 -04:00
CalculateHeightmap ( a_BlockTypes ) ;
}
2014-04-06 18:30:21 -04:00
2014-05-29 12:25:08 -04:00
m_ChunkData . SetBlockTypes ( a_BlockTypes ) ;
m_ChunkData . SetMetas ( a_BlockMeta ) ;
2014-05-24 08:33:40 -04:00
m_ChunkData . SetBlockLight ( a_BlockLight ) ;
2014-05-21 14:58:48 -04:00
m_ChunkData . SetSkyLight ( a_BlockSkyLight ) ;
2012-06-14 09:06:06 -04:00
m_IsLightValid = ( a_BlockLight ! = NULL ) & & ( a_BlockSkyLight ! = NULL ) ;
// Clear the block entities present - either the loader / saver has better, or we'll create empty ones:
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) ; itr ! = m_BlockEntities . end ( ) ; + + itr )
{
delete * itr ;
}
std : : swap ( a_BlockEntities , m_BlockEntities ) ;
2013-04-06 17:21:57 -04:00
// Set all block entities' World variable:
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) ; itr ! = m_BlockEntities . end ( ) ; + + itr )
{
( * itr ) - > SetWorld ( m_World ) ;
}
2012-06-14 09:06:06 -04:00
// Create block entities that the loader didn't load; fill them with defaults
CreateBlockEntities ( ) ;
2013-03-03 10:33:55 -05:00
2013-03-14 16:02:52 -04:00
// Set the chunk data as valid. This may be needed for some simulators that perform actions upon block adding (Vaporize)
SetValid ( ) ;
2013-03-03 10:33:55 -05:00
// Wake up all simulators for their respective blocks:
WakeUpSimulators ( ) ;
2012-06-14 09:06:06 -04:00
m_HasLoadFailed = false ;
}
void cChunk : : SetLight (
const cChunkDef : : BlockNibbles & a_BlockLight ,
const cChunkDef : : BlockNibbles & a_SkyLight
)
{
// TODO: We might get cases of wrong lighting when a chunk changes in the middle of a lighting calculation.
// Postponing until we see how bad it is :)
2014-04-06 18:30:21 -04:00
2014-05-24 08:33:40 -04:00
m_ChunkData . SetBlockLight ( a_BlockLight ) ;
2014-04-06 18:30:21 -04:00
2014-05-21 15:08:34 -04:00
m_ChunkData . SetSkyLight ( a_SkyLight ) ;
2014-04-06 18:30:21 -04:00
2012-06-14 09:06:06 -04:00
m_IsLightValid = true ;
}
void cChunk : : GetBlockTypes ( BLOCKTYPE * a_BlockTypes )
{
2014-05-29 12:25:08 -04:00
m_ChunkData . CopyBlockTypes ( a_BlockTypes ) ;
2012-06-14 09:06:06 -04:00
}
2012-10-06 12:58:31 -04:00
void cChunk : : WriteBlockArea ( cBlockArea & a_Area , int a_MinBlockX , int a_MinBlockY , int a_MinBlockZ , int a_DataTypes )
{
if ( ( a_DataTypes & ( cBlockArea : : baTypes | cBlockArea : : baMetas ) ) ! = ( cBlockArea : : baTypes | cBlockArea : : baMetas ) )
{
LOGWARNING ( " cChunk::WriteBlockArea(): unsupported datatype request, can write only types + metas (0x%x), requested 0x%x. Ignoring. " ,
( cBlockArea : : baTypes | cBlockArea : : baMetas ) , a_DataTypes & ( cBlockArea : : baTypes | cBlockArea : : baMetas )
) ;
return ;
}
// SizeX, SizeZ are the dimensions of the block data to copy to the chunk (size of the geometric union)
int BlockStartX = std : : max ( a_MinBlockX , m_PosX * cChunkDef : : Width ) ;
int BlockEndX = std : : min ( a_MinBlockX + a_Area . GetSizeX ( ) , ( m_PosX + 1 ) * cChunkDef : : Width ) ;
int BlockStartZ = std : : max ( a_MinBlockZ , m_PosZ * cChunkDef : : Width ) ;
int BlockEndZ = std : : min ( a_MinBlockZ + a_Area . GetSizeZ ( ) , ( m_PosZ + 1 ) * cChunkDef : : Width ) ;
int SizeX = BlockEndX - BlockStartX ;
int SizeZ = BlockEndZ - BlockStartZ ;
int OffX = BlockStartX - m_PosX * cChunkDef : : Width ;
int OffZ = BlockStartZ - m_PosZ * cChunkDef : : Width ;
int BaseX = BlockStartX - a_MinBlockX ;
int BaseZ = BlockStartZ - a_MinBlockZ ;
int SizeY = a_Area . GetSizeY ( ) ;
// TODO: Improve this by not calling FastSetBlock() and doing the processing here
// so that the heightmap is touched only once for each column.
BLOCKTYPE * AreaBlockTypes = a_Area . GetBlockTypes ( ) ;
NIBBLETYPE * AreaBlockMetas = a_Area . GetBlockMetas ( ) ;
for ( int y = 0 ; y < SizeY ; y + + )
{
int ChunkY = a_MinBlockY + y ;
int AreaY = y ;
for ( int z = 0 ; z < SizeZ ; z + + )
{
int ChunkZ = OffZ + z ;
int AreaZ = BaseZ + z ;
for ( int x = 0 ; x < SizeX ; x + + )
{
int ChunkX = OffX + x ;
int AreaX = BaseX + x ;
int idx = a_Area . MakeIndex ( AreaX , AreaY , AreaZ ) ;
BLOCKTYPE BlockType = AreaBlockTypes [ idx ] ;
NIBBLETYPE BlockMeta = AreaBlockMetas [ idx ] ;
FastSetBlock ( ChunkX , ChunkY , ChunkZ , BlockType , BlockMeta ) ;
} // for x
} // for z
} // for y
}
2012-06-14 09:06:06 -04:00
/// Returns true if there is a block entity at the coords specified
bool cChunk : : HasBlockEntityAt ( int a_BlockX , int a_BlockY , int a_BlockZ )
{
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) ; itr ! = m_BlockEntities . end ( ) ; + + itr )
{
if (
( ( * itr ) - > GetPosX ( ) = = a_BlockX ) & &
( ( * itr ) - > GetPosY ( ) = = a_BlockY ) & &
( ( * itr ) - > GetPosZ ( ) = = a_BlockZ )
)
{
return true ;
}
} // for itr - m_BlockEntities[]
return false ;
}
void cChunk : : Stay ( bool a_Stay )
{
m_StayCount + = ( a_Stay ? 1 : - 1 ) ;
ASSERT ( m_StayCount > = 0 ) ;
}
2013-09-07 16:19:56 -04:00
void cChunk : : CollectMobCensus ( cMobCensus & toFill )
{
2013-09-08 06:25:07 -04:00
toFill . CollectSpawnableChunk ( * this ) ;
2013-09-07 16:19:56 -04:00
std : : list < const Vector3d * > playerPositions ;
cPlayer * currentPlayer ;
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) , end = m_LoadedByClient . end ( ) ; itr ! = end ; + + itr )
{
currentPlayer = ( * itr ) - > GetPlayer ( ) ;
playerPositions . push_back ( & ( currentPlayer - > GetPosition ( ) ) ) ;
}
Vector3d currentPosition ;
for ( cEntityList : : iterator itr = m_Entities . begin ( ) ; itr ! = m_Entities . end ( ) ; + + itr )
{
//LOGD("Counting entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass());
if ( ( * itr ) - > IsMob ( ) )
{
2013-09-09 12:45:39 -04:00
cMonster & Monster = ( cMonster & ) ( * * itr ) ;
currentPosition = Monster . GetPosition ( ) ;
2014-04-18 15:09:44 -04:00
for ( std : : list < const Vector3d * > : : const_iterator itr2 = playerPositions . begin ( ) ; itr2 ! = playerPositions . end ( ) ; + + itr2 )
2013-09-07 16:19:56 -04:00
{
2013-09-09 12:45:39 -04:00
toFill . CollectMob ( Monster , * this , ( currentPosition - * * itr2 ) . SqrLength ( ) ) ;
2013-09-07 16:19:56 -04:00
}
}
} // for itr - m_Entitites[]
}
2013-09-07 18:11:38 -04:00
void cChunk : : getThreeRandomNumber ( int & a_X , int & a_Y , int & a_Z , int a_MaxX , int a_MaxY , int a_MaxZ )
{
2013-09-08 06:20:19 -04:00
ASSERT ( a_MaxX * a_MaxY * a_MaxZ * 8 < 0x00ffffff ) ;
2013-09-07 18:11:38 -04:00
int Random = m_World - > GetTickRandomNumber ( 0x00ffffff ) ;
a_X = Random % ( a_MaxX * 2 ) ;
a_Y = ( Random / ( a_MaxX * 2 ) ) % ( a_MaxY * 2 ) ;
a_Z = ( ( Random / ( a_MaxX * 2 ) ) / ( a_MaxY * 2 ) ) % ( a_MaxZ * 2 ) ;
a_X / = 2 ;
a_Y / = 2 ;
a_Z / = 2 ;
}
2013-09-08 05:48:48 -04:00
void cChunk : : getRandomBlockCoords ( int & a_X , int & a_Y , int & a_Z )
2013-09-07 18:11:38 -04:00
{
// MG TODO : check if this kind of optimization (only one random call) is still needed
// MG TODO : if so propagate it
getThreeRandomNumber ( a_X , a_Y , a_Z , Width , Height - 2 , Width ) ;
a_Y + + ;
}
void cChunk : : SpawnMobs ( cMobSpawner & a_MobSpawner )
{
2013-09-07 20:47:02 -04:00
int Center_X , Center_Y , Center_Z ;
2013-09-08 05:48:48 -04:00
getRandomBlockCoords ( Center_X , Center_Y , Center_Z ) ;
2013-09-07 20:47:02 -04:00
BLOCKTYPE PackCenterBlock = GetBlock ( Center_X , Center_Y , Center_Z ) ;
if ( a_MobSpawner . CheckPackCenter ( PackCenterBlock ) )
{
a_MobSpawner . NewPack ( ) ;
int NumberOfTries = 0 ;
int NumberOfSuccess = 0 ;
int MaxNbOfSuccess = 4 ; // this can be changed during the process for Wolves and Ghass
while ( NumberOfTries < 12 & & NumberOfSuccess < MaxNbOfSuccess )
{
const int HorizontalRange = 20 ; // MG TODO : relocate
const int VerticalRange = 0 ; // MG TODO : relocate
int Try_X , Try_Y , Try_Z ;
getThreeRandomNumber ( Try_X , Try_Y , Try_Z , 2 * HorizontalRange + 1 , 2 * VerticalRange + 1 , 2 * HorizontalRange + 1 ) ;
Try_X - = HorizontalRange ;
Try_Y - = VerticalRange ;
Try_Z - = HorizontalRange ;
Try_X + = Center_X ;
Try_Y + = Center_Y ;
Try_Z + = Center_Z ;
2013-09-08 06:20:19 -04:00
ASSERT ( Try_Y > 0 ) ;
ASSERT ( Try_Y < cChunkDef : : Height - 1 ) ;
2013-09-07 20:47:02 -04:00
2013-10-28 11:49:06 -04:00
EMCSBiome Biome = m_ChunkMap - > GetBiomeAt ( Try_X , Try_Z ) ;
// MG TODO :
// Moon cycle (for slime)
// check player and playerspawn presence < 24 blocks
// check mobs presence on the block
2013-09-07 20:47:02 -04:00
2013-10-28 11:49:06 -04:00
// MG TODO : check that "Level" really means Y
2013-12-22 11:11:34 -05:00
/*
2013-10-28 11:49:06 -04:00
NIBBLETYPE SkyLight = 0 ;
2013-10-21 16:38:38 -04:00
2013-10-28 11:49:06 -04:00
NIBBLETYPE BlockLight = 0 ;
2013-12-22 11:11:34 -05:00
*/
2013-10-21 11:41:48 -04:00
2013-10-28 11:49:06 -04:00
if ( IsLightValid ( ) )
{
2013-10-29 12:44:51 -04:00
cEntity * newMob = a_MobSpawner . TryToSpawnHere ( this , Try_X , Try_Y , Try_Z , Biome , MaxNbOfSuccess ) ;
2013-10-28 11:49:06 -04:00
if ( newMob )
2013-09-07 20:47:02 -04:00
{
2013-10-28 11:49:06 -04:00
int WorldX , WorldY , WorldZ ;
PositionToWorldPosition ( Try_X , Try_Y , Try_Z , WorldX , WorldY , WorldZ ) ;
double ActualX = WorldX + 0.5 ;
double ActualZ = WorldZ + 0.5 ;
newMob - > SetPosition ( ActualX , WorldY , ActualZ ) ;
LOGD ( " Spawning %s #%i at %d,%d,%d " , newMob - > GetClass ( ) , newMob - > GetUniqueID ( ) , WorldX , WorldY , WorldZ ) ;
NumberOfSuccess + + ;
2013-09-07 20:47:02 -04:00
}
}
NumberOfTries + + ;
}
}
2013-09-07 18:11:38 -04:00
}
2012-06-14 09:06:06 -04:00
2013-04-13 17:02:10 -04:00
void cChunk : : Tick ( float a_Dt )
2012-06-14 09:06:06 -04:00
{
2012-08-25 13:52:08 -04:00
BroadcastPendingBlockChanges ( ) ;
2012-06-14 09:06:06 -04:00
2013-08-18 16:44:22 -04:00
// Set all blocks that have been queued for setting later:
ProcessQueuedSetBlocks ( ) ;
2012-06-14 09:06:06 -04:00
CheckBlocks ( ) ;
2013-03-01 14:35:29 -05:00
// Tick simulators:
m_World - > GetSimulatorManager ( ) - > SimulateChunk ( a_Dt , m_PosX , m_PosZ , this ) ;
2013-04-13 17:02:10 -04:00
TickBlocks ( ) ;
2012-06-14 09:06:06 -04:00
2013-04-01 16:56:25 -04:00
// Tick all block entities in this chunk:
2012-06-14 09:06:06 -04:00
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) ; itr ! = m_BlockEntities . end ( ) ; + + itr )
{
2013-05-28 14:50:44 -04:00
m_IsDirty = ( * itr ) - > Tick ( a_Dt , * this ) | m_IsDirty ;
2012-06-14 09:06:06 -04:00
}
2013-04-01 16:56:25 -04:00
2013-09-07 19:43:55 -04:00
// Tick all entities in this chunk (except mobs):
2014-06-12 10:21:07 -04:00
m_EntityTickIteratorData . first = true ;
for ( cEntityList : : iterator itr = m_Entities . begin ( ) ; itr ! = m_Entities . end ( ) ; )
2013-04-13 17:02:10 -04:00
{
2014-06-12 10:21:07 -04:00
// Mobs are ticked inside cWorld::TickMobs() (as we don't have to tick them if they are far away from players)
2014-05-31 17:28:51 -04:00
// Don't tick things queued to be removed
2014-06-12 10:21:07 -04:00
if ( ! ( ( * itr ) - > IsMob ( ) ) )
2013-09-07 19:43:55 -04:00
{
2014-06-12 10:21:07 -04:00
m_EntityTickIteratorData . second = & itr ;
2013-09-07 19:43:55 -04:00
( * itr ) - > Tick ( a_Dt , * this ) ;
2014-06-12 10:21:07 -04:00
if ( itr ! = * m_EntityTickIteratorData . second )
{
itr = * m_EntityTickIteratorData . second ;
}
else
{
+ + itr ;
}
continue ;
2013-09-07 19:43:55 -04:00
}
2014-06-12 10:21:07 -04:00
+ + itr ;
2013-04-13 17:02:10 -04:00
} // for itr - m_Entitites[]
2014-06-12 10:21:07 -04:00
m_EntityTickIteratorData . first = false ;
2013-04-13 17:02:10 -04:00
for ( cEntityList : : iterator itr = m_Entities . begin ( ) ; itr ! = m_Entities . end ( ) ; )
{
2014-06-12 10:21:07 -04:00
if ( ( * itr ) - > IsDestroyed ( ) ) // Remove all entities that were scheduled for removal:
2014-05-31 17:28:51 -04:00
{
2014-06-12 10:21:07 -04:00
LOGD ( " Destroying entity #%i (%s) " , ( * itr ) - > GetUniqueID ( ) , ( * itr ) - > GetClass ( ) ) ;
cEntity * ToDelete = * itr ;
2014-05-31 17:28:51 -04:00
itr = m_Entities . erase ( itr ) ;
2014-06-12 10:21:07 -04:00
delete ToDelete ;
2014-05-31 17:28:51 -04:00
}
else if ( // If any entity moved out of the chunk, move it to the neighbor:
2013-04-13 17:02:10 -04:00
( ( * itr ) - > GetChunkX ( ) ! = m_PosX ) | |
( ( * itr ) - > GetChunkZ ( ) ! = m_PosZ )
)
{
MoveEntityToNewChunk ( * itr ) ;
itr = m_Entities . erase ( itr ) ;
}
else
{
2014-06-12 10:21:07 -04:00
+ + itr ;
2013-04-13 17:02:10 -04:00
}
2014-05-31 17:28:51 -04:00
} // for itr - m_Entitites[]
2013-04-13 17:02:10 -04:00
2013-04-01 16:56:25 -04:00
ApplyWeatherToTop ( ) ;
2012-06-14 09:06:06 -04:00
}
2013-11-30 09:58:27 -05:00
void cChunk : : TickBlock ( int a_RelX , int a_RelY , int a_RelZ )
{
2014-04-26 13:50:23 -04:00
cBlockHandler * Handler = BlockHandler ( GetBlock ( a_RelX , a_RelY , a_RelZ ) ) ;
2013-11-30 09:58:27 -05:00
ASSERT ( Handler ! = NULL ) ; // Happenned on server restart, FS #243
2014-02-02 09:49:37 -05:00
cChunkInterface ChunkInterface ( this - > GetWorld ( ) - > GetChunkMap ( ) ) ;
cBlockInServerPluginInterface PluginInterface ( * this - > GetWorld ( ) ) ;
Handler - > OnUpdate ( ChunkInterface , * this - > GetWorld ( ) , PluginInterface , * this , a_RelX , a_RelY , a_RelZ ) ;
2013-11-30 09:58:27 -05:00
}
2013-04-13 17:02:10 -04:00
void cChunk : : MoveEntityToNewChunk ( cEntity * a_Entity )
{
2013-05-19 07:49:01 -04:00
cChunk * Neighbor = GetNeighborChunk ( a_Entity - > GetChunkX ( ) * cChunkDef : : Width , a_Entity - > GetChunkZ ( ) * cChunkDef : : Width ) ;
2013-04-13 17:02:10 -04:00
if ( Neighbor = = NULL )
{
2013-05-06 14:32:22 -04:00
Neighbor = m_ChunkMap - > GetChunkNoLoad ( a_Entity - > GetChunkX ( ) , ZERO_CHUNK_Y , a_Entity - > GetChunkZ ( ) ) ;
if ( Neighbor = = NULL )
{
// TODO: What to do with this?
LOGWARNING ( " %s: Failed to move entity, destination chunk unreachable. Entity lost " , __FUNCTION__ ) ;
return ;
}
2013-04-13 17:02:10 -04:00
}
2013-05-19 07:49:01 -04:00
ASSERT ( Neighbor ! = this ) ; // Moving into the same chunk? wtf?
2013-04-13 17:02:10 -04:00
Neighbor - > AddEntity ( a_Entity ) ;
class cMover :
public cClientDiffCallback
{
virtual void Removed ( cClientHandle * a_Client ) override
{
a_Client - > SendDestroyEntity ( * m_Entity ) ;
}
virtual void Added ( cClientHandle * a_Client ) override
{
m_Entity - > SpawnOn ( * a_Client ) ;
}
cEntity * m_Entity ;
public :
cMover ( cEntity * a_Entity ) :
m_Entity ( a_Entity )
{ }
} Mover ( a_Entity ) ;
m_ChunkMap - > CompareChunkClients ( this , Neighbor , Mover ) ;
}
2013-08-18 16:44:22 -04:00
void cChunk : : ProcessQueuedSetBlocks ( void )
{
Int64 CurrTick = m_World - > GetWorldAge ( ) ;
for ( sSetBlockQueueVector : : iterator itr = m_SetBlockQueue . begin ( ) ; itr ! = m_SetBlockQueue . end ( ) ; )
{
2013-11-18 17:30:34 -05:00
if ( itr - > m_Tick < = CurrTick )
2013-08-18 16:44:22 -04:00
{
2014-04-27 12:35:41 -04:00
if ( itr - > m_PreviousType ! = E_BLOCK_AIR ) // PreviousType defaults to 0 if not specified
2013-12-06 17:29:15 -05:00
{
if ( GetBlock ( itr - > m_RelX , itr - > m_RelY , itr - > m_RelZ ) = = itr - > m_PreviousType )
{
// Current world age is bigger than/equal to target world age - delay time reached AND
// Previous block type was the same as current block type (to prevent duplication)
2013-12-12 19:06:47 -05:00
SetBlock ( itr - > m_RelX , itr - > m_RelY , itr - > m_RelZ , itr - > m_BlockType , itr - > m_BlockMeta ) ; // SetMeta doesn't send to client
2013-12-06 17:29:15 -05:00
itr = m_SetBlockQueue . erase ( itr ) ;
LOGD ( " Successfully set queued block - previous and current types matched " ) ;
}
else
{
itr = m_SetBlockQueue . erase ( itr ) ;
LOGD ( " Failure setting queued block - previous and current blocktypes didn't match " ) ;
}
}
else
{
// Current world age is bigger than/equal to target world age - delay time reached
SetBlock ( itr - > m_RelX , itr - > m_RelY , itr - > m_RelZ , itr - > m_BlockType , itr - > m_BlockMeta ) ;
itr = m_SetBlockQueue . erase ( itr ) ;
LOGD ( " Successfully set queued block - previous type ignored " ) ;
}
2013-08-18 16:44:22 -04:00
}
else
{
2013-11-18 17:30:34 -05:00
// Not yet
+ + itr ;
continue ;
2013-08-18 16:44:22 -04:00
}
} // for itr - m_SetBlockQueue[]
}
2012-08-25 13:52:08 -04:00
void cChunk : : BroadcastPendingBlockChanges ( void )
{
2013-08-19 15:55:03 -04:00
if ( m_PendingSendBlocks . empty ( ) )
{
return ;
}
2012-08-25 13:52:08 -04:00
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) , end = m_LoadedByClient . end ( ) ; itr ! = end ; + + itr )
{
2013-08-19 03:13:19 -04:00
( * itr ) - > SendBlockChanges ( m_PosX , m_PosZ , m_PendingSendBlocks ) ;
2012-08-25 13:52:08 -04:00
}
2013-08-19 03:13:19 -04:00
m_PendingSendBlocks . clear ( ) ;
2012-08-25 13:52:08 -04:00
}
2014-01-31 18:17:41 -05:00
void cChunk : : CheckBlocks ( )
2012-06-14 09:06:06 -04:00
{
2014-04-24 16:49:56 -04:00
if ( m_ToTickBlocks . empty ( ) )
2012-06-14 09:06:06 -04:00
{
return ;
}
2014-04-26 13:50:23 -04:00
std : : vector < Vector3i > ToTickBlocks ;
2013-03-15 16:18:11 -04:00
std : : swap ( m_ToTickBlocks , ToTickBlocks ) ;
2012-06-14 09:06:06 -04:00
2014-01-31 18:17:41 -05:00
cChunkInterface ChunkInterface ( m_World - > GetChunkMap ( ) ) ;
2014-02-02 09:49:37 -05:00
cBlockInServerPluginInterface PluginInterface ( * m_World ) ;
2014-01-31 18:17:41 -05:00
2014-04-26 13:50:23 -04:00
for ( std : : vector < Vector3i > : : const_iterator itr = ToTickBlocks . begin ( ) , end = ToTickBlocks . end ( ) ; itr ! = end ; + + itr )
2012-06-14 09:06:06 -04:00
{
2014-04-26 13:50:23 -04:00
Vector3i Pos = ( * itr ) ;
2012-06-14 09:06:06 -04:00
2014-04-26 13:50:23 -04:00
cBlockHandler * Handler = BlockHandler ( GetBlock ( Pos ) ) ;
Handler - > Check ( ChunkInterface , PluginInterface , Pos . x , Pos . y , Pos . z , * this ) ;
2012-06-14 09:06:06 -04:00
} // for itr - ToTickBlocks[]
}
2013-04-13 17:02:10 -04:00
void cChunk : : TickBlocks ( void )
2012-06-14 09:06:06 -04:00
{
// Tick dem blocks
// _X: We must limit the random number or else we get a nasty int overflow bug ( http://forum.mc-server.org/showthread.php?tid=457 )
2013-04-13 17:02:10 -04:00
int RandomX = m_World - > GetTickRandomNumber ( 0x00ffffff ) ;
int RandomY = m_World - > GetTickRandomNumber ( 0x00ffffff ) ;
int RandomZ = m_World - > GetTickRandomNumber ( 0x00ffffff ) ;
2012-06-14 09:06:06 -04:00
int TickX = m_BlockTickX ;
int TickY = m_BlockTickY ;
int TickZ = m_BlockTickZ ;
2014-02-02 09:49:37 -05:00
cChunkInterface ChunkInterface ( this - > GetWorld ( ) - > GetChunkMap ( ) ) ;
cBlockInServerPluginInterface PluginInterface ( * this - > GetWorld ( ) ) ;
2012-06-14 09:06:06 -04:00
// This for loop looks disgusting, but it actually does a simple thing - first processes m_BlockTick, then adds random to it
// This is so that SetNextBlockTick() works
for ( int i = 0 ; i < 50 ; i + + ,
// This weird construct (*2, then /2) is needed,
// otherwise the blocktick distribution is too biased towards even coords!
TickX = ( TickX + RandomX ) % ( Width * 2 ) ,
TickY = ( TickY + RandomY ) % ( Height * 2 ) ,
TickZ = ( TickZ + RandomZ ) % ( Width * 2 ) ,
m_BlockTickX = TickX / 2 ,
m_BlockTickY = TickY / 2 ,
m_BlockTickZ = TickZ / 2
)
{
if ( m_BlockTickY > cChunkDef : : GetHeight ( m_HeightMap , m_BlockTickX , m_BlockTickZ ) )
{
continue ; // It's all air up here
}
2014-04-26 13:50:23 -04:00
cBlockHandler * Handler = BlockHandler ( GetBlock ( m_BlockTickX , m_BlockTickY , m_BlockTickZ ) ) ;
2012-10-07 06:08:57 -04:00
ASSERT ( Handler ! = NULL ) ; // Happenned on server restart, FS #243
2014-02-02 09:49:37 -05:00
Handler - > OnUpdate ( ChunkInterface , * this - > GetWorld ( ) , PluginInterface , * this , m_BlockTickX , m_BlockTickY , m_BlockTickZ ) ;
2012-10-07 06:08:57 -04:00
} // for i - tickblocks
2012-06-14 09:06:06 -04:00
}
2012-09-04 11:07:08 -04:00
2013-04-01 16:56:25 -04:00
void cChunk : : ApplyWeatherToTop ( )
2012-10-21 17:15:57 -04:00
{
if (
2013-04-01 16:56:25 -04:00
( m_World - > GetTickRandomNumber ( 100 ) ! = 0 ) | |
2012-10-21 17:15:57 -04:00
(
( m_World - > GetWeather ( ) ! = eWeather_Rain ) & &
( m_World - > GetWeather ( ) ! = eWeather_ThunderStorm )
)
)
{
// Not the right weather, or not at this tick; bail out
return ;
}
2013-04-01 16:56:25 -04:00
int X = m_World - > GetTickRandomNumber ( 15 ) ;
int Z = m_World - > GetTickRandomNumber ( 15 ) ;
2012-10-21 17:15:57 -04:00
switch ( GetBiomeAt ( X , Z ) )
{
case biTaiga :
case biFrozenOcean :
case biFrozenRiver :
case biIcePlains :
case biIceMountains :
case biTaigaHills :
{
// TODO: Check light levels, don't snow over when the BlockLight is higher than (7?)
int Height = GetHeight ( X , Z ) ;
BLOCKTYPE TopBlock = GetBlock ( X , Height , Z ) ;
NIBBLETYPE TopMeta = GetMeta ( X , Height , Z ) ;
if ( m_World - > IsDeepSnowEnabled ( ) & & ( TopBlock = = E_BLOCK_SNOW ) )
{
int MaxSize = 7 ;
BLOCKTYPE BlockType [ 4 ] ;
NIBBLETYPE BlockMeta [ 4 ] ;
UnboundedRelGetBlock ( X - 1 , Height , Z , BlockType [ 0 ] , BlockMeta [ 0 ] ) ;
UnboundedRelGetBlock ( X + 1 , Height , Z , BlockType [ 1 ] , BlockMeta [ 1 ] ) ;
UnboundedRelGetBlock ( X , Height , Z - 1 , BlockType [ 2 ] , BlockMeta [ 2 ] ) ;
UnboundedRelGetBlock ( X , Height , Z + 1 , BlockType [ 3 ] , BlockMeta [ 3 ] ) ;
for ( int i = 0 ; i < 4 ; i + + )
{
switch ( BlockType [ i ] )
{
case E_BLOCK_AIR :
{
MaxSize = 0 ;
break ;
}
case E_BLOCK_SNOW :
{
MaxSize = std : : min ( BlockMeta [ i ] + 1 , MaxSize ) ;
break ;
}
}
}
if ( TopMeta < MaxSize )
{
FastSetBlock ( X , Height , Z , E_BLOCK_SNOW , TopMeta + 1 ) ;
}
else if ( TopMeta > MaxSize )
{
FastSetBlock ( X , Height , Z , E_BLOCK_SNOW , TopMeta - 1 ) ;
}
}
2014-03-28 18:51:39 -04:00
else if ( cBlockInfo : : IsSnowable ( TopBlock ) & & ( Height + 1 < cChunkDef : : Height ) )
2012-10-21 17:15:57 -04:00
{
SetBlock ( X , Height + 1 , Z , E_BLOCK_SNOW , 0 ) ;
}
else if ( ( TopBlock = = E_BLOCK_WATER ) | | ( TopBlock = = E_BLOCK_STATIONARY_WATER ) )
{
SetBlock ( X , Height , Z , E_BLOCK_ICE , 0 ) ;
}
2012-10-22 10:32:54 -04:00
else if (
( m_World - > IsDeepSnowEnabled ( ) ) & &
(
( TopBlock = = E_BLOCK_RED_ROSE ) | |
( TopBlock = = E_BLOCK_YELLOW_FLOWER ) | |
( TopBlock = = E_BLOCK_RED_MUSHROOM ) | |
( TopBlock = = E_BLOCK_BROWN_MUSHROOM )
)
)
{
SetBlock ( X , Height , Z , E_BLOCK_SNOW , 0 ) ;
}
2012-10-21 17:15:57 -04:00
break ;
} // case (snowy biomes)
2013-12-09 09:05:32 -05:00
default :
{
break ;
}
2012-10-21 17:15:57 -04:00
} // switch (biome)
}
2012-06-14 09:06:06 -04:00
void cChunk : : GrowMelonPumpkin ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE a_BlockType , MTRand & a_TickRandom )
{
// Convert the stem BlockType into produce BlockType
BLOCKTYPE ProduceType ;
switch ( a_BlockType )
{
case E_BLOCK_MELON_STEM : ProduceType = E_BLOCK_MELON ; break ;
case E_BLOCK_PUMPKIN_STEM : ProduceType = E_BLOCK_PUMPKIN ; break ;
default :
{
ASSERT ( ! " Unhandled blocktype in TickMelonPumpkin() " ) ;
return ;
}
}
// Check if there's another melon / pumpkin around that stem, if so, abort:
bool IsValid ;
BLOCKTYPE BlockType [ 4 ] ;
NIBBLETYPE BlockMeta ; // unused
IsValid = UnboundedRelGetBlock ( a_RelX + 1 , a_RelY , a_RelZ , BlockType [ 0 ] , BlockMeta ) ;
IsValid = IsValid & & UnboundedRelGetBlock ( a_RelX - 1 , a_RelY , a_RelZ , BlockType [ 1 ] , BlockMeta ) ;
IsValid = IsValid & & UnboundedRelGetBlock ( a_RelX , a_RelY , a_RelZ + 1 , BlockType [ 2 ] , BlockMeta ) ;
IsValid = IsValid & & UnboundedRelGetBlock ( a_RelX , a_RelY , a_RelZ - 1 , BlockType [ 3 ] , BlockMeta ) ;
if (
! IsValid | |
( BlockType [ 0 ] = = ProduceType ) | |
( BlockType [ 1 ] = = ProduceType ) | |
( BlockType [ 2 ] = = ProduceType ) | |
( BlockType [ 3 ] = = ProduceType )
)
{
// Neighbors not valid or already taken by the same produce
return ;
}
// Pick a direction in which to place the produce:
int x = 0 , z = 0 ;
int CheckType = a_TickRandom . randInt ( 3 ) ; // The index to the neighbors array which should be checked for emptiness
switch ( CheckType )
{
case 0 : x = 1 ; break ;
case 1 : x = - 1 ; break ;
case 2 : z = 1 ; break ;
case 3 : z = - 1 ; break ;
}
// Check that the block in that direction is empty:
switch ( BlockType [ CheckType ] )
{
case E_BLOCK_AIR :
case E_BLOCK_SNOW :
case E_BLOCK_TALL_GRASS :
case E_BLOCK_DEAD_BUSH :
{
break ;
}
default : return ;
}
// Check if there's soil under the neighbor. We already know the neighbors are valid. Place produce if ok
BLOCKTYPE Soil ;
UnboundedRelGetBlock ( a_RelX + x , a_RelY - 1 , a_RelZ + z , Soil , BlockMeta ) ;
switch ( Soil )
{
case E_BLOCK_DIRT :
case E_BLOCK_GRASS :
case E_BLOCK_FARMLAND :
{
2013-04-03 12:43:37 -04:00
// DEBUG: This is here to catch FS #349 - melons growing over other crops.
LOG ( " Growing melon/pumpkin overwriting %s, growing on %s " ,
ItemTypeToString ( BlockType [ CheckType ] ) . c_str ( ) ,
ItemTypeToString ( Soil ) . c_str ( )
) ;
2012-06-14 09:06:06 -04:00
// Place a randomly-facing produce:
UnboundedRelFastSetBlock ( a_RelX + x , a_RelY , a_RelZ + z , ProduceType , ( NIBBLETYPE ) ( a_TickRandom . randInt ( 4 ) % 4 ) ) ;
break ;
}
}
}
void cChunk : : GrowSugarcane ( int a_RelX , int a_RelY , int a_RelZ , int a_NumBlocks )
{
// Check the total height of the sugarcane blocks here:
int Top = a_RelY + 1 ;
while (
( Top < cChunkDef : : Height ) & &
( GetBlock ( a_RelX , Top , a_RelZ ) = = E_BLOCK_SUGARCANE )
)
{
+ + Top ;
}
int Bottom = a_RelY - 1 ;
while (
( Bottom > 0 ) & &
( GetBlock ( a_RelX , Bottom , a_RelZ ) = = E_BLOCK_SUGARCANE )
)
{
- - Bottom ;
}
// Grow by at most a_NumBlocks, but no more than max height:
int ToGrow = std : : min ( a_NumBlocks , m_World - > GetMaxSugarcaneHeight ( ) + 1 - ( Top - Bottom ) ) ;
for ( int i = 0 ; i < ToGrow ; i + + )
{
BLOCKTYPE BlockType ;
NIBBLETYPE BlockMeta ;
if ( UnboundedRelGetBlock ( a_RelX , Top + i , a_RelZ , BlockType , BlockMeta ) & & ( BlockType = = E_BLOCK_AIR ) )
{
UnboundedRelFastSetBlock ( a_RelX , Top + i , a_RelZ , E_BLOCK_SUGARCANE , 0 ) ;
}
else
{
break ;
}
} // for i
}
void cChunk : : GrowCactus ( int a_RelX , int a_RelY , int a_RelZ , int a_NumBlocks )
{
// Check the total height of the sugarcane blocks here:
int Top = a_RelY + 1 ;
while (
( Top < cChunkDef : : Height ) & &
( GetBlock ( a_RelX , Top , a_RelZ ) = = E_BLOCK_CACTUS )
)
{
+ + Top ;
}
int Bottom = a_RelY - 1 ;
while (
( Bottom > 0 ) & &
( GetBlock ( a_RelX , Bottom , a_RelZ ) = = E_BLOCK_CACTUS )
)
{
- - Bottom ;
}
// Grow by at most a_NumBlocks, but no more than max height:
int ToGrow = std : : min ( a_NumBlocks , m_World - > GetMaxCactusHeight ( ) + 1 - ( Top - Bottom ) ) ;
for ( int i = 0 ; i < ToGrow ; i + + )
{
BLOCKTYPE BlockType ;
NIBBLETYPE BlockMeta ;
if ( UnboundedRelGetBlock ( a_RelX , Top + i , a_RelZ , BlockType , BlockMeta ) & & ( BlockType = = E_BLOCK_AIR ) )
{
// TODO: Check the surrounding blocks, if they aren't air, break the cactus block into pickups (and continue breaking blocks above in the next loop iterations)
UnboundedRelFastSetBlock ( a_RelX , Top + i , a_RelZ , E_BLOCK_CACTUS , 0 ) ;
}
else
{
break ;
}
} // for i
}
2013-03-15 16:18:11 -04:00
bool cChunk : : UnboundedRelGetBlock ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE & a_BlockType , NIBBLETYPE & a_BlockMeta ) const
2012-06-14 09:06:06 -04:00
{
2013-03-15 16:18:11 -04:00
if ( ( a_RelY < 0 ) | | ( a_RelY > = cChunkDef : : Height ) )
2012-06-14 09:06:06 -04:00
{
2013-05-28 08:05:23 -04:00
LOGWARNING ( " %s: requesting a block with a_RelY out of range: %d " , __FUNCTION__ , a_RelY ) ;
2012-06-14 09:06:06 -04:00
return false ;
}
2013-10-22 11:54:09 -04:00
cChunk * Chunk = GetRelNeighborChunkAdjustCoords ( a_RelX , a_RelZ ) ;
if ( ( Chunk = = NULL ) | | ! Chunk - > IsValid ( ) )
2012-12-14 17:38:30 -05:00
{
2013-10-22 11:54:09 -04:00
// The chunk is not available, bail out
return false ;
2012-12-14 17:38:30 -05:00
}
2013-10-22 11:54:09 -04:00
Chunk - > GetBlockTypeMeta ( a_RelX , a_RelY , a_RelZ , a_BlockType , a_BlockMeta ) ;
return true ;
2012-06-14 09:06:06 -04:00
}
2013-05-28 08:05:23 -04:00
bool cChunk : : UnboundedRelGetBlockType ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE & a_BlockType ) const
{
if ( ( a_RelY < 0 ) | | ( a_RelY > = cChunkDef : : Height ) )
{
LOGWARNING ( " %s: requesting a block with a_RelY out of range: %d " , __FUNCTION__ , a_RelY ) ;
return false ;
}
2013-10-22 11:54:09 -04:00
cChunk * Chunk = GetRelNeighborChunkAdjustCoords ( a_RelX , a_RelZ ) ;
if ( ( Chunk = = NULL ) | | ! Chunk - > IsValid ( ) )
2013-05-28 08:05:23 -04:00
{
2013-10-22 11:54:09 -04:00
// The chunk is not available, bail out
return false ;
2013-05-28 08:05:23 -04:00
}
2013-10-22 11:54:09 -04:00
a_BlockType = Chunk - > GetBlock ( a_RelX , a_RelY , a_RelZ ) ;
return true ;
2013-05-28 08:05:23 -04:00
}
bool cChunk : : UnboundedRelGetBlockMeta ( int a_RelX , int a_RelY , int a_RelZ , NIBBLETYPE & a_BlockMeta ) const
{
if ( ( a_RelY < 0 ) | | ( a_RelY > = cChunkDef : : Height ) )
{
LOGWARNING ( " %s: requesting a block with a_RelY out of range: %d " , __FUNCTION__ , a_RelY ) ;
return false ;
}
2013-10-22 11:54:09 -04:00
cChunk * Chunk = GetRelNeighborChunkAdjustCoords ( a_RelX , a_RelZ ) ;
if ( ( Chunk = = NULL ) | | ! Chunk - > IsValid ( ) )
2013-05-28 08:05:23 -04:00
{
2013-10-22 11:54:09 -04:00
// The chunk is not available, bail out
return false ;
2013-05-28 08:05:23 -04:00
}
2013-10-22 11:54:09 -04:00
a_BlockMeta = Chunk - > GetMeta ( a_RelX , a_RelY , a_RelZ ) ;
return true ;
}
2013-05-28 08:05:23 -04:00
2013-10-22 11:54:09 -04:00
bool cChunk : : UnboundedRelGetBlockBlockLight ( int a_RelX , int a_RelY , int a_RelZ , NIBBLETYPE & a_BlockBlockLight ) const
{
if ( ( a_RelY < 0 ) | | ( a_RelY > = cChunkDef : : Height ) )
2013-05-28 08:05:23 -04:00
{
2013-10-22 11:54:09 -04:00
LOGWARNING ( " %s: requesting a block with a_RelY out of range: %d " , __FUNCTION__ , a_RelY ) ;
return false ;
2013-05-28 08:05:23 -04:00
}
2013-10-22 11:54:09 -04:00
cChunk * Chunk = GetRelNeighborChunkAdjustCoords ( a_RelX , a_RelZ ) ;
if ( ( Chunk = = NULL ) | | ! Chunk - > IsValid ( ) )
2013-05-28 08:05:23 -04:00
{
2013-10-22 11:54:09 -04:00
// The chunk is not available, bail out
return false ;
2013-05-28 08:05:23 -04:00
}
2013-10-22 11:54:09 -04:00
a_BlockBlockLight = Chunk - > GetBlockLight ( a_RelX , a_RelY , a_RelZ ) ;
return true ;
}
bool cChunk : : UnboundedRelGetBlockSkyLight ( int a_RelX , int a_RelY , int a_RelZ , NIBBLETYPE & a_BlockSkyLight ) const
{
if ( ( a_RelY < 0 ) | | ( a_RelY > = cChunkDef : : Height ) )
2013-05-28 08:05:23 -04:00
{
2013-10-22 11:54:09 -04:00
LOGWARNING ( " %s: requesting a block with a_RelY out of range: %d " , __FUNCTION__ , a_RelY ) ;
return false ;
2013-05-28 08:05:23 -04:00
}
2013-10-22 11:54:09 -04:00
cChunk * Chunk = GetRelNeighborChunkAdjustCoords ( a_RelX , a_RelZ ) ;
if ( ( Chunk = = NULL ) | | ! Chunk - > IsValid ( ) )
2013-05-28 08:05:23 -04:00
{
2013-10-22 11:54:09 -04:00
// The chunk is not available, bail out
return false ;
2013-05-28 08:05:23 -04:00
}
2013-10-22 11:54:09 -04:00
a_BlockSkyLight = Chunk - > GetSkyLight ( a_RelX , a_RelY , a_RelZ ) ;
return true ;
2013-05-28 08:05:23 -04:00
}
2013-10-27 04:19:13 -04:00
bool cChunk : : UnboundedRelGetBlockLights ( int a_RelX , int a_RelY , int a_RelZ , NIBBLETYPE & a_BlockLight , NIBBLETYPE & a_SkyLight ) const
{
if ( ( a_RelY < 0 ) | | ( a_RelY > = cChunkDef : : Height ) )
{
LOGWARNING ( " %s: requesting a block with a_RelY out of range: %d " , __FUNCTION__ , a_RelY ) ;
return false ;
}
cChunk * Chunk = GetRelNeighborChunkAdjustCoords ( a_RelX , a_RelZ ) ;
if ( ( Chunk = = NULL ) | | ! Chunk - > IsValid ( ) )
{
// The chunk is not available, bail out
return false ;
}
2014-04-26 13:50:23 -04:00
a_BlockLight = Chunk - > GetBlockLight ( a_RelX , a_RelY , a_RelZ ) ;
a_SkyLight = Chunk - > GetSkyLight ( a_RelX , a_RelY , a_RelZ ) ;
2013-10-27 04:19:13 -04:00
return true ;
}
2012-06-14 09:06:06 -04:00
bool cChunk : : UnboundedRelSetBlock ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta )
{
2012-12-14 17:38:30 -05:00
if ( ( a_RelY < 0 ) | | ( a_RelY > cChunkDef : : Height ) )
{
LOGWARNING ( " UnboundedRelSetBlock(): requesting a block with a_RelY out of range: %d " , a_RelY ) ;
return false ;
}
2013-10-22 11:54:09 -04:00
cChunk * Chunk = GetRelNeighborChunkAdjustCoords ( a_RelX , a_RelZ ) ;
if ( ( Chunk = = NULL ) | | ! Chunk - > IsValid ( ) )
2012-12-14 17:38:30 -05:00
{
2013-10-22 11:54:09 -04:00
// The chunk is not available, bail out
return false ;
2012-12-14 17:38:30 -05:00
}
2013-10-22 11:54:09 -04:00
Chunk - > SetBlock ( a_RelX , a_RelY , a_RelZ , a_BlockType , a_BlockMeta ) ;
return true ;
}
2012-06-14 09:06:06 -04:00
bool cChunk : : UnboundedRelFastSetBlock ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta )
{
2012-12-14 17:38:30 -05:00
if ( ( a_RelY < 0 ) | | ( a_RelY > cChunkDef : : Height ) )
{
LOGWARNING ( " UnboundedRelFastSetBlock(): requesting a block with a_RelY out of range: %d " , a_RelY ) ;
return false ;
}
2013-10-22 11:54:09 -04:00
cChunk * Chunk = GetRelNeighborChunkAdjustCoords ( a_RelX , a_RelZ ) ;
if ( ( Chunk = = NULL ) | | ! Chunk - > IsValid ( ) )
2012-12-14 17:38:30 -05:00
{
2013-10-22 11:54:09 -04:00
// The chunk is not available, bail out
return false ;
2012-12-14 17:38:30 -05:00
}
2013-10-22 11:54:09 -04:00
Chunk - > FastSetBlock ( a_RelX , a_RelY , a_RelZ , a_BlockType , a_BlockMeta ) ;
return true ;
2012-06-14 09:06:06 -04:00
}
2013-03-22 12:48:45 -04:00
void cChunk : : UnboundedQueueTickBlock ( int a_RelX , int a_RelY , int a_RelZ )
{
2013-04-27 09:23:20 -04:00
if ( ( a_RelY < 0 ) | | ( a_RelY > = cChunkDef : : Height ) )
{
// Outside of chunkmap
return ;
}
2013-10-22 11:54:09 -04:00
cChunk * Chunk = GetRelNeighborChunkAdjustCoords ( a_RelX , a_RelZ ) ;
if ( ( Chunk ! = NULL ) & & Chunk - > IsValid ( ) )
2013-03-22 12:48:45 -04:00
{
2013-10-22 11:54:09 -04:00
Chunk - > QueueTickBlock ( a_RelX , a_RelY , a_RelZ ) ;
2013-03-22 12:48:45 -04:00
}
}
2013-10-22 11:54:09 -04:00
int cChunk : : GetHeight ( int a_X , int a_Z )
2012-06-14 09:06:06 -04:00
{
ASSERT ( ( a_X > = 0 ) & & ( a_X < Width ) & & ( a_Z > = 0 ) & & ( a_Z < Width ) ) ;
if ( ( a_X > = 0 ) & & ( a_X < Width ) & & ( a_Z > = 0 ) & & ( a_Z < Width ) )
{
return m_HeightMap [ a_X + a_Z * Width ] ;
}
return 0 ;
}
void cChunk : : CreateBlockEntities ( void )
{
for ( int x = 0 ; x < Width ; x + + )
{
for ( int z = 0 ; z < Width ; z + + )
{
for ( int y = 0 ; y < Height ; y + + )
{
2014-03-23 10:34:19 -04:00
BLOCKTYPE BlockType = GetBlock ( x , y , z ) ;
2013-04-06 17:21:57 -04:00
switch ( BlockType )
2012-06-14 09:06:06 -04:00
{
2014-04-11 18:01:15 -04:00
case E_BLOCK_BEACON :
2012-06-14 09:06:06 -04:00
case E_BLOCK_CHEST :
2014-01-18 08:16:47 -05:00
case E_BLOCK_COMMAND_BLOCK :
2012-12-19 16:19:36 -05:00
case E_BLOCK_DISPENSER :
2013-05-26 10:39:04 -04:00
case E_BLOCK_DROPPER :
2013-12-06 19:18:58 -05:00
case E_BLOCK_ENDER_CHEST :
2013-06-20 07:41:44 -04:00
case E_BLOCK_LIT_FURNACE :
2012-06-14 09:06:06 -04:00
case E_BLOCK_FURNACE :
2013-06-13 03:36:43 -04:00
case E_BLOCK_HOPPER :
2012-06-14 09:06:06 -04:00
case E_BLOCK_SIGN_POST :
case E_BLOCK_WALLSIGN :
2014-02-17 14:14:08 -05:00
case E_BLOCK_HEAD :
2012-08-26 13:50:42 -04:00
case E_BLOCK_NOTE_BLOCK :
2012-10-21 03:46:28 -04:00
case E_BLOCK_JUKEBOX :
2014-03-06 19:30:34 -05:00
case E_BLOCK_FLOWER_POT :
2012-10-21 03:46:28 -04:00
{
if ( ! HasBlockEntityAt ( x + m_PosX * Width , y + m_PosY * Height , z + m_PosZ * Width ) )
{
2013-11-14 09:37:09 -05:00
m_BlockEntities . push_back ( cBlockEntity : : CreateByBlockType (
BlockType , GetMeta ( x , y , z ) ,
x + m_PosX * Width , y + m_PosY * Height , z + m_PosZ * Width , m_World
) ) ;
2012-10-21 03:46:28 -04:00
}
break ;
}
2012-06-14 09:06:06 -04:00
} // switch (BlockType)
} // for y
} // for z
} // for x
}
2013-03-03 10:33:55 -05:00
void cChunk : : WakeUpSimulators ( void )
{
cSimulator * WaterSimulator = m_World - > GetWaterSimulator ( ) ;
cSimulator * LavaSimulator = m_World - > GetLavaSimulator ( ) ;
2013-12-12 18:49:10 -05:00
cSimulator * RedstoneSimulator = m_World - > GetRedstoneSimulator ( ) ;
2013-03-03 10:33:55 -05:00
int BaseX = m_PosX * cChunkDef : : Width ;
int BaseZ = m_PosZ * cChunkDef : : Width ;
for ( int x = 0 ; x < Width ; x + + )
{
int BlockX = x + BaseX ;
for ( int z = 0 ; z < Width ; z + + )
{
int BlockZ = z + BaseZ ;
for ( int y = GetHeight ( x , z ) ; y > = 0 ; y - - )
{
2014-03-23 10:34:19 -04:00
BLOCKTYPE Block = GetBlock ( x , y , z ) ;
2013-12-13 14:01:15 -05:00
// The redstone sim takes multiple blocks, use the inbuilt checker
if ( RedstoneSimulator - > IsAllowedBlock ( Block ) )
{
RedstoneSimulator - > AddBlock ( BlockX , y , BlockZ , this ) ;
continue ;
}
switch ( Block )
2013-03-03 10:33:55 -05:00
{
case E_BLOCK_WATER :
{
WaterSimulator - > AddBlock ( BlockX , y , BlockZ , this ) ;
break ;
}
case E_BLOCK_LAVA :
{
LavaSimulator - > AddBlock ( BlockX , y , BlockZ , this ) ;
break ;
}
2013-12-12 18:49:10 -05:00
default :
{
break ;
}
2013-03-03 10:33:55 -05:00
} // switch (BlockType)
} // for y
} // for z
} // for x
}
2014-04-07 15:57:14 -04:00
void cChunk : : CalculateHeightmap ( const BLOCKTYPE * a_BlockTypes )
2012-06-14 09:06:06 -04:00
{
for ( int x = 0 ; x < Width ; x + + )
{
for ( int z = 0 ; z < Width ; z + + )
{
for ( int y = Height - 1 ; y > - 1 ; y - - )
{
int index = MakeIndex ( x , y , z ) ;
2014-04-07 15:57:14 -04:00
if ( a_BlockTypes [ index ] ! = E_BLOCK_AIR )
2012-06-14 09:06:06 -04:00
{
2014-06-02 14:49:14 -04:00
m_HeightMap [ x + z * Width ] = ( HEIGHTTYPE ) y ;
2012-06-14 09:06:06 -04:00
break ;
}
} // for y
} // for z
} // for x
}
2014-05-25 08:46:34 -04:00
void cChunk : : SetBlock ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , bool a_SendToClients )
2012-06-14 09:06:06 -04:00
{
2014-05-25 08:46:34 -04:00
FastSetBlock ( a_RelX , a_RelY , a_RelZ , a_BlockType , a_BlockMeta , a_SendToClients ) ;
2012-06-14 09:06:06 -04:00
2013-08-19 03:19:45 -04:00
// Tick this block and its neighbors:
2014-04-26 13:50:23 -04:00
m_ToTickBlocks . push_back ( Vector3i ( a_RelX , a_RelY , a_RelZ ) ) ;
2013-02-28 02:42:45 -05:00
QueueTickBlockNeighbors ( a_RelX , a_RelY , a_RelZ ) ;
2012-06-14 09:06:06 -04:00
2013-08-19 03:19:45 -04:00
// If there was a block entity, remove it:
2013-02-28 02:42:45 -05:00
Vector3i WorldPos = PositionToWorldPosition ( a_RelX , a_RelY , a_RelZ ) ;
cBlockEntity * BlockEntity = GetBlockEntity ( WorldPos ) ;
if ( BlockEntity ! = NULL )
2012-06-14 09:06:06 -04:00
{
BlockEntity - > Destroy ( ) ;
2013-02-28 02:42:45 -05:00
RemoveBlockEntity ( BlockEntity ) ;
2012-06-14 09:06:06 -04:00
delete BlockEntity ;
}
2013-02-28 02:42:45 -05:00
2013-08-19 03:19:45 -04:00
// If the new block is a block entity, create the entity object:
2013-02-28 02:42:45 -05:00
switch ( a_BlockType )
2012-06-14 09:06:06 -04:00
{
2014-04-11 18:01:15 -04:00
case E_BLOCK_BEACON :
2012-06-14 09:06:06 -04:00
case E_BLOCK_CHEST :
2014-01-18 08:16:47 -05:00
case E_BLOCK_COMMAND_BLOCK :
2012-12-19 16:19:36 -05:00
case E_BLOCK_DISPENSER :
2013-05-26 10:39:04 -04:00
case E_BLOCK_DROPPER :
2013-12-06 19:18:58 -05:00
case E_BLOCK_ENDER_CHEST :
2013-06-20 07:41:44 -04:00
case E_BLOCK_LIT_FURNACE :
2012-06-14 09:06:06 -04:00
case E_BLOCK_FURNACE :
2013-06-13 03:36:43 -04:00
case E_BLOCK_HOPPER :
2012-06-14 09:06:06 -04:00
case E_BLOCK_SIGN_POST :
case E_BLOCK_WALLSIGN :
2014-02-17 14:14:08 -05:00
case E_BLOCK_HEAD :
2012-08-26 13:50:42 -04:00
case E_BLOCK_NOTE_BLOCK :
2012-10-21 03:46:28 -04:00
case E_BLOCK_JUKEBOX :
2014-03-06 19:30:34 -05:00
case E_BLOCK_FLOWER_POT :
2012-10-21 03:46:28 -04:00
{
2013-11-14 09:37:09 -05:00
AddBlockEntity ( cBlockEntity : : CreateByBlockType ( a_BlockType , a_BlockMeta , WorldPos . x , WorldPos . y , WorldPos . z , m_World ) ) ;
2012-10-21 03:46:28 -04:00
break ;
}
2012-06-14 09:06:06 -04:00
} // switch (a_BlockType)
}
2013-12-06 17:29:15 -05:00
void cChunk : : QueueSetBlock ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , Int64 a_Tick , BLOCKTYPE a_PreviousBlockType )
2013-08-18 16:44:22 -04:00
{
2013-12-06 17:29:15 -05:00
m_SetBlockQueue . push_back ( sSetBlockQueueItem ( a_RelX , a_RelY , a_RelZ , a_BlockType , a_BlockMeta , a_Tick , a_PreviousBlockType ) ) ;
2013-08-18 16:44:22 -04:00
}
2013-02-28 02:42:45 -05:00
void cChunk : : QueueTickBlock ( int a_RelX , int a_RelY , int a_RelZ )
2012-10-14 14:30:16 -04:00
{
2013-04-27 09:23:20 -04:00
ASSERT (
( a_RelX > = 0 ) & & ( a_RelX < Width ) & &
( a_RelY > = 0 ) & & ( a_RelY < Height ) & &
( a_RelZ > = 0 ) & & ( a_RelZ < Width )
) ; // Coords need to be valid
2013-02-28 02:42:45 -05:00
if ( ! IsValid ( ) )
2012-10-14 14:30:16 -04:00
{
2013-02-28 02:42:45 -05:00
return ;
2012-10-14 14:30:16 -04:00
}
2014-04-27 09:45:33 -04:00
m_ToTickBlocks . push_back ( Vector3i ( a_RelX , a_RelY , a_RelZ ) ) ;
2012-10-14 14:30:16 -04:00
}
2013-02-28 02:42:45 -05:00
void cChunk : : QueueTickBlockNeighbors ( int a_RelX , int a_RelY , int a_RelZ )
2012-10-14 14:30:16 -04:00
{
2013-02-28 02:42:45 -05:00
struct
2012-10-14 14:30:16 -04:00
{
2013-02-28 02:42:45 -05:00
int x , y , z ;
2012-10-14 14:30:16 -04:00
}
2013-02-28 02:42:45 -05:00
Coords [ ] =
{
{ 1 , 0 , 0 } ,
{ - 1 , 0 , 0 } ,
{ 0 , 1 , 0 } ,
{ 0 , - 1 , 0 } ,
{ 0 , 0 , 1 } ,
{ 0 , 0 , - 1 } ,
} ;
2013-12-20 10:15:39 -05:00
for ( size_t i = 0 ; i < ARRAYCOUNT ( Coords ) ; i + + )
2013-02-28 02:42:45 -05:00
{
2013-03-22 12:48:45 -04:00
UnboundedQueueTickBlock ( a_RelX + Coords [ i ] . x , a_RelY + Coords [ i ] . y , a_RelZ + Coords [ i ] . z ) ;
2013-02-28 02:42:45 -05:00
} // for i - Coords[]
2012-10-14 14:30:16 -04:00
}
2014-05-25 08:46:34 -04:00
void cChunk : : FastSetBlock ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE a_BlockType , BLOCKTYPE a_BlockMeta , bool a_SendToClients )
2012-06-14 09:06:06 -04:00
{
2013-03-14 17:56:01 -04:00
ASSERT ( ! ( ( a_RelX < 0 ) | | ( a_RelX > = Width ) | | ( a_RelY < 0 ) | | ( a_RelY > = Height ) | | ( a_RelZ < 0 ) | | ( a_RelZ > = Width ) ) ) ;
2012-06-14 09:06:06 -04:00
ASSERT ( IsValid ( ) ) ;
2014-04-26 13:50:23 -04:00
const BLOCKTYPE OldBlockType = GetBlock ( a_RelX , a_RelY , a_RelZ ) ;
2014-05-21 14:58:48 -04:00
const BLOCKTYPE OldBlockMeta = m_ChunkData . GetMeta ( a_RelX , a_RelY , a_RelZ ) ;
2013-03-14 17:56:01 -04:00
if ( ( OldBlockType = = a_BlockType ) & & ( OldBlockMeta = = a_BlockMeta ) )
2012-06-14 09:06:06 -04:00
{
return ;
}
MarkDirty ( ) ;
2014-06-04 18:23:09 -04:00
m_IsRedstoneDirty = true ;
2014-03-23 10:34:19 -04:00
2014-05-21 14:58:48 -04:00
m_ChunkData . SetBlock ( a_RelX , a_RelY , a_RelZ , a_BlockType ) ;
2012-06-14 09:06:06 -04:00
2014-05-29 10:59:39 -04:00
if ( // Queue block to be sent only if ...
a_SendToClients & & // ... we are told to do so AND ...
2014-06-01 15:00:11 -04:00
(
( OldBlockMeta ! = a_BlockMeta ) | | // ... the meta value is different OR ...
! ( // ... the old and new blocktypes AREN'T liquids (because client doesn't need to distinguish betwixt them); see below for specifics:
( ( OldBlockType = = E_BLOCK_STATIONARY_WATER ) & & ( a_BlockType = = E_BLOCK_WATER ) ) | | // Replacing stationary water with water
( ( OldBlockType = = E_BLOCK_WATER ) & & ( a_BlockType = = E_BLOCK_STATIONARY_WATER ) ) | | // Replacing water with stationary water
( ( OldBlockType = = E_BLOCK_STATIONARY_LAVA ) & & ( a_BlockType = = E_BLOCK_LAVA ) ) | | // Replacing stationary water with water
( ( OldBlockType = = E_BLOCK_LAVA ) & & ( a_BlockType = = E_BLOCK_STATIONARY_LAVA ) ) // Replacing water with stationary water
)
2013-03-22 12:48:45 -04:00
)
)
2012-06-14 09:06:06 -04:00
{
2013-03-14 17:56:01 -04:00
m_PendingSendBlocks . push_back ( sSetBlock ( m_PosX , m_PosZ , a_RelX , a_RelY , a_RelZ , a_BlockType , a_BlockMeta ) ) ;
2012-06-14 09:06:06 -04:00
}
2014-05-21 14:58:48 -04:00
m_ChunkData . SetMeta ( a_RelX , a_RelY , a_RelZ , a_BlockMeta ) ;
2012-06-14 09:06:06 -04:00
// ONLY recalculate lighting if it's necessary!
2014-03-01 14:34:19 -05:00
if (
( cBlockInfo : : GetLightValue ( OldBlockType ) ! = cBlockInfo : : GetLightValue ( a_BlockType ) ) | |
( cBlockInfo : : GetSpreadLightFalloff ( OldBlockType ) ! = cBlockInfo : : GetSpreadLightFalloff ( a_BlockType ) ) | |
( cBlockInfo : : IsTransparent ( OldBlockType ) ! = cBlockInfo : : IsTransparent ( a_BlockType ) )
2012-06-14 09:06:06 -04:00
)
{
m_IsLightValid = false ;
}
// Update heightmap, if needed:
2013-03-14 17:56:01 -04:00
if ( a_RelY > = m_HeightMap [ a_RelX + a_RelZ * Width ] )
2012-06-14 09:06:06 -04:00
{
if ( a_BlockType ! = E_BLOCK_AIR )
{
2014-06-02 14:49:14 -04:00
m_HeightMap [ a_RelX + a_RelZ * Width ] = ( HEIGHTTYPE ) a_RelY ;
2012-06-14 09:06:06 -04:00
}
else
{
2013-03-14 17:56:01 -04:00
for ( int y = a_RelY - 1 ; y > 0 ; - - y )
2012-06-14 09:06:06 -04:00
{
2014-04-27 09:45:33 -04:00
if ( GetBlock ( a_RelX , y , a_RelZ ) ! = E_BLOCK_AIR )
2012-06-14 09:06:06 -04:00
{
2014-06-02 14:49:14 -04:00
m_HeightMap [ a_RelX + a_RelZ * Width ] = ( HEIGHTTYPE ) y ;
2012-06-14 09:06:06 -04:00
break ;
}
} // for y - column in m_BlockData
}
}
}
2012-08-25 13:52:08 -04:00
void cChunk : : SendBlockTo ( int a_RelX , int a_RelY , int a_RelZ , cClientHandle * a_Client )
2012-06-14 09:06:06 -04:00
{
2012-08-25 13:52:08 -04:00
if ( a_Client = = NULL )
2012-06-14 09:06:06 -04:00
{
2012-08-25 13:52:08 -04:00
// Queue the block for all clients in the chunk (will be sent in Tick())
2014-04-27 09:45:33 -04:00
m_PendingSendBlocks . push_back ( sSetBlock ( m_PosX , m_PosZ , a_RelX , a_RelY , a_RelZ , GetBlock ( a_RelX , a_RelY , a_RelZ ) , GetMeta ( a_RelX , a_RelY , a_RelZ ) ) ) ;
2012-08-25 13:52:08 -04:00
return ;
2012-06-14 09:06:06 -04:00
}
2012-08-25 13:52:08 -04:00
Vector3i wp = PositionToWorldPosition ( a_RelX , a_RelY , a_RelZ ) ;
2014-04-27 09:45:33 -04:00
a_Client - > SendBlockChange ( wp . x , wp . y , wp . z , GetBlock ( a_RelX , a_RelY , a_RelZ ) , GetMeta ( a_RelX , a_RelY , a_RelZ ) ) ;
2012-11-11 03:48:38 -05:00
// FS #268 - if a BlockEntity digging is cancelled by a plugin, the entire block entity must be re-sent to the client:
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , end = m_BlockEntities . end ( ) ; itr ! = end ; + + itr )
{
if ( ( ( * itr ) - > GetPosX ( ) = = wp . x ) & & ( ( * itr ) - > GetPosY ( ) = = wp . y ) & & ( ( * itr ) - > GetPosZ ( ) = = wp . z ) )
{
( * itr ) - > SendTo ( * a_Client ) ;
}
} // for itr - m_BlockEntities
2012-06-14 09:06:06 -04:00
}
2013-03-01 14:35:29 -05:00
void cChunk : : AddBlockEntity ( cBlockEntity * a_BlockEntity )
2012-06-14 09:06:06 -04:00
{
2013-08-19 03:13:19 -04:00
MarkDirty ( ) ;
m_BlockEntities . push_back ( a_BlockEntity ) ;
2012-06-14 09:06:06 -04:00
}
2013-03-01 14:35:29 -05:00
cBlockEntity * cChunk : : GetBlockEntity ( int a_BlockX , int a_BlockY , int a_BlockZ )
2012-06-14 09:06:06 -04:00
{
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) ; itr ! = m_BlockEntities . end ( ) ; + + itr )
{
if (
2013-03-01 14:35:29 -05:00
( ( * itr ) - > GetPosX ( ) = = a_BlockX ) & &
( ( * itr ) - > GetPosY ( ) = = a_BlockY ) & &
( ( * itr ) - > GetPosZ ( ) = = a_BlockZ )
2012-06-14 09:06:06 -04:00
)
{
return * itr ;
}
} // for itr - m_BlockEntities[]
return NULL ;
}
void cChunk : : UseBlockEntity ( cPlayer * a_Player , int a_X , int a_Y , int a_Z )
{
cBlockEntity * be = GetBlockEntity ( a_X , a_Y , a_Z ) ;
if ( be ! = NULL )
{
be - > UsedBy ( a_Player ) ;
}
}
2014-02-18 07:06:18 -05:00
void cChunk : : SetBiomeAt ( int a_RelX , int a_RelZ , EMCSBiome a_Biome )
{
cChunkDef : : SetBiome ( m_BiomeMap , a_RelX , a_RelZ , a_Biome ) ;
MarkDirty ( ) ;
}
void cChunk : : SetAreaBiome ( int a_MinRelX , int a_MaxRelX , int a_MinRelZ , int a_MaxRelZ , EMCSBiome a_Biome )
{
for ( int z = a_MinRelZ ; z < = a_MaxRelZ ; z + + )
{
for ( int x = a_MinRelX ; x < = a_MaxRelX ; x + + )
{
cChunkDef : : SetBiome ( m_BiomeMap , x , z , a_Biome ) ;
}
}
MarkDirty ( ) ;
// Re-send the chunk to all clients:
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
m_World - > ForceSendChunkTo ( m_PosX , m_PosZ , ( * itr ) ) ;
} // for itr - m_LoadedByClient[]
}
2012-06-14 09:06:06 -04:00
void cChunk : : CollectPickupsByPlayer ( cPlayer * a_Player )
{
double PosX = a_Player - > GetPosX ( ) ;
double PosY = a_Player - > GetPosY ( ) ;
double PosZ = a_Player - > GetPosZ ( ) ;
for ( cEntityList : : iterator itr = m_Entities . begin ( ) ; itr ! = m_Entities . end ( ) ; + + itr )
{
2013-11-12 16:43:20 -05:00
if ( ( ! ( * itr ) - > IsPickup ( ) ) & & ( ! ( * itr ) - > IsProjectile ( ) ) )
2012-06-14 09:06:06 -04:00
{
2013-11-12 16:43:20 -05:00
continue ; // Only pickups and projectiles
2012-06-14 09:06:06 -04:00
}
float DiffX = ( float ) ( ( * itr ) - > GetPosX ( ) - PosX ) ;
float DiffY = ( float ) ( ( * itr ) - > GetPosY ( ) - PosY ) ;
float DiffZ = ( float ) ( ( * itr ) - > GetPosZ ( ) - PosZ ) ;
float SqrDist = DiffX * DiffX + DiffY * DiffY + DiffZ * DiffZ ;
if ( SqrDist < 1.5f * 1.5f ) // 1.5 block
{
2013-05-17 10:30:18 -04:00
/*
2013-05-13 16:26:45 -04:00
LOG ( " Pickup %d being collected by player \" %s \" , distance %f " ,
( * itr ) - > GetUniqueID ( ) , a_Player - > GetName ( ) . c_str ( ) , SqrDist
) ;
2013-05-17 10:30:18 -04:00
*/
2012-06-14 09:06:06 -04:00
MarkDirty ( ) ;
2013-11-12 16:43:20 -05:00
if ( ( * itr ) - > IsPickup ( ) )
{
( reinterpret_cast < cPickup * > ( * itr ) ) - > CollectedBy ( a_Player ) ;
}
else
{
( reinterpret_cast < cProjectileEntity * > ( * itr ) ) - > CollectedBy ( a_Player ) ;
}
2012-06-14 09:06:06 -04:00
}
2013-05-13 16:26:45 -04:00
else if ( SqrDist < 5 * 5 )
{
2013-05-17 10:30:18 -04:00
/*
2013-05-13 16:26:45 -04:00
LOG ( " Pickup %d close to player \" %s \" , but still too far to collect: %f " ,
( * itr ) - > GetUniqueID ( ) , a_Player - > GetName ( ) . c_str ( ) , SqrDist
) ;
2013-05-17 10:30:18 -04:00
*/
2013-05-13 16:26:45 -04:00
}
2012-06-14 09:06:06 -04:00
}
}
2013-06-12 03:14:06 -04:00
bool cChunk : : SetSignLines ( 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 )
2012-06-14 09:06:06 -04:00
{
// Also sends update packets to all clients in the chunk
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) ; itr ! = m_BlockEntities . end ( ) ; + + itr )
{
if (
( ( * itr ) - > GetPosX ( ) = = a_PosX ) & &
( ( * itr ) - > GetPosY ( ) = = a_PosY ) & &
( ( * itr ) - > GetPosZ ( ) = = a_PosZ ) & &
(
( ( * itr ) - > GetBlockType ( ) = = E_BLOCK_WALLSIGN ) | |
( ( * itr ) - > GetBlockType ( ) = = E_BLOCK_SIGN_POST )
)
)
{
MarkDirty ( ) ;
( reinterpret_cast < cSignEntity * > ( * itr ) ) - > SetLines ( a_Line1 , a_Line2 , a_Line3 , a_Line4 ) ;
2012-08-24 03:58:26 -04:00
m_World - > BroadcastBlockEntity ( a_PosX , a_PosY , a_PosZ ) ;
2013-06-12 03:14:06 -04:00
return true ;
2012-06-14 09:06:06 -04:00
}
} // for itr - m_BlockEntities[]
2013-06-12 03:14:06 -04:00
return false ;
2012-06-14 09:06:06 -04:00
}
void cChunk : : RemoveBlockEntity ( cBlockEntity * a_BlockEntity )
{
MarkDirty ( ) ;
2013-08-19 03:13:19 -04:00
m_BlockEntities . remove ( a_BlockEntity ) ;
2012-06-14 09:06:06 -04:00
}
2014-05-31 17:28:51 -04:00
bool cChunk : : AddClient ( cClientHandle * a_Client )
2012-06-14 09:06:06 -04:00
{
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( a_Client = = * itr )
{
// Already there, nothing needed
return false ;
}
}
m_LoadedByClient . push_back ( a_Client ) ;
for ( cEntityList : : iterator itr = m_Entities . begin ( ) ; itr ! = m_Entities . end ( ) ; + + itr )
{
2014-01-16 14:31:06 -05:00
/*
// DEBUG:
LOGD ( " cChunk: Entity #%d (%s) at [%i, %i, %i] spawning for player \" %s \" " ,
( * itr ) - > GetUniqueID ( ) , ( * itr ) - > GetClass ( ) ,
m_PosX , m_PosY , m_PosZ ,
a_Client - > GetUsername ( ) . c_str ( )
) ;
*/
2012-08-24 03:58:26 -04:00
( * itr ) - > SpawnOn ( * a_Client ) ;
2012-06-14 09:06:06 -04:00
}
return true ;
}
2014-05-31 17:28:51 -04:00
void cChunk : : RemoveClient ( cClientHandle * a_Client )
2012-06-14 09:06:06 -04:00
{
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr ! = a_Client )
{
continue ;
}
2014-05-31 17:28:51 -04:00
2012-06-14 09:06:06 -04:00
m_LoadedByClient . erase ( itr ) ;
2012-08-25 13:52:08 -04:00
if ( ! a_Client - > IsDestroyed ( ) )
2012-06-14 09:06:06 -04:00
{
2014-05-31 17:28:51 -04:00
for ( cEntityList : : iterator itr = m_Entities . begin ( ) ; itr ! = m_Entities . end ( ) ; + + itr )
2012-06-14 09:06:06 -04:00
{
2014-01-16 14:31:06 -05:00
/*
// DEBUG:
LOGD ( " chunk [%i, %i] destroying entity #%i for player \" %s \" " ,
m_PosX , m_PosZ ,
( * itr ) - > GetUniqueID ( ) , a_Client - > GetUsername ( ) . c_str ( )
) ;
*/
2012-08-25 13:52:08 -04:00
a_Client - > SendDestroyEntity ( * ( * itr ) ) ;
2012-06-14 09:06:06 -04:00
}
}
return ;
} // for itr - m_LoadedByClient[]
}
2014-05-31 17:28:51 -04:00
bool cChunk : : HasClient ( cClientHandle * a_Client )
2012-06-14 09:06:06 -04:00
{
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( ( * itr ) = = a_Client )
{
return true ;
}
}
return false ;
}
bool cChunk : : HasAnyClients ( void )
{
return ! m_LoadedByClient . empty ( ) ;
}
2012-12-21 07:52:14 -05:00
void cChunk : : AddEntity ( cEntity * a_Entity )
2012-06-14 09:06:06 -04:00
{
2012-12-21 07:52:14 -05:00
if ( ! a_Entity - > IsPlayer ( ) )
2012-06-14 09:06:06 -04:00
{
MarkDirty ( ) ;
}
2014-05-31 17:28:51 -04:00
2014-06-12 10:21:07 -04:00
ASSERT ( std : : find ( m_Entities . begin ( ) , m_Entities . end ( ) , a_Entity ) = = m_Entities . end ( ) ) ;
2014-05-31 17:28:51 -04:00
2012-12-21 07:52:14 -05:00
m_Entities . push_back ( a_Entity ) ;
2012-06-14 09:06:06 -04:00
}
void cChunk : : RemoveEntity ( cEntity * a_Entity )
{
2014-06-12 10:21:07 -04:00
if ( m_EntityTickIteratorData . first )
{
* m_EntityTickIteratorData . second = m_Entities . erase ( * m_EntityTickIteratorData . second ) ;
}
else
{
m_Entities . remove ( a_Entity ) ;
}
2014-05-31 17:28:51 -04:00
// Mark as dirty if it was a server-generated entity:
if ( ! a_Entity - > IsPlayer ( ) )
2012-06-14 09:06:06 -04:00
{
2014-05-31 17:28:51 -04:00
MarkDirty ( ) ;
2012-06-14 09:06:06 -04:00
}
}
2013-04-13 17:02:10 -04:00
bool cChunk : : HasEntity ( int a_EntityID )
{
for ( cEntityList : : const_iterator itr = m_Entities . begin ( ) , end = m_Entities . end ( ) ; itr ! = end ; + + itr )
{
if ( ( * itr ) - > GetUniqueID ( ) = = a_EntityID )
{
return true ;
}
} // for itr - m_Entities[]
return false ;
}
2012-06-16 04:35:07 -04:00
bool cChunk : : ForEachEntity ( cEntityCallback & a_Callback )
{
// The entity list is locked by the parent chunkmap's CS
2012-06-19 16:31:21 -04:00
for ( cEntityList : : iterator itr = m_Entities . begin ( ) , itr2 = itr ; itr ! = m_Entities . end ( ) ; itr = itr2 )
2012-06-16 04:35:07 -04:00
{
2012-06-19 16:31:21 -04:00
+ + itr2 ;
2012-06-16 04:35:07 -04:00
if ( a_Callback . Item ( * itr ) )
{
return false ;
}
} // for itr - m_Entitites[]
return true ;
}
2013-04-13 17:02:10 -04:00
bool cChunk : : DoWithEntityByID ( int a_EntityID , cEntityCallback & a_Callback , bool & a_CallbackResult )
{
// The entity list is locked by the parent chunkmap's CS
for ( cEntityList : : iterator itr = m_Entities . begin ( ) , end = m_Entities . end ( ) ; itr ! = end ; + + itr )
{
if ( ( * itr ) - > GetUniqueID ( ) = = a_EntityID )
{
a_CallbackResult = a_Callback . Item ( * itr ) ;
return true ;
}
} // for itr - m_Entitites[]
return false ;
}
2013-11-20 15:53:29 -05:00
bool cChunk : : ForEachBlockEntity ( cBlockEntityCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
{
+ + itr2 ;
if ( a_Callback . Item ( * itr ) )
{
return false ;
}
} // for itr - m_BlockEntitites[]
return true ;
}
2012-06-17 15:58:39 -04:00
bool cChunk : : ForEachChest ( cChestCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
2012-06-19 16:31:21 -04:00
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
2012-06-17 15:58:39 -04:00
{
2012-06-19 16:31:21 -04:00
+ + itr2 ;
2012-06-17 15:58:39 -04:00
if ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_CHEST )
{
continue ;
}
if ( a_Callback . Item ( ( cChestEntity * ) * itr ) )
{
return false ;
}
} // for itr - m_BlockEntitites[]
return true ;
}
2012-12-26 12:16:33 -05:00
bool cChunk : : ForEachDispenser ( cDispenserCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
{
+ + itr2 ;
if ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_DISPENSER )
{
continue ;
}
if ( a_Callback . Item ( ( cDispenserEntity * ) * itr ) )
{
return false ;
}
} // for itr - m_BlockEntitites[]
return true ;
}
2013-05-26 10:39:04 -04:00
bool cChunk : : ForEachDropper ( cDropperCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
{
+ + itr2 ;
if ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_DROPPER )
{
continue ;
}
if ( a_Callback . Item ( ( cDropperEntity * ) * itr ) )
{
return false ;
}
} // for itr - m_BlockEntitites[]
return true ;
}
bool cChunk : : ForEachDropSpenser ( cDropSpenserCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
{
+ + itr2 ;
if ( ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_DISPENSER ) & & ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_DROPPER ) )
{
continue ;
}
if ( a_Callback . Item ( ( cDropSpenserEntity * ) * itr ) )
{
return false ;
}
} // for itr - m_BlockEntitites[]
return true ;
}
2012-06-17 15:58:39 -04:00
bool cChunk : : ForEachFurnace ( cFurnaceCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
2012-06-19 16:31:21 -04:00
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
2012-06-17 15:58:39 -04:00
{
2012-06-19 16:31:21 -04:00
+ + itr2 ;
2012-06-17 15:58:39 -04:00
switch ( ( * itr ) - > GetBlockType ( ) )
{
case E_BLOCK_FURNACE :
case E_BLOCK_LIT_FURNACE :
{
break ;
}
default :
{
continue ;
}
}
if ( a_Callback . Item ( ( cFurnaceEntity * ) * itr ) )
{
return false ;
}
} // for itr - m_BlockEntitites[]
return true ;
}
2013-11-20 15:53:29 -05:00
bool cChunk : : DoWithBlockEntityAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cBlockEntityCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
{
+ + itr2 ;
if ( ( ( * itr ) - > GetPosX ( ) ! = a_BlockX ) | | ( ( * itr ) - > GetPosY ( ) ! = a_BlockY ) | | ( ( * itr ) - > GetPosZ ( ) ! = a_BlockZ ) )
{
continue ;
}
if ( a_Callback . Item ( * itr ) )
{
return false ;
}
return true ;
} // for itr - m_BlockEntitites[]
// Not found:
return false ;
}
2012-06-17 15:58:39 -04:00
bool cChunk : : DoWithChestAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cChestCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
2012-06-19 16:31:21 -04:00
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
2012-06-17 15:58:39 -04:00
{
2012-06-19 16:31:21 -04:00
+ + itr2 ;
2012-06-17 15:58:39 -04:00
if ( ( ( * itr ) - > GetPosX ( ) ! = a_BlockX ) | | ( ( * itr ) - > GetPosY ( ) ! = a_BlockY ) | | ( ( * itr ) - > GetPosZ ( ) ! = a_BlockZ ) )
{
continue ;
}
if ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_CHEST )
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false ;
}
// The correct block entity is here
if ( a_Callback . Item ( ( cChestEntity * ) * itr ) )
{
return false ;
}
return true ;
} // for itr - m_BlockEntitites[]
// Not found:
return false ;
}
2012-12-26 12:16:33 -05:00
bool cChunk : : DoWithDispenserAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cDispenserCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
{
+ + itr2 ;
if ( ( ( * itr ) - > GetPosX ( ) ! = a_BlockX ) | | ( ( * itr ) - > GetPosY ( ) ! = a_BlockY ) | | ( ( * itr ) - > GetPosZ ( ) ! = a_BlockZ ) )
{
continue ;
}
if ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_DISPENSER )
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false ;
}
// The correct block entity is here
if ( a_Callback . Item ( ( cDispenserEntity * ) * itr ) )
{
return false ;
}
return true ;
} // for itr - m_BlockEntitites[]
// Not found:
return false ;
}
2013-05-26 10:39:04 -04:00
bool cChunk : : DoWithDropperAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cDropperCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
{
+ + itr2 ;
if ( ( ( * itr ) - > GetPosX ( ) ! = a_BlockX ) | | ( ( * itr ) - > GetPosY ( ) ! = a_BlockY ) | | ( ( * itr ) - > GetPosZ ( ) ! = a_BlockZ ) )
{
continue ;
}
if ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_DROPPER )
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false ;
}
// The correct block entity is here
if ( a_Callback . Item ( ( cDropperEntity * ) * itr ) )
{
return false ;
}
return true ;
} // for itr - m_BlockEntitites[]
// Not found:
return false ;
}
bool cChunk : : DoWithDropSpenserAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cDropSpenserCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
{
+ + itr2 ;
if ( ( ( * itr ) - > GetPosX ( ) ! = a_BlockX ) | | ( ( * itr ) - > GetPosY ( ) ! = a_BlockY ) | | ( ( * itr ) - > GetPosZ ( ) ! = a_BlockZ ) )
{
continue ;
}
if ( ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_DISPENSER ) & & ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_DROPPER ) )
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false ;
}
// The correct block entity is here
if ( a_Callback . Item ( ( cDropSpenserEntity * ) * itr ) )
{
return false ;
}
return true ;
} // for itr - m_BlockEntitites[]
// Not found:
return false ;
}
2012-06-17 15:58:39 -04:00
bool cChunk : : DoWithFurnaceAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cFurnaceCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
2012-06-19 16:31:21 -04:00
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
2012-06-17 15:58:39 -04:00
{
2012-06-19 16:31:21 -04:00
+ + itr2 ;
2012-06-17 15:58:39 -04:00
if ( ( ( * itr ) - > GetPosX ( ) ! = a_BlockX ) | | ( ( * itr ) - > GetPosY ( ) ! = a_BlockY ) | | ( ( * itr ) - > GetPosZ ( ) ! = a_BlockZ ) )
{
continue ;
}
switch ( ( * itr ) - > GetBlockType ( ) )
{
case E_BLOCK_FURNACE :
case E_BLOCK_LIT_FURNACE :
{
break ;
}
default :
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false ;
}
} // switch (BlockType)
// The correct block entity is here,
if ( a_Callback . Item ( ( cFurnaceEntity * ) * itr ) )
{
return false ;
}
return true ;
} // for itr - m_BlockEntitites[]
// Not found:
return false ;
}
2013-12-14 11:52:22 -05:00
bool cChunk : : DoWithNoteBlockAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cNoteBlockCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
{
+ + itr2 ;
if ( ( ( * itr ) - > GetPosX ( ) ! = a_BlockX ) | | ( ( * itr ) - > GetPosY ( ) ! = a_BlockY ) | | ( ( * itr ) - > GetPosZ ( ) ! = a_BlockZ ) )
{
continue ;
}
if ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_NOTE_BLOCK )
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false ;
}
// The correct block entity is here,
if ( a_Callback . Item ( ( cNoteEntity * ) * itr ) )
{
return false ;
}
return true ;
} // for itr - m_BlockEntitites[]
// Not found:
return false ;
}
2014-01-18 08:16:47 -05:00
bool cChunk : : DoWithCommandBlockAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cCommandBlockCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
{
+ + itr2 ;
if ( ( ( * itr ) - > GetPosX ( ) ! = a_BlockX ) | | ( ( * itr ) - > GetPosY ( ) ! = a_BlockY ) | | ( ( * itr ) - > GetPosZ ( ) ! = a_BlockZ ) )
{
continue ;
}
if ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_COMMAND_BLOCK )
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false ;
}
// The correct block entity is here,
if ( a_Callback . Item ( ( cCommandBlockEntity * ) * itr ) )
{
return false ;
}
return true ;
} // for itr - m_BlockEntitites[]
// Not found:
return false ;
}
2014-03-07 05:44:16 -05:00
bool cChunk : : DoWithMobHeadAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cMobHeadCallback & a_Callback )
2014-02-18 15:40:02 -05:00
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
{
+ + itr2 ;
if ( ( ( * itr ) - > GetPosX ( ) ! = a_BlockX ) | | ( ( * itr ) - > GetPosY ( ) ! = a_BlockY ) | | ( ( * itr ) - > GetPosZ ( ) ! = a_BlockZ ) )
{
continue ;
}
if ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_HEAD )
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false ;
}
// The correct block entity is here,
2014-02-19 08:45:09 -05:00
if ( a_Callback . Item ( ( cMobHeadEntity * ) * itr ) )
2014-02-18 15:40:02 -05:00
{
return false ;
}
return true ;
} // for itr - m_BlockEntitites[]
// Not found:
return false ;
}
2014-03-06 19:30:34 -05:00
bool cChunk : : DoWithFlowerPotAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cFlowerPotCallback & a_Callback )
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) , itr2 = itr ; itr ! = m_BlockEntities . end ( ) ; itr = itr2 )
{
+ + itr2 ;
if ( ( ( * itr ) - > GetPosX ( ) ! = a_BlockX ) | | ( ( * itr ) - > GetPosY ( ) ! = a_BlockY ) | | ( ( * itr ) - > GetPosZ ( ) ! = a_BlockZ ) )
{
continue ;
}
if ( ( * itr ) - > GetBlockType ( ) ! = E_BLOCK_FLOWER_POT )
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false ;
}
// The correct block entity is here,
if ( a_Callback . Item ( ( cFlowerPotEntity * ) * itr ) )
{
return false ;
}
return true ;
} // for itr - m_BlockEntitites[]
// Not found:
return false ;
}
2012-06-17 15:58:39 -04:00
bool cChunk : : GetSignLines ( int a_BlockX , int a_BlockY , int a_BlockZ , AString & a_Line1 , AString & a_Line2 , AString & a_Line3 , AString & a_Line4 )
{
// The blockentity list is locked by the parent chunkmap's CS
for ( cBlockEntityList : : iterator itr = m_BlockEntities . begin ( ) ; itr ! = m_BlockEntities . end ( ) ; + + itr )
{
if ( ( ( * itr ) - > GetPosX ( ) ! = a_BlockX ) | | ( ( * itr ) - > GetPosY ( ) ! = a_BlockY ) | | ( ( * itr ) - > GetPosZ ( ) ! = a_BlockZ ) )
{
continue ;
}
switch ( ( * itr ) - > GetBlockType ( ) )
{
case E_BLOCK_WALLSIGN :
case E_BLOCK_SIGN_POST :
{
a_Line1 = ( ( cSignEntity * ) * itr ) - > GetLine ( 0 ) ;
a_Line2 = ( ( cSignEntity * ) * itr ) - > GetLine ( 1 ) ;
a_Line3 = ( ( cSignEntity * ) * itr ) - > GetLine ( 2 ) ;
a_Line4 = ( ( cSignEntity * ) * itr ) - > GetLine ( 3 ) ;
return true ;
}
} // switch (BlockType)
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false ;
} // for itr - m_BlockEntitites[]
// Not found:
return false ;
}
2013-03-15 16:18:11 -04:00
BLOCKTYPE cChunk : : GetBlock ( int a_RelX , int a_RelY , int a_RelZ ) const
2012-06-14 09:06:06 -04:00
{
2013-03-15 16:18:11 -04:00
if (
( a_RelX < 0 ) | | ( a_RelX > = Width ) | |
( a_RelY < 0 ) | | ( a_RelY > = Height ) | |
( a_RelZ < 0 ) | | ( a_RelZ > = Width )
)
{
ASSERT ( ! " GetBlock(x, y, z) out of bounds! " ) ;
return 0 ; // Clip
}
2012-06-14 09:06:06 -04:00
2014-05-21 14:58:48 -04:00
return m_ChunkData . GetBlock ( a_RelX , a_RelY , a_RelZ ) ;
2012-06-14 09:06:06 -04:00
}
void cChunk : : GetBlockTypeMeta ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE & a_BlockType , NIBBLETYPE & a_BlockMeta )
{
2014-04-26 13:50:23 -04:00
a_BlockType = GetBlock ( a_RelX , a_RelY , a_RelZ ) ;
2014-05-21 14:58:48 -04:00
a_BlockMeta = m_ChunkData . GetMeta ( a_RelX , a_RelY , a_RelZ ) ;
2012-06-14 09:06:06 -04:00
}
2012-10-20 07:40:34 -04:00
void cChunk : : GetBlockInfo ( int a_RelX , int a_RelY , int a_RelZ , BLOCKTYPE & a_BlockType , NIBBLETYPE & a_Meta , NIBBLETYPE & a_SkyLight , NIBBLETYPE & a_BlockLight )
{
2014-04-27 09:45:33 -04:00
a_BlockType = GetBlock ( a_RelX , a_RelY , a_RelZ ) ;
2014-05-21 14:58:48 -04:00
a_Meta = m_ChunkData . GetMeta ( a_RelX , a_RelY , a_RelZ ) ;
a_SkyLight = m_ChunkData . GetSkyLight ( a_RelX , a_RelY , a_RelZ ) ;
a_BlockLight = m_ChunkData . GetBlockLight ( a_RelX , a_RelY , a_RelZ ) ;
2012-10-20 07:40:34 -04:00
}
2013-03-01 14:35:29 -05:00
cChunk * cChunk : : GetNeighborChunk ( int a_BlockX , int a_BlockZ )
2013-02-28 02:42:45 -05:00
{
// Convert coords to relative, then call the relative version:
a_BlockX - = m_PosX * cChunkDef : : Width ;
a_BlockZ - = m_PosZ * cChunkDef : : Width ;
2013-03-01 14:35:29 -05:00
return GetRelNeighborChunk ( a_BlockX , a_BlockZ ) ;
2013-02-28 02:42:45 -05:00
}
2013-03-01 14:35:29 -05:00
cChunk * cChunk : : GetRelNeighborChunk ( int a_RelX , int a_RelZ )
2013-02-28 02:42:45 -05:00
{
2014-03-27 13:13:52 -04:00
// If the relative coords are too far away, use the parent's chunk lookup instead:
2014-04-08 11:57:35 -04:00
if ( ( a_RelX < - 128 ) | | ( a_RelX > 128 ) | | ( a_RelZ < - 128 ) | | ( a_RelZ > 128 ) )
2014-03-27 13:13:52 -04:00
{
int BlockX = m_PosX * cChunkDef : : Width + a_RelX ;
int BlockZ = m_PosZ * cChunkDef : : Width + a_RelZ ;
int BlockY , ChunkX , ChunkZ ;
AbsoluteToRelative ( BlockX , BlockY , BlockZ , ChunkX , ChunkZ ) ;
return m_ChunkMap - > GetChunkNoLoad ( ChunkX , ZERO_CHUNK_Y , ChunkZ ) ;
}
// Walk the neighbors:
2013-02-28 02:42:45 -05:00
bool ReturnThis = true ;
if ( a_RelX < 0 )
{
if ( m_NeighborXM ! = NULL )
{
2013-03-01 14:35:29 -05:00
cChunk * Candidate = m_NeighborXM - > GetRelNeighborChunk ( a_RelX + cChunkDef : : Width , a_RelZ ) ;
2013-02-28 02:42:45 -05:00
if ( Candidate ! = NULL )
{
return Candidate ;
}
}
// Going X first failed, but if the request is crossing Z as well, let's try the Z first later on.
ReturnThis = false ;
}
else if ( a_RelX > = cChunkDef : : Width )
{
if ( m_NeighborXP ! = NULL )
{
2013-03-01 14:35:29 -05:00
cChunk * Candidate = m_NeighborXP - > GetRelNeighborChunk ( a_RelX - cChunkDef : : Width , a_RelZ ) ;
2013-02-28 02:42:45 -05:00
if ( Candidate ! = NULL )
{
return Candidate ;
}
}
// Going X first failed, but if the request is crossing Z as well, let's try the Z first later on.
ReturnThis = false ;
}
if ( a_RelZ < 0 )
{
if ( m_NeighborZM ! = NULL )
{
2013-03-01 14:35:29 -05:00
return m_NeighborZM - > GetRelNeighborChunk ( a_RelX , a_RelZ + cChunkDef : : Width ) ;
2013-02-28 02:42:45 -05:00
// For requests crossing both X and Z, the X-first way has been already tried
}
return NULL ;
2013-03-03 14:05:11 -05:00
}
else if ( a_RelZ > = cChunkDef : : Width )
{
2013-02-28 02:42:45 -05:00
if ( m_NeighborZP ! = NULL )
{
2013-03-01 14:35:29 -05:00
return m_NeighborZP - > GetRelNeighborChunk ( a_RelX , a_RelZ - cChunkDef : : Width ) ;
2013-02-28 02:42:45 -05:00
// For requests crossing both X and Z, the X-first way has been already tried
}
return NULL ;
}
return ( ReturnThis ? this : NULL ) ;
}
2013-10-22 11:54:09 -04:00
cChunk * cChunk : : GetRelNeighborChunkAdjustCoords ( int & a_RelX , int & a_RelZ ) const
2013-05-28 08:18:03 -04:00
{
2013-10-22 11:54:09 -04:00
cChunk * ToReturn = const_cast < cChunk * > ( this ) ;
// The most common case: inside this chunk:
if (
( a_RelX > = 0 ) & & ( a_RelX < Width ) & &
( a_RelZ > = 0 ) & & ( a_RelZ < Width )
)
{
return ToReturn ;
}
// Request for a different chunk, calculate chunk offset:
int RelX = a_RelX ; // Make a local copy of the coords (faster access)
2013-05-28 08:18:03 -04:00
int RelZ = a_RelZ ;
2013-10-22 11:54:09 -04:00
while ( ( RelX > = Width ) & & ( ToReturn ! = NULL ) )
2013-05-28 08:18:03 -04:00
{
2013-10-22 11:54:09 -04:00
RelX - = Width ;
ToReturn = ToReturn - > m_NeighborXP ;
2013-05-28 08:18:03 -04:00
}
2013-10-22 11:54:09 -04:00
while ( ( RelX < 0 ) & & ( ToReturn ! = NULL ) )
2013-05-28 08:18:03 -04:00
{
2013-10-22 11:54:09 -04:00
RelX + = Width ;
ToReturn = ToReturn - > m_NeighborXM ;
2013-05-28 08:18:03 -04:00
}
2013-10-22 11:54:09 -04:00
while ( ( RelZ > = Width ) & & ( ToReturn ! = NULL ) )
2013-05-28 08:18:03 -04:00
{
2013-10-22 11:54:09 -04:00
RelZ - = Width ;
ToReturn = ToReturn - > m_NeighborZP ;
2013-05-28 08:18:03 -04:00
}
2013-10-22 11:54:09 -04:00
while ( ( RelZ < 0 ) & & ( ToReturn ! = NULL ) )
2013-05-28 08:18:03 -04:00
{
2013-10-22 11:54:09 -04:00
RelZ + = Width ;
ToReturn = ToReturn - > m_NeighborZM ;
}
if ( ToReturn ! = NULL )
{
a_RelX = RelX ;
a_RelZ = RelZ ;
return ToReturn ;
2013-05-28 08:18:03 -04:00
}
2013-10-22 11:54:09 -04:00
// The chunk cannot be walked through neighbors, find it through the chunkmap:
int AbsX = a_RelX + m_PosX * Width ;
int AbsZ = a_RelZ + m_PosZ * Width ;
int DstChunkX , DstChunkZ ;
BlockToChunk ( AbsX , AbsZ , DstChunkX , DstChunkZ ) ;
ToReturn = m_ChunkMap - > FindChunk ( DstChunkX , DstChunkZ ) ;
a_RelX = AbsX - DstChunkX * Width ;
a_RelZ = AbsZ - DstChunkZ * Width ;
return ToReturn ;
2013-05-28 08:18:03 -04:00
}
2013-03-03 14:05:11 -05:00
void cChunk : : BroadcastAttachEntity ( const cEntity & a_Entity , const cEntity * a_Vehicle )
{
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
( * itr ) - > SendAttachEntity ( a_Entity , a_Vehicle ) ;
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastBlockAction ( int a_BlockX , int a_BlockY , int a_BlockZ , char a_Byte1 , char a_Byte2 , BLOCKTYPE a_BlockType , const cClientHandle * a_Exclude )
2012-08-19 07:51:17 -04:00
{
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendBlockAction ( a_BlockX , a_BlockY , a_BlockZ , a_Byte1 , a_Byte2 , a_BlockType ) ;
2012-08-19 07:51:17 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastBlockBreakAnimation ( int a_entityID , int a_blockX , int a_blockY , int a_blockZ , char a_stage , const cClientHandle * a_Exclude )
2012-08-19 07:51:17 -04:00
{
2013-07-07 09:06:06 -04:00
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
2012-08-19 07:51:17 -04:00
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendBlockBreakAnim ( a_entityID , a_blockX , a_blockY , a_blockZ , a_stage ) ;
2012-08-19 07:51:17 -04:00
} // for itr - LoadedByClient[]
2013-03-17 22:51:55 -04:00
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastBlockEntity ( int a_BlockX , int a_BlockY , int a_BlockZ , const cClientHandle * a_Exclude )
2013-03-17 22:51:55 -04:00
{
2013-07-07 09:06:06 -04:00
// We can operate on entity pointers, we're inside the ChunkMap's CS lock which guards the list
cBlockEntity * Entity = GetBlockEntity ( a_BlockX , a_BlockY , a_BlockZ ) ;
if ( Entity = = NULL )
{
return ;
}
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
2013-03-17 22:51:55 -04:00
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
Entity - > SendTo ( * ( * itr ) ) ;
2013-03-17 22:51:55 -04:00
} // for itr - LoadedByClient[]
2012-08-19 07:51:17 -04:00
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastChunkData ( cChunkDataSerializer & a_Serializer , const cClientHandle * a_Exclude )
2012-08-19 15:42:32 -04:00
{
2013-07-07 09:06:06 -04:00
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
2012-08-19 15:42:32 -04:00
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendChunkData ( m_PosX , m_PosZ , a_Serializer ) ;
2012-08-19 15:42:32 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastCollectPickup ( const cPickup & a_Pickup , const cPlayer & a_Player , const cClientHandle * a_Exclude )
2012-08-19 15:42:32 -04:00
{
2013-07-07 09:06:06 -04:00
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
2012-08-19 15:42:32 -04:00
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendCollectPickup ( a_Pickup , a_Player ) ;
2012-08-19 15:42:32 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastDestroyEntity ( const cEntity & a_Entity , const cClientHandle * a_Exclude )
2012-08-19 15:42:32 -04:00
{
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendDestroyEntity ( a_Entity ) ;
2012-08-19 15:42:32 -04:00
} // for itr - LoadedByClient[]
}
2013-12-15 04:51:46 -05:00
void cChunk : : BroadcastEntityEffect ( const cEntity & a_Entity , int a_EffectID , int a_Amplifier , short a_Duration , const cClientHandle * a_Exclude )
{
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
( * itr ) - > SendEntityEffect ( a_Entity , a_EffectID , a_Amplifier , a_Duration ) ;
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastEntityEquipment ( const cEntity & a_Entity , short a_SlotNum , const cItem & a_Item , const cClientHandle * a_Exclude )
2012-08-19 15:42:32 -04:00
{
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendEntityEquipment ( a_Entity , a_SlotNum , a_Item ) ;
2012-08-19 15:42:32 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastEntityHeadLook ( const cEntity & a_Entity , const cClientHandle * a_Exclude )
2012-08-19 15:42:32 -04:00
{
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendEntityHeadLook ( a_Entity ) ;
2012-08-19 15:42:32 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastEntityLook ( const cEntity & a_Entity , const cClientHandle * a_Exclude )
2012-08-19 15:42:32 -04:00
{
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendEntityLook ( a_Entity ) ;
2012-08-19 15:42:32 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastEntityMetadata ( const cEntity & a_Entity , const cClientHandle * a_Exclude )
2012-08-19 17:14:45 -04:00
{
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendEntityMetadata ( a_Entity ) ;
2012-08-19 17:14:45 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastEntityRelMove ( const cEntity & a_Entity , char a_RelX , char a_RelY , char a_RelZ , const cClientHandle * a_Exclude )
2012-08-19 17:14:45 -04:00
{
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendEntityRelMove ( a_Entity , a_RelX , a_RelY , a_RelZ ) ;
2012-08-19 17:14:45 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastEntityRelMoveLook ( const cEntity & a_Entity , char a_RelX , char a_RelY , char a_RelZ , const cClientHandle * a_Exclude )
2012-08-24 03:58:26 -04:00
{
2013-07-07 09:06:06 -04:00
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
2012-08-24 03:58:26 -04:00
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendEntityRelMoveLook ( a_Entity , a_RelX , a_RelY , a_RelZ ) ;
2012-08-24 03:58:26 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastEntityStatus ( const cEntity & a_Entity , char a_Status , const cClientHandle * a_Exclude )
2012-08-24 05:49:00 -04:00
{
2013-07-07 09:06:06 -04:00
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
2012-08-24 05:49:00 -04:00
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendEntityStatus ( a_Entity , a_Status ) ;
2012-08-24 05:49:00 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastEntityVelocity ( const cEntity & a_Entity , const cClientHandle * a_Exclude )
2012-08-25 17:46:18 -04:00
{
2013-07-07 09:06:06 -04:00
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
2012-08-25 17:46:18 -04:00
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendEntityVelocity ( a_Entity ) ;
2012-08-25 17:46:18 -04:00
} // for itr - LoadedByClient[]
}
2013-12-06 18:47:07 -05:00
void cChunk : : BroadcastEntityAnimation ( const cEntity & a_Entity , char a_Animation , const cClientHandle * a_Exclude )
2012-09-11 08:01:34 -04:00
{
2013-07-07 09:06:06 -04:00
for ( cClientHandleList : : const_iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
2012-09-11 08:01:34 -04:00
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-12-06 18:47:07 -05:00
( * itr ) - > SendEntityAnimation ( a_Entity , a_Animation ) ;
2012-09-11 08:01:34 -04:00
} // for itr - LoadedByClient[]
}
2013-12-22 08:45:25 -05:00
void cChunk : : BroadcastParticleEffect ( const AString & a_ParticleName , float a_SrcX , float a_SrcY , float a_SrcZ , float a_OffsetX , float a_OffsetY , float a_OffsetZ , float a_ParticleData , int a_ParticleAmmount , cClientHandle * a_Exclude )
{
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
( * itr ) - > SendParticleEffect ( a_ParticleName , a_SrcX , a_SrcY , a_SrcZ , a_OffsetX , a_OffsetY , a_OffsetZ , a_ParticleData , a_ParticleAmmount ) ;
} // for itr - LoadedByClient[]
}
2013-12-15 04:51:46 -05:00
void cChunk : : BroadcastRemoveEntityEffect ( const cEntity & a_Entity , int a_EffectID , const cClientHandle * a_Exclude )
{
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
( * itr ) - > SendRemoveEntityEffect ( a_Entity , a_EffectID ) ;
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastSoundEffect ( const AString & a_SoundName , int a_SrcX , int a_SrcY , int a_SrcZ , float a_Volume , float a_Pitch , const cClientHandle * a_Exclude )
2012-10-21 03:46:28 -04:00
{
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendSoundEffect ( a_SoundName , a_SrcX , a_SrcY , a_SrcZ , a_Volume , a_Pitch ) ;
2012-10-21 03:46:28 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastSoundParticleEffect ( int a_EffectID , int a_SrcX , int a_SrcY , int a_SrcZ , int a_Data , const cClientHandle * a_Exclude )
2012-09-25 05:54:36 -04:00
{
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendSoundParticleEffect ( a_EffectID , a_SrcX , a_SrcY , a_SrcZ , a_Data ) ;
2012-09-25 05:54:36 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastSpawnEntity ( cEntity & a_Entity , const cClientHandle * a_Exclude )
2012-09-29 16:43:42 -04:00
{
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
2013-07-07 09:06:06 -04:00
if ( * itr = = a_Exclude )
{
continue ;
}
a_Entity . SpawnOn ( * ( * itr ) ) ;
2012-09-29 16:43:42 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastThunderbolt ( int a_BlockX , int a_BlockY , int a_BlockZ , const cClientHandle * a_Exclude )
2012-08-26 17:01:07 -04:00
{
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
if ( * itr = = a_Exclude )
{
continue ;
}
2013-07-07 09:06:06 -04:00
( * itr ) - > SendThunderbolt ( a_BlockX , a_BlockY , a_BlockZ ) ;
2012-08-26 17:01:07 -04:00
} // for itr - LoadedByClient[]
}
2013-07-07 09:06:06 -04:00
void cChunk : : BroadcastUseBed ( const cEntity & a_Entity , int a_BlockX , int a_BlockY , int a_BlockZ )
2012-08-24 03:58:26 -04:00
{
for ( cClientHandleList : : iterator itr = m_LoadedByClient . begin ( ) ; itr ! = m_LoadedByClient . end ( ) ; + + itr )
{
2013-07-07 09:06:06 -04:00
( * itr ) - > SendUseBed ( a_Entity , a_BlockX , a_BlockY , a_BlockZ ) ;
2012-08-24 03:58:26 -04:00
} // for itr - LoadedByClient[]
}
void cChunk : : SendBlockEntity ( int a_BlockX , int a_BlockY , int a_BlockZ , cClientHandle & a_Client )
{
cBlockEntity * Entity = GetBlockEntity ( a_BlockX , a_BlockY , a_BlockZ ) ;
if ( Entity = = NULL )
{
return ;
}
Entity - > SendTo ( a_Client ) ;
}
2012-08-25 13:52:08 -04:00
void cChunk : : PositionToWorldPosition ( int a_RelX , int a_RelY , int a_RelZ , int & a_BlockX , int & a_BlockY , int & a_BlockZ )
2012-06-14 09:06:06 -04:00
{
2012-08-25 13:52:08 -04:00
a_BlockY = a_RelY ;
a_BlockX = m_PosX * Width + a_RelX ;
a_BlockZ = m_PosZ * Width + a_RelZ ;
2012-06-14 09:06:06 -04:00
}
2012-08-25 13:52:08 -04:00
Vector3i cChunk : : PositionToWorldPosition ( int a_RelX , int a_RelY , int a_RelZ )
2012-06-14 09:06:06 -04:00
{
2012-08-25 13:52:08 -04:00
return Vector3i ( m_PosX * Width + a_RelX , m_PosY * Height + a_RelY , m_PosZ * Width + a_RelZ ) ;
2012-06-14 09:06:06 -04:00
}
2013-10-29 12:44:51 -04:00
NIBBLETYPE cChunk : : GetTimeAlteredLight ( NIBBLETYPE a_Skylight ) const
{
a_Skylight - = m_World - > GetSkyDarkness ( ) ;
2013-10-30 18:14:42 -04:00
// Because NIBBLETYPE is unsigned, we clamp it to 0 .. 15 by checking for values above 15
2013-10-29 12:44:51 -04:00
return ( a_Skylight < 16 ) ? a_Skylight : 0 ;
}
2012-06-14 09:06:06 -04:00