2011-12-26 23:23:05 +00:00
2012-01-29 19:28:19 +00:00
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2011-10-03 18:41:19 +00:00
#ifndef _WIN32
2012-02-01 12:46:44 +00:00
#include <cstdlib>
2011-10-03 18:41:19 +00:00
#endif
2011-12-22 21:36:24 +00:00
2011-10-03 18:41:19 +00:00
#include "cChunk.h"
#include "cWorld.h"
2011-12-22 21:36:24 +00:00
#include "cWaterSimulator.h"
#include "cLavaSimulator.h"
2011-10-03 18:41:19 +00:00
#include "cClientHandle.h"
#include "cServer.h"
#include "zlib.h"
#include "Defines.h"
#include "cChestEntity.h"
#include "cFurnaceEntity.h"
#include "cSignEntity.h"
#include "cTorch.h"
#include "cLadder.h"
#include "cPickup.h"
2011-11-07 22:59:29 +00:00
#include "cRedstone.h"
2011-10-03 18:41:19 +00:00
#include "cItem.h"
#include "cNoise.h"
#include "cRoot.h"
2011-12-26 02:39:43 +00:00
#include "cWorldGenerator.h"
2011-11-07 22:59:29 +00:00
#include "cBlockToPickup.h"
2011-12-26 09:09:47 +00:00
#include "MersenneTwister.h"
2012-02-13 21:47:03 +00:00
#include "cPlayer.h"
2011-10-03 18:41:19 +00:00
#include "packets/cPacket_DestroyEntity.h"
#include "packets/cPacket_PreChunk.h"
#include "packets/cPacket_BlockChange.h"
#include "packets/cPacket_MapChunk.h"
#include "packets/cPacket_MultiBlock.h"
#include <json/json.h>
2012-01-29 19:28:19 +00:00
2011-10-21 21:25:29 +00:00
2011-10-03 18:41:19 +00:00
extern bool g_bWaterPhysics ;
2012-01-29 19:28:19 +00:00
2012-01-30 16:01:45 +00:00
2012-02-18 20:10:57 +00:00
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// sSetBlock:
sSetBlock :: sSetBlock ( int a_X , int a_Y , int a_Z , char a_BlockType , char a_BlockMeta ) // absolute block position
: x ( a_X )
, y ( a_Y )
, z ( a_Z )
, BlockType ( a_BlockType )
, BlockMeta ( a_BlockMeta )
{
2012-03-14 20:56:09 +00:00
cChunkDef :: AbsoluteToRelative ( x , y , z , ChunkX , ChunkZ );
2012-02-18 20:10:57 +00:00
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cChunk:
2012-02-21 16:27:30 +00:00
cChunk :: cChunk ( int a_X , int a_Y , int a_Z , cChunkMap * a_ChunkMap , cWorld * a_World )
2012-02-13 21:47:03 +00:00
: m_bCalculateLighting ( false )
2012-01-30 16:01:45 +00:00
, m_PosX ( a_X )
, m_PosY ( a_Y )
, m_PosZ ( a_Z )
, m_BlockTickNum ( 0 )
, m_BlockTickX ( 0 )
, m_BlockTickY ( 0 )
, m_BlockTickZ ( 0 )
, m_World ( a_World )
2012-02-21 16:27:30 +00:00
, m_ChunkMap ( a_ChunkMap )
2012-02-13 21:47:03 +00:00
, m_IsValid ( false )
2012-02-16 13:42:35 +00:00
, m_IsDirty ( false )
, m_IsSaving ( false )
2012-02-26 16:15:09 +00:00
, m_StayCount ( 0 )
2012-01-30 16:01:45 +00:00
{
2012-02-13 21:47:03 +00:00
// LOGINFO("### new cChunk (%i, %i) at %p, thread 0x%x ###", a_X, a_Z, this, GetCurrentThreadId());
2012-01-30 16:01:45 +00:00
}
2011-10-03 18:41:19 +00:00
cChunk ::~ cChunk ()
{
2012-02-13 21:47:03 +00: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 )
2011-10-03 18:41:19 +00:00
{
delete * itr ;
}
2012-02-13 21:47:03 +00:00
m_BlockEntities . clear ();
2011-10-03 18:41:19 +00:00
2012-02-13 21:47:03 +00:00
// Remove and destroy all entities that are not players:
cEntityList Entities ;
for ( cEntityList :: const_iterator itr = m_Entities . begin (); itr != m_Entities . end (); ++ itr )
2011-10-03 18:41:19 +00:00
{
2012-03-09 13:42:28 +00:00
if (( * itr ) -> GetEntityType () != cEntity :: eEntityType_Player )
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
Entities . push_back ( * itr );
2011-10-03 18:41:19 +00:00
}
}
2012-02-13 21:47:03 +00:00
for ( cEntityList :: iterator itr = Entities . begin (); itr != Entities . end (); ++ itr )
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
( * itr ) -> RemoveFromChunk ();
( * itr ) -> Destroy ();
2011-10-03 18:41:19 +00:00
}
2012-02-13 21:47:03 +00:00
m_Entities . clear ();
2011-10-03 18:41:19 +00:00
}
2012-01-30 16:01:45 +00:00
2011-10-03 18:41:19 +00:00
2012-02-13 21:47:03 +00:00
void cChunk :: SetValid ( bool a_SendToClients )
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
m_IsValid = true ;
2012-02-18 17:53:22 +00:00
m_World -> GetChunkMap () -> ChunkValidated ();
2012-02-13 21:47:03 +00:00
if ( ! a_SendToClients )
{
return ;
}
if ( m_LoadedByClient . empty ())
{
return ;
}
// Sending the chunk here interferes with the lighting done in the tick thread and results in the "invalid compressed data" on the client
/*
cPacket_PreChunk PreChunk;
PreChunk.m_PosX = m_PosX;
PreChunk.m_PosZ = m_PosZ;
PreChunk.m_bLoad = true;
cPacket_MapChunk MapChunk(this);
Broadcast(&PreChunk);
Broadcast(&MapChunk);
// Let all clients of this chunk know that it has been already sent to the client
for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr)
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
(*itr)->ChunkJustSent(this);
} // for itr - m_LoadedByClient[]
*/
}
2011-10-03 18:41:19 +00:00
2011-12-24 23:34:30 +00:00
2012-02-13 21:47:03 +00:00
bool cChunk :: CanUnload ( void )
{
2012-02-26 16:15:09 +00:00
return m_LoadedByClient . empty () && ! m_IsDirty && ( m_StayCount == 0 );
2012-02-16 13:42:35 +00:00
}
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 ;
2012-02-18 17:53:22 +00:00
SetValid ();
2012-02-16 13:42:35 +00:00
}
2012-02-28 12:11:14 +00:00
void cChunk :: MarkLoadFailed ( void )
{
if ( m_IsValid )
{
return ;
}
m_HasLoadFailed = true ;
}
2012-03-09 13:42:28 +00:00
void cChunk :: GetAllData ( cChunkDataCallback & a_Callback )
2012-02-16 13:42:35 +00:00
{
2012-03-14 20:56:09 +00:00
a_Callback . HeightMap ( & m_HeightMap );
a_Callback . BlockTypes ( m_BlockTypes );
a_Callback . BlockMeta ( m_BlockMeta );
a_Callback . BlockLight ( m_BlockLight );
a_Callback . BlockSkyLight ( m_BlockSkyLight );
2012-02-16 13:42:35 +00:00
for ( cEntityList :: iterator itr = m_Entities . begin (); itr != m_Entities . end (); ++ itr )
{
2012-03-09 13:42:28 +00:00
a_Callback . Entity ( * itr );
2012-02-16 13:42:35 +00:00
}
for ( cBlockEntityList :: iterator itr = m_BlockEntities . begin (); itr != m_BlockEntities . end (); ++ itr )
{
2012-03-09 13:42:28 +00:00
a_Callback . BlockEntity ( * itr );
2012-02-16 13:42:35 +00:00
}
}
2012-03-14 20:56:09 +00:00
void cChunk :: SetAllData (
const BLOCKTYPE * a_BlockTypes ,
const BLOCKTYPE * a_BlockMeta ,
const BLOCKTYPE * a_BlockLight ,
const BLOCKTYPE * a_BlockSkyLight ,
const HeightMap * a_HeightMap ,
cEntityList & a_Entities ,
cBlockEntityList & a_BlockEntities
)
2012-02-16 13:42:35 +00:00
{
2012-03-14 20:56:09 +00:00
if ( a_HeightMap != NULL )
{
memcpy ( m_HeightMap , a_HeightMap , sizeof ( m_HeightMap ));
}
memcpy ( m_BlockTypes , a_BlockTypes , sizeof ( m_BlockTypes ));
memcpy ( m_BlockMeta , a_BlockMeta , sizeof ( m_BlockMeta ));
memcpy ( m_BlockLight , a_BlockLight , sizeof ( m_BlockLight ));
memcpy ( m_BlockSkyLight , a_BlockSkyLight , sizeof ( m_BlockSkyLight ));
if ( a_HeightMap == NULL )
{
CalculateHeightmap ();
}
2012-02-16 13:42:35 +00:00
// Clear the internal entities:
for ( cEntityList :: iterator itr = m_Entities . begin (); itr != m_Entities . end (); ++ itr )
{
2012-03-09 13:42:28 +00:00
if (( * itr ) -> GetEntityType () == cEntity :: eEntityType_Player )
2012-02-16 13:42:35 +00:00
{
// Move players into the new entity list
a_Entities . push_back ( * itr );
}
else
{
// Delete other entities (there should not be any, since we're now loading / generating the chunk)
LOGWARNING ( "cChunk: There is an unexpected entity #%d of type %s in chunk [%d, %d]; it will be deleted" ,
( * itr ) -> GetUniqueID (), ( * itr ) -> GetClass (),
m_PosX , m_PosZ
);
2012-02-22 20:33:33 +00:00
2012-03-10 19:30:06 +00:00
// MD 2012_03_10: This may happen if a mob is generated near the edge of loaded chunks and walks off of the edge.
// Older: Assert because this is a very curious case. These lines were executed once before, when a player died, re spawned, and walked around a bit. It's uncertain why an entity would be in the chunk in this case.
// ASSERT(!"Unexpected entity in chunk!");
2012-02-22 20:33:33 +00:00
( * itr ) -> Destroy ();
2012-02-16 13:42:35 +00:00
}
}
for ( cBlockEntityList :: iterator itr = m_BlockEntities . begin (); itr != m_BlockEntities . end (); ++ itr )
{
delete * itr ;
}
// Swap the entity lists:
std :: swap ( a_Entities , m_Entities );
std :: swap ( a_BlockEntities , m_BlockEntities );
// Create block entities that the loader didn't load; fill them with defaults
CreateBlockEntities ();
2012-02-16 15:40:38 +00:00
2012-02-28 12:11:14 +00:00
m_HasLoadFailed = false ;
2012-02-16 13:42:35 +00:00
}
2012-03-14 20:56:09 +00:00
void cChunk :: GetBlockTypes ( BLOCKTYPE * a_BlockTypes )
2012-02-18 19:18:16 +00:00
{
2012-03-14 20:56:09 +00:00
memcpy ( a_BlockTypes , m_BlockTypes , NumBlocks );
2012-02-18 19:18:16 +00:00
}
2012-03-14 20:56:09 +00:00
void cChunk :: GetBlockData ( BLOCKTYPE * a_BlockData )
2012-03-05 16:41:57 +00:00
{
2012-03-14 20:56:09 +00:00
memcpy ( a_BlockData , m_BlockTypes , NumBlocks );
memcpy ( a_BlockData + MetaOffset , m_BlockMeta , NumBlocks / 2 );
memcpy ( a_BlockData + LightOffset , m_BlockLight , NumBlocks / 2 );
memcpy ( a_BlockData + SkyLightOffset , m_BlockSkyLight , NumBlocks / 2 );
2012-03-05 16:41:57 +00:00
}
2012-02-16 13:42:35 +00: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 ;
2011-10-03 18:41:19 +00:00
}
2012-01-30 16:01:45 +00:00
2012-02-26 16:15:09 +00:00
/// Sets or resets the internal flag that prevents chunk from being unloaded
void cChunk :: Stay ( bool a_Stay )
{
m_StayCount += ( a_Stay ? 1 : - 1 );
ASSERT ( m_StayCount >= 0 );
}
2012-02-08 12:36:54 +00:00
void cChunk :: Tick ( float a_Dt , MTRand & a_TickRandom )
2011-10-03 18:41:19 +00:00
{
2012-01-30 16:01:45 +00:00
if ( m_bCalculateLighting )
{
2011-10-03 18:41:19 +00:00
CalculateLighting ();
2012-01-30 16:01:45 +00:00
}
2011-10-03 18:41:19 +00:00
2012-02-13 21:47:03 +00:00
cCSLock Lock ( m_CSBlockLists );
unsigned int PendingSendBlocks = m_PendingSendBlocks . size ();
2012-01-26 20:39:46 +00:00
if ( PendingSendBlocks > 1 )
{
cPacket_MultiBlock MultiBlock ;
MultiBlock . m_ChunkX = m_PosX ;
MultiBlock . m_ChunkZ = m_PosZ ;
MultiBlock . m_NumBlocks = ( short ) PendingSendBlocks ;
2012-03-02 01:22:06 +00:00
#if (MINECRAFT_1_2_2 == 1)
MultiBlock . m_Data = new cPacket_MultiBlock :: sBlockChange [ PendingSendBlocks ];
MultiBlock . m_DataSize = PendingSendBlocks * sizeof ( cPacket_MultiBlock :: sBlockChange );
#else
2012-01-26 20:39:46 +00:00
MultiBlock . m_BlockCoordinates = new unsigned short [ PendingSendBlocks ];
MultiBlock . m_BlockTypes = new char [ PendingSendBlocks ];
MultiBlock . m_BlockMetas = new char [ PendingSendBlocks ];
2012-03-02 01:22:06 +00:00
#endif
2012-01-26 20:39:46 +00:00
//LOG("Sending multiblock packet for %i blocks", PendingSendBlocks );
for ( unsigned int i = 0 ; i < PendingSendBlocks ; i ++ )
{
2012-02-13 21:47:03 +00:00
unsigned int index = m_PendingSendBlocks [ i ];
2012-03-10 00:25:05 +00:00
Vector3i BlockPos = IndexToCoordinate ( index );
2012-01-26 20:39:46 +00:00
2012-03-02 01:22:06 +00:00
#if (MINECRAFT_1_2_2 == 1)
2012-03-14 20:56:09 +00:00
unsigned int Coords = BlockPos . y | ( BlockPos . z << 8 ) | ( BlockPos . x << 12 );
unsigned int Blocks = GetNibble ( m_BlockMeta , index ) | ( m_BlockTypes [ index ] << 4 );
2012-03-02 13:41:42 +00:00
MultiBlock . m_Data [ i ]. Data = Coords << 16 | Blocks ;
2012-03-02 01:22:06 +00:00
#else
2012-03-10 00:25:05 +00:00
MultiBlock . m_BlockCoordinates [ i ] = ( BlockPos . z & 0xf ) | ( BlockPos . x & 0xf ) << 4 | ( BlockPos . y & 0xff ) << 8 ;
2012-01-26 20:39:46 +00:00
//LOG("X: %i Y: %i Z: %i Combo: 0x%04x", X, Y, Z, MultiBlock.m_BlockCoordinates[i] );
2012-03-14 20:56:09 +00:00
MultiBlock . m_BlockTypes [ i ] = m_BlockTypes [ index ];
2012-03-05 16:41:57 +00:00
MultiBlock . m_BlockMetas [ i ] = GetNibble ( m_BlockMeta , index );
2012-03-02 01:22:06 +00:00
#endif
2012-01-26 20:39:46 +00:00
}
2012-02-13 21:47:03 +00:00
m_PendingSendBlocks . clear ();
PendingSendBlocks = m_PendingSendBlocks . size ();
2012-01-26 20:39:46 +00:00
Broadcast ( MultiBlock );
}
2011-10-03 18:41:19 +00:00
if ( PendingSendBlocks > 0 )
{
for ( unsigned int i = 0 ; i < PendingSendBlocks ; i ++ )
{
2012-02-13 21:47:03 +00:00
unsigned int index = m_PendingSendBlocks [ i ];
2012-03-10 00:25:05 +00:00
Vector3i WorldPos = PositionToWorldPosition ( IndexToCoordinate ( index ) );
2011-10-03 18:41:19 +00:00
cPacket_BlockChange BlockChange ;
2012-03-10 00:25:05 +00:00
BlockChange . m_PosX = WorldPos . x ;
BlockChange . m_PosY = ( unsigned char ) WorldPos . y ;
BlockChange . m_PosZ = WorldPos . z ;
2012-03-14 20:56:09 +00:00
BlockChange . m_BlockType = m_BlockTypes [ index ];
2012-03-05 16:41:57 +00:00
BlockChange . m_BlockMeta = GetNibble ( m_BlockMeta , index );
2011-10-03 18:41:19 +00:00
Broadcast ( BlockChange );
}
2012-02-13 21:47:03 +00:00
m_PendingSendBlocks . clear ();
2011-10-03 18:41:19 +00:00
}
2012-01-30 21:54:40 +00:00
Lock . Unlock ();
2011-10-03 18:41:19 +00:00
2012-02-13 21:47:03 +00:00
while ( ! m_UnloadQuery . empty () )
2011-10-03 18:41:19 +00:00
{
cPacket_PreChunk UnloadPacket ;
UnloadPacket . m_PosX = GetPosX ();
UnloadPacket . m_PosZ = GetPosZ ();
UnloadPacket . m_bLoad = false ; // Unload
2012-02-13 21:47:03 +00:00
( * m_UnloadQuery . begin ()) -> Send ( UnloadPacket );
m_UnloadQuery . remove ( * m_UnloadQuery . begin () );
2011-10-03 18:41:19 +00:00
}
2012-02-13 21:47:03 +00:00
cCSLock Lock2 ( m_CSBlockLists );
2012-02-28 14:22:03 +00:00
unsigned int NumTickBlocks = m_ToTickBlocks . size ();
2012-01-30 21:54:40 +00:00
Lock2 . Unlock ();
2011-10-03 18:41:19 +00:00
2012-02-28 14:22:03 +00:00
if ( NumTickBlocks > 0 )
{
Lock2 . Lock ();
std :: deque < unsigned int > ToTickBlocks = m_ToTickBlocks ;
m_ToTickBlocks . clear ();
Lock2 . Unlock ();
bool isRedstone = false ;
for ( std :: deque < unsigned int >:: iterator itr = ToTickBlocks . begin (); itr != ToTickBlocks . end (); ++ itr )
2011-10-03 18:41:19 +00:00
{
2012-02-28 14:22:03 +00:00
unsigned int index = ( * itr );
2012-03-10 00:25:05 +00:00
Vector3i BlockPos = IndexToCoordinate ( index );
2012-02-28 14:22:03 +00:00
char BlockID = GetBlock ( index );
switch ( BlockID )
2011-10-03 18:41:19 +00:00
{
2012-02-28 14:22:03 +00:00
case E_BLOCK_REDSTONE_REPEATER_OFF :
case E_BLOCK_REDSTONE_REPEATER_ON :
case E_BLOCK_REDSTONE_WIRE :
{
isRedstone = true ;
}
case E_BLOCK_CACTUS :
case E_BLOCK_REEDS :
case E_BLOCK_WOODEN_PRESSURE_PLATE :
case E_BLOCK_STONE_PRESSURE_PLATE :
case E_BLOCK_MINECART_TRACKS :
case E_BLOCK_SIGN_POST :
case E_BLOCK_CROPS :
case E_BLOCK_SAPLING :
case E_BLOCK_YELLOW_FLOWER :
case E_BLOCK_RED_ROSE :
case E_BLOCK_RED_MUSHROOM :
case E_BLOCK_BROWN_MUSHROOM : // Stuff that drops when block below is destroyed
2011-10-03 18:41:19 +00:00
{
2012-03-10 00:25:05 +00:00
if ( GetBlock ( BlockPos . x , BlockPos . y - 1 , BlockPos . z ) == E_BLOCK_AIR )
2012-02-28 14:22:03 +00:00
{
2012-03-10 00:25:05 +00:00
SetBlock ( BlockPos , E_BLOCK_AIR , 0 );
2011-12-22 21:36:24 +00:00
2012-03-10 00:25:05 +00:00
Vector3i WorldPos = PositionToWorldPosition ( BlockPos );
2011-12-22 21:36:24 +00:00
2012-03-10 00:25:05 +00:00
m_World -> GetSimulatorManager () -> WakeUp ( WorldPos . x , WorldPos . y , WorldPos . z );
cPickup * Pickup = new cPickup ( WorldPos . x * 32 + 16 , WorldPos . y * 32 + 16 , WorldPos . z * 32 + 16 , cItem ( cBlockToPickup :: ToPickup ( ( ENUM_ITEM_ID ) BlockID , E_ITEM_EMPTY ) , 1 ) );
2012-02-28 14:22:03 +00:00
Pickup -> Initialize ( m_World );
2011-11-07 22:59:29 +00:00
}
2011-10-03 18:41:19 +00:00
}
2012-02-28 14:22:03 +00:00
break ;
case E_BLOCK_REDSTONE_TORCH_OFF :
case E_BLOCK_REDSTONE_TORCH_ON :
isRedstone = true ;
case E_BLOCK_TORCH :
2011-10-03 18:41:19 +00:00
{
2012-03-10 00:25:05 +00:00
char Dir = cTorch :: MetaDataToDirection ( GetNibble ( m_BlockMeta , BlockPos ) );
Vector3i WorldPos = PositionToWorldPosition ( BlockPos );
Vector3i AttachedTo = WorldPos ;
AddDirection ( AttachedTo . x , AttachedTo . y , AttachedTo . z , Dir , true );
if ( m_World -> GetBlock ( AttachedTo ) == E_BLOCK_AIR )
2012-02-28 14:22:03 +00:00
{
2012-03-10 00:25:05 +00:00
SetBlock ( BlockPos , E_BLOCK_AIR , 0 );
2012-03-01 15:18:59 +00:00
2012-03-10 00:25:05 +00:00
m_World -> GetSimulatorManager () -> WakeUp ( WorldPos . x , WorldPos . y , WorldPos . z );
2012-03-01 15:18:59 +00:00
2012-03-10 00:25:05 +00:00
cPickup * Pickup = new cPickup ( WorldPos . x * 32 + 16 , WorldPos . y * 32 + 16 , WorldPos . z * 32 + 16 , cItem ( cBlockToPickup :: ToPickup ( ( ENUM_ITEM_ID ) BlockID , E_ITEM_EMPTY ) , 1 ) );
2012-02-28 14:22:03 +00:00
Pickup -> Initialize ( m_World );
2011-11-07 22:59:29 +00:00
}
2011-10-03 18:41:19 +00:00
}
2012-02-28 14:22:03 +00:00
break ;
case E_BLOCK_LADDER :
2011-10-03 18:41:19 +00:00
{
2012-03-10 00:25:05 +00:00
char Dir = cLadder :: MetaDataToDirection ( GetNibble ( m_BlockMeta , BlockPos ) );
Vector3i WorldPos = PositionToWorldPosition ( BlockPos );
Vector3i AttachedTo = WorldPos ;
AddDirection ( AttachedTo . x , AttachedTo . y , AttachedTo . z , Dir , true );
if ( m_World -> GetBlock ( AttachedTo ) == E_BLOCK_AIR )
2012-02-28 14:22:03 +00:00
{
2012-03-10 00:25:05 +00:00
SetBlock ( BlockPos , E_BLOCK_AIR , 0 );
cPickup * Pickup = new cPickup ( WorldPos . x * 32 + 16 , WorldPos . y * 32 + 16 , WorldPos . z * 32 + 16 , cItem ( ( ENUM_ITEM_ID ) BlockID , 1 ) );
2012-02-28 14:22:03 +00:00
Pickup -> Initialize ( m_World );
}
2011-10-03 18:41:19 +00:00
}
2012-02-28 14:22:03 +00:00
break ;
default :
break ;
};
}
2011-10-03 18:41:19 +00:00
}
2011-12-28 14:52:31 +00:00
2011-10-03 18:41:19 +00:00
// Tick dem blocks
2012-02-08 12:36:54 +00:00
int RandomX = a_TickRandom . randInt ();
int RandomY = a_TickRandom . randInt ();
int RandomZ = a_TickRandom . randInt ();
2011-10-03 18:41:19 +00:00
for ( int i = 0 ; i < 50 ; i ++ )
{
2012-03-14 20:56:09 +00:00
m_BlockTickX = ( m_BlockTickX + RandomX ) % Width ;
m_BlockTickY = ( m_BlockTickY + RandomY ) % Height ;
m_BlockTickZ = ( m_BlockTickZ + RandomZ ) % Width ;
2011-10-03 18:41:19 +00:00
2012-03-14 20:56:09 +00:00
if ( m_BlockTickY > m_HeightMap [ m_BlockTickX + m_BlockTickZ * Width ] ) continue ; // It's all air up here
2011-10-03 18:41:19 +00:00
2012-03-10 00:25:05 +00:00
unsigned int Index = MakeIndexNoCheck ( m_BlockTickX , m_BlockTickY , m_BlockTickZ );
2012-03-14 20:56:09 +00:00
char ID = m_BlockTypes [ Index ];
2011-10-03 18:41:19 +00:00
switch ( ID )
{
2012-02-13 21:47:03 +00:00
/*
// TODO: re-enable
case E_BLOCK_DIRT:
2011-10-03 18:41:19 +00:00
{
char AboveBlock = GetBlock( Index+1 );
2012-03-05 16:41:57 +00:00
if ( (AboveBlock == 0) && GetNibble( m_BlockSkyLight, Index ) > 0xf/2 ) // Half lit //changed to not allow grass if any one hit object is on top
2011-10-03 18:41:19 +00:00
{
2012-03-05 16:41:57 +00:00
FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_GRASS, GetNibble( m_BlockMeta, Index ) );
2011-10-03 18:41:19 +00:00
}
2012-03-05 16:41:57 +00:00
if ( (g_BlockOneHitDig[AboveBlock]) && GetNibble( m_BlockSkyLight, Index+1 ) > 0xf/2 ) // Half lit //ch$
2011-11-09 01:31:19 +00:00
{
2012-03-05 16:41:57 +00:00
FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_GRASS, GetNibble( m_BlockMeta, Index ) );
2011-11-09 01:31:19 +00:00
}
2011-11-05 19:31:25 +00:00
2012-02-13 21:47:03 +00:00
break;
2011-10-03 18:41:19 +00:00
}
2012-02-13 21:47:03 +00:00
*/
case E_BLOCK_GRASS :
2011-10-03 18:41:19 +00:00
{
2012-03-10 02:39:36 +00:00
#if AXIS_ORDER == AXIS_ORDER_YZX
2011-10-03 18:41:19 +00:00
char AboveBlock = GetBlock ( Index + 1 );
2012-03-10 13:49:40 +00:00
#elif AXIS_ORDER == AXIS_ORDER_XZY
2012-03-14 20:56:09 +00:00
char AboveBlock = GetBlock ( Index + ( Width * Width ) );
2012-03-10 02:39:36 +00:00
#endif
2011-11-06 09:23:20 +00:00
if ( ! ( ( AboveBlock == 0 ) || ( g_BlockOneHitDig [ AboveBlock ]) || ( g_BlockTransparent [ AboveBlock ]) ) ) //changed to not allow grass if any one hit object is on top
2011-10-03 18:41:19 +00:00
{
2012-03-05 16:41:57 +00:00
FastSetBlock ( m_BlockTickX , m_BlockTickY , m_BlockTickZ , E_BLOCK_DIRT , GetNibble ( m_BlockMeta , Index ) );
2011-10-03 18:41:19 +00:00
}
}
break ;
2011-11-05 19:31:25 +00:00
case E_BLOCK_SAPLING : //todo: check meta of sapling. change m_World->GrowTree to look change trunk and leaves based on meta of sapling
2011-10-03 18:41:19 +00:00
{
2012-03-05 16:41:57 +00:00
FastSetBlock ( m_BlockTickX , m_BlockTickY , m_BlockTickZ , E_BLOCK_AIR , GetNibble ( m_BlockMeta , Index ) );
2012-03-14 20:56:09 +00:00
m_World -> GrowTree ( m_BlockTickX + m_PosX * Width , m_BlockTickY , m_BlockTickZ + m_PosZ * Width );
2011-10-03 18:41:19 +00:00
}
2011-11-10 03:35:46 +00:00
break ;
case E_BLOCK_LEAVES : //todo, http://www.minecraftwiki.net/wiki/Data_values#Leaves
{
}
break ;
2011-10-03 18:41:19 +00:00
default :
break ;
}
}
2012-02-13 21:47:03 +00:00
// Tick block entities (furnaces)
for ( cBlockEntityList :: iterator itr = m_BlockEntities . begin (); itr != m_BlockEntities . end (); ++ itr )
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
if (( * itr ) -> GetBlockType () == E_BLOCK_FURNACE )
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
(( cFurnaceEntity * )( * itr )) -> Tick ( a_Dt );
2011-10-03 18:41:19 +00:00
}
}
}
2012-02-08 12:36:54 +00:00
2012-02-18 17:53:22 +00:00
int cChunk :: GetHeight ( int a_X , int a_Z )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
ASSERT (( a_X >= 0 ) && ( a_X < Width ) && ( a_Z >= 0 ) && ( a_Z < Width ));
2012-02-21 13:44:06 +00:00
2012-03-14 20:56:09 +00:00
if (( a_X >= 0 ) && ( a_X < Width ) && ( a_Z >= 0 ) && ( a_Z < Width ))
2012-02-13 21:47:03 +00:00
{
2012-03-14 20:56:09 +00:00
return m_HeightMap [ a_X + a_Z * Width ];
2012-02-13 21:47:03 +00:00
}
2011-10-03 18:41:19 +00:00
return 0 ;
}
2012-02-08 19:49:57 +00:00
2012-02-16 13:42:35 +00:00
void cChunk :: CreateBlockEntities ( void )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
for ( int x = 0 ; x < Width ; x ++ )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
for ( int z = 0 ; z < Width ; z ++ )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
for ( int y = 0 ; y < Height ; y ++ )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
ENUM_BLOCK_ID BlockType = ( ENUM_BLOCK_ID ) m_BlockTypes [ MakeIndex ( x , y , z ) ];
2012-02-13 21:47:03 +00:00
switch ( BlockType )
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
case E_BLOCK_CHEST :
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
if ( ! HasBlockEntityAt ( x + m_PosX * Width , y + m_PosY * Height , z + m_PosZ * Width ))
2012-02-16 13:42:35 +00:00
{
2012-03-14 20:56:09 +00:00
m_BlockEntities . push_back ( new cChestEntity ( x + m_PosX * Width , y + m_PosY * Height , z + m_PosZ * Width , m_World ) );
2012-02-16 13:42:35 +00:00
}
2012-02-13 21:47:03 +00:00
break ;
2011-10-03 18:41:19 +00:00
}
2012-02-13 21:47:03 +00:00
case E_BLOCK_FURNACE :
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
if ( ! HasBlockEntityAt ( x + m_PosX * Width , y + m_PosY * Height , z + m_PosZ * Width ))
2012-02-16 13:42:35 +00:00
{
2012-03-14 20:56:09 +00:00
m_BlockEntities . push_back ( new cFurnaceEntity ( x + m_PosX * Width , y + m_PosY * Height , z + m_PosZ * Width , m_World ) );
2012-02-16 13:42:35 +00:00
}
2012-02-13 21:47:03 +00:00
break ;
2011-10-03 18:41:19 +00:00
}
2012-02-13 21:47:03 +00:00
case E_BLOCK_SIGN_POST :
case E_BLOCK_WALLSIGN :
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
if ( ! HasBlockEntityAt ( x + m_PosX * Width , y + m_PosY * Height , z + m_PosZ * Width ))
2012-02-16 13:42:35 +00:00
{
2012-03-14 20:56:09 +00:00
m_BlockEntities . push_back ( new cSignEntity ( BlockType , x + m_PosX * Width , y + m_PosY * Height , z + m_PosZ * Width , m_World ) );
2012-02-16 13:42:35 +00:00
}
2012-02-13 21:47:03 +00:00
break ;
2011-10-03 18:41:19 +00:00
}
2012-02-13 21:47:03 +00:00
} // switch (BlockType)
} // for y
} // for z
} // for x
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2011-10-03 18:41:19 +00:00
void cChunk :: CalculateHeightmap ()
{
2012-03-14 20:56:09 +00:00
for ( int x = 0 ; x < Width ; x ++ )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
for ( int z = 0 ; z < Width ; z ++ )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
for ( int y = Height - 1 ; y > - 1 ; y -- )
2011-10-03 18:41:19 +00:00
{
int index = MakeIndex ( x , y , z );
2012-03-14 20:56:09 +00:00
if ( m_BlockTypes [ index ] != E_BLOCK_AIR )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
m_HeightMap [ x + z * Width ] = ( unsigned char ) y ;
2011-10-03 18:41:19 +00:00
break ;
}
2012-02-13 21:47:03 +00:00
} // for y
} // for z
} // for x
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2011-10-03 18:41:19 +00:00
void cChunk :: CalculateLighting ()
{
// Calculate sunlight
2012-03-14 20:56:09 +00:00
memset ( m_BlockSkyLight , 0xff , NumBlocks / 2 ); // Set all to fully lit, so everything above HeightMap is lit
for ( int x = 0 ; x < Width ; x ++ )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
for ( int z = 0 ; z < Width ; z ++ )
2011-10-03 18:41:19 +00:00
{
char sunlight = 0xf ;
2012-03-14 20:56:09 +00:00
for ( int y = m_HeightMap [ x + z * Width ]; y > - 1 ; y -- )
2011-10-03 18:41:19 +00:00
{
2012-03-10 00:25:05 +00:00
int index = MakeIndexNoCheck ( x , y , z );
2011-10-03 18:41:19 +00:00
2012-03-14 20:56:09 +00:00
if ( g_BlockTransparent [ ( int ) m_BlockTypes [ index ] ] == false )
2011-10-03 18:41:19 +00:00
{
sunlight = 0x0 ;
}
2012-03-10 00:25:05 +00:00
SetNibble ( m_BlockSkyLight , index , sunlight );
2011-10-03 18:41:19 +00:00
}
}
}
// Calculate blocklights
2012-03-14 20:56:09 +00:00
for ( int x = 0 ; x < Width ; x ++ )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
for ( int z = 0 ; z < Width ; z ++ )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
int MaxHeight = m_HeightMap [ x + z * Width ];
2012-03-05 16:41:57 +00:00
for ( int y = 0 ; y < MaxHeight ; y ++ )
2011-10-03 18:41:19 +00:00
{
char BlockID = GetBlock ( x , y , z );
2012-03-05 16:41:57 +00:00
SetNibble ( m_BlockLight , x , y , z , g_BlockLightValue [( int ) BlockID ] );
2011-10-03 18:41:19 +00:00
}
}
}
SpreadLight ( m_BlockSkyLight );
SpreadLight ( m_BlockLight );
2012-03-05 16:41:57 +00:00
MarkDirty ();
2011-10-03 18:41:19 +00:00
// Stop it from calculating again :P
m_bCalculateLighting = false ;
}
2012-02-08 19:49:57 +00:00
2012-03-14 21:21:03 +00:00
void cChunk :: SpreadLight ( BLOCKTYPE * a_LightBuffer )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
// Spread the light
for ( int x = 0 ; x < Width ; x ++ ) for ( int z = 0 ; z < Width ; z ++ ) for ( int y = 0 ; y < Height ; y ++ )
2011-10-03 18:41:19 +00:00
{
2012-03-10 00:25:05 +00:00
int index = MakeIndexNoCheck ( x , y , z );
2012-03-14 20:56:09 +00:00
if ( g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ] > 0 )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
SpreadLightOfBlock ( a_LightBuffer , x , y , z , g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ]);
2011-10-03 18:41:19 +00:00
}
}
2012-03-14 20:56:09 +00:00
for ( int x = Width - 1 ; x > - 1 ; x -- ) for ( int z = Width - 1 ; z > - 1 ; z -- ) for ( int y = Height - 1 ; y > - 1 ; y -- )
2011-10-03 18:41:19 +00:00
{
2012-03-10 00:25:05 +00:00
int index = MakeIndexNoCheck ( x , y , z );
2012-03-14 20:56:09 +00:00
if ( g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ] > 0 )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
SpreadLightOfBlock ( a_LightBuffer , x , y , z , g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ]);
2011-10-03 18:41:19 +00:00
}
}
bool bCalcLeft , bCalcRight , bCalcFront , bCalcBack ;
bCalcLeft = bCalcRight = bCalcFront = bCalcBack = false ;
2012-02-13 21:47:03 +00:00
2011-10-03 18:41:19 +00:00
// Spread to neighbour chunks X-axis
2012-02-21 16:27:30 +00:00
cChunkPtr LeftChunk = m_ChunkMap -> GetChunkNoGen ( m_PosX - 1 , m_PosY , m_PosZ );
cChunkPtr RightChunk = m_ChunkMap -> GetChunkNoGen ( m_PosX + 1 , m_PosY , m_PosZ );
2012-03-14 21:21:03 +00:00
BLOCKTYPE * LeftSky = NULL , * RightSky = NULL ;
2012-02-13 21:47:03 +00:00
if ( LeftChunk -> IsValid ())
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
LeftSky = ( a_LightBuffer == m_BlockSkyLight ) ? LeftChunk -> m_BlockSkyLight : LeftChunk -> m_BlockLight ;
2012-02-13 21:47:03 +00:00
}
if ( RightChunk -> IsValid ())
{
2012-03-14 20:56:09 +00:00
RightSky = ( a_LightBuffer == m_BlockSkyLight ) ? RightChunk -> m_BlockSkyLight : RightChunk -> m_BlockLight ;
2012-02-13 21:47:03 +00:00
}
2012-03-14 20:56:09 +00:00
for ( int z = 0 ; z < Width ; z ++ ) for ( int y = 0 ; y < Height ; y ++ )
2012-02-13 21:47:03 +00:00
{
if ( LeftSky != NULL )
2011-10-03 18:41:19 +00:00
{
2012-03-10 00:25:05 +00:00
int index = MakeIndexNoCheck ( 0 , y , z );
2012-03-14 20:56:09 +00:00
if ( g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ] > 0 )
2011-10-03 18:41:19 +00:00
{
2012-03-14 21:21:03 +00:00
BLOCKTYPE CurrentLight = GetNibble ( a_LightBuffer , 0 , y , z );
BLOCKTYPE LeftLight = GetNibble ( LeftSky , Width - 1 , y , z );
2012-03-14 20:56:09 +00:00
if ( LeftLight < CurrentLight - g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ] )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
SetNibble ( LeftSky , Width - 1 , y , z , MAX ( 0 , CurrentLight - g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ]) );
2011-10-03 18:41:19 +00:00
bCalcLeft = true ;
}
}
}
2012-02-13 21:47:03 +00:00
if ( RightSky != NULL )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
int index = MakeIndexNoCheck ( Width - 1 , y , z );
if ( g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ] > 0 )
2011-10-03 18:41:19 +00:00
{
2012-03-14 21:21:03 +00:00
BLOCKTYPE CurrentLight = GetNibble ( a_LightBuffer , Width - 1 , y , z );
BLOCKTYPE RightLight = GetNibble ( RightSky , 0 , y , z );
2012-03-14 20:56:09 +00:00
if ( RightLight < CurrentLight - g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ] )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
SetNibble ( RightSky , 0 , y , z , MAX ( 0 , CurrentLight - g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ]) );
2011-10-03 18:41:19 +00:00
bCalcRight = true ;
}
}
}
}
// Spread to neighbour chunks Z-axis
2012-02-21 16:27:30 +00:00
cChunkPtr FrontChunk = m_ChunkMap -> GetChunkNoGen ( m_PosX , m_PosY , m_PosZ - 1 );
cChunkPtr BackChunk = m_ChunkMap -> GetChunkNoGen ( m_PosX , m_PosY , m_PosZ + 1 );
2012-03-14 21:21:03 +00:00
BLOCKTYPE * FrontSky = NULL , * BackSky = NULL ;
2012-02-13 21:47:03 +00:00
if ( FrontChunk -> IsValid ())
{
2012-03-14 20:56:09 +00:00
FrontSky = ( a_LightBuffer == m_BlockSkyLight ) ? FrontChunk -> m_BlockSkyLight : FrontChunk -> m_BlockLight ;
2012-02-13 21:47:03 +00:00
}
if ( BackChunk -> IsValid ())
{
2012-03-14 20:56:09 +00:00
BackSky = ( a_LightBuffer == m_BlockSkyLight ) ? BackChunk -> m_BlockSkyLight : BackChunk -> m_BlockLight ;
2012-02-13 21:47:03 +00:00
}
2012-03-14 20:56:09 +00:00
for ( int x = 0 ; x < Width ; x ++ ) for ( int y = 0 ; y < Height ; y ++ )
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
if ( FrontSky != NULL )
2011-10-03 18:41:19 +00:00
{
2012-03-10 00:25:05 +00:00
int index = MakeIndexNoCheck ( x , y , 0 );
2012-03-14 20:56:09 +00:00
if ( g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ] > 0 )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
BLOCKTYPE CurrentLight = GetNibble ( a_LightBuffer , x , y , 0 );
BLOCKTYPE FrontLight = GetNibble ( FrontSky , x , y , Width - 1 );
if ( FrontLight < CurrentLight - g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ] )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
SetNibble ( FrontSky , x , y , Width - 1 , MAX ( 0 , CurrentLight - g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ]) );
2011-10-03 18:41:19 +00:00
bCalcFront = true ;
}
}
}
2012-02-13 21:47:03 +00:00
if ( BackSky != NULL )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
int index = MakeIndexNoCheck ( x , y , Width - 1 );
if ( g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ] > 0 )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
BLOCKTYPE CurrentLight = GetNibble ( a_LightBuffer , x , y , Width - 1 );
BLOCKTYPE BackLight = GetNibble ( BackSky , x , y , 0 );
if ( BackLight < CurrentLight - g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ] )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
SetNibble ( BackSky , x , y , 0 , MAX ( 0 , CurrentLight - g_BlockSpreadLightFalloff [ m_BlockTypes [ index ] ]) );
2011-10-03 18:41:19 +00:00
bCalcBack = true ;
}
}
}
}
2012-03-05 16:41:57 +00:00
if ( bCalcLeft ) m_World -> ReSpreadLighting ( m_PosX - 1 , m_PosY , m_PosZ );
if ( bCalcRight ) m_World -> ReSpreadLighting ( m_PosX + 1 , m_PosY , m_PosZ );
if ( bCalcFront ) m_World -> ReSpreadLighting ( m_PosX , m_PosY , m_PosZ - 1 );
if ( bCalcBack ) m_World -> ReSpreadLighting ( m_PosX , m_PosY , m_PosZ + 1 );
// No need to set those neighbors dirty, they will recalc their light anyway so they'll get marked dirty there
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2012-03-14 20:56:09 +00:00
void cChunk :: SetBlock ( int a_X , int a_Y , int a_Z , BLOCKTYPE a_BlockType , BLOCKTYPE a_BlockMeta )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
if ( a_X < 0 || a_X >= Width || a_Y < 0 || a_Y >= Height || a_Z < 0 || a_Z >= Width )
2011-10-03 18:41:19 +00:00
{
2012-02-08 19:49:57 +00:00
return ; // Clip
2011-10-03 18:41:19 +00:00
}
2012-02-19 23:00:00 +00:00
ASSERT ( IsValid ()); // Is this chunk loaded / generated?
2012-02-13 21:47:03 +00:00
2012-03-10 00:25:05 +00:00
int index = MakeIndexNoCheck ( a_X , a_Y , a_Z );
2012-03-14 20:56:09 +00:00
BLOCKTYPE OldBlockMeta = GetNibble ( m_BlockMeta , index );
BLOCKTYPE OldBlockType = m_BlockTypes [ index ];
m_BlockTypes [ index ] = a_BlockType ;
2011-10-03 18:41:19 +00:00
2012-03-05 16:41:57 +00:00
SetNibble ( m_BlockMeta , index , a_BlockMeta );
2011-10-03 18:41:19 +00:00
2012-02-08 19:49:57 +00:00
if (( OldBlockType == a_BlockType ) && ( OldBlockMeta == a_BlockMeta ))
{
return ;
}
2012-02-16 17:45:26 +00:00
MarkDirty ();
2012-02-21 13:44:06 +00:00
{
cCSLock Lock ( m_CSBlockLists );
m_PendingSendBlocks . push_back ( index );
}
// ONLY recalculate lighting if it's necessary!
if (
( g_BlockLightValue [ OldBlockType ] != g_BlockLightValue [ a_BlockType ]) ||
( g_BlockSpreadLightFalloff [ OldBlockType ] != g_BlockSpreadLightFalloff [ a_BlockType ]) ||
( g_BlockTransparent [ OldBlockType ] != g_BlockTransparent [ a_BlockType ] )
)
{
RecalculateLighting ();
}
// Update heightmap, if needed:
2012-03-14 20:56:09 +00:00
if ( a_Y >= m_HeightMap [ a_X + a_Z * Width ])
2012-02-21 13:44:06 +00:00
{
2012-02-21 15:18:02 +00:00
if ( a_BlockType != E_BLOCK_AIR )
{
2012-03-14 20:56:09 +00:00
m_HeightMap [ a_X + a_Z * Width ] = ( unsigned char ) a_Y ;
2012-02-21 15:18:02 +00:00
}
else
{
for ( int y = a_Y - 1 ; y > 0 ; -- y )
{
2012-03-14 20:56:09 +00:00
if ( m_BlockTypes [ MakeIndex ( a_X , y , a_Z )] != E_BLOCK_AIR )
2012-02-21 15:18:02 +00:00
{
2012-03-14 20:56:09 +00:00
m_HeightMap [ a_X + a_Z * Width ] = ( unsigned char ) y ;
2012-02-21 15:18:02 +00:00
break ;
}
} // for y - column in m_BlockData
}
2012-02-21 13:44:06 +00:00
}
2012-02-08 19:49:57 +00:00
2012-02-28 14:22:03 +00:00
m_ToTickBlocks . push_back ( MakeIndex ( a_X , a_Y , a_Z ) );
m_ToTickBlocks . push_back ( MakeIndex ( a_X + 1 , a_Y , a_Z ) );
m_ToTickBlocks . push_back ( MakeIndex ( a_X - 1 , a_Y , a_Z ) );
m_ToTickBlocks . push_back ( MakeIndex ( a_X , a_Y + 1 , a_Z ) );
m_ToTickBlocks . push_back ( MakeIndex ( a_X , a_Y - 1 , a_Z ) );
m_ToTickBlocks . push_back ( MakeIndex ( a_X , a_Y , a_Z + 1 ) );
m_ToTickBlocks . push_back ( MakeIndex ( a_X , a_Y , a_Z - 1 ) );
2012-02-08 19:49:57 +00:00
2012-03-10 00:25:05 +00:00
Vector3i WorldPos = PositionToWorldPosition ( a_X , a_Y , a_Z );
cBlockEntity * BlockEntity = GetBlockEntity ( WorldPos );
2012-02-08 19:49:57 +00:00
if ( BlockEntity )
{
BlockEntity -> Destroy ();
RemoveBlockEntity ( BlockEntity );
delete BlockEntity ;
}
switch ( a_BlockType )
2011-10-03 18:41:19 +00:00
{
case E_BLOCK_CHEST :
2012-02-08 19:49:57 +00:00
{
2012-03-10 00:25:05 +00:00
AddBlockEntity ( new cChestEntity ( WorldPos . x , WorldPos . y , WorldPos . z , m_World ) );
2011-10-03 18:41:19 +00:00
break ;
2012-02-08 19:49:57 +00:00
}
2011-10-03 18:41:19 +00:00
case E_BLOCK_FURNACE :
2012-02-08 19:49:57 +00:00
{
2012-03-10 00:25:05 +00:00
AddBlockEntity ( new cFurnaceEntity ( WorldPos . x , WorldPos . y , WorldPos . z , m_World ) );
2011-10-03 18:41:19 +00:00
break ;
2012-02-08 19:49:57 +00:00
}
2011-10-03 18:41:19 +00:00
case E_BLOCK_SIGN_POST :
case E_BLOCK_WALLSIGN :
2012-02-08 19:49:57 +00:00
{
2012-03-10 00:25:05 +00:00
AddBlockEntity ( new cSignEntity ( ( ENUM_BLOCK_ID ) a_BlockType , WorldPos . x , WorldPos . y , WorldPos . z , m_World ) );
2011-10-03 18:41:19 +00:00
break ;
2012-02-08 19:49:57 +00:00
}
} // switch (a_BlockType)
}
2011-12-28 14:52:31 +00:00
2011-10-03 18:41:19 +00:00
2012-03-14 20:56:09 +00:00
void cChunk :: FastSetBlock ( int a_X , int a_Y , int a_Z , BLOCKTYPE a_BlockType , BLOCKTYPE a_BlockMeta )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
ASSERT ( ! (( a_X < 0 || a_X >= Width || a_Y < 0 || a_Y >= Height || a_Z < 0 || a_Z >= Width )));
2011-10-03 18:41:19 +00:00
2012-02-19 23:00:00 +00:00
ASSERT ( IsValid ());
2012-02-13 21:47:03 +00:00
2012-03-10 00:25:05 +00:00
const int index = MakeIndexNoCheck ( a_X , a_Y , a_Z );
2012-03-14 20:56:09 +00:00
const BLOCKTYPE OldBlock = m_BlockTypes [ index ];
const BLOCKTYPE OldBlockMeta = GetNibble ( m_BlockMeta , index );
if (( OldBlock == a_BlockType ) && ( OldBlockMeta == a_BlockMeta ))
2012-02-13 21:47:03 +00:00
{
return ;
}
2012-02-16 17:45:26 +00:00
MarkDirty ();
2012-03-14 20:56:09 +00:00
m_BlockTypes [ index ] = a_BlockType ;
2011-12-28 14:52:31 +00:00
2012-02-13 21:47:03 +00:00
{
cCSLock Lock ( m_CSBlockLists );
m_PendingSendBlocks . push_back ( index );
}
2012-03-05 16:41:57 +00:00
SetNibble ( m_BlockMeta , index , a_BlockMeta );
2011-10-03 18:41:19 +00:00
2011-12-24 23:34:30 +00:00
// ONLY recalculate lighting if it's necessary!
2012-02-18 20:10:57 +00:00
if (
( g_BlockLightValue [ OldBlock ] != g_BlockLightValue [ a_BlockType ]) ||
( g_BlockSpreadLightFalloff [ OldBlock ] != g_BlockSpreadLightFalloff [ a_BlockType ]) ||
( g_BlockTransparent [ OldBlock ] != g_BlockTransparent [ a_BlockType ] )
)
2011-10-03 18:41:19 +00:00
{
RecalculateLighting ();
}
2012-02-21 13:44:06 +00:00
// Update heightmap, if needed:
2012-03-14 20:56:09 +00:00
if ( a_Y >= m_HeightMap [ a_X + a_Z * Width ])
2012-02-21 13:44:06 +00:00
{
2012-02-21 15:18:02 +00:00
if ( a_BlockType != E_BLOCK_AIR )
{
2012-03-14 20:56:09 +00:00
m_HeightMap [ a_X + a_Z * Width ] = ( unsigned char ) a_Y ;
2012-02-21 15:18:02 +00:00
}
else
{
for ( int y = a_Y - 1 ; y > 0 ; -- y )
{
2012-03-14 20:56:09 +00:00
if ( m_BlockTypes [ MakeIndexNoCheck ( a_X , y , a_Z )] != E_BLOCK_AIR )
2012-02-21 15:18:02 +00:00
{
2012-03-14 20:56:09 +00:00
m_HeightMap [ a_X + a_Z * Width ] = ( unsigned char ) y ;
2012-02-21 15:18:02 +00:00
break ;
}
} // for y - column in m_BlockData
}
2012-02-21 13:44:06 +00:00
}
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2011-10-03 18:41:19 +00:00
void cChunk :: SendBlockTo ( int a_X , int a_Y , int a_Z , cClientHandle * a_Client )
{
if ( a_Client == 0 )
{
2012-02-13 21:47:03 +00:00
cCSLock Lock ( m_CSBlockLists );
2012-03-04 13:54:33 +00:00
unsigned int index = MakeIndex ( a_X , a_Y , a_Z );
if ( index != INDEX_OUT_OF_RANGE )
{
2012-03-10 00:25:05 +00:00
m_PendingSendBlocks . push_back ( index );
}
else
{
LOGWARN ( "cChunk::SendBlockTo Index out of range!" );
2012-03-04 13:54:33 +00:00
}
2011-10-03 18:41:19 +00:00
return ;
}
2012-02-13 21:47:03 +00:00
for ( cClientHandleList :: iterator itr = m_LoadedByClient . begin (); itr != m_LoadedByClient . end (); ++ itr )
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
if ( * itr == a_Client )
2011-10-03 18:41:19 +00:00
{
unsigned int index = MakeIndex ( a_X , a_Y , a_Z );
2012-03-10 00:25:05 +00:00
Vector3i WorldPos = PositionToWorldPosition ( a_X , a_Y , a_Z );
2011-10-03 18:41:19 +00:00
cPacket_BlockChange BlockChange ;
2012-03-10 00:25:05 +00:00
BlockChange . m_PosX = WorldPos . x ;
BlockChange . m_PosY = ( unsigned char ) WorldPos . y ;
BlockChange . m_PosZ = WorldPos . z ;
2012-03-04 13:54:33 +00:00
if ( index != INDEX_OUT_OF_RANGE )
{
2012-03-14 20:56:09 +00:00
BlockChange . m_BlockType = m_BlockTypes [ index ];
2012-03-05 16:41:57 +00:00
BlockChange . m_BlockMeta = GetNibble ( m_BlockMeta , index );
2012-03-04 13:54:33 +00:00
} // else it's both 0
2011-10-03 18:41:19 +00:00
a_Client -> Send ( BlockChange );
break ;
}
}
}
2012-02-08 19:49:57 +00:00
2011-10-03 18:41:19 +00:00
void cChunk :: AddBlockEntity ( cBlockEntity * a_BlockEntity )
{
2012-02-13 21:47:03 +00:00
cCSLock Lock ( m_CSBlockLists );
m_BlockEntities . push_back ( a_BlockEntity );
}
cBlockEntity * cChunk :: GetBlockEntity ( int a_X , int a_Y , int a_Z )
{
// Assumes that the m_CSBlockList is already locked, we're being called from SetBlock()
for ( cBlockEntityList :: iterator itr = m_BlockEntities . begin (); itr != m_BlockEntities . end (); ++ itr )
{
if (
(( * itr ) -> GetPosX () == a_X ) &&
(( * itr ) -> GetPosY () == a_Y ) &&
(( * itr ) -> GetPosZ () == a_Z )
)
{
return * itr ;
}
} // for itr - m_BlockEntities[]
return NULL ;
}
2012-02-15 14:22:44 +00:00
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 );
}
}
2012-02-13 21:47:03 +00: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 )
{
2012-03-09 13:42:28 +00:00
if ( ( * itr ) -> GetEntityType () != cEntity :: eEntityType_Pickup )
2012-02-13 21:47:03 +00:00
{
continue ; // Only pickups
}
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
{
2012-02-16 13:42:35 +00:00
MarkDirty ();
2012-02-13 21:47:03 +00:00
( reinterpret_cast < cPickup *> ( * itr )) -> CollectedBy ( a_Player );
}
}
}
void cChunk :: UpdateSign ( int a_PosX , int a_PosY , int a_PosZ , const AString & a_Line1 , const AString & a_Line2 , const AString & a_Line3 , const AString & a_Line4 )
{
// Also sends update packets to all clients in the chunk
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 )
)
)
{
2012-02-16 13:42:35 +00:00
MarkDirty ();
2012-02-13 21:47:03 +00:00
( reinterpret_cast < cSignEntity *> ( * itr )) -> SetLines ( a_Line1 , a_Line2 , a_Line3 , a_Line4 );
( * itr ) -> SendTo ( NULL );
}
} // for itr - m_BlockEntities[]
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2011-10-03 18:41:19 +00:00
void cChunk :: RemoveBlockEntity ( cBlockEntity * a_BlockEntity )
{
2012-02-13 21:47:03 +00:00
cCSLock Lock ( m_CSBlockLists );
2012-02-16 13:42:35 +00:00
MarkDirty ();
2012-02-13 21:47:03 +00:00
m_BlockEntities . remove ( a_BlockEntity );
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2012-02-21 15:18:02 +00:00
bool cChunk :: AddClient ( cClientHandle * a_Client )
2011-10-03 18:41:19 +00:00
{
2012-02-23 21:21:37 +00:00
for ( cClientHandleList :: iterator itr = m_LoadedByClient . begin (); itr != m_LoadedByClient . end (); ++ itr )
2012-02-13 21:47:03 +00:00
{
2012-02-23 21:21:37 +00:00
if ( a_Client == * itr )
2012-02-21 15:18:02 +00:00
{
2012-02-23 21:21:37 +00:00
// Already there, nothing needed
return false ;
2012-02-21 15:18:02 +00:00
}
2012-02-13 21:47:03 +00:00
}
2012-02-23 21:21:37 +00:00
m_LoadedByClient . push_back ( a_Client );
2011-10-03 18:41:19 +00:00
2012-02-13 21:47:03 +00:00
for ( cEntityList :: iterator itr = m_Entities . begin (); itr != m_Entities . end (); ++ itr )
2011-10-03 18:41:19 +00:00
{
2012-02-21 15:18:02 +00:00
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 () );
2011-10-03 18:41:19 +00:00
( * itr ) -> SpawnOn ( a_Client );
}
2012-02-21 15:18:02 +00:00
return true ;
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2011-10-03 18:41:19 +00:00
void cChunk :: RemoveClient ( cClientHandle * a_Client )
{
2012-02-23 21:21:37 +00:00
m_LoadedByClient . remove ( a_Client );
2011-10-03 18:41:19 +00:00
2012-02-13 21:47:03 +00:00
if ( ! a_Client -> IsDestroyed () )
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
for ( cEntityList :: iterator itr = m_Entities . begin (); itr != m_Entities . end (); ++ itr )
2011-11-02 20:19:57 +00:00
{
2012-02-13 21:47:03 +00:00
LOG ( "chunk [%i, %i] destroying entity #%i for player \" %s \" " , m_PosX , m_PosZ , ( * itr ) -> GetUniqueID (), a_Client -> GetUsername (). c_str () );
2011-11-02 20:19:57 +00:00
cPacket_DestroyEntity DestroyEntity ( * itr );
a_Client -> Send ( DestroyEntity );
}
2011-10-03 18:41:19 +00:00
}
}
2012-02-08 19:49:57 +00:00
2012-02-13 21:47:03 +00:00
bool cChunk :: HasClient ( cClientHandle * a_Client )
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
for ( cClientHandleList :: const_iterator itr = m_LoadedByClient . begin (); itr != m_LoadedByClient . end (); ++ itr )
{
if (( * itr ) == a_Client )
{
return true ;
}
}
return false ;
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2012-02-16 17:45:26 +00:00
bool cChunk :: HasAnyClients ( void )
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
return ! m_LoadedByClient . empty ();
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2012-02-20 16:39:00 +00:00
void cChunk :: AddEntity ( cEntity * a_Entity )
2011-10-03 18:41:19 +00:00
{
2012-03-09 13:42:28 +00:00
if ( a_Entity -> GetEntityType () != cEntity :: eEntityType_Player )
2012-02-16 13:42:35 +00:00
{
MarkDirty ();
}
2012-02-13 21:47:03 +00:00
m_Entities . push_back ( a_Entity );
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2012-02-13 21:47:03 +00:00
void cChunk :: RemoveEntity ( cEntity * a_Entity )
2011-10-03 18:41:19 +00:00
{
2012-02-23 21:21:37 +00:00
size_t SizeBefore = m_Entities . size ();
m_Entities . remove ( a_Entity );
size_t SizeAfter = m_Entities . size ();
2012-02-20 16:39:00 +00:00
if ( SizeBefore != SizeAfter )
2012-02-16 13:42:35 +00:00
{
2012-02-20 16:39:00 +00:00
// Mark as dirty if it was a server-generated entity:
2012-03-09 13:42:28 +00:00
if ( a_Entity -> GetEntityType () != cEntity :: eEntityType_Player )
2012-02-20 16:39:00 +00:00
{
MarkDirty ();
}
2012-02-16 13:42:35 +00:00
}
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2012-03-14 20:56:09 +00:00
BLOCKTYPE cChunk :: GetBlock ( int a_X , int a_Y , int a_Z )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
if (( a_X < 0 ) || ( a_X >= Width ) || ( a_Y < 0 ) || ( a_Y >= Height ) || ( a_Z < 0 ) || ( a_Z >= Width )) return 0 ; // Clip
2011-10-03 18:41:19 +00:00
2012-03-14 20:56:09 +00:00
return m_BlockTypes [ MakeIndexNoCheck ( a_X , a_Y , a_Z ) ];
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2012-03-14 20:56:09 +00:00
BLOCKTYPE cChunk :: GetBlock ( int a_BlockIdx )
2011-10-03 18:41:19 +00:00
{
2012-03-14 20:56:09 +00:00
if ( a_BlockIdx < 0 || a_BlockIdx >= NumBlocks ) return 0 ;
return m_BlockTypes [ a_BlockIdx ];
2011-10-03 18:41:19 +00:00
}
2012-02-08 19:49:57 +00:00
2012-02-23 21:21:37 +00:00
/*
// _X 2012_02_23: Loading in old format not supported anymore
2012-01-30 16:01:45 +00:00
/// Loads the chunk from the old-format disk file, erases the file afterwards. Returns true if successful
2011-10-03 18:41:19 +00:00
bool cChunk::LoadFromDisk()
{
2012-02-01 13:43:47 +00:00
AString SourceFile;
Printf(SourceFile, "world/X%i_Y%i_Z%i.bin", m_PosX, m_PosY, m_PosZ );
2012-01-30 16:01:45 +00:00
cFile f;
if (!f.Open(SourceFile, cFile::fmRead))
2011-10-03 18:41:19 +00:00
{
2012-01-30 16:01:45 +00:00
return false;
}
2011-10-03 18:41:19 +00:00
2012-01-30 16:01:45 +00:00
if (f.Read(m_BlockData, sizeof(m_BlockData)) != sizeof(m_BlockData))
{
2012-02-01 13:50:09 +00:00
LOGERROR("ERROR READING FROM FILE %s", SourceFile.c_str());
2012-01-30 16:01:45 +00:00
return false;
}
2012-02-23 21:21:37 +00:00
// Now load Block Entities:
2012-01-30 16:01:45 +00:00
ENUM_BLOCK_ID BlockType;
while (f.Read(&BlockType, sizeof(ENUM_BLOCK_ID)) == sizeof(ENUM_BLOCK_ID))
{
switch (BlockType)
2011-10-03 18:41:19 +00:00
{
case E_BLOCK_CHEST:
2012-01-30 16:01:45 +00:00
{
2012-02-13 21:47:03 +00:00
cChestEntity * ChestEntity = new cChestEntity( 0, 0, 0, m_World );
2012-01-30 16:01:45 +00:00
if (!ChestEntity->LoadFromFile(f))
2011-10-03 18:41:19 +00:00
{
2012-02-01 13:50:09 +00:00
LOGERROR("ERROR READING CHEST FROM FILE %s", SourceFile.c_str());
2012-01-30 16:01:45 +00:00
delete ChestEntity;
return false;
2011-10-03 18:41:19 +00:00
}
2012-02-13 21:47:03 +00:00
m_BlockEntities.push_back( ChestEntity );
2011-10-03 18:41:19 +00:00
break;
2012-01-30 16:01:45 +00:00
}
2011-10-03 18:41:19 +00:00
case E_BLOCK_FURNACE:
2012-01-30 16:01:45 +00:00
{
2012-02-13 21:47:03 +00:00
cFurnaceEntity* FurnaceEntity = new cFurnaceEntity( 0, 0, 0, m_World );
2012-01-30 16:01:45 +00:00
if (!FurnaceEntity->LoadFromFile(f))
2011-10-03 18:41:19 +00:00
{
2012-02-01 13:50:09 +00:00
LOGERROR("ERROR READING FURNACE FROM FILE %s", SourceFile.c_str());
2012-01-30 16:01:45 +00:00
delete FurnaceEntity;
return false;
2011-10-03 18:41:19 +00:00
}
2012-02-13 21:47:03 +00:00
m_BlockEntities.push_back( FurnaceEntity );
2011-10-03 18:41:19 +00:00
break;
2012-01-30 16:01:45 +00:00
}
2011-10-03 18:41:19 +00:00
case E_BLOCK_SIGN_POST:
case E_BLOCK_WALLSIGN:
2012-01-30 16:01:45 +00:00
{
2012-02-13 21:47:03 +00:00
cSignEntity * SignEntity = new cSignEntity(BlockType, 0, 0, 0, m_World );
2012-01-30 16:01:45 +00:00
if (!SignEntity->LoadFromFile( f ) )
2011-10-03 18:41:19 +00:00
{
2012-02-01 13:50:09 +00:00
LOGERROR("ERROR READING SIGN FROM FILE %s", SourceFile.c_str());
2012-01-30 16:01:45 +00:00
delete SignEntity;
return false;
2011-10-03 18:41:19 +00:00
}
2012-02-13 21:47:03 +00:00
m_BlockEntities.push_back( SignEntity );
2011-10-03 18:41:19 +00:00
break;
2012-01-30 16:01:45 +00:00
}
2011-10-03 18:41:19 +00:00
default:
2012-01-30 16:01:45 +00:00
{
2012-02-19 23:00:00 +00:00
ASSERT(!"Unhandled block entity in file");
2011-10-03 18:41:19 +00:00
break;
}
}
2012-01-30 16:01:45 +00:00
}
f.Close();
2011-10-03 18:41:19 +00:00
2012-01-30 16:01:45 +00:00
// Delete old format file
2012-02-01 13:43:47 +00:00
if (std::remove(SourceFile.c_str()) != 0)
2012-01-30 16:01:45 +00:00
{
2012-02-01 13:50:09 +00:00
LOGERROR("Could not delete file %s", SourceFile.c_str());
2011-10-03 18:41:19 +00:00
}
else
{
2012-02-01 13:50:09 +00:00
LOGINFO("Successfully deleted old format file \"%s\"", SourceFile.c_str());
2011-10-03 18:41:19 +00:00
}
2012-02-16 13:42:35 +00:00
m_IsDirty = false;
2012-01-30 16:01:45 +00:00
return true;
2011-10-03 18:41:19 +00:00
}
2012-02-23 21:21:37 +00:00
*/
2011-10-03 18:41:19 +00:00
2012-01-30 16:01:45 +00:00
2012-02-13 21:47:03 +00:00
void cChunk :: Broadcast ( const cPacket * a_Packet , cClientHandle * a_Exclude )
2011-10-03 18:41:19 +00:00
{
2012-02-13 21:47:03 +00:00
for ( cClientHandleList :: const_iterator itr = m_LoadedByClient . begin (); itr != m_LoadedByClient . end (); ++ itr )
2011-10-03 18:41:19 +00:00
{
2012-01-30 16:01:45 +00:00
if ( * itr == a_Exclude )
{
continue ;
}
2012-03-10 21:34:47 +00:00
( * itr ) -> Send ( * a_Packet );
2012-01-30 16:01:45 +00:00
} // for itr - LoadedByClient[]
2011-10-03 18:41:19 +00:00
}
2012-01-30 16:01:45 +00:00
2011-12-22 21:36:24 +00:00
void cChunk :: PositionToWorldPosition ( int a_ChunkX , int a_ChunkY , int a_ChunkZ , int & a_X , int & a_Y , int & a_Z )
{
a_Y = a_ChunkY ;
2012-03-14 20:56:09 +00:00
a_X = m_PosX * Width + a_ChunkX ;
a_Z = m_PosZ * Width + a_ChunkZ ;
2011-12-31 21:08:23 +00:00
}
2012-01-30 16:01:45 +00:00
2012-03-10 00:25:05 +00:00
Vector3i cChunk :: PositionToWorldPosition ( int a_ChunkX , int a_ChunkY , int a_ChunkZ )
2012-03-01 15:18:59 +00:00
{
2012-03-14 20:56:09 +00:00
return Vector3i ( m_PosX * Width + a_ChunkX , m_PosY * Height + a_ChunkY , m_PosZ * Width + a_ChunkZ );
2012-03-01 15:18:59 +00:00
}
2011-12-31 21:08:23 +00:00
#if !C_CHUNK_USE_INLINE
2012-03-10 00:25:05 +00:00
# include "cChunk.inl.h"
2012-01-30 16:01:45 +00:00
#endif