2014-08-19 16:14:37 -04:00
2012-06-14 09:06:06 -04:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
# include "BlockID.h"
2012-09-23 18:09:57 -04:00
# include "World.h"
2012-06-14 09:06:06 -04:00
# include "ChunkDef.h"
2012-09-23 18:09:57 -04:00
# include "ClientHandle.h"
# include "Server.h"
# include "Item.h"
# include "Root.h"
2013-11-26 12:06:00 -05:00
# include "inifile/iniFile.h"
2012-09-23 18:09:57 -04:00
# include "ChunkMap.h"
2014-01-10 16:22:54 -05:00
# include "Generating/ChunkDesc.h"
2013-08-19 16:23:25 -04:00
# include "OSSupport/Timer.h"
2014-07-24 12:32:05 -04:00
# include "SetChunkData.h"
2014-02-13 14:36:24 -05:00
2014-02-20 09:38:37 -05:00
// Serializers
2014-01-22 08:49:21 -05:00
# include "WorldStorage/ScoreboardSerializer.h"
2012-10-13 05:53:28 -04:00
2013-08-22 02:55:58 -04:00
// Entities (except mobs):
2013-11-25 15:03:26 -05:00
# include "Entities/ExpOrb.h"
2013-12-07 08:26:52 -05:00
# include "Entities/FallingBlock.h"
2014-01-12 08:33:32 -05:00
# include "Entities/Minecart.h"
2013-08-22 02:55:58 -04:00
# include "Entities/Pickup.h"
# include "Entities/Player.h"
# include "Entities/TNTEntity.h"
2014-01-23 07:57:04 -05:00
# include "BlockEntities/CommandBlockEntity.h"
2014-07-30 16:19:51 -04:00
# include "BlockEntities/BeaconEntity.h"
2014-01-23 07:57:04 -05:00
2012-10-13 05:53:28 -04:00
// Simulators:
# include "Simulator/SimulatorManager.h"
2012-10-14 13:06:21 -04:00
# include "Simulator/FloodyFluidSimulator.h"
2012-10-13 05:53:28 -04:00
# include "Simulator/FluidSimulator.h"
# include "Simulator/FireSimulator.h"
2013-03-14 16:03:42 -04:00
# include "Simulator/NoopFluidSimulator.h"
2014-02-07 16:13:55 -05:00
# include "Simulator/NoopRedstoneSimulator.h"
2012-10-13 05:53:28 -04:00
# include "Simulator/SandSimulator.h"
2014-02-07 16:59:08 -05:00
# include "Simulator/IncrementalRedstoneSimulator.h"
2014-03-05 08:54:38 -05:00
# include "Simulator/VanillaFluidSimulator.h"
2013-03-14 15:44:27 -04:00
# include "Simulator/VaporizeFluidSimulator.h"
2012-09-23 16:53:08 -04:00
// Mobs:
2013-09-07 14:07:56 -04:00
# include "Mobs/IncludeAllMonsters.h"
2013-09-07 16:19:56 -04:00
# include "MobCensus.h"
2013-09-07 20:47:02 -04:00
# include "MobSpawner.h"
2012-09-23 16:53:08 -04:00
2012-06-14 09:06:06 -04:00
# include "MersenneTwister.h"
2012-09-23 16:14:04 -04:00
# include "Generating/Trees.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"
2012-06-14 09:06:06 -04:00
2013-08-19 05:39:13 -04:00
# include "Tracer.h"
2012-06-14 09:06:06 -04:00
2013-08-04 10:08:09 -04:00
// DEBUG: Test out the cLineBlockTracer class by tracing a few lines:
# include "LineBlockTracer.h"
2012-06-14 09:06:06 -04:00
# ifndef _WIN32
# include <stdlib.h>
# endif
2013-10-30 18:33:42 -04:00
const int TIME_SUNSET = 12000 ;
const int TIME_NIGHT_START = 13187 ;
const int TIME_NIGHT_END = 22812 ;
const int TIME_SUNRISE = 23999 ;
const int TIME_SPAWN_DIVISOR = 148 ;
2012-06-14 09:06:06 -04:00
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2012-06-14 09:06:06 -04:00
// cWorldLoadProgress:
/// A simple thread that displays the progress of world loading / saving in cWorld::InitializeSpawn()
class cWorldLoadProgress :
public cIsThread
{
public :
cWorldLoadProgress ( cWorld * a_World ) :
cIsThread ( " cWorldLoadProgress " ) ,
m_World ( a_World )
{
Start ( ) ;
}
void Stop ( void )
{
m_ShouldTerminate = true ;
Wait ( ) ;
}
protected :
cWorld * m_World ;
virtual void Execute ( void ) override
{
for ( ; ; )
{
2014-07-17 10:33:09 -04:00
LOG ( " " SIZE_T_FMT " chunks to load, %d chunks to generate " ,
2012-06-14 09:06:06 -04:00
m_World - > GetStorage ( ) . GetLoadQueueLength ( ) ,
m_World - > GetGenerator ( ) . GetQueueLength ( )
) ;
// Wait for 2 sec, but be "reasonably wakeable" when the thread is to finish
for ( int i = 0 ; i < 20 ; i + + )
{
cSleep : : MilliSleep ( 100 ) ;
if ( m_ShouldTerminate )
{
return ;
}
}
} // for (-ever)
}
} ;
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2013-08-11 13:18:06 -04:00
// cWorldLightingProgress:
2012-06-14 09:06:06 -04:00
/// A simple thread that displays the progress of world lighting in cWorld::InitializeSpawn()
class cWorldLightingProgress :
public cIsThread
{
public :
cWorldLightingProgress ( cLightingThread * a_Lighting ) :
cIsThread ( " cWorldLightingProgress " ) ,
m_Lighting ( a_Lighting )
{
Start ( ) ;
}
void Stop ( void )
{
m_ShouldTerminate = true ;
Wait ( ) ;
}
protected :
cLightingThread * m_Lighting ;
virtual void Execute ( void ) override
{
for ( ; ; )
{
2014-03-12 13:34:50 -04:00
LOG ( " " SIZE_T_FMT " chunks remaining to light " , m_Lighting - > GetQueueLength ( )
2012-06-14 09:06:06 -04:00
) ;
// Wait for 2 sec, but be "reasonably wakeable" when the thread is to finish
for ( int i = 0 ; i < 20 ; i + + )
{
cSleep : : MilliSleep ( 100 ) ;
if ( m_ShouldTerminate )
{
return ;
}
}
} // for (-ever)
}
} ;
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2013-06-15 11:29:20 -04:00
// cWorld::cLock:
cWorld : : cLock : : cLock ( cWorld & a_World ) :
super ( & ( a_World . m_ChunkMap - > GetCS ( ) ) )
{
}
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2013-08-11 13:18:06 -04:00
// cWorld::cTickThread:
2012-06-14 09:06:06 -04:00
2013-08-11 13:18:06 -04:00
cWorld : : cTickThread : : cTickThread ( cWorld & a_World ) :
super ( Printf ( " WorldTickThread: %s " , a_World . GetName ( ) . c_str ( ) ) ) ,
m_World ( a_World )
2012-06-14 09:06:06 -04:00
{
2013-08-11 13:18:06 -04:00
}
2012-06-14 09:06:06 -04:00
2013-08-11 13:18:06 -04:00
void cWorld : : cTickThread : : Execute ( void )
{
2013-08-19 16:23:25 -04:00
cTimer Timer ;
2013-11-30 08:22:26 -05:00
const Int64 msPerTick = 50 ;
Int64 LastTime = Timer . GetNowTime ( ) ;
2013-08-19 16:23:25 -04:00
2013-11-30 08:22:26 -05:00
Int64 TickDuration = 50 ;
2013-08-11 13:18:06 -04:00
while ( ! m_ShouldTerminate )
2013-03-11 13:15:34 -04:00
{
2013-11-30 08:22:26 -05:00
Int64 NowTime = Timer . GetNowTime ( ) ;
2013-08-19 16:23:25 -04:00
float DeltaTime = ( float ) ( NowTime - LastTime ) ;
2013-11-30 08:22:26 -05:00
m_World . Tick ( DeltaTime , ( int ) TickDuration ) ;
TickDuration = Timer . GetNowTime ( ) - NowTime ;
2013-08-19 16:23:25 -04:00
2013-11-30 08:22:26 -05:00
if ( TickDuration < msPerTick )
2013-03-11 13:15:34 -04:00
{
2013-08-19 16:23:25 -04:00
// Stretch tick time until it's at least msPerTick
2013-11-30 08:22:26 -05:00
cSleep : : MilliSleep ( ( unsigned int ) ( msPerTick - TickDuration ) ) ;
2013-03-11 13:15:34 -04:00
}
2013-08-19 16:23:25 -04:00
LastTime = NowTime ;
2012-06-14 09:06:06 -04:00
}
2013-08-11 13:18:06 -04:00
}
2012-06-14 09:06:06 -04:00
2012-07-15 16:36:34 -04:00
2012-06-14 09:06:06 -04:00
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2012-06-14 09:06:06 -04:00
// cWorld:
2012-10-14 13:06:21 -04:00
2014-06-10 15:43:27 -04:00
cWorld : : cWorld ( const AString & a_WorldName , eDimension a_Dimension , const AString & a_OverworldName ) :
2013-08-11 13:18:06 -04:00
m_WorldName ( a_WorldName ) ,
2014-06-12 13:56:48 -04:00
m_OverworldName ( a_OverworldName ) ,
2013-08-11 13:18:06 -04:00
m_IniFileName ( m_WorldName + " /world.ini " ) ,
2013-08-11 14:16:41 -04:00
m_StorageSchema ( " Default " ) ,
2014-01-30 12:02:37 -05:00
# ifdef __arm__
2014-01-25 16:29:27 -05:00
m_StorageCompressionFactor ( 0 ) ,
2014-01-25 09:42:26 -05:00
# else
2014-01-17 14:01:14 -05:00
m_StorageCompressionFactor ( 6 ) ,
2014-01-25 09:42:26 -05:00
# endif
2014-06-12 13:56:48 -04:00
m_Dimension ( a_Dimension ) ,
2013-12-20 13:10:07 -05:00
m_IsSpawnExplicitlySet ( false ) ,
2014-08-10 10:46:03 -04:00
m_IsDaylightCycleEnabled ( true ) ,
2012-11-01 17:38:20 -04:00
m_WorldAgeSecs ( 0 ) ,
m_TimeOfDaySecs ( 0 ) ,
m_WorldAge ( 0 ) ,
m_TimeOfDay ( 0 ) ,
m_LastTimeUpdate ( 0 ) ,
2013-12-20 13:10:07 -05:00
m_SkyDarkness ( 0 ) ,
2014-08-21 15:53:25 -04:00
m_GameMode ( gmNotSet ) ,
m_bEnabledPVP ( false ) ,
m_IsDeepSnowEnabled ( false ) ,
m_ShouldLavaSpawnFire ( true ) ,
m_VillagersShouldHarvestCrops ( true ) ,
m_SimulatorManager ( NULL ) ,
m_SandSimulator ( NULL ) ,
m_WaterSimulator ( NULL ) ,
m_LavaSimulator ( NULL ) ,
m_FireSimulator ( NULL ) ,
m_RedstoneSimulator ( NULL ) ,
m_MaxPlayers ( 10 ) ,
m_ChunkMap ( NULL ) ,
m_bAnimals ( true ) ,
2012-10-25 15:20:29 -04:00
m_Weather ( eWeather_Sunny ) ,
2013-08-11 13:18:06 -04:00
m_WeatherInterval ( 24000 ) , // Guaranteed 1 day of sunshine at server start :)
2014-08-21 15:53:25 -04:00
m_MaxCactusHeight ( 3 ) ,
m_MaxSugarcaneHeight ( 4 ) ,
m_IsCactusBonemealable ( false ) ,
m_IsCarrotsBonemealable ( true ) ,
m_IsCropsBonemealable ( true ) ,
m_IsGrassBonemealable ( true ) ,
m_IsMelonStemBonemealable ( true ) ,
m_IsMelonBonemealable ( true ) ,
m_IsPotatoesBonemealable ( true ) ,
m_IsPumpkinStemBonemealable ( true ) ,
m_IsPumpkinBonemealable ( true ) ,
m_IsSaplingBonemealable ( true ) ,
m_IsSugarcaneBonemealable ( false ) ,
m_bCommandBlocksEnabled ( true ) ,
m_bUseChatPrefixes ( false ) ,
m_TNTShrapnelLevel ( slNone ) ,
2014-02-05 12:43:49 -05:00
m_Scoreboard ( this ) ,
2014-02-23 08:03:40 -05:00
m_MapManager ( this ) ,
2014-01-10 16:22:54 -05:00
m_GeneratorCallbacks ( * this ) ,
2014-07-23 16:12:59 -04:00
m_TickThread ( * this )
2012-06-14 09:06:06 -04:00
{
2013-08-11 15:05:44 -04:00
LOGD ( " cWorld::cWorld( \" %s \" ) " , a_WorldName . c_str ( ) ) ;
2012-06-14 09:06:06 -04:00
2013-10-09 03:57:48 -04:00
cFile : : CreateFolder ( FILE_IO_PREFIX + m_WorldName ) ;
2014-01-22 08:49:21 -05:00
// Load the scoreboard
cScoreboardSerializer Serializer ( m_WorldName , & m_Scoreboard ) ;
Serializer . Load ( ) ;
2012-06-14 09:06:06 -04:00
}
2013-01-11 23:46:01 -05:00
cWorld : : ~ cWorld ( )
{
2014-06-19 04:49:56 -04:00
delete m_SimulatorManager ; m_SimulatorManager = NULL ;
delete m_SandSimulator ; m_SandSimulator = NULL ;
delete m_WaterSimulator ; m_WaterSimulator = NULL ;
delete m_LavaSimulator ; m_LavaSimulator = NULL ;
delete m_FireSimulator ; m_FireSimulator = NULL ;
delete m_RedstoneSimulator ; m_RedstoneSimulator = NULL ;
2013-01-11 23:46:01 -05:00
UnloadUnusedChunks ( ) ;
m_Storage . WaitForFinish ( ) ;
2014-01-22 08:49:21 -05:00
// Unload the scoreboard
cScoreboardSerializer Serializer ( m_WorldName , & m_Scoreboard ) ;
Serializer . Save ( ) ;
2014-02-23 08:03:40 -05:00
m_MapManager . SaveMapData ( ) ;
2014-02-13 14:36:24 -05:00
2013-01-11 23:46:01 -05:00
delete m_ChunkMap ;
}
2013-02-13 14:22:08 -05:00
void cWorld : : CastThunderbolt ( int a_BlockX , int a_BlockY , int a_BlockZ )
{
BroadcastThunderbolt ( a_BlockX , a_BlockY , a_BlockZ ) ;
}
2014-03-02 15:04:01 -05:00
int cWorld : : GetDefaultWeatherInterval ( eWeather a_Weather )
{
switch ( a_Weather )
{
case eWeather_Sunny :
{
return 14400 + ( m_TickRand . randInt ( ) % 4800 ) ; // 12 - 16 minutes
}
case eWeather_Rain :
{
return 9600 + ( m_TickRand . randInt ( ) % 7200 ) ; // 8 - 14 minutes
}
case eWeather_ThunderStorm :
{
return 2400 + ( m_TickRand . randInt ( ) % 4800 ) ; // 2 - 6 minutes
}
2014-04-24 23:25:03 -04:00
}
LOGWARNING ( " %s: Missing default weather interval for weather %d. " , __FUNCTION__ , a_Weather ) ;
return - 1 ;
2014-03-02 15:04:01 -05:00
}
2013-02-13 14:22:08 -05:00
void cWorld : : SetWeather ( eWeather a_NewWeather )
2012-06-14 09:06:06 -04:00
{
2013-02-13 14:22:08 -05:00
// Do the plugins agree? Do they want a different weather?
2014-03-02 15:04:01 -05:00
if ( cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHookWeatherChanging ( * this , a_NewWeather ) )
{
m_WeatherInterval = GetDefaultWeatherInterval ( m_Weather ) ;
return ;
}
2013-02-13 14:22:08 -05:00
// Set new period for the selected weather:
2014-03-02 15:04:01 -05:00
m_WeatherInterval = GetDefaultWeatherInterval ( a_NewWeather ) ;
// The weather can't be found:
2014-03-03 14:55:04 -05:00
if ( m_WeatherInterval < 0 )
2012-06-14 09:06:06 -04:00
{
2014-03-02 15:04:01 -05:00
return ;
}
2013-02-13 14:22:08 -05:00
m_Weather = a_NewWeather ;
BroadcastWeather ( m_Weather ) ;
// Let the plugins know about the change:
cPluginManager : : Get ( ) - > CallHookWeatherChanged ( * this ) ;
2012-06-14 09:06:06 -04:00
}
2013-02-13 14:22:08 -05:00
void cWorld : : ChangeWeather ( void )
2012-06-14 09:06:06 -04:00
{
2013-02-13 14:22:08 -05:00
// In the next tick the weather will be changed
m_WeatherInterval = 0 ;
2012-06-14 09:06:06 -04:00
}
2012-08-25 17:46:18 -04:00
2012-06-14 09:06:06 -04:00
void cWorld : : SetNextBlockTick ( int a_BlockX , int a_BlockY , int a_BlockZ )
{
return m_ChunkMap - > SetNextBlockTick ( a_BlockX , a_BlockY , a_BlockZ ) ;
}
2012-08-25 17:46:18 -04:00
2012-06-14 09:06:06 -04:00
void cWorld : : InitializeSpawn ( void )
{
2014-07-17 13:13:23 -04:00
if ( ! m_IsSpawnExplicitlySet )
2013-11-26 16:54:40 -05:00
{
2014-07-17 13:13:23 -04:00
// Spawn position wasn't already explicitly set, enerate random solid-land coordinate and then write it to the world configuration:
GenerateRandomSpawn ( ) ;
2013-11-26 16:54:40 -05:00
cIniFile IniFile ;
IniFile . ReadFile ( m_IniFileName ) ;
IniFile . SetValueF ( " SpawnPosition " , " X " , m_SpawnX ) ;
IniFile . SetValueF ( " SpawnPosition " , " Y " , m_SpawnY ) ;
IniFile . SetValueF ( " SpawnPosition " , " Z " , m_SpawnZ ) ;
IniFile . WriteFile ( m_IniFileName ) ;
}
2014-07-06 18:50:22 -04:00
int ChunkX = 0 , ChunkZ = 0 ;
cChunkDef : : BlockToChunk ( ( int ) m_SpawnX , ( int ) m_SpawnZ , ChunkX , ChunkZ ) ;
2012-06-14 09:06:06 -04:00
// For the debugging builds, don't make the server build too much world upon start:
2012-11-16 17:06:12 -05:00
# if defined(_DEBUG) || defined(ANDROID_NDK)
2014-05-09 12:31:48 -04:00
const int DefaultViewDist = 9 ;
2012-06-14 09:06:06 -04:00
# else
2014-05-09 12:31:48 -04:00
const int DefaultViewDist = 20 ; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is
2012-06-14 09:06:06 -04:00
# endif // _DEBUG
2014-05-09 12:31:48 -04:00
cIniFile IniFile ;
IniFile . ReadFile ( m_IniFileName ) ;
int ViewDist = IniFile . GetValueSetI ( " SpawnPosition " , " PregenerateDistance " , DefaultViewDist ) ;
IniFile . WriteFile ( m_IniFileName ) ;
2012-06-14 09:06:06 -04:00
2014-08-22 04:35:51 -04:00
LOG ( " Preparing spawn area in world \" %s \" , %d x %d chunks, total %d chunks... " , m_WorldName . c_str ( ) , ViewDist , ViewDist , ViewDist * ViewDist ) ;
2012-06-14 09:06:06 -04:00
for ( int x = 0 ; x < ViewDist ; x + + )
{
for ( int z = 0 ; z < ViewDist ; z + + )
{
2014-08-28 05:36:35 -04:00
m_ChunkMap - > TouchChunk ( x + ChunkX - ( ViewDist - 1 ) / 2 , z + ChunkZ - ( ViewDist - 1 ) / 2 ) ; // Queue the chunk in the generator / loader
2012-06-14 09:06:06 -04:00
}
}
{
// Display progress during this process:
cWorldLoadProgress Progress ( this ) ;
// Wait for the loader to finish loading
2014-01-02 07:32:55 -05:00
m_Storage . WaitForLoadQueueEmpty ( ) ;
2012-06-14 09:06:06 -04:00
// Wait for the generator to finish generating
m_Generator . WaitForQueueEmpty ( ) ;
2014-01-02 07:32:55 -05:00
// Wait for the loader to finish saving
m_Storage . WaitForSaveQueueEmpty ( ) ;
2012-06-14 09:06:06 -04:00
Progress . Stop ( ) ;
}
// Light all chunks that have been newly generated:
LOG ( " Lighting spawn area in world \" %s \" ... " , m_WorldName . c_str ( ) ) ;
for ( int x = 0 ; x < ViewDist ; x + + )
{
int ChX = x + ChunkX - ( ViewDist - 1 ) / 2 ;
for ( int z = 0 ; z < ViewDist ; z + + )
{
int ChZ = z + ChunkZ - ( ViewDist - 1 ) / 2 ;
if ( ! m_ChunkMap - > IsChunkLighted ( ChX , ChZ ) )
{
m_Lighting . QueueChunk ( ChX , ChZ ) ; // Queue the chunk in the lighting thread
}
} // for z
} // for x
{
cWorldLightingProgress Progress ( & m_Lighting ) ;
m_Lighting . WaitForQueueEmpty ( ) ;
Progress . Stop ( ) ;
}
2013-08-04 10:08:09 -04:00
# ifdef TEST_LINEBLOCKTRACER
// DEBUG: Test out the cLineBlockTracer class by tracing a few lines:
class cTracerCallbacks :
public cBlockTracer : : cCallbacks
{
virtual bool OnNextBlock ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta ) override
{
LOGD ( " Block {%d, %d, %d}: %d:%d (%s) " ,
a_BlockX , a_BlockY , a_BlockZ , a_BlockType , a_BlockMeta ,
ItemToString ( cItem ( a_BlockType , 1 , a_BlockMeta ) ) . c_str ( )
) ;
return false ;
}
virtual bool OnNextBlockNoData ( int a_BlockX , int a_BlockY , int a_BlockZ ) override
{
LOGD ( " Block {%d, %d, %d}: no data available " ,
a_BlockX , a_BlockY , a_BlockZ
) ;
return false ;
}
virtual bool OnOutOfWorld ( double a_BlockX , double a_BlockY , double a_BlockZ ) override
{
LOGD ( " Out of world at {%f, %f, %f} " , a_BlockX , a_BlockY , a_BlockZ ) ;
return false ;
}
virtual bool OnIntoWorld ( double a_BlockX , double a_BlockY , double a_BlockZ ) override
{
LOGD ( " Into world at {%f, %f, %f} " , a_BlockX , a_BlockY , a_BlockZ ) ;
return false ;
}
virtual void OnNoMoreHits ( void ) override
{
LOGD ( " No more hits " ) ;
}
} Callbacks ;
LOGD ( " Spawn is at {%f, %f, %f} " , m_SpawnX , m_SpawnY , m_SpawnZ ) ;
LOGD ( " Tracing a line along +X: " ) ;
cLineBlockTracer : : Trace ( * this , Callbacks , m_SpawnX - 10 , m_SpawnY , m_SpawnZ , m_SpawnX + 10 , m_SpawnY , m_SpawnZ ) ;
LOGD ( " Tracing a line along -Z: " ) ;
cLineBlockTracer : : Trace ( * this , Callbacks , m_SpawnX , m_SpawnY , m_SpawnZ + 10 , m_SpawnX , m_SpawnY , m_SpawnZ - 10 ) ;
LOGD ( " Tracing a line along -Y, out of world: " ) ;
cLineBlockTracer : : Trace ( * this , Callbacks , m_SpawnX , 260 , m_SpawnZ , m_SpawnX , - 5 , m_SpawnZ ) ;
LOGD ( " Tracing a line along XY: " ) ;
cLineBlockTracer : : Trace ( * this , Callbacks , m_SpawnX - 10 , m_SpawnY - 10 , m_SpawnZ , m_SpawnX + 10 , m_SpawnY + 10 , m_SpawnZ ) ;
LOGD ( " Tracing a line in generic direction: " ) ;
cLineBlockTracer : : Trace ( * this , Callbacks , m_SpawnX - 15 , m_SpawnY - 5 , m_SpawnZ + 7.5 , m_SpawnX + 13 , m_SpawnY - 10 , m_SpawnZ + 8.5 ) ;
LOGD ( " Tracing tests done " ) ;
# endif // TEST_LINEBLOCKTRACER
2012-06-14 09:06:06 -04:00
}
2014-07-21 17:49:06 -04:00
void cWorld : : Start ( void )
2012-07-15 16:07:38 -04:00
{
2013-11-26 16:54:40 -05:00
m_SpawnX = 0 ;
2013-08-11 14:16:41 -04:00
m_SpawnY = cChunkDef : : Height ;
2013-11-26 16:54:40 -05:00
m_SpawnZ = 0 ;
2013-08-11 14:16:41 -04:00
m_GameMode = eGameMode_Creative ;
2013-10-25 05:15:44 -04:00
cIniFile IniFile ;
if ( ! IniFile . ReadFile ( m_IniFileName ) )
2013-08-11 14:16:41 -04:00
{
LOGWARNING ( " Cannot read world settings from \" %s \" , defaults will be used. " , m_IniFileName . c_str ( ) ) ;
2014-07-20 05:46:45 -04:00
// TODO: More descriptions for each key
IniFile . AddHeaderComment ( " This is the per-world configuration file, managing settings such as generators, simulators, and spawn points " ) ;
2014-07-22 12:26:48 -04:00
IniFile . AddKeyComment ( " LinkedWorlds " , " This section governs portal world linkage; leave a value blank to disabled that associated method of teleportation " ) ;
2013-08-11 14:16:41 -04:00
}
2014-06-10 15:43:27 -04:00
2014-07-20 05:46:45 -04:00
// The presence of a configuration value overrides everything
// If no configuration value is found, GetDimension() is written to file and the variable is written to again to ensure that cosmic rays haven't sneakily changed its value
m_Dimension = StringToDimension ( IniFile . GetValueSet ( " General " , " Dimension " , DimensionToString ( GetDimension ( ) ) ) ) ;
2013-11-26 16:54:40 -05:00
2014-07-26 18:39:39 -04:00
m_BroadcastDeathMessages = IniFile . GetValueSetB ( " Broadcasting " , " BroadcastDeathMessages " , true ) ;
m_BroadcastAchievementMessages = IniFile . GetValueSetB ( " Broadcasting " , " BroadcastAchievementMessages " , true ) ;
2013-11-30 09:03:29 -05:00
// Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found
2013-11-26 16:54:40 -05:00
int KeyNum = IniFile . FindKey ( " SpawnPosition " ) ;
2013-12-20 13:10:07 -05:00
m_IsSpawnExplicitlySet =
2013-11-30 09:03:29 -05:00
(
( KeyNum > = 0 ) & &
(
2014-07-20 05:46:45 -04:00
( IniFile . FindValue ( KeyNum , " X " ) > = 0 ) & &
( IniFile . FindValue ( KeyNum , " Y " ) > = 0 ) & &
2013-11-30 09:03:29 -05:00
( IniFile . FindValue ( KeyNum , " Z " ) > = 0 )
)
) ;
2013-11-26 16:54:40 -05:00
2013-12-20 13:10:07 -05:00
if ( m_IsSpawnExplicitlySet )
2013-11-26 16:54:40 -05:00
{
2013-11-30 09:03:29 -05:00
LOGD ( " Spawnpoint explicitly set! " ) ;
2013-11-26 16:54:40 -05:00
m_SpawnX = IniFile . GetValueF ( " SpawnPosition " , " X " , m_SpawnX ) ;
m_SpawnY = IniFile . GetValueF ( " SpawnPosition " , " Y " , m_SpawnY ) ;
m_SpawnZ = IniFile . GetValueF ( " SpawnPosition " , " Z " , m_SpawnZ ) ;
}
2014-03-20 04:28:29 -04:00
m_StorageSchema = IniFile . GetValueSet ( " Storage " , " Schema " , m_StorageSchema ) ;
m_StorageCompressionFactor = IniFile . GetValueSetI ( " Storage " , " CompressionFactor " , m_StorageCompressionFactor ) ;
m_MaxCactusHeight = IniFile . GetValueSetI ( " Plants " , " MaxCactusHeight " , 3 ) ;
m_MaxSugarcaneHeight = IniFile . GetValueSetI ( " Plants " , " MaxSugarcaneHeight " , 3 ) ;
m_IsCactusBonemealable = IniFile . GetValueSetB ( " Plants " , " IsCactusBonemealable " , false ) ;
m_IsCarrotsBonemealable = IniFile . GetValueSetB ( " Plants " , " IsCarrotsBonemealable " , true ) ;
m_IsCropsBonemealable = IniFile . GetValueSetB ( " Plants " , " IsCropsBonemealable " , true ) ;
m_IsGrassBonemealable = IniFile . GetValueSetB ( " Plants " , " IsGrassBonemealable " , true ) ;
m_IsMelonStemBonemealable = IniFile . GetValueSetB ( " Plants " , " IsMelonStemBonemealable " , true ) ;
m_IsMelonBonemealable = IniFile . GetValueSetB ( " Plants " , " IsMelonBonemealable " , false ) ;
m_IsPotatoesBonemealable = IniFile . GetValueSetB ( " Plants " , " IsPotatoesBonemealable " , true ) ;
m_IsPumpkinStemBonemealable = IniFile . GetValueSetB ( " Plants " , " IsPumpkinStemBonemealable " , true ) ;
m_IsPumpkinBonemealable = IniFile . GetValueSetB ( " Plants " , " IsPumpkinBonemealable " , false ) ;
m_IsSaplingBonemealable = IniFile . GetValueSetB ( " Plants " , " IsSaplingBonemealable " , true ) ;
m_IsSugarcaneBonemealable = IniFile . GetValueSetB ( " Plants " , " IsSugarcaneBonemealable " , false ) ;
m_IsDeepSnowEnabled = IniFile . GetValueSetB ( " Physics " , " DeepSnow " , true ) ;
m_ShouldLavaSpawnFire = IniFile . GetValueSetB ( " Physics " , " ShouldLavaSpawnFire " , true ) ;
2014-04-15 08:15:56 -04:00
int TNTShrapnelLevel = IniFile . GetValueSetI ( " Physics " , " TNTShrapnelLevel " , ( int ) slAll ) ;
2014-03-20 04:28:29 -04:00
m_bCommandBlocksEnabled = IniFile . GetValueSetB ( " Mechanics " , " CommandBlocksEnabled " , false ) ;
m_bEnabledPVP = IniFile . GetValueSetB ( " Mechanics " , " PVPEnabled " , true ) ;
m_bUseChatPrefixes = IniFile . GetValueSetB ( " Mechanics " , " UseChatPrefixes " , true ) ;
m_VillagersShouldHarvestCrops = IniFile . GetValueSetB ( " Monsters " , " VillagersShouldHarvestCrops " , true ) ;
2014-08-10 10:48:20 -04:00
m_IsDaylightCycleEnabled = IniFile . GetValueSetB ( " General " , " IsDaylightCycleEnabled " , true ) ;
2014-03-20 04:28:29 -04:00
int GameMode = IniFile . GetValueSetI ( " General " , " Gamemode " , ( int ) m_GameMode ) ;
2014-06-04 15:52:54 -04:00
int Weather = IniFile . GetValueSetI ( " General " , " Weather " , ( int ) m_Weather ) ;
2014-08-01 17:15:14 -04:00
2014-07-22 05:33:16 -04:00
if ( GetDimension ( ) = = dimOverworld )
{
2014-07-23 16:12:59 -04:00
m_NetherWorldName = IniFile . GetValueSet ( " LinkedWorlds " , " NetherWorldName " , GetName ( ) + " _nether " ) ;
m_EndWorldName = IniFile . GetValueSet ( " LinkedWorlds " , " EndWorldName " , GetName ( ) + " _end " ) ;
2014-07-22 05:33:16 -04:00
}
2014-07-20 05:46:45 -04:00
else
{
m_OverworldName = IniFile . GetValueSet ( " LinkedWorlds " , " OverworldName " , GetLinkedOverworldName ( ) ) ;
}
2014-03-20 04:28:29 -04:00
// Adjust the enum-backed variables into their respective bounds:
m_GameMode = ( eGameMode ) Clamp ( GameMode , ( int ) gmSurvival , ( int ) gmAdventure ) ;
m_TNTShrapnelLevel = ( eShrapnelLevel ) Clamp ( TNTShrapnelLevel , ( int ) slNone , ( int ) slAll ) ;
2014-06-04 15:52:54 -04:00
m_Weather = ( eWeather ) Clamp ( Weather , ( int ) wSunny , ( int ) wStorm ) ;
2013-08-11 14:16:41 -04:00
2014-07-21 17:49:06 -04:00
InitialiseGeneratorDefaults ( IniFile ) ;
InitialiseAndLoadMobSpawningValues ( IniFile ) ;
2014-08-01 17:15:14 -04:00
SetTimeOfDay ( IniFile . GetValueSetI ( " General " , " TimeInTicks " , m_TimeOfDay ) ) ;
2013-08-11 14:16:41 -04:00
m_ChunkMap = new cChunkMap ( this ) ;
m_LastSave = 0 ;
m_LastUnload = 0 ;
2013-09-10 16:02:46 -04:00
// preallocate some memory for ticking blocks so we don't need to allocate that often
2013-08-11 14:16:41 -04:00
m_BlockTickQueue . reserve ( 1000 ) ;
m_BlockTickQueueCopy . reserve ( 1000 ) ;
// Simulators:
m_SimulatorManager = new cSimulatorManager ( * this ) ;
m_WaterSimulator = InitializeFluidSimulator ( IniFile , " Water " , E_BLOCK_WATER , E_BLOCK_STATIONARY_WATER ) ;
m_LavaSimulator = InitializeFluidSimulator ( IniFile , " Lava " , E_BLOCK_LAVA , E_BLOCK_STATIONARY_LAVA ) ;
m_SandSimulator = new cSandSimulator ( * this , IniFile ) ;
m_FireSimulator = new cFireSimulator ( * this , IniFile ) ;
2014-02-07 16:13:55 -05:00
m_RedstoneSimulator = InitializeRedstoneSimulator ( IniFile ) ;
2013-08-11 14:16:41 -04:00
2014-02-08 05:20:00 -05:00
// Water, Lava and Redstone simulators get registered in their initialize function.
2013-08-11 14:16:41 -04:00
m_SimulatorManager - > RegisterSimulator ( m_SandSimulator , 1 ) ;
m_SimulatorManager - > RegisterSimulator ( m_FireSimulator , 1 ) ;
m_Lighting . Start ( this ) ;
2014-07-21 09:19:48 -04:00
m_Storage . Start ( this , m_StorageSchema , m_StorageCompressionFactor ) ;
2014-01-10 16:22:54 -05:00
m_Generator . Start ( m_GeneratorCallbacks , m_GeneratorCallbacks , IniFile ) ;
2013-08-11 14:16:41 -04:00
m_ChunkSender . Start ( this ) ;
m_TickThread . Start ( ) ;
2013-09-07 20:47:02 -04:00
// Init of the spawn monster time (as they are supposed to have different spawn rate)
2013-10-20 04:23:30 -04:00
m_LastSpawnMonster . insert ( std : : map < cMonster : : eFamily , Int64 > : : value_type ( cMonster : : mfHostile , 0 ) ) ;
m_LastSpawnMonster . insert ( std : : map < cMonster : : eFamily , Int64 > : : value_type ( cMonster : : mfPassive , 0 ) ) ;
m_LastSpawnMonster . insert ( std : : map < cMonster : : eFamily , Int64 > : : value_type ( cMonster : : mfAmbient , 0 ) ) ;
m_LastSpawnMonster . insert ( std : : map < cMonster : : eFamily , Int64 > : : value_type ( cMonster : : mfWater , 0 ) ) ;
2013-09-07 20:47:02 -04:00
2014-03-04 12:40:55 -05:00
m_MapManager . LoadMapData ( ) ;
2013-09-07 20:47:02 -04:00
2013-08-11 14:16:41 -04:00
// Save any changes that the defaults may have done to the ini file:
2013-10-25 05:15:44 -04:00
if ( ! IniFile . WriteFile ( m_IniFileName ) )
2013-08-11 14:16:41 -04:00
{
LOGWARNING ( " Could not write world config to %s " , m_IniFileName . c_str ( ) ) ;
}
}
2013-11-26 16:54:40 -05:00
void cWorld : : GenerateRandomSpawn ( void )
{
LOGD ( " Generating random spawnpoint... " ) ;
2014-02-02 16:48:21 -05:00
while ( IsBlockWaterOrIce ( GetBlock ( ( int ) m_SpawnX , GetHeight ( ( int ) m_SpawnX , ( int ) m_SpawnZ ) , ( int ) m_SpawnZ ) ) )
2013-11-26 16:54:40 -05:00
{
2014-07-17 13:13:23 -04:00
if ( ( GetTickRandomNumber ( 4 ) % 2 ) = = 0 ) // Randomise whether to increment X or Z coords
2013-11-26 16:54:40 -05:00
{
m_SpawnX + = cChunkDef : : Width ;
}
else
{
m_SpawnZ + = cChunkDef : : Width ;
}
}
2014-07-17 13:13:23 -04:00
m_SpawnY = ( double ) GetHeight ( ( int ) m_SpawnX , ( int ) m_SpawnZ ) + 1.6f ; // 1.6f to accomodate player height
2013-11-26 16:54:40 -05:00
LOGD ( " Generated random spawnpoint %i %i %i " , ( int ) m_SpawnX , ( int ) m_SpawnY , ( int ) m_SpawnZ ) ;
}
2014-04-25 19:55:38 -04:00
eWeather cWorld : : ChooseNewWeather ( )
{
// Pick a new weather. Only reasonable transitions allowed:
switch ( m_Weather )
{
case eWeather_Sunny :
case eWeather_ThunderStorm : return eWeather_Rain ;
case eWeather_Rain :
{
// 1/8 chance of turning into a thunderstorm
return ( ( m_TickRand . randInt ( ) % 256 ) < 32 ) ? eWeather_ThunderStorm : eWeather_Sunny ;
}
}
LOGWARNING ( " Unknown current weather: %d. Setting sunny. " , m_Weather ) ;
ASSERT ( ! " Unknown weather " ) ;
return eWeather_Sunny ;
}
2014-07-21 17:49:06 -04:00
void cWorld : : InitialiseGeneratorDefaults ( cIniFile & a_IniFile )
{
switch ( GetDimension ( ) )
{
case dimEnd :
{
a_IniFile . GetValueSet ( " Generator " , " BiomeGen " , " Constant " ) ;
a_IniFile . GetValueSet ( " Generator " , " ConstantBiome " , " End " ) ;
a_IniFile . GetValueSet ( " Generator " , " HeightGen " , " Biomal " ) ;
a_IniFile . GetValueSet ( " Generator " , " CompositionGen " , " End " ) ;
break ;
}
case dimOverworld :
{
a_IniFile . GetValueSet ( " Generator " , " BiomeGen " , " MultiStepMap " ) ;
a_IniFile . GetValueSet ( " Generator " , " HeightGen " , " DistortedHeightmap " ) ;
a_IniFile . GetValueSet ( " Generator " , " CompositionGen " , " DistortedHeightmap " ) ;
a_IniFile . GetValueSet ( " Generator " , " Finishers " , " Ravines, WormNestCaves, WaterLakes, WaterSprings, LavaLakes, LavaSprings, OreNests, Mineshafts, Trees, SprinkleFoliage, Ice, Snow, Lilypads, BottomLava, DeadBushes, PreSimulator " ) ;
break ;
}
case dimNether :
{
a_IniFile . GetValueSet ( " Generator " , " BiomeGen " , " Constant " ) ;
a_IniFile . GetValueSet ( " Generator " , " ConstantBiome " , " Nether " ) ;
a_IniFile . GetValueSet ( " Generator " , " HeightGen " , " Flat " ) ;
a_IniFile . GetValueSet ( " Generator " , " FlatHeight " , " 128 " ) ;
a_IniFile . GetValueSet ( " Generator " , " CompositionGen " , " Nether " ) ;
a_IniFile . GetValueSet ( " Generator " , " Finishers " , " WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherForts, PreSimulator " ) ;
a_IniFile . GetValueSet ( " Generator " , " BottomLavaHeight " , " 30 " ) ;
break ;
}
}
}
void cWorld : : InitialiseAndLoadMobSpawningValues ( cIniFile & a_IniFile )
{
AString DefaultMonsters ;
switch ( m_Dimension )
{
case dimOverworld : DefaultMonsters = " bat, cavespider, chicken, cow, creeper, enderman, horse, mooshroom, ocelot, pig, sheep, silverfish, skeleton, slime, spider, squid, wolf, zombie " ; break ;
case dimNether : DefaultMonsters = " blaze, ghast, magmacube, skeleton, zombie, zombiepigman " ; break ;
case dimEnd : DefaultMonsters = " enderman " ; break ;
}
m_bAnimals = a_IniFile . GetValueSetB ( " Monsters " , " AnimalsOn " , true ) ;
AString AllMonsters = a_IniFile . GetValueSet ( " Monsters " , " Types " , DefaultMonsters ) ;
if ( ! m_bAnimals )
{
return ;
}
AStringVector SplitList = StringSplitAndTrim ( AllMonsters , " , " ) ;
for ( AStringVector : : const_iterator itr = SplitList . begin ( ) , end = SplitList . end ( ) ; itr ! = end ; + + itr )
{
cMonster : : eType ToAdd = cMonster : : StringToMobType ( * itr ) ;
if ( ToAdd ! = cMonster : : mtInvalidType )
{
m_AllowedMobs . insert ( ToAdd ) ;
LOGD ( " Allowed mob: %s " , itr - > c_str ( ) ) ;
}
else
{
LOG ( " World \" %s \" : Unknown mob type: %s " , m_WorldName . c_str ( ) , itr - > c_str ( ) ) ;
}
}
}
2013-08-11 14:16:41 -04:00
void cWorld : : Stop ( void )
2012-07-15 16:07:38 -04:00
{
2013-08-14 13:56:29 -04:00
// Delete the clients that have been in this world:
{
cCSLock Lock ( m_CSClients ) ;
for ( cClientHandleList : : iterator itr = m_Clients . begin ( ) ; itr ! = m_Clients . end ( ) ; + + itr )
{
( * itr ) - > Destroy ( ) ;
delete * itr ;
} // for itr - m_Clients[]
m_Clients . clear ( ) ;
}
2014-06-04 15:00:55 -04:00
// Write settings to file; these are all plugin changeable values - keep updated!
cIniFile IniFile ;
IniFile . ReadFile ( m_IniFileName ) ;
2014-07-22 12:26:48 -04:00
if ( GetDimension ( ) = = dimOverworld )
2014-06-04 15:00:55 -04:00
{
2014-07-18 15:12:27 -04:00
IniFile . SetValue ( " LinkedWorlds " , " NetherWorldName " , m_NetherWorldName ) ;
IniFile . SetValue ( " LinkedWorlds " , " EndWorldName " , m_EndWorldName ) ;
2014-06-04 15:00:55 -04:00
}
2014-06-10 15:43:27 -04:00
else
{
2014-07-18 15:12:27 -04:00
IniFile . SetValue ( " LinkedWorlds " , " OverworldName " , m_OverworldName ) ;
2014-06-10 15:43:27 -04:00
}
2014-06-04 15:00:55 -04:00
IniFile . SetValueI ( " Physics " , " TNTShrapnelLevel " , ( int ) m_TNTShrapnelLevel ) ;
IniFile . SetValueB ( " Mechanics " , " CommandBlocksEnabled " , m_bCommandBlocksEnabled ) ;
IniFile . SetValueB ( " Mechanics " , " UseChatPrefixes " , m_bUseChatPrefixes ) ;
2014-08-10 10:48:20 -04:00
IniFile . SetValueB ( " General " , " IsDaylightCycleEnabled " , m_IsDaylightCycleEnabled ) ;
2014-06-04 15:52:54 -04:00
IniFile . SetValueI ( " General " , " Weather " , ( int ) m_Weather ) ;
2014-06-05 12:58:29 -04:00
IniFile . SetValueI ( " General " , " TimeInTicks " , m_TimeOfDay ) ;
2014-06-04 15:00:55 -04:00
IniFile . WriteFile ( m_IniFileName ) ;
2013-08-14 13:56:29 -04:00
2013-08-11 14:16:41 -04:00
m_TickThread . Stop ( ) ;
m_Lighting . Stop ( ) ;
2012-07-15 16:07:38 -04:00
m_Generator . Stop ( ) ;
m_ChunkSender . Stop ( ) ;
2013-08-11 14:16:41 -04:00
m_Storage . Stop ( ) ;
2012-07-15 16:07:38 -04:00
}
2013-11-30 08:22:26 -05:00
void cWorld : : Tick ( float a_Dt , int a_LastTickDurationMSec )
2012-06-14 09:06:06 -04:00
{
2013-08-19 03:28:22 -04:00
// Call the plugins
2013-11-30 08:22:26 -05:00
cPluginManager : : Get ( ) - > CallHookWorldTick ( * this , a_Dt , a_LastTickDurationMSec ) ;
2013-08-19 03:28:22 -04:00
2014-07-24 12:32:05 -04:00
// Set any chunk data that has been queued for setting:
cSetChunkDataPtrs SetChunkDataQueue ;
{
cCSLock Lock ( m_CSSetChunkDataQueue ) ;
std : : swap ( SetChunkDataQueue , m_SetChunkDataQueue ) ;
}
for ( cSetChunkDataPtrs : : iterator itr = SetChunkDataQueue . begin ( ) , end = SetChunkDataQueue . end ( ) ; itr ! = end ; + + itr )
{
SetChunkData ( * * itr ) ;
} // for itr - SetChunkDataQueue[]
2014-08-06 19:07:32 -04:00
2012-11-01 17:38:20 -04:00
m_WorldAgeSecs + = ( double ) a_Dt / 1000.0 ;
2014-08-06 19:07:32 -04:00
m_WorldAge = ( Int64 ) ( m_WorldAgeSecs * 20.0 ) ;
2012-06-14 09:06:06 -04:00
2014-08-10 10:46:03 -04:00
if ( m_IsDaylightCycleEnabled )
2012-06-14 09:06:06 -04:00
{
2014-08-06 19:07:32 -04:00
// We need sub-tick precision here, that's why we store the time in seconds and calculate ticks off of it
m_TimeOfDaySecs + = ( double ) a_Dt / 1000.0 ;
2012-11-01 17:38:20 -04:00
2014-08-06 19:07:32 -04:00
// Wrap time of day each 20 minutes (1200 seconds)
if ( m_TimeOfDaySecs > 1200.0 )
{
m_TimeOfDaySecs - = 1200.0 ;
}
2012-11-01 17:38:20 -04:00
2014-08-06 19:07:32 -04:00
m_TimeOfDay = ( Int64 ) ( m_TimeOfDaySecs * 20.0 ) ;
2013-10-29 12:44:51 -04:00
2014-08-06 19:07:32 -04:00
// Updates the sky darkness based on current time of day
UpdateSkyDarkness ( ) ;
// Broadcast time update every 40 ticks (2 seconds)
if ( m_LastTimeUpdate < m_WorldAge - 40 )
{
BroadcastTimeUpdate ( ) ;
m_LastTimeUpdate = m_WorldAge ;
}
2012-06-14 09:06:06 -04:00
}
2014-06-06 16:31:16 -04:00
// Add entities waiting in the queue to be added:
{
cCSLock Lock ( m_CSEntitiesToAdd ) ;
for ( cEntityList : : iterator itr = m_EntitiesToAdd . begin ( ) , end = m_EntitiesToAdd . end ( ) ; itr ! = end ; + + itr )
{
( * itr ) - > SetWorld ( this ) ;
m_ChunkMap - > AddEntity ( * itr ) ;
}
m_EntitiesToAdd . clear ( ) ;
}
2014-06-08 15:58:08 -04:00
// Add players waiting in the queue to be added:
AddQueuedPlayers ( ) ;
2013-04-13 17:02:10 -04:00
m_ChunkMap - > Tick ( a_Dt ) ;
2012-07-15 16:36:34 -04:00
2013-08-13 16:45:29 -04:00
TickClients ( a_Dt ) ;
2013-09-16 03:25:23 -04:00
TickQueuedBlocks ( ) ;
2013-08-11 15:05:44 -04:00
TickQueuedTasks ( ) ;
2014-01-14 15:17:03 -05:00
TickScheduledTasks ( ) ;
2012-06-14 09:06:06 -04:00
GetSimulatorManager ( ) - > Simulate ( a_Dt ) ;
TickWeather ( a_Dt ) ;
2014-01-26 09:20:39 -05:00
m_ChunkMap - > FastSetQueuedBlocks ( ) ;
2012-06-14 09:06:06 -04:00
2014-07-17 13:13:23 -04:00
if ( m_WorldAge - m_LastSave > 60 * 5 * 20 ) // Save each 5 minutes
2012-06-14 09:06:06 -04:00
{
SaveAllChunks ( ) ;
}
2014-07-17 13:13:23 -04:00
if ( m_WorldAge - m_LastUnload > 10 * 20 ) // Unload every 10 seconds
2012-06-14 09:06:06 -04:00
{
UnloadUnusedChunks ( ) ;
}
2013-09-07 19:43:55 -04:00
TickMobs ( a_Dt ) ;
2012-06-14 09:06:06 -04:00
}
2013-02-13 14:22:08 -05:00
void cWorld : : TickWeather ( float a_Dt )
2012-06-14 09:06:06 -04:00
{
2013-12-22 09:55:24 -05:00
UNUSED ( a_Dt ) ;
2013-06-24 12:50:32 -04:00
// There are no weather changes anywhere but in the Overworld:
if ( GetDimension ( ) ! = dimOverworld )
{
return ;
}
2013-02-13 14:22:08 -05:00
if ( m_WeatherInterval > 0 )
2012-06-14 09:06:06 -04:00
{
2013-02-13 14:22:08 -05:00
// Not yet, wait for the weather period to end
m_WeatherInterval - - ;
2012-06-14 09:06:06 -04:00
}
2013-02-13 14:22:08 -05:00
else
2012-06-14 09:06:06 -04:00
{
2013-02-13 14:22:08 -05:00
// Change weather:
2014-04-25 19:55:38 -04:00
SetWeather ( ChooseNewWeather ( ) ) ;
}
2012-06-14 09:06:06 -04:00
2013-02-13 14:22:08 -05:00
if ( m_Weather = = eWeather_ThunderStorm )
2012-06-14 09:06:06 -04:00
{
2013-02-13 14:22:08 -05:00
// 0.5% chance per tick of thunderbolt
if ( m_TickRand . randInt ( ) % 199 = = 0 )
2012-06-14 09:06:06 -04:00
{
2013-02-13 14:22:08 -05:00
CastThunderbolt ( 0 , 0 , 0 ) ; // TODO: find random possitions near players to cast thunderbolts.
2012-06-14 09:06:06 -04:00
}
}
}
2013-09-07 19:43:55 -04:00
void cWorld : : TickMobs ( float a_Dt )
2012-06-14 09:06:06 -04:00
{
2013-10-22 12:30:26 -04:00
// _X 2013_10_22: This is a quick fix for #283 - the world needs to be locked while ticking mobs
cWorld : : cLock Lock ( * this ) ;
2013-10-20 08:16:21 -04:00
// before every Mob action, we have to count them depending on the distance to players, on their family ...
2013-09-07 16:19:56 -04:00
cMobCensus MobCensus ;
m_ChunkMap - > CollectMobCensus ( MobCensus ) ;
2013-10-20 08:00:45 -04:00
if ( m_bAnimals )
2012-06-14 09:06:06 -04:00
{
2013-10-20 08:16:21 -04:00
// Spawning is enabled, spawn now:
static const cMonster : : eFamily AllFamilies [ ] =
{
cMonster : : mfHostile ,
cMonster : : mfPassive ,
cMonster : : mfAmbient ,
cMonster : : mfWater ,
} ;
2013-12-22 09:55:24 -05:00
for ( size_t i = 0 ; i < ARRAYCOUNT ( AllFamilies ) ; i + + )
2013-06-25 02:36:59 -04:00
{
2013-10-20 08:16:21 -04:00
cMonster : : eFamily Family = AllFamilies [ i ] ;
2013-10-24 10:45:13 -04:00
int SpawnDelay = cMonster : : GetSpawnDelay ( Family ) ;
2013-10-20 08:00:45 -04:00
if (
2013-10-24 10:45:13 -04:00
( m_LastSpawnMonster [ Family ] > m_WorldAge - SpawnDelay ) | | // Not reached the needed ticks before the next round
2013-10-20 08:16:21 -04:00
MobCensus . IsCapped ( Family )
2013-10-20 08:00:45 -04:00
)
{
continue ;
}
2013-10-20 08:16:21 -04:00
m_LastSpawnMonster [ Family ] = m_WorldAge ;
cMobSpawner Spawner ( Family , m_AllowedMobs ) ;
2013-10-20 08:00:45 -04:00
if ( Spawner . CanSpawnAnything ( ) )
2013-08-16 04:48:19 -04:00
{
2013-10-20 08:00:45 -04:00
m_ChunkMap - > SpawnMobs ( Spawner ) ;
// do the spawn
2014-04-18 15:09:44 -04:00
for ( cMobSpawner : : tSpawnedContainer : : const_iterator itr2 = Spawner . getSpawned ( ) . begin ( ) ; itr2 ! = Spawner . getSpawned ( ) . end ( ) ; + + itr2 )
2013-08-16 04:48:19 -04:00
{
2013-10-20 08:00:45 -04:00
SpawnMobFinalize ( * itr2 ) ;
2013-08-16 04:48:19 -04:00
}
2013-10-20 08:00:45 -04:00
}
2014-07-17 13:13:23 -04:00
} // for i - AllFamilies[]
} // if (Spawning enabled)
2012-06-14 09:06:06 -04:00
2013-09-07 20:47:02 -04:00
// move close mobs
2013-10-18 14:02:53 -04:00
cMobProximityCounter : : sIterablePair allCloseEnoughToMoveMobs = MobCensus . GetProximityCounter ( ) . getMobWithinThosesDistances ( - 1 , 64 * 16 ) ; // MG TODO : deal with this magic number (the 16 is the size of a block)
2014-07-20 17:10:31 -04:00
for ( cMobProximityCounter : : tDistanceToMonster : : const_iterator itr = allCloseEnoughToMoveMobs . m_Begin ; itr ! = allCloseEnoughToMoveMobs . m_End ; + + itr )
2012-06-14 09:06:06 -04:00
{
2013-10-18 14:02:53 -04:00
itr - > second . m_Monster . Tick ( a_Dt , itr - > second . m_Chunk ) ;
2013-09-07 20:47:02 -04:00
}
2012-06-14 09:06:06 -04:00
2013-09-07 20:47:02 -04:00
// remove too far mobs
2013-10-18 14:02:53 -04:00
cMobProximityCounter : : sIterablePair allTooFarMobs = MobCensus . GetProximityCounter ( ) . getMobWithinThosesDistances ( 128 * 16 , - 1 ) ; // MG TODO : deal with this magic number (the 16 is the size of a block)
2014-07-20 17:10:31 -04:00
for ( cMobProximityCounter : : tDistanceToMonster : : const_iterator itr = allTooFarMobs . m_Begin ; itr ! = allTooFarMobs . m_End ; + + itr )
2012-06-14 09:06:06 -04:00
{
2013-09-07 20:47:02 -04:00
itr - > second . m_Monster . Destroy ( true ) ;
2012-06-14 09:06:06 -04:00
}
}
2013-08-11 15:05:44 -04:00
void cWorld : : TickQueuedTasks ( void )
{
// Make a copy of the tasks to avoid deadlocks on accessing m_Tasks
cTasks Tasks ;
{
cCSLock Lock ( m_CSTasks ) ;
std : : swap ( Tasks , m_Tasks ) ;
}
// Execute and delete each task:
2013-10-12 16:24:59 -04:00
for ( cTasks : : iterator itr = Tasks . begin ( ) , end = Tasks . end ( ) ; itr ! = end ; + + itr )
2013-08-11 15:05:44 -04:00
{
( * itr ) - > Run ( * this ) ;
delete * itr ;
} // for itr - m_Tasks[]
}
2014-01-19 17:49:19 -05:00
void cWorld : : TickScheduledTasks ( void )
2014-01-14 15:17:03 -05:00
{
// Make a copy of the tasks to avoid deadlocks on accessing m_Tasks
2014-01-19 17:49:19 -05:00
cScheduledTasks Tasks ;
2014-01-14 15:17:03 -05:00
{
cCSLock Lock ( m_CSScheduledTasks ) ;
2014-01-19 17:49:19 -05:00
while ( ! m_ScheduledTasks . empty ( ) & & ( m_ScheduledTasks . front ( ) - > m_TargetTick < m_WorldAge ) )
2014-01-14 15:17:03 -05:00
{
Tasks . push_back ( m_ScheduledTasks . front ( ) ) ;
m_ScheduledTasks . pop_front ( ) ;
}
}
// Execute and delete each task:
2014-01-19 17:49:19 -05:00
for ( cScheduledTasks : : iterator itr = Tasks . begin ( ) , end = Tasks . end ( ) ; itr ! = end ; + + itr )
2014-01-14 15:17:03 -05:00
{
2014-01-19 17:49:19 -05:00
( * itr ) - > m_Task - > Run ( * this ) ;
2014-01-14 15:17:03 -05:00
delete * itr ;
} // for itr - m_Tasks[]
}
2013-08-11 15:05:44 -04:00
2013-08-13 16:45:29 -04:00
void cWorld : : TickClients ( float a_Dt )
{
cClientHandleList RemoveClients ;
{
cCSLock Lock ( m_CSClients ) ;
2013-08-14 07:43:55 -04:00
// Remove clients scheduled for removal:
for ( cClientHandleList : : iterator itr = m_ClientsToRemove . begin ( ) , end = m_ClientsToRemove . end ( ) ; itr ! = end ; + + itr )
{
m_Clients . remove ( * itr ) ;
} // for itr - m_ClientsToRemove[]
m_ClientsToRemove . clear ( ) ;
// Add clients scheduled for adding:
for ( cClientHandleList : : iterator itr = m_ClientsToAdd . begin ( ) , end = m_ClientsToAdd . end ( ) ; itr ! = end ; + + itr )
{
2014-07-22 12:26:48 -04:00
ASSERT ( std : : find ( m_Clients . begin ( ) , m_Clients . end ( ) , * itr ) = = m_Clients . end ( ) ) ;
2013-08-14 07:43:55 -04:00
m_Clients . push_back ( * itr ) ;
} // for itr - m_ClientsToRemove[]
m_ClientsToAdd . clear ( ) ;
2013-08-13 16:45:29 -04:00
// Tick the clients, take out those that have been destroyed into RemoveClients
for ( cClientHandleList : : iterator itr = m_Clients . begin ( ) ; itr ! = m_Clients . end ( ) ; )
{
if ( ( * itr ) - > IsDestroyed ( ) )
{
// Remove the client later, when CS is not held, to avoid deadlock
RemoveClients . push_back ( * itr ) ;
itr = m_Clients . erase ( itr ) ;
continue ;
}
( * itr ) - > Tick ( a_Dt ) ;
+ + itr ;
} // for itr - m_Clients[]
}
// Delete the clients that have been destroyed
for ( cClientHandleList : : iterator itr = RemoveClients . begin ( ) ; itr ! = RemoveClients . end ( ) ; + + itr )
{
delete * itr ;
2014-07-17 13:13:23 -04:00
} // for itr - RemoveClients[]
2013-08-13 16:45:29 -04:00
}
2013-10-30 18:33:42 -04:00
void cWorld : : UpdateSkyDarkness ( void )
{
int TempTime = ( int ) m_TimeOfDay ;
if ( TempTime < = TIME_SUNSET )
{
m_SkyDarkness = 0 ;
}
else if ( TempTime < = TIME_NIGHT_START )
{
m_SkyDarkness = ( TIME_NIGHT_START - TempTime ) / TIME_SPAWN_DIVISOR ;
}
else if ( TempTime < = TIME_NIGHT_END )
{
m_SkyDarkness = 8 ;
}
else
{
m_SkyDarkness = ( TIME_SUNRISE - TempTime ) / TIME_SPAWN_DIVISOR ;
}
}
2013-02-28 02:42:45 -05:00
void cWorld : : WakeUpSimulators ( int a_BlockX , int a_BlockY , int a_BlockZ )
{
return m_ChunkMap - > WakeUpSimulators ( a_BlockX , a_BlockY , a_BlockZ ) ;
}
2013-06-21 16:47:58 -04:00
/// Wakes up the simulators for the specified area of blocks
void cWorld : : WakeUpSimulatorsInArea ( int a_MinBlockX , int a_MaxBlockX , int a_MinBlockY , int a_MaxBlockY , int a_MinBlockZ , int a_MaxBlockZ )
{
return m_ChunkMap - > WakeUpSimulatorsInArea ( a_MinBlockX , a_MaxBlockX , a_MinBlockY , a_MaxBlockY , a_MinBlockZ , a_MaxBlockZ ) ;
}
2013-11-20 15:53:29 -05:00
bool cWorld : : ForEachBlockEntityInChunk ( int a_ChunkX , int a_ChunkZ , cBlockEntityCallback & a_Callback )
{
return m_ChunkMap - > ForEachBlockEntityInChunk ( a_ChunkX , a_ChunkZ , a_Callback ) ;
}
2012-06-17 15:58:39 -04:00
bool cWorld : : ForEachChestInChunk ( int a_ChunkX , int a_ChunkZ , cChestCallback & a_Callback )
{
return m_ChunkMap - > ForEachChestInChunk ( a_ChunkX , a_ChunkZ , a_Callback ) ;
}
2012-12-26 12:16:33 -05:00
bool cWorld : : ForEachDispenserInChunk ( int a_ChunkX , int a_ChunkZ , cDispenserCallback & a_Callback )
{
return m_ChunkMap - > ForEachDispenserInChunk ( a_ChunkX , a_ChunkZ , a_Callback ) ;
}
2013-05-26 10:39:04 -04:00
bool cWorld : : ForEachDropperInChunk ( int a_ChunkX , int a_ChunkZ , cDropperCallback & a_Callback )
{
return m_ChunkMap - > ForEachDropperInChunk ( a_ChunkX , a_ChunkZ , a_Callback ) ;
}
bool cWorld : : ForEachDropSpenserInChunk ( int a_ChunkX , int a_ChunkZ , cDropSpenserCallback & a_Callback )
{
return m_ChunkMap - > ForEachDropSpenserInChunk ( a_ChunkX , a_ChunkZ , a_Callback ) ;
}
2012-06-17 15:58:39 -04:00
bool cWorld : : ForEachFurnaceInChunk ( int a_ChunkX , int a_ChunkZ , cFurnaceCallback & a_Callback )
{
return m_ChunkMap - > ForEachFurnaceInChunk ( a_ChunkX , a_ChunkZ , a_Callback ) ;
}
2013-09-07 12:12:22 -04:00
void cWorld : : DoExplosionAt ( double a_ExplosionSize , double a_BlockX , double a_BlockY , double a_BlockZ , bool a_CanCauseFire , eExplosionSource a_Source , void * a_SourceData )
2013-04-17 22:42:45 -04:00
{
Added OnExploding() and OnExploded() hooks.
As requested in FS 413, with extra parameters:
World, BlockX, BlockY, BlockZ, Size, CanCauseFire, Source, SourceData
OnExploding() can return 3 values:
StopHook, CanCauseFire, ExplosionSize
2013-08-09 08:58:43 -04:00
if ( cPluginManager : : Get ( ) - > CallHookExploding ( * this , a_ExplosionSize , a_CanCauseFire , a_BlockX , a_BlockY , a_BlockZ , a_Source , a_SourceData ) | | ( a_ExplosionSize < = 0 ) )
{
return ;
}
2014-08-29 08:44:10 -04:00
// TODO: Implement block hardiness
2013-06-18 04:24:34 -04:00
Vector3d explosion_pos = Vector3d ( a_BlockX , a_BlockY , a_BlockZ ) ;
2013-06-18 15:09:51 -04:00
cVector3iArray BlocksAffected ;
2013-09-07 12:12:22 -04:00
m_ChunkMap - > DoExplosionAt ( a_ExplosionSize , a_BlockX , a_BlockY , a_BlockZ , BlocksAffected ) ;
2014-07-12 20:08:02 -04:00
BroadcastSoundEffect ( " random.explode " , ( double ) a_BlockX , ( double ) a_BlockY , ( double ) a_BlockZ , 1.0f , 0.6f ) ;
2014-08-29 08:44:10 -04:00
2013-04-17 22:42:45 -04:00
{
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
{
cClientHandle * ch = ( * itr ) - > GetClientHandle ( ) ;
2014-08-29 08:44:10 -04:00
if ( ch = = NULL )
2013-04-17 22:42:45 -04:00
{
continue ;
}
2014-08-29 08:44:10 -04:00
2013-04-17 22:42:45 -04:00
Vector3d distance_explosion = ( * itr ) - > GetPosition ( ) - explosion_pos ;
if ( distance_explosion . SqrLength ( ) < 4096.0 )
{
2014-08-29 08:44:10 -04:00
double real_distance = std : : max ( 0.004 , distance_explosion . Length ( ) ) ;
2013-04-17 22:42:45 -04:00
double power = a_ExplosionSize / real_distance ;
if ( power < = 1 )
2013-04-19 04:21:39 -04:00
{
2013-04-17 22:42:45 -04:00
power = 0 ;
2013-04-19 04:21:39 -04:00
}
2013-04-17 22:42:45 -04:00
distance_explosion . Normalize ( ) ;
distance_explosion * = power ;
Added OnExploding() and OnExploded() hooks.
As requested in FS 413, with extra parameters:
World, BlockX, BlockY, BlockZ, Size, CanCauseFire, Source, SourceData
OnExploding() can return 3 values:
StopHook, CanCauseFire, ExplosionSize
2013-08-09 08:58:43 -04:00
ch - > SendExplosion ( a_BlockX , a_BlockY , a_BlockZ , ( float ) a_ExplosionSize , BlocksAffected , distance_explosion ) ;
2013-04-17 22:42:45 -04:00
}
}
}
2014-08-29 08:44:10 -04:00
Added OnExploding() and OnExploded() hooks.
As requested in FS 413, with extra parameters:
World, BlockX, BlockY, BlockZ, Size, CanCauseFire, Source, SourceData
OnExploding() can return 3 values:
StopHook, CanCauseFire, ExplosionSize
2013-08-09 08:58:43 -04:00
cPluginManager : : Get ( ) - > CallHookExploded ( * this , a_ExplosionSize , a_CanCauseFire , a_BlockX , a_BlockY , a_BlockZ , a_Source , a_SourceData ) ;
2013-04-17 22:42:45 -04:00
}
2013-11-20 15:53:29 -05:00
bool cWorld : : DoWithBlockEntityAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cBlockEntityCallback & a_Callback )
{
return m_ChunkMap - > DoWithBlockEntityAt ( a_BlockX , a_BlockY , a_BlockZ , a_Callback ) ;
}
2014-07-30 16:19:51 -04:00
bool cWorld : : DoWithBeaconAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cBeaconCallback & a_Callback )
{
return m_ChunkMap - > DoWithBeaconAt ( a_BlockX , a_BlockY , a_BlockZ , a_Callback ) ;
}
2012-06-17 15:58:39 -04:00
bool cWorld : : DoWithChestAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cChestCallback & a_Callback )
{
return m_ChunkMap - > DoWithChestAt ( a_BlockX , a_BlockY , a_BlockZ , a_Callback ) ;
}
2012-12-26 12:16:33 -05:00
bool cWorld : : DoWithDispenserAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cDispenserCallback & a_Callback )
{
return m_ChunkMap - > DoWithDispenserAt ( a_BlockX , a_BlockY , a_BlockZ , a_Callback ) ;
}
2013-05-26 10:39:04 -04:00
bool cWorld : : DoWithDropperAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cDropperCallback & a_Callback )
{
return m_ChunkMap - > DoWithDropperAt ( a_BlockX , a_BlockY , a_BlockZ , a_Callback ) ;
}
bool cWorld : : DoWithDropSpenserAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cDropSpenserCallback & a_Callback )
{
return m_ChunkMap - > DoWithDropSpenserAt ( a_BlockX , a_BlockY , a_BlockZ , a_Callback ) ;
}
2012-12-26 12:16:33 -05:00
2012-06-17 15:58:39 -04:00
bool cWorld : : DoWithFurnaceAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cFurnaceCallback & a_Callback )
{
return m_ChunkMap - > DoWithFurnaceAt ( a_BlockX , a_BlockY , a_BlockZ , a_Callback ) ;
}
2013-12-14 11:52:22 -05:00
bool cWorld : : DoWithNoteBlockAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cNoteBlockCallback & a_Callback )
{
return m_ChunkMap - > DoWithNoteBlockAt ( a_BlockX , a_BlockY , a_BlockZ , a_Callback ) ;
}
2014-01-18 08:16:47 -05:00
bool cWorld : : DoWithCommandBlockAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cCommandBlockCallback & a_Callback )
{
return m_ChunkMap - > DoWithCommandBlockAt ( a_BlockX , a_BlockY , a_BlockZ , a_Callback ) ;
}
2014-03-07 05:44:16 -05:00
bool cWorld : : DoWithMobHeadAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cMobHeadCallback & a_Callback )
2014-02-18 15:40:02 -05:00
{
2014-03-07 05:44:16 -05:00
return m_ChunkMap - > DoWithMobHeadAt ( a_BlockX , a_BlockY , a_BlockZ , a_Callback ) ;
2014-02-18 15:40:02 -05:00
}
2014-03-06 19:30:34 -05:00
bool cWorld : : DoWithFlowerPotAt ( int a_BlockX , int a_BlockY , int a_BlockZ , cFlowerPotCallback & a_Callback )
2014-02-18 15:40:02 -05:00
{
2014-03-06 19:30:34 -05:00
return m_ChunkMap - > DoWithFlowerPotAt ( a_BlockX , a_BlockY , a_BlockZ , a_Callback ) ;
2014-02-18 15:40:02 -05:00
}
2012-06-17 15:58:39 -04:00
bool cWorld : : GetSignLines ( int a_BlockX , int a_BlockY , int a_BlockZ , AString & a_Line1 , AString & a_Line2 , AString & a_Line3 , AString & a_Line4 )
{
return m_ChunkMap - > GetSignLines ( a_BlockX , a_BlockY , a_BlockZ , a_Line1 , a_Line2 , a_Line3 , a_Line4 ) ;
}
2013-08-03 14:26:50 -04:00
bool cWorld : : DoWithChunk ( int a_ChunkX , int a_ChunkZ , cChunkCallback & a_Callback )
{
return m_ChunkMap - > DoWithChunk ( a_ChunkX , a_ChunkZ , a_Callback ) ;
}
2013-03-03 14:05:11 -05:00
void cWorld : : GrowTree ( int a_X , int a_Y , int a_Z )
2012-06-14 09:06:06 -04:00
{
if ( GetBlock ( a_X , a_Y , a_Z ) = = E_BLOCK_SAPLING )
{
// There is a sapling here, grow a tree according to its type:
GrowTreeFromSapling ( a_X , a_Y , a_Z , GetBlockMeta ( a_X , a_Y , a_Z ) ) ;
}
else
{
// There is nothing here, grow a tree based on the current biome here:
GrowTreeByBiome ( a_X , a_Y , a_Z ) ;
}
}
2013-09-15 16:11:02 -04:00
void cWorld : : GrowTreeFromSapling ( int a_X , int a_Y , int a_Z , NIBBLETYPE a_SaplingMeta )
2012-06-14 09:06:06 -04:00
{
cNoise Noise ( m_Generator . GetSeed ( ) ) ;
2012-07-15 09:33:43 -04:00
sSetBlockVector Logs , Other ;
2012-06-14 09:06:06 -04:00
switch ( a_SaplingMeta & 0x07 )
{
2014-02-19 13:18:40 -05:00
case E_META_SAPLING_APPLE : GetAppleTreeImage ( a_X , a_Y , a_Z , Noise , ( int ) ( m_WorldAge & 0xffffffff ) , Logs , Other ) ; break ;
case E_META_SAPLING_BIRCH : GetBirchTreeImage ( a_X , a_Y , a_Z , Noise , ( int ) ( m_WorldAge & 0xffffffff ) , Logs , Other ) ; break ;
case E_META_SAPLING_CONIFER : GetConiferTreeImage ( a_X , a_Y , a_Z , Noise , ( int ) ( m_WorldAge & 0xffffffff ) , Logs , Other ) ; break ;
case E_META_SAPLING_JUNGLE : GetJungleTreeImage ( a_X , a_Y , a_Z , Noise , ( int ) ( m_WorldAge & 0xffffffff ) , Logs , Other ) ; break ;
case E_META_SAPLING_ACACIA : GetAcaciaTreeImage ( a_X , a_Y , a_Z , Noise , ( int ) ( m_WorldAge & 0xffffffff ) , Logs , Other ) ; break ;
case E_META_SAPLING_DARK_OAK : GetDarkoakTreeImage ( a_X , a_Y , a_Z , Noise , ( int ) ( m_WorldAge & 0xffffffff ) , Logs , Other ) ; break ;
2012-06-14 09:06:06 -04:00
}
2012-07-15 09:33:43 -04:00
Other . insert ( Other . begin ( ) , Logs . begin ( ) , Logs . end ( ) ) ;
Logs . clear ( ) ;
2012-10-03 15:01:34 -04:00
GrowTreeImage ( Other ) ;
2012-06-14 09:06:06 -04:00
}
void cWorld : : GrowTreeByBiome ( int a_X , int a_Y , int a_Z )
{
cNoise Noise ( m_Generator . GetSeed ( ) ) ;
2012-07-15 09:33:43 -04:00
sSetBlockVector Logs , Other ;
2014-02-03 15:26:17 -05:00
GetTreeImageByBiome ( a_X , a_Y , a_Z , Noise , ( int ) ( m_WorldAge & 0xffffffff ) , GetBiomeAt ( a_X , a_Z ) , Logs , Other ) ;
2012-07-15 09:33:43 -04:00
Other . insert ( Other . begin ( ) , Logs . begin ( ) , Logs . end ( ) ) ;
Logs . clear ( ) ;
GrowTreeImage ( Other ) ;
2012-06-14 09:06:06 -04:00
}
void cWorld : : GrowTreeImage ( const sSetBlockVector & a_Blocks )
{
// Check that the tree has place to grow
// Make a copy of the log blocks:
sSetBlockVector b2 ;
for ( sSetBlockVector : : const_iterator itr = a_Blocks . begin ( ) ; itr ! = a_Blocks . end ( ) ; + + itr )
{
if ( itr - > BlockType = = E_BLOCK_LOG )
{
b2 . push_back ( * itr ) ;
}
} // for itr - a_Blocks[]
// Query blocktypes and metas at those log blocks:
if ( ! GetBlocks ( b2 , false ) )
{
return ;
}
// Check that at each log's coord there's an block allowed to be overwritten:
for ( sSetBlockVector : : const_iterator itr = b2 . begin ( ) ; itr ! = b2 . end ( ) ; + + itr )
{
switch ( itr - > BlockType )
{
CASE_TREE_ALLOWED_BLOCKS :
{
break ;
}
default :
{
return ;
}
}
} // for itr - b2[]
// All ok, replace blocks with the tree image:
m_ChunkMap - > ReplaceTreeBlocks ( a_Blocks ) ;
}
2012-10-03 04:52:11 -04:00
bool cWorld : : GrowRipePlant ( int a_BlockX , int a_BlockY , int a_BlockZ , bool a_IsByBonemeal )
2012-06-14 09:06:06 -04:00
{
BLOCKTYPE BlockType ;
NIBBLETYPE BlockMeta ;
GetBlockTypeMeta ( a_BlockX , a_BlockY , a_BlockZ , BlockType , BlockMeta ) ;
switch ( BlockType )
{
2013-04-05 09:45:00 -04:00
case E_BLOCK_CARROTS :
{
if ( a_IsByBonemeal & & ! m_IsCarrotsBonemealable )
{
return false ;
}
if ( BlockMeta < 7 )
{
FastSetBlock ( a_BlockX , a_BlockY , a_BlockZ , BlockType , 7 ) ;
2013-12-07 18:45:33 -05:00
BroadcastSoundParticleEffect ( 2005 , a_BlockX , a_BlockY , a_BlockZ , 0 ) ;
2013-04-05 09:45:00 -04:00
}
return true ;
}
2012-06-14 09:06:06 -04:00
case E_BLOCK_CROPS :
{
2013-04-05 09:45:00 -04:00
if ( a_IsByBonemeal & & ! m_IsCropsBonemealable )
2012-06-14 09:06:06 -04:00
{
return false ;
}
if ( BlockMeta < 7 )
{
FastSetBlock ( a_BlockX , a_BlockY , a_BlockZ , BlockType , 7 ) ;
2013-12-07 18:45:33 -05:00
BroadcastSoundParticleEffect ( 2005 , a_BlockX , a_BlockY , a_BlockZ , 0 ) ;
2012-06-14 09:06:06 -04:00
}
return true ;
}
case E_BLOCK_MELON_STEM :
{
if ( BlockMeta < 7 )
{
if ( a_IsByBonemeal & & ! m_IsMelonStemBonemealable )
{
return false ;
}
FastSetBlock ( a_BlockX , a_BlockY , a_BlockZ , BlockType , 7 ) ;
2013-12-07 18:45:33 -05:00
BroadcastSoundParticleEffect ( 2005 , a_BlockX , a_BlockY , a_BlockZ , 0 ) ;
2012-06-14 09:06:06 -04:00
}
else
{
if ( a_IsByBonemeal & & ! m_IsMelonBonemealable )
{
return false ;
}
GrowMelonPumpkin ( a_BlockX , a_BlockY , a_BlockZ , BlockType ) ;
}
return true ;
}
2013-04-05 09:45:00 -04:00
case E_BLOCK_POTATOES :
{
if ( a_IsByBonemeal & & ! m_IsPotatoesBonemealable )
{
return false ;
}
if ( BlockMeta < 7 )
{
FastSetBlock ( a_BlockX , a_BlockY , a_BlockZ , BlockType , 7 ) ;
2013-12-07 18:45:33 -05:00
BroadcastSoundParticleEffect ( 2005 , a_BlockX , a_BlockY , a_BlockZ , 0 ) ;
2013-04-05 09:45:00 -04:00
}
return true ;
}
2012-06-14 09:06:06 -04:00
case E_BLOCK_PUMPKIN_STEM :
{
if ( BlockMeta < 7 )
{
if ( a_IsByBonemeal & & ! m_IsPumpkinStemBonemealable )
{
return false ;
}
FastSetBlock ( a_BlockX , a_BlockY , a_BlockZ , BlockType , 7 ) ;
2013-12-07 18:45:33 -05:00
BroadcastSoundParticleEffect ( 2005 , a_BlockX , a_BlockY , a_BlockZ , 0 ) ;
2012-06-14 09:06:06 -04:00
}
else
{
if ( a_IsByBonemeal & & ! m_IsPumpkinBonemealable )
{
return false ;
}
GrowMelonPumpkin ( a_BlockX , a_BlockY , a_BlockZ , BlockType ) ;
}
return true ;
}
case E_BLOCK_SAPLING :
{
if ( a_IsByBonemeal & & ! m_IsSaplingBonemealable )
{
return false ;
}
GrowTreeFromSapling ( a_BlockX , a_BlockY , a_BlockZ , BlockMeta ) ;
return true ;
}
case E_BLOCK_GRASS :
{
if ( a_IsByBonemeal & & ! m_IsGrassBonemealable )
{
return false ;
}
MTRand r1 ;
for ( int i = 0 ; i < 60 ; i + + )
{
int OfsX = ( r1 . randInt ( 3 ) + r1 . randInt ( 3 ) + r1 . randInt ( 3 ) + r1 . randInt ( 3 ) ) / 2 - 3 ;
int OfsY = r1 . randInt ( 3 ) + r1 . randInt ( 3 ) - 3 ;
int OfsZ = ( r1 . randInt ( 3 ) + r1 . randInt ( 3 ) + r1 . randInt ( 3 ) + r1 . randInt ( 3 ) ) / 2 - 3 ;
BLOCKTYPE Ground = GetBlock ( a_BlockX + OfsX , a_BlockY + OfsY , a_BlockZ + OfsZ ) ;
if ( Ground ! = E_BLOCK_GRASS )
{
continue ;
}
BLOCKTYPE Above = GetBlock ( a_BlockX + OfsX , a_BlockY + OfsY + 1 , a_BlockZ + OfsZ ) ;
if ( Above ! = E_BLOCK_AIR )
{
continue ;
}
BLOCKTYPE SpawnType ;
NIBBLETYPE SpawnMeta = 0 ;
switch ( r1 . randInt ( 10 ) )
{
case 0 : SpawnType = E_BLOCK_YELLOW_FLOWER ; break ;
case 1 : SpawnType = E_BLOCK_RED_ROSE ; break ;
default :
{
SpawnType = E_BLOCK_TALL_GRASS ;
SpawnMeta = E_META_TALL_GRASS_GRASS ;
break ;
}
2012-10-03 04:52:11 -04:00
} // switch (random spawn block type)
2012-06-14 09:06:06 -04:00
FastSetBlock ( a_BlockX + OfsX , a_BlockY + OfsY + 1 , a_BlockZ + OfsZ , SpawnType , SpawnMeta ) ;
2013-12-07 18:45:33 -05:00
BroadcastSoundParticleEffect ( 2005 , a_BlockX + OfsX , a_BlockY + OfsY , a_BlockZ + OfsZ , 0 ) ;
2012-06-14 09:06:06 -04:00
} // for i - 50 times
return true ;
}
case E_BLOCK_SUGARCANE :
{
if ( a_IsByBonemeal & & ! m_IsSugarcaneBonemealable )
{
return false ;
}
m_ChunkMap - > GrowSugarcane ( a_BlockX , a_BlockY , a_BlockZ , m_MaxSugarcaneHeight ) ;
return true ;
}
case E_BLOCK_CACTUS :
{
if ( a_IsByBonemeal & & ! m_IsCactusBonemealable )
{
return false ;
}
m_ChunkMap - > GrowCactus ( a_BlockX , a_BlockY , a_BlockZ , m_MaxCactusHeight ) ;
return true ;
}
} // switch (BlockType)
return false ;
}
2012-10-03 04:52:11 -04:00
void cWorld : : GrowCactus ( int a_BlockX , int a_BlockY , int a_BlockZ , int a_NumBlocksToGrow )
{
m_ChunkMap - > GrowCactus ( a_BlockX , a_BlockY , a_BlockZ , a_NumBlocksToGrow ) ;
}
2013-09-15 16:11:02 -04:00
void cWorld : : GrowMelonPumpkin ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType )
2012-06-14 09:06:06 -04:00
{
MTRand Rand ;
m_ChunkMap - > GrowMelonPumpkin ( a_BlockX , a_BlockY , a_BlockZ , a_BlockType , Rand ) ;
}
2012-10-03 04:52:11 -04:00
void cWorld : : GrowSugarcane ( int a_BlockX , int a_BlockY , int a_BlockZ , int a_NumBlocksToGrow )
{
m_ChunkMap - > GrowSugarcane ( a_BlockX , a_BlockY , a_BlockZ , a_NumBlocksToGrow ) ;
}
2014-02-03 15:26:17 -05:00
EMCSBiome cWorld : : GetBiomeAt ( int a_BlockX , int a_BlockZ )
2012-06-14 09:06:06 -04:00
{
return m_ChunkMap - > GetBiomeAt ( a_BlockX , a_BlockZ ) ;
}
2014-02-18 07:06:18 -05:00
bool cWorld : : SetBiomeAt ( int a_BlockX , int a_BlockZ , EMCSBiome a_Biome )
{
return m_ChunkMap - > SetBiomeAt ( a_BlockX , a_BlockZ , a_Biome ) ;
}
bool cWorld : : SetAreaBiome ( int a_MinX , int a_MaxX , int a_MinZ , int a_MaxZ , EMCSBiome a_Biome )
{
return m_ChunkMap - > SetAreaBiome ( a_MinX , a_MaxX , a_MinZ , a_MaxZ , a_Biome ) ;
}
bool cWorld : : SetAreaBiome ( const cCuboid & a_Area , EMCSBiome a_Biome )
{
2014-02-18 07:44:40 -05:00
return SetAreaBiome (
std : : min ( a_Area . p1 . x , a_Area . p2 . x ) , std : : max ( a_Area . p1 . x , a_Area . p2 . x ) ,
std : : min ( a_Area . p1 . z , a_Area . p2 . z ) , std : : max ( a_Area . p1 . z , a_Area . p2 . z ) ,
a_Biome
) ;
2014-02-18 07:06:18 -05:00
}
2014-05-25 08:46:34 -04:00
void cWorld : : SetBlock ( int a_BlockX , int a_BlockY , int a_BlockZ , 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
m_ChunkMap - > SetBlock ( * this , a_BlockX , a_BlockY , a_BlockZ , a_BlockType , a_BlockMeta , a_SendToClients ) ;
2012-06-14 09:06:06 -04:00
}
2013-03-03 14:05:11 -05:00
void cWorld : : SetBlockMeta ( int a_X , int a_Y , int a_Z , NIBBLETYPE a_MetaData )
2012-06-14 09:06:06 -04:00
{
m_ChunkMap - > SetBlockMeta ( a_X , a_Y , a_Z , a_MetaData ) ;
}
2013-03-03 14:05:11 -05:00
NIBBLETYPE cWorld : : GetBlockSkyLight ( int a_X , int a_Y , int a_Z )
2012-06-14 09:06:06 -04:00
{
return m_ChunkMap - > GetBlockSkyLight ( a_X , a_Y , a_Z ) ;
}
2012-10-20 07:40:34 -04:00
NIBBLETYPE cWorld : : GetBlockBlockLight ( int a_BlockX , int a_BlockY , int a_BlockZ )
{
return m_ChunkMap - > GetBlockBlockLight ( a_BlockX , a_BlockY , a_BlockZ ) ;
}
2012-10-26 04:47:30 -04:00
bool cWorld : : GetBlockTypeMeta ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE & a_BlockType , NIBBLETYPE & a_BlockMeta )
2012-06-14 09:06:06 -04:00
{
2012-10-26 04:47:30 -04:00
return m_ChunkMap - > GetBlockTypeMeta ( a_BlockX , a_BlockY , a_BlockZ , ( BLOCKTYPE & ) a_BlockType , ( NIBBLETYPE & ) a_BlockMeta ) ;
2012-06-14 09:06:06 -04:00
}
2012-10-26 04:47:30 -04:00
bool cWorld : : GetBlockInfo ( int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE & a_BlockType , NIBBLETYPE & a_Meta , NIBBLETYPE & a_SkyLight , NIBBLETYPE & a_BlockLight )
2012-10-20 07:40:34 -04:00
{
2012-10-26 04:47:30 -04:00
return m_ChunkMap - > GetBlockInfo ( a_BlockX , a_BlockY , a_BlockZ , a_BlockType , a_Meta , a_SkyLight , a_BlockLight ) ;
2012-10-20 07:40:34 -04:00
}
2012-10-06 12:58:31 -04:00
bool cWorld : : WriteBlockArea ( cBlockArea & a_Area , int a_MinBlockX , int a_MinBlockY , int a_MinBlockZ , int a_DataTypes )
{
return m_ChunkMap - > WriteBlockArea ( a_Area , a_MinBlockX , a_MinBlockY , a_MinBlockZ , a_DataTypes ) ;
}
2013-10-23 19:30:20 -04:00
void cWorld : : SpawnItemPickups ( const cItems & a_Pickups , double a_BlockX , double a_BlockY , double a_BlockZ , double a_FlyAwaySpeed , bool IsPlayerCreated )
2012-06-14 09:06:06 -04:00
{
2013-12-09 18:43:06 -05:00
a_FlyAwaySpeed / = 100 ; // Pre-divide, so that we don't have to divide each time inside the loop
2012-06-14 09:06:06 -04:00
for ( cItems : : const_iterator itr = a_Pickups . begin ( ) ; itr ! = a_Pickups . end ( ) ; + + itr )
{
2014-02-02 14:10:22 -05:00
if ( ! IsValidItem ( itr - > m_ItemType ) | | itr - > m_ItemType = = E_BLOCK_AIR )
2013-12-06 15:39:42 -05:00
{
// Don't spawn pickup if item isn't even valid; should prevent client crashing too
continue ;
}
2014-04-12 08:14:35 -04:00
float SpeedX = ( float ) ( a_FlyAwaySpeed * ( GetTickRandomNumber ( 10 ) - 5 ) ) ;
float SpeedY = ( float ) ( a_FlyAwaySpeed * GetTickRandomNumber ( 50 ) ) ;
float SpeedZ = ( float ) ( a_FlyAwaySpeed * ( GetTickRandomNumber ( 10 ) - 5 ) ) ;
2013-05-12 17:00:21 -04:00
2012-06-14 09:06:06 -04:00
cPickup * Pickup = new cPickup (
2013-09-18 17:20:08 -04:00
a_BlockX , a_BlockY , a_BlockZ ,
2013-10-23 19:30:20 -04:00
* itr , IsPlayerCreated , SpeedX , SpeedY , SpeedZ
2012-06-14 09:06:06 -04:00
) ;
2014-06-08 15:58:08 -04:00
Pickup - > Initialize ( * this ) ;
2012-06-14 09:06:06 -04:00
}
}
2013-10-23 19:30:20 -04:00
void cWorld : : SpawnItemPickups ( const cItems & a_Pickups , double a_BlockX , double a_BlockY , double a_BlockZ , double a_SpeedX , double a_SpeedY , double a_SpeedZ , bool IsPlayerCreated )
2012-06-14 09:06:06 -04:00
{
for ( cItems : : const_iterator itr = a_Pickups . begin ( ) ; itr ! = a_Pickups . end ( ) ; + + itr )
{
2014-02-02 14:10:22 -05:00
if ( ! IsValidItem ( itr - > m_ItemType ) | | itr - > m_ItemType = = E_BLOCK_AIR )
2013-12-06 15:39:42 -05:00
{
continue ;
}
2012-06-14 09:06:06 -04:00
cPickup * Pickup = new cPickup (
2013-09-18 17:20:08 -04:00
a_BlockX , a_BlockY , a_BlockZ ,
2013-10-23 19:30:20 -04:00
* itr , IsPlayerCreated , ( float ) a_SpeedX , ( float ) a_SpeedY , ( float ) a_SpeedZ
2012-06-14 09:06:06 -04:00
) ;
2014-06-08 15:58:08 -04:00
Pickup - > Initialize ( * this ) ;
2012-06-14 09:06:06 -04:00
}
}
2013-12-07 08:26:52 -05:00
int cWorld : : SpawnFallingBlock ( int a_X , int a_Y , int a_Z , BLOCKTYPE BlockType , NIBBLETYPE BlockMeta )
{
cFallingBlock * FallingBlock = new cFallingBlock ( Vector3i ( a_X , a_Y , a_Z ) , BlockType , BlockMeta ) ;
2014-06-08 15:58:08 -04:00
FallingBlock - > Initialize ( * this ) ;
2013-12-07 08:26:52 -05:00
return FallingBlock - > GetUniqueID ( ) ;
}
2013-11-26 09:37:15 -05:00
int cWorld : : SpawnExperienceOrb ( double a_X , double a_Y , double a_Z , int a_Reward )
2013-11-25 15:03:26 -05:00
{
2014-04-18 07:54:17 -04:00
if ( a_Reward < 1 )
{
return - 1 ;
}
2013-11-25 15:03:26 -05:00
cExpOrb * ExpOrb = new cExpOrb ( a_X , a_Y , a_Z , a_Reward ) ;
2014-06-08 15:58:08 -04:00
ExpOrb - > Initialize ( * this ) ;
2013-11-26 09:37:15 -05:00
return ExpOrb - > GetUniqueID ( ) ;
2013-11-25 15:03:26 -05:00
}
2014-01-12 12:04:41 -05:00
int cWorld : : SpawnMinecart ( double a_X , double a_Y , double a_Z , int a_MinecartType , const cItem & a_Content , int a_BlockHeight )
2014-01-12 08:33:32 -05:00
{
cMinecart * Minecart ;
switch ( a_MinecartType )
{
2014-01-12 12:04:41 -05:00
case E_ITEM_MINECART : Minecart = new cRideableMinecart ( a_X , a_Y , a_Z , a_Content , a_BlockHeight ) ; break ;
2014-01-12 08:33:32 -05:00
case E_ITEM_CHEST_MINECART : Minecart = new cMinecartWithChest ( a_X , a_Y , a_Z ) ; break ;
case E_ITEM_FURNACE_MINECART : Minecart = new cMinecartWithFurnace ( a_X , a_Y , a_Z ) ; break ;
case E_ITEM_MINECART_WITH_TNT : Minecart = new cMinecartWithTNT ( a_X , a_Y , a_Z ) ; break ;
case E_ITEM_MINECART_WITH_HOPPER : Minecart = new cMinecartWithHopper ( a_X , a_Y , a_Z ) ; break ;
default :
{
return - 1 ;
}
} // switch (a_MinecartType)
2014-06-08 15:58:08 -04:00
Minecart - > Initialize ( * this ) ;
2014-01-12 09:27:50 -05:00
return Minecart - > GetUniqueID ( ) ;
2014-01-12 08:33:32 -05:00
}
2014-03-08 06:24:33 -05:00
void cWorld : : SpawnPrimedTNT ( double a_X , double a_Y , double a_Z , int a_FuseTicks , double a_InitialVelocityCoeff )
2013-06-18 15:09:51 -04:00
{
2014-03-08 06:24:33 -05:00
cTNTEntity * TNT = new cTNTEntity ( a_X , a_Y , a_Z , a_FuseTicks ) ;
2014-06-08 15:58:08 -04:00
TNT - > Initialize ( * this ) ;
2014-03-05 17:12:48 -05:00
TNT - > SetSpeed (
a_InitialVelocityCoeff * ( GetTickRandomNumber ( 2 ) - 1 ) , /** -1, 0, 1 */
a_InitialVelocityCoeff * 2 ,
a_InitialVelocityCoeff * ( GetTickRandomNumber ( 2 ) - 1 )
2014-03-20 04:28:29 -04:00
) ;
2013-06-18 15:09:51 -04:00
}
2012-06-14 09:06:06 -04:00
void cWorld : : ReplaceBlocks ( const sSetBlockVector & a_Blocks , BLOCKTYPE a_FilterBlockType )
{
m_ChunkMap - > ReplaceBlocks ( a_Blocks , a_FilterBlockType ) ;
}
bool cWorld : : GetBlocks ( sSetBlockVector & a_Blocks , bool a_ContinueOnFailure )
{
return m_ChunkMap - > GetBlocks ( a_Blocks , a_ContinueOnFailure ) ;
}
2013-03-03 14:05:11 -05:00
bool cWorld : : DigBlock ( int a_X , int a_Y , int a_Z )
2012-06-14 09:06:06 -04:00
{
2014-03-02 14:25:05 -05:00
cBlockHandler * Handler = cBlockInfo : : GetHandler ( GetBlock ( a_X , a_Y , a_Z ) ) ;
2014-02-01 08:06:32 -05:00
cChunkInterface ChunkInterface ( GetChunkMap ( ) ) ;
Handler - > OnDestroyed ( ChunkInterface , * this , a_X , a_Y , a_Z ) ;
2012-06-14 09:06:06 -04:00
return m_ChunkMap - > DigBlock ( a_X , a_Y , a_Z ) ;
}
2013-03-03 14:05:11 -05:00
void cWorld : : SendBlockTo ( int a_X , int a_Y , int a_Z , cPlayer * a_Player )
2012-06-14 09:06:06 -04:00
{
m_ChunkMap - > SendBlockTo ( a_X , a_Y , a_Z , a_Player ) ;
}
2013-03-03 14:05:11 -05:00
int cWorld : : GetHeight ( int a_X , int a_Z )
2012-06-14 09:06:06 -04:00
{
return m_ChunkMap - > GetHeight ( a_X , a_Z ) ;
}
2013-04-13 17:02:10 -04:00
bool cWorld : : TryGetHeight ( int a_BlockX , int a_BlockZ , int & a_Height )
{
return m_ChunkMap - > TryGetHeight ( a_BlockX , a_BlockZ , a_Height ) ;
}
2013-03-03 14:05:11 -05:00
void cWorld : : BroadcastAttachEntity ( const cEntity & a_Entity , const cEntity * a_Vehicle )
{
return m_ChunkMap - > BroadcastAttachEntity ( a_Entity , a_Vehicle ) ;
}
2013-07-07 09:06:06 -04:00
void cWorld : : 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-18 06:38:15 -04:00
{
2013-07-07 09:06:06 -04:00
m_ChunkMap - > BroadcastBlockAction ( a_BlockX , a_BlockY , a_BlockZ , a_Byte1 , a_Byte2 , a_BlockType , a_Exclude ) ;
2012-08-18 06:38:15 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : 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
m_ChunkMap - > BroadcastBlockBreakAnimation ( a_EntityID , a_BlockX , a_BlockY , a_BlockZ , a_Stage , a_Exclude ) ;
2012-08-19 07:51:17 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastBlockEntity ( int a_BlockX , int a_BlockY , int a_BlockZ , const cClientHandle * a_Exclude )
2012-08-19 07:51:17 -04:00
{
2013-07-07 09:06:06 -04:00
m_ChunkMap - > BroadcastBlockEntity ( a_BlockX , a_BlockY , a_BlockZ , a_Exclude ) ;
2012-08-19 07:51:17 -04:00
}
2014-02-15 17:26:19 -05:00
void cWorld : : BroadcastChat ( const AString & a_Message , const cClientHandle * a_Exclude , eMessageType a_ChatPrefix )
2012-08-19 15:42:32 -04:00
{
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
{
cClientHandle * ch = ( * itr ) - > GetClientHandle ( ) ;
if ( ( ch = = a_Exclude ) | | ( ch = = NULL ) | | ! ch - > IsLoggedIn ( ) | | ch - > IsDestroyed ( ) )
{
continue ;
}
2014-02-07 13:58:52 -05:00
ch - > SendChat ( a_Message , a_ChatPrefix ) ;
2012-08-19 15:42:32 -04:00
}
}
2014-02-15 17:16:44 -05:00
void cWorld : : BroadcastChat ( const cCompositeChat & a_Message , const cClientHandle * a_Exclude )
{
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
{
cClientHandle * ch = ( * itr ) - > GetClientHandle ( ) ;
if ( ( ch = = a_Exclude ) | | ( ch = = NULL ) | | ! ch - > IsLoggedIn ( ) | | ch - > IsDestroyed ( ) )
{
continue ;
}
ch - > SendChat ( a_Message ) ;
}
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastChunkData ( int a_ChunkX , int a_ChunkZ , cChunkDataSerializer & a_Serializer , const cClientHandle * a_Exclude )
2012-08-19 15:42:32 -04:00
{
2013-07-07 09:06:06 -04:00
m_ChunkMap - > BroadcastChunkData ( a_ChunkX , a_ChunkZ , a_Serializer , a_Exclude ) ;
2012-08-19 15:42:32 -04:00
}
2014-06-27 14:56:29 -04:00
void cWorld : : BroadcastCollectEntity ( const cEntity & a_Entity , const cPlayer & a_Player , const cClientHandle * a_Exclude )
2012-08-19 15:42:32 -04:00
{
2014-06-27 14:56:29 -04:00
m_ChunkMap - > BroadcastCollectEntity ( a_Entity , a_Player , a_Exclude ) ;
2012-08-19 15:42:32 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastDestroyEntity ( const cEntity & a_Entity , const cClientHandle * a_Exclude )
2012-08-19 15:42:32 -04:00
{
2013-07-07 09:06:06 -04:00
m_ChunkMap - > BroadcastDestroyEntity ( a_Entity , a_Exclude ) ;
2012-08-19 15:42:32 -04:00
}
2013-12-15 04:51:46 -05:00
void cWorld : : BroadcastEntityEffect ( const cEntity & a_Entity , int a_EffectID , int a_Amplifier , short a_Duration , const cClientHandle * a_Exclude )
{
m_ChunkMap - > BroadcastEntityEffect ( a_Entity , a_EffectID , a_Amplifier , a_Duration , a_Exclude ) ;
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastEntityEquipment ( const cEntity & a_Entity , short a_SlotNum , const cItem & a_Item , const cClientHandle * a_Exclude )
2012-08-19 15:42:32 -04:00
{
2013-07-07 09:06:06 -04:00
m_ChunkMap - > BroadcastEntityEquipment ( a_Entity , a_SlotNum , a_Item , a_Exclude ) ;
2012-08-19 15:42:32 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastEntityHeadLook ( const cEntity & a_Entity , const cClientHandle * a_Exclude )
2012-08-19 15:42:32 -04:00
{
2013-07-07 09:06:06 -04:00
m_ChunkMap - > BroadcastEntityHeadLook ( a_Entity , a_Exclude ) ;
2012-08-19 15:42:32 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastEntityLook ( const cEntity & a_Entity , const cClientHandle * a_Exclude )
2012-08-19 15:42:32 -04:00
{
2013-07-07 09:06:06 -04:00
m_ChunkMap - > BroadcastEntityLook ( a_Entity , a_Exclude ) ;
2012-08-19 15:42:32 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastEntityMetadata ( const cEntity & a_Entity , const cClientHandle * a_Exclude )
2012-08-19 17:14:45 -04:00
{
2013-07-07 09:06:06 -04:00
m_ChunkMap - > BroadcastEntityMetadata ( a_Entity , a_Exclude ) ;
2012-08-19 17:14:45 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : 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
{
2013-07-07 09:06:06 -04:00
m_ChunkMap - > BroadcastEntityRelMove ( a_Entity , a_RelX , a_RelY , a_RelZ , a_Exclude ) ;
2012-08-19 17:14:45 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : 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
m_ChunkMap - > BroadcastEntityRelMoveLook ( a_Entity , a_RelX , a_RelY , a_RelZ , a_Exclude ) ;
2012-08-24 03:58:26 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : 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
m_ChunkMap - > BroadcastEntityStatus ( a_Entity , a_Status , a_Exclude ) ;
2012-08-24 05:49:00 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastEntityVelocity ( const cEntity & a_Entity , const cClientHandle * a_Exclude )
{
m_ChunkMap - > BroadcastEntityVelocity ( a_Entity , a_Exclude ) ;
}
2013-12-06 18:47:07 -05:00
void cWorld : : BroadcastEntityAnimation ( const cEntity & a_Entity , char a_Animation , const cClientHandle * a_Exclude )
2013-07-07 09:06:06 -04:00
{
2013-12-06 18:47:07 -05:00
m_ChunkMap - > BroadcastEntityAnimation ( a_Entity , a_Animation , a_Exclude ) ;
2013-07-07 09:06:06 -04:00
}
2013-12-22 08:45:25 -05:00
void cWorld : : 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 )
{
m_ChunkMap - > BroadcastParticleEffect ( a_ParticleName , a_SrcX , a_SrcY , a_SrcZ , a_OffsetX , a_OffsetY , a_OffsetZ , a_ParticleData , a_ParticleAmmount , a_Exclude ) ;
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastPlayerListItem ( const cPlayer & a_Player , bool a_IsOnline , const cClientHandle * a_Exclude )
2012-08-25 17:46:18 -04:00
{
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
{
cClientHandle * ch = ( * itr ) - > GetClientHandle ( ) ;
if ( ( ch = = a_Exclude ) | | ( ch = = NULL ) | | ! ch - > IsLoggedIn ( ) | | ch - > IsDestroyed ( ) )
{
continue ;
}
2013-07-07 09:06:06 -04:00
ch - > SendPlayerListItem ( a_Player , a_IsOnline ) ;
2012-08-25 17:46:18 -04:00
}
}
2013-12-15 04:51:46 -05:00
void cWorld : : BroadcastRemoveEntityEffect ( const cEntity & a_Entity , int a_EffectID , const cClientHandle * a_Exclude )
{
m_ChunkMap - > BroadcastRemoveEntityEffect ( a_Entity , a_EffectID , a_Exclude ) ;
}
2014-01-21 08:58:17 -05:00
void cWorld : : BroadcastScoreboardObjective ( const AString & a_Name , const AString & a_DisplayName , Byte a_Mode )
{
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
{
cClientHandle * ch = ( * itr ) - > GetClientHandle ( ) ;
if ( ( ch = = NULL ) | | ! ch - > IsLoggedIn ( ) | | ch - > IsDestroyed ( ) )
{
continue ;
}
ch - > SendScoreboardObjective ( a_Name , a_DisplayName , a_Mode ) ;
}
}
void cWorld : : BroadcastScoreUpdate ( const AString & a_Objective , const AString & a_Player , cObjective : : Score a_Score , Byte a_Mode )
{
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
{
cClientHandle * ch = ( * itr ) - > GetClientHandle ( ) ;
if ( ( ch = = NULL ) | | ! ch - > IsLoggedIn ( ) | | ch - > IsDestroyed ( ) )
{
continue ;
}
ch - > SendScoreUpdate ( a_Objective , a_Player , a_Score , a_Mode ) ;
}
}
void cWorld : : BroadcastDisplayObjective ( const AString & a_Objective , cScoreboard : : eDisplaySlot a_Display )
{
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
{
cClientHandle * ch = ( * itr ) - > GetClientHandle ( ) ;
if ( ( ch = = NULL ) | | ! ch - > IsLoggedIn ( ) | | ch - > IsDestroyed ( ) )
{
continue ;
}
ch - > SendDisplayObjective ( a_Objective , a_Display ) ;
}
}
2014-07-12 20:08:02 -04:00
void cWorld : : BroadcastSoundEffect ( const AString & a_SoundName , double a_X , double a_Y , double a_Z , float a_Volume , float a_Pitch , const cClientHandle * a_Exclude )
2012-08-25 17:46:18 -04:00
{
2014-07-12 20:08:02 -04:00
m_ChunkMap - > BroadcastSoundEffect ( a_SoundName , a_X , a_Y , a_Z , a_Volume , a_Pitch , a_Exclude ) ;
2012-08-25 17:46:18 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastSoundParticleEffect ( int a_EffectID , int a_SrcX , int a_SrcY , int a_SrcZ , int a_Data , const cClientHandle * a_Exclude )
2012-08-25 17:46:18 -04:00
{
2013-07-07 09:06:06 -04:00
m_ChunkMap - > BroadcastSoundParticleEffect ( a_EffectID , a_SrcX , a_SrcY , a_SrcZ , a_Data , a_Exclude ) ;
2012-08-25 17:46:18 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastSpawnEntity ( cEntity & a_Entity , const cClientHandle * a_Exclude )
2012-08-26 17:01:07 -04:00
{
2013-07-07 09:06:06 -04:00
m_ChunkMap - > BroadcastSpawnEntity ( a_Entity , a_Exclude ) ;
2012-08-26 17:01:07 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastTeleportEntity ( const cEntity & a_Entity , const cClientHandle * a_Exclude )
2012-08-27 13:31:16 -04:00
{
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
{
cClientHandle * ch = ( * itr ) - > GetClientHandle ( ) ;
if ( ( ch = = a_Exclude ) | | ( ch = = NULL ) | | ! ch - > IsLoggedIn ( ) | | ch - > IsDestroyed ( ) )
{
continue ;
}
2013-07-07 09:06:06 -04:00
ch - > SendTeleportEntity ( a_Entity ) ;
2012-08-27 13:31:16 -04:00
}
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastThunderbolt ( int a_BlockX , int a_BlockY , int a_BlockZ , const cClientHandle * a_Exclude )
2012-09-25 05:54:36 -04:00
{
2013-07-07 09:06:06 -04:00
m_ChunkMap - > BroadcastThunderbolt ( a_BlockX , a_BlockY , a_BlockZ , a_Exclude ) ;
2012-10-21 03:46:28 -04:00
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastTimeUpdate ( const cClientHandle * a_Exclude )
2012-10-21 03:46:28 -04:00
{
2013-07-07 09:06:06 -04:00
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
{
cClientHandle * ch = ( * itr ) - > GetClientHandle ( ) ;
if ( ( ch = = a_Exclude ) | | ( ch = = NULL ) | | ! ch - > IsLoggedIn ( ) | | ch - > IsDestroyed ( ) )
{
continue ;
}
2014-08-10 18:20:28 -04:00
ch - > SendTimeUpdate ( m_WorldAge , m_TimeOfDay , m_IsDaylightCycleEnabled ) ;
2013-07-07 09:06:06 -04:00
}
2012-09-25 05:54:36 -04:00
}
2013-03-03 14:05:11 -05:00
void cWorld : : BroadcastUseBed ( const cEntity & a_Entity , int a_BlockX , int a_BlockY , int a_BlockZ )
2012-09-29 16:43:42 -04:00
{
m_ChunkMap - > BroadcastUseBed ( a_Entity , a_BlockX , a_BlockY , a_BlockZ ) ;
}
2013-07-07 09:06:06 -04:00
void cWorld : : BroadcastWeather ( eWeather a_Weather , const cClientHandle * a_Exclude )
2012-08-24 03:58:26 -04:00
{
2013-07-07 09:06:06 -04:00
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
{
cClientHandle * ch = ( * itr ) - > GetClientHandle ( ) ;
if ( ( ch = = a_Exclude ) | | ( ch = = NULL ) | | ! ch - > IsLoggedIn ( ) | | ch - > IsDestroyed ( ) )
{
continue ;
}
ch - > SendWeather ( a_Weather ) ;
}
2012-08-24 03:58:26 -04:00
}
void cWorld : : SendBlockEntity ( int a_BlockX , int a_BlockY , int a_BlockZ , cClientHandle & a_Client )
{
m_ChunkMap - > SendBlockEntity ( a_BlockX , a_BlockY , a_BlockZ , a_Client ) ;
}
2014-07-06 18:50:22 -04:00
void cWorld : : MarkRedstoneDirty ( int a_ChunkX , int a_ChunkZ )
2012-06-14 09:06:06 -04:00
{
2014-07-06 18:50:22 -04:00
m_ChunkMap - > MarkRedstoneDirty ( a_ChunkX , a_ChunkZ ) ;
}
void cWorld : : MarkChunkDirty ( int a_ChunkX , int a_ChunkZ , bool a_MarkRedstoneDirty )
{
m_ChunkMap - > MarkChunkDirty ( a_ChunkX , a_ChunkZ , a_MarkRedstoneDirty ) ;
2012-06-14 09:06:06 -04:00
}
2013-04-13 17:02:10 -04:00
void cWorld : : MarkChunkSaving ( int a_ChunkX , int a_ChunkZ )
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
m_ChunkMap - > MarkChunkSaving ( a_ChunkX , a_ChunkZ ) ;
2012-06-14 09:06:06 -04:00
}
2013-04-13 17:02:10 -04:00
void cWorld : : MarkChunkSaved ( int a_ChunkX , int a_ChunkZ )
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
m_ChunkMap - > MarkChunkSaved ( a_ChunkX , a_ChunkZ ) ;
2012-06-14 09:06:06 -04:00
}
2014-07-24 12:32:05 -04:00
void cWorld : : QueueSetChunkData ( const cSetChunkDataPtr & a_SetChunkData )
2012-06-14 09:06:06 -04:00
{
2014-09-05 16:16:48 -04:00
ASSERT ( IsChunkQueued ( a_SetChunkData - > GetChunkX ( ) , a_SetChunkData - > GetChunkZ ( ) ) ) ;
2012-06-14 09:06:06 -04:00
// Validate biomes, if needed:
2014-07-24 12:32:05 -04:00
if ( ! a_SetChunkData - > AreBiomesValid ( ) )
2012-06-14 09:06:06 -04:00
{
// The biomes are not assigned, get them from the generator:
2014-07-24 12:32:05 -04:00
m_Generator . GenerateBiomes ( a_SetChunkData - > GetChunkX ( ) , a_SetChunkData - > GetChunkZ ( ) , a_SetChunkData - > GetBiomes ( ) ) ;
a_SetChunkData - > MarkBiomesValid ( ) ;
2012-06-14 09:06:06 -04:00
}
2014-07-24 12:32:05 -04:00
// Validate heightmap, if needed:
if ( ! a_SetChunkData - > IsHeightMapValid ( ) )
{
a_SetChunkData - > CalculateHeightMap ( ) ;
}
// Store a copy of the data in the queue:
// TODO: If the queue is too large, wait for it to get processed. Not likely, though.
cCSLock Lock ( m_CSSetChunkDataQueue ) ;
m_SetChunkDataQueue . push_back ( a_SetChunkData ) ;
}
void cWorld : : SetChunkData ( cSetChunkData & a_SetChunkData )
{
ASSERT ( a_SetChunkData . AreBiomesValid ( ) ) ;
ASSERT ( a_SetChunkData . IsHeightMapValid ( ) ) ;
m_ChunkMap - > SetChunkData ( a_SetChunkData ) ;
2013-04-01 16:56:25 -04:00
// Initialize the entities (outside the m_ChunkMap's CS, to fix FS #347):
2014-07-24 12:32:05 -04:00
cEntityList Entities ;
std : : swap ( a_SetChunkData . GetEntities ( ) , Entities ) ;
for ( cEntityList : : iterator itr = Entities . begin ( ) , end = Entities . end ( ) ; itr ! = end ; + + itr )
2013-04-01 14:24:05 -04:00
{
2014-06-08 15:58:08 -04:00
( * itr ) - > Initialize ( * this ) ;
2013-04-01 14:24:05 -04:00
}
2012-06-14 09:06:06 -04:00
// If a client is requesting this chunk, send it to them:
2014-07-24 12:32:05 -04:00
int ChunkX = a_SetChunkData . GetChunkX ( ) ;
int ChunkZ = a_SetChunkData . GetChunkZ ( ) ;
if ( m_ChunkMap - > HasChunkAnyClients ( ChunkX , ChunkZ ) )
{
m_ChunkSender . ChunkReady ( ChunkX , ChunkZ ) ;
}
// Save the chunk right after generating, so that we don't have to generate it again on next run
if ( a_SetChunkData . ShouldMarkDirty ( ) )
2012-06-14 09:06:06 -04:00
{
2014-08-28 05:36:35 -04:00
m_Storage . QueueSaveChunk ( ChunkX , ChunkZ ) ;
2012-06-14 09:06:06 -04:00
}
}
void cWorld : : ChunkLighted (
int a_ChunkX , int a_ChunkZ ,
const cChunkDef : : BlockNibbles & a_BlockLight ,
const cChunkDef : : BlockNibbles & a_SkyLight
)
{
m_ChunkMap - > ChunkLighted ( a_ChunkX , a_ChunkZ , a_BlockLight , a_SkyLight ) ;
}
2013-04-13 17:02:10 -04:00
bool cWorld : : GetChunkData ( int a_ChunkX , int a_ChunkZ , cChunkDataCallback & a_Callback )
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
return m_ChunkMap - > GetChunkData ( a_ChunkX , a_ChunkZ , a_Callback ) ;
2012-06-14 09:06:06 -04:00
}
2013-04-13 17:02:10 -04:00
bool cWorld : : GetChunkBlockTypes ( int a_ChunkX , int a_ChunkZ , BLOCKTYPE * a_BlockTypes )
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
return m_ChunkMap - > GetChunkBlockTypes ( a_ChunkX , a_ChunkZ , a_BlockTypes ) ;
2012-06-14 09:06:06 -04:00
}
2014-09-05 16:16:48 -04:00
bool cWorld : : IsChunkQueued ( int a_ChunkX , int a_ChunkZ ) const
{
return m_ChunkMap - > IsChunkQueued ( a_ChunkX , a_ChunkZ ) ;
}
2013-04-13 17:02:10 -04:00
bool cWorld : : IsChunkValid ( int a_ChunkX , int a_ChunkZ ) const
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
return m_ChunkMap - > IsChunkValid ( a_ChunkX , a_ChunkZ ) ;
2012-06-14 09:06:06 -04:00
}
2013-04-13 17:02:10 -04:00
bool cWorld : : HasChunkAnyClients ( int a_ChunkX , int a_ChunkZ ) const
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
return m_ChunkMap - > HasChunkAnyClients ( a_ChunkX , a_ChunkZ ) ;
2012-06-14 09:06:06 -04:00
}
2013-03-03 14:05:11 -05:00
void cWorld : : UnloadUnusedChunks ( void )
2012-06-14 09:06:06 -04:00
{
2012-11-01 17:38:20 -04:00
m_LastUnload = m_WorldAge ;
2012-06-14 09:06:06 -04:00
m_ChunkMap - > UnloadUnusedChunks ( ) ;
}
2014-02-10 20:00:07 -05:00
void cWorld : : QueueUnloadUnusedChunks ( void )
{
QueueTask ( new cWorld : : cTaskUnloadUnusedChunks ) ;
}
2012-06-14 09:06:06 -04:00
2014-02-11 08:01:25 -05:00
2012-06-14 09:06:06 -04:00
void cWorld : : CollectPickupsByPlayer ( cPlayer * a_Player )
{
m_ChunkMap - > CollectPickupsByPlayer ( a_Player ) ;
}
2013-04-13 17:02:10 -04:00
void cWorld : : AddPlayer ( cPlayer * a_Player )
2012-06-14 09:06:06 -04:00
{
2014-06-08 15:58:08 -04:00
cCSLock Lock ( m_CSPlayersToAdd ) ;
m_PlayersToAdd . push_back ( a_Player ) ;
2012-06-14 09:06:06 -04:00
}
2014-07-29 15:50:30 -04:00
void cWorld : : RemovePlayer ( cPlayer * a_Player , bool a_RemoveFromChunk )
2012-06-14 09:06:06 -04:00
{
2014-07-29 15:50:30 -04:00
if ( a_RemoveFromChunk )
2014-06-21 17:07:38 -04:00
{
2014-07-29 15:50:30 -04:00
// To prevent iterator invalidations when an entity goes through a portal and calls this function whilst being ticked by cChunk
// we should not change cChunk's entity list if asked not to
2014-06-21 17:07:38 -04:00
m_ChunkMap - > RemoveEntity ( a_Player ) ;
}
2014-06-08 15:58:08 -04:00
{
cCSLock Lock ( m_CSPlayersToAdd ) ;
m_PlayersToAdd . remove ( a_Player ) ;
}
2013-08-13 16:45:29 -04:00
{
cCSLock Lock ( m_CSPlayers ) ;
2014-07-14 14:49:31 -04:00
LOGD ( " Removing player %s from world \" %s \" " , a_Player - > GetName ( ) . c_str ( ) , m_WorldName . c_str ( ) ) ;
2013-08-13 16:45:29 -04:00
m_Players . remove ( a_Player ) ;
}
// Remove the player's client from the list of clients to be ticked:
2014-06-08 15:58:08 -04:00
cClientHandle * Client = a_Player - > GetClientHandle ( ) ;
if ( Client ! = NULL )
2013-08-13 16:45:29 -04:00
{
2014-06-08 15:58:08 -04:00
Client - > RemoveFromWorld ( ) ;
m_ChunkMap - > RemoveClientFromChunks ( Client ) ;
2013-08-13 16:45:29 -04:00
cCSLock Lock ( m_CSClients ) ;
2014-06-08 15:58:08 -04:00
m_ClientsToRemove . push_back ( Client ) ;
2013-08-13 16:45:29 -04:00
}
2012-06-14 09:06:06 -04:00
}
bool cWorld : : ForEachPlayer ( cPlayerListCallback & a_Callback )
{
// Calls the callback for each player in the list
cCSLock Lock ( m_CSPlayers ) ;
2012-06-19 16:31:21 -04:00
for ( cPlayerList : : iterator itr = m_Players . begin ( ) , itr2 = itr ; itr ! = m_Players . end ( ) ; itr = itr2 )
2012-06-14 09:06:06 -04:00
{
2012-06-19 16:31:21 -04:00
+ + itr2 ;
2012-06-14 09:06:06 -04:00
if ( a_Callback . Item ( * itr ) )
{
return false ;
}
} // for itr - m_Players[]
return true ;
}
2012-07-02 07:21:21 -04:00
bool cWorld : : DoWithPlayer ( const AString & a_PlayerName , cPlayerListCallback & a_Callback )
{
// Calls the callback for each player in the list
2012-06-14 09:06:06 -04:00
cCSLock Lock ( m_CSPlayers ) ;
2012-07-02 07:21:21 -04:00
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
2012-06-14 09:06:06 -04:00
{
2012-07-13 15:25:53 -04:00
if ( NoCaseCompare ( ( * itr ) - > GetName ( ) , a_PlayerName ) = = 0 )
2012-06-14 09:06:06 -04:00
{
2012-07-02 07:21:21 -04:00
a_Callback . Item ( * itr ) ;
return true ;
2012-06-14 09:06:06 -04:00
}
2012-07-02 07:21:21 -04:00
} // for itr - m_Players[]
return false ;
2012-06-14 09:06:06 -04:00
}
2013-02-01 14:59:58 -05:00
bool cWorld : : FindAndDoWithPlayer ( const AString & a_PlayerNameHint , cPlayerListCallback & a_Callback )
2012-08-22 19:05:12 -04:00
{
2013-02-01 14:59:58 -05:00
cPlayer * BestMatch = NULL ;
2014-05-08 14:16:35 -04:00
size_t BestRating = 0 ;
size_t NameLength = a_PlayerNameHint . length ( ) ;
2012-08-22 19:05:12 -04:00
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
{
2014-05-08 14:16:35 -04:00
size_t Rating = RateCompareString ( a_PlayerNameHint , ( * itr ) - > GetName ( ) ) ;
2013-02-01 14:59:58 -05:00
if ( Rating > = BestRating )
2012-08-22 19:05:12 -04:00
{
BestMatch = * itr ;
BestRating = Rating ;
}
2013-02-01 14:59:58 -05:00
if ( Rating = = NameLength ) // Perfect match
2012-08-22 19:05:12 -04:00
{
break ;
}
} // for itr - m_Players[]
2013-02-01 14:59:58 -05:00
if ( BestMatch ! = NULL )
2012-08-22 19:05:12 -04:00
{
return a_Callback . Item ( BestMatch ) ;
}
return false ;
}
2012-07-02 07:21:21 -04:00
// TODO: This interface is dangerous!
2014-02-03 14:52:11 -05:00
cPlayer * cWorld : : FindClosestPlayer ( const Vector3d & a_Pos , float a_SightLimit , bool a_CheckLineOfSight )
2012-06-14 09:06:06 -04:00
{
cTracer LineOfSight ( this ) ;
2014-03-14 09:36:44 -04:00
double ClosestDistance = a_SightLimit ;
cPlayer * ClosestPlayer = NULL ;
2012-06-14 09:06:06 -04:00
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : const_iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
{
Vector3f Pos = ( * itr ) - > GetPosition ( ) ;
2014-03-14 09:36:44 -04:00
double Distance = ( Pos - a_Pos ) . Length ( ) ;
2012-06-14 09:06:06 -04:00
2013-08-24 16:43:17 -04:00
if ( Distance < ClosestDistance )
2012-06-14 09:06:06 -04:00
{
2014-07-15 07:52:02 -04:00
if ( a_CheckLineOfSight )
2014-01-25 09:42:26 -05:00
{
2014-07-20 17:10:31 -04:00
if ( ! LineOfSight . Trace ( a_Pos , ( Pos - a_Pos ) , ( int ) ( Pos - a_Pos ) . Length ( ) ) )
2014-07-15 07:52:02 -04:00
{
ClosestDistance = Distance ;
ClosestPlayer = * itr ;
}
2014-01-25 09:42:26 -05:00
}
else
2012-06-14 09:06:06 -04:00
{
2013-08-24 16:43:17 -04:00
ClosestDistance = Distance ;
ClosestPlayer = * itr ;
2012-06-14 09:06:06 -04:00
}
}
}
return ClosestPlayer ;
}
void cWorld : : SendPlayerList ( cPlayer * a_DestPlayer )
{
// Sends the playerlist to a_DestPlayer
cCSLock Lock ( m_CSPlayers ) ;
2012-08-19 15:42:32 -04:00
for ( cPlayerList : : iterator itr = m_Players . begin ( ) ; itr ! = m_Players . end ( ) ; + + itr )
2012-06-14 09:06:06 -04:00
{
cClientHandle * ch = ( * itr ) - > GetClientHandle ( ) ;
if ( ( ch ! = NULL ) & & ! ch - > IsDestroyed ( ) )
{
2012-08-27 13:31:16 -04:00
a_DestPlayer - > GetClientHandle ( ) - > SendPlayerListItem ( * ( * itr ) , true ) ;
2012-06-14 09:06:06 -04:00
}
}
}
2012-06-16 04:35:07 -04:00
bool cWorld : : ForEachEntity ( cEntityCallback & a_Callback )
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
return m_ChunkMap - > ForEachEntity ( a_Callback ) ;
2012-06-14 09:06:06 -04:00
}
2012-06-16 04:35:07 -04:00
bool cWorld : : ForEachEntityInChunk ( int a_ChunkX , int a_ChunkZ , cEntityCallback & a_Callback )
2012-06-14 09:06:06 -04:00
{
2012-06-16 04:35:07 -04:00
return m_ChunkMap - > ForEachEntityInChunk ( a_ChunkX , a_ChunkZ , a_Callback ) ;
2012-06-14 09:06:06 -04:00
}
2014-09-03 11:00:26 -04:00
bool cWorld : : ForEachEntityInBox ( const cBoundingBox & a_Box , cEntityCallback & a_Callback )
{
return m_ChunkMap - > ForEachEntityInBox ( a_Box , a_Callback ) ;
}
2013-03-03 14:05:11 -05:00
bool cWorld : : DoWithEntityByID ( int a_UniqueID , cEntityCallback & a_Callback )
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
return m_ChunkMap - > DoWithEntityByID ( a_UniqueID , a_Callback ) ;
2012-06-14 09:06:06 -04:00
}
2013-04-13 17:02:10 -04:00
void cWorld : : CompareChunkClients ( int a_ChunkX1 , int a_ChunkZ1 , int a_ChunkX2 , int a_ChunkZ2 , cClientDiffCallback & a_Callback )
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
m_ChunkMap - > CompareChunkClients ( a_ChunkX1 , a_ChunkZ1 , a_ChunkX2 , a_ChunkZ2 , a_Callback ) ;
2012-06-14 09:06:06 -04:00
}
2013-04-13 17:02:10 -04:00
bool cWorld : : AddChunkClient ( int a_ChunkX , int a_ChunkZ , cClientHandle * a_Client )
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
return m_ChunkMap - > AddChunkClient ( a_ChunkX , a_ChunkZ , a_Client ) ;
2012-06-14 09:06:06 -04:00
}
2013-04-13 17:02:10 -04:00
void cWorld : : RemoveChunkClient ( int a_ChunkX , int a_ChunkZ , cClientHandle * a_Client )
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
m_ChunkMap - > RemoveChunkClient ( a_ChunkX , a_ChunkZ , a_Client ) ;
2012-06-14 09:06:06 -04:00
}
void cWorld : : RemoveClientFromChunks ( cClientHandle * a_Client )
{
m_ChunkMap - > RemoveClientFromChunks ( a_Client ) ;
}
2013-04-13 17:02:10 -04:00
void cWorld : : SendChunkTo ( int a_ChunkX , int a_ChunkZ , cClientHandle * a_Client )
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
m_ChunkSender . QueueSendChunkTo ( a_ChunkX , a_ChunkZ , a_Client ) ;
2012-06-14 09:06:06 -04:00
}
2014-02-18 07:06:18 -05:00
void cWorld : : ForceSendChunkTo ( int a_ChunkX , int a_ChunkZ , cClientHandle * a_Client )
{
a_Client - > AddWantedChunk ( a_ChunkX , a_ChunkZ ) ;
m_ChunkSender . QueueSendChunkTo ( a_ChunkX , a_ChunkZ , a_Client ) ;
}
2012-06-14 09:06:06 -04:00
void cWorld : : RemoveClientFromChunkSender ( cClientHandle * a_Client )
{
m_ChunkSender . RemoveClient ( a_Client ) ;
}
2014-08-28 05:36:35 -04:00
void cWorld : : TouchChunk ( int a_ChunkX , int a_ChunkZ )
2012-06-14 09:06:06 -04:00
{
2014-08-28 05:36:35 -04:00
m_ChunkMap - > TouchChunk ( a_ChunkX , a_ChunkZ ) ;
2012-06-14 09:06:06 -04:00
}
2014-08-28 05:36:35 -04:00
void cWorld : : ChunkLoadFailed ( int a_ChunkX , int a_ChunkZ )
2012-06-14 09:06:06 -04:00
{
2014-08-28 05:36:35 -04:00
m_ChunkMap - > ChunkLoadFailed ( a_ChunkX , a_ChunkZ ) ;
2012-06-14 09:06:06 -04:00
}
2013-06-12 03:14:06 -04:00
bool cWorld : : SetSignLines ( int a_BlockX , int a_BlockY , int a_BlockZ , const AString & a_Line1 , const AString & a_Line2 , const AString & a_Line3 , const AString & a_Line4 , cPlayer * a_Player )
2012-06-14 09:06:06 -04:00
{
2012-06-16 11:06:14 -04:00
AString Line1 ( a_Line1 ) ;
AString Line2 ( a_Line2 ) ;
AString Line3 ( a_Line3 ) ;
AString Line4 ( a_Line4 ) ;
2012-09-01 17:31:20 -04:00
if ( cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHookUpdatingSign ( this , a_BlockX , a_BlockY , a_BlockZ , Line1 , Line2 , Line3 , Line4 , a_Player ) )
2012-06-16 11:06:14 -04:00
{
2013-06-12 03:14:06 -04:00
return false ;
}
if ( m_ChunkMap - > SetSignLines ( a_BlockX , a_BlockY , a_BlockZ , Line1 , Line2 , Line3 , Line4 ) )
{
cRoot : : Get ( ) - > GetPluginManager ( ) - > CallHookUpdatedSign ( this , a_BlockX , a_BlockY , a_BlockZ , Line1 , Line2 , Line3 , Line4 , a_Player ) ;
return true ;
2012-06-16 11:06:14 -04:00
}
2013-06-12 03:14:06 -04:00
return false ;
}
bool cWorld : : UpdateSign ( int a_BlockX , int a_BlockY , int a_BlockZ , const AString & a_Line1 , const AString & a_Line2 , const AString & a_Line3 , const AString & a_Line4 , cPlayer * a_Player )
{
return SetSignLines ( a_BlockX , a_BlockY , a_BlockZ , a_Line1 , a_Line2 , a_Line3 , a_Line4 , a_Player ) ;
2012-06-14 09:06:06 -04:00
}
2014-01-23 07:57:04 -05:00
bool cWorld : : SetCommandBlockCommand ( int a_BlockX , int a_BlockY , int a_BlockZ , const AString & a_Command )
{
class cUpdateCommandBlock : public cCommandBlockCallback
{
AString m_Command ;
public :
cUpdateCommandBlock ( const AString & a_Command ) : m_Command ( a_Command ) { }
virtual bool Item ( cCommandBlockEntity * a_CommandBlock ) override
{
a_CommandBlock - > SetCommand ( m_Command ) ;
return false ;
}
} CmdBlockCB ( a_Command ) ;
return DoWithCommandBlockAt ( a_BlockX , a_BlockY , a_BlockZ , CmdBlockCB ) ;
}
2014-03-02 10:01:37 -05:00
bool cWorld : : IsTrapdoorOpen ( int a_BlockX , int a_BlockY , int a_BlockZ )
{
2014-03-02 10:16:22 -05:00
BLOCKTYPE Block ;
NIBBLETYPE Meta ;
GetBlockTypeMeta ( a_BlockX , a_BlockY , a_BlockZ , Block , Meta ) ;
if ( Block ! = E_BLOCK_TRAPDOOR )
2014-03-02 10:01:37 -05:00
{
return false ;
}
return ( Meta & 0x4 ) > 0 ;
}
bool cWorld : : SetTrapdoorOpen ( int a_BlockX , int a_BlockY , int a_BlockZ , bool a_Open )
{
2014-03-02 10:16:22 -05:00
BLOCKTYPE Block ;
NIBBLETYPE Meta ;
GetBlockTypeMeta ( a_BlockX , a_BlockY , a_BlockZ , Block , Meta ) ;
if ( Block ! = E_BLOCK_TRAPDOOR )
2014-03-02 10:01:37 -05:00
{
return false ;
}
bool IsOpen = ( Meta & 0x4 ) > 0 ;
if ( a_Open ! = IsOpen )
{
SetBlockMeta ( a_BlockX , a_BlockY , a_BlockZ , Meta ^ 0x4 ) ;
BroadcastSoundParticleEffect ( 1003 , a_BlockX , a_BlockY , a_BlockZ , 0 ) ;
return true ;
}
return false ;
}
2012-06-14 09:06:06 -04:00
void cWorld : : RegenerateChunk ( int a_ChunkX , int a_ChunkZ )
{
m_ChunkMap - > MarkChunkRegenerating ( a_ChunkX , a_ChunkZ ) ;
2014-09-02 18:14:51 -04:00
m_Generator . QueueGenerateChunk ( a_ChunkX , a_ChunkZ , true ) ;
2012-06-14 09:06:06 -04:00
}
void cWorld : : GenerateChunk ( int a_ChunkX , int a_ChunkZ )
{
2014-09-02 18:14:51 -04:00
m_Generator . QueueGenerateChunk ( a_ChunkX , a_ChunkZ , false ) ;
2012-06-14 09:06:06 -04:00
}
void cWorld : : QueueLightChunk ( int a_ChunkX , int a_ChunkZ , cChunkCoordCallback * a_Callback )
{
m_Lighting . QueueChunk ( a_ChunkX , a_ChunkZ , a_Callback ) ;
}
bool cWorld : : IsChunkLighted ( int a_ChunkX , int a_ChunkZ )
{
return m_ChunkMap - > IsChunkLighted ( a_ChunkX , a_ChunkZ ) ;
}
2012-07-02 12:30:17 -04:00
bool cWorld : : ForEachChunkInRect ( int a_MinChunkX , int a_MaxChunkX , int a_MinChunkZ , int a_MaxChunkZ , cChunkDataCallback & a_Callback )
{
return m_ChunkMap - > ForEachChunkInRect ( a_MinChunkX , a_MaxChunkX , a_MinChunkZ , a_MaxChunkZ , a_Callback ) ;
}
2012-06-14 09:06:06 -04:00
void cWorld : : SaveAllChunks ( void )
{
2012-11-01 17:38:20 -04:00
m_LastSave = m_WorldAge ;
2012-06-14 09:06:06 -04:00
m_ChunkMap - > SaveAllChunks ( ) ;
}
2013-08-11 15:05:44 -04:00
void cWorld : : QueueSaveAllChunks ( void )
{
QueueTask ( new cWorld : : cTaskSaveAllChunks ) ;
}
void cWorld : : QueueTask ( cTask * a_Task )
{
cCSLock Lock ( m_CSTasks ) ;
m_Tasks . push_back ( a_Task ) ;
}
2014-01-19 17:49:19 -05:00
void cWorld : : ScheduleTask ( int a_DelayTicks , cTask * a_Task )
2014-01-14 15:17:03 -05:00
{
2014-01-19 17:49:19 -05:00
Int64 TargetTick = a_DelayTicks + m_WorldAge ;
// Insert the task into the list of scheduled tasks, ordered by its target tick
2014-01-14 15:17:03 -05:00
cCSLock Lock ( m_CSScheduledTasks ) ;
2014-01-19 17:49:19 -05:00
for ( cScheduledTasks : : iterator itr = m_ScheduledTasks . begin ( ) , end = m_ScheduledTasks . end ( ) ; itr ! = end ; + + itr )
2014-01-14 15:17:03 -05:00
{
2014-01-19 17:49:19 -05:00
if ( ( * itr ) - > m_TargetTick > = TargetTick )
2014-01-14 15:17:03 -05:00
{
2014-01-19 17:49:19 -05:00
m_ScheduledTasks . insert ( itr , new cScheduledTask ( TargetTick , a_Task ) ) ;
2014-01-14 15:17:03 -05:00
return ;
}
}
2014-01-19 17:49:19 -05:00
m_ScheduledTasks . push_back ( new cScheduledTask ( TargetTick , a_Task ) ) ;
2014-01-14 15:17:03 -05:00
}
2013-08-11 15:05:44 -04:00
2014-06-06 16:31:16 -04:00
2012-11-01 17:38:20 -04:00
void cWorld : : AddEntity ( cEntity * a_Entity )
2012-06-14 09:06:06 -04:00
{
2014-06-06 16:31:16 -04:00
cCSLock Lock ( m_CSEntitiesToAdd ) ;
m_EntitiesToAdd . push_back ( a_Entity ) ;
2013-04-13 17:02:10 -04:00
}
bool cWorld : : HasEntity ( int a_UniqueID )
{
2014-06-06 16:31:16 -04:00
// Check if the entity is in the queue to be added to the world:
{
cCSLock Lock ( m_CSEntitiesToAdd ) ;
for ( cEntityList : : const_iterator itr = m_EntitiesToAdd . begin ( ) , end = m_EntitiesToAdd . end ( ) ; itr ! = end ; + + itr )
{
if ( ( * itr ) - > GetUniqueID ( ) = = a_UniqueID )
{
return true ;
}
} // for itr - m_EntitiesToAdd[]
}
// Check if the entity is in the chunkmap:
2013-04-13 17:02:10 -04:00
return m_ChunkMap - > HasEntity ( a_UniqueID ) ;
2012-06-14 09:06:06 -04:00
}
2013-08-11 13:18:06 -04:00
/*
2012-11-01 17:38:20 -04:00
unsigned int cWorld : : GetNumPlayers ( void )
2012-06-14 09:06:06 -04:00
{
cCSLock Lock ( m_CSPlayers ) ;
2014-07-17 10:33:09 -04:00
return m_Players . size ( ) ;
2012-06-14 09:06:06 -04:00
}
2013-08-11 13:18:06 -04:00
*/
2012-06-14 09:06:06 -04:00
int cWorld : : GetNumChunks ( void ) const
{
return m_ChunkMap - > GetNumChunks ( ) ;
}
void cWorld : : GetChunkStats ( int & a_NumValid , int & a_NumDirty , int & a_NumInLightingQueue )
{
m_ChunkMap - > GetChunkStats ( a_NumValid , a_NumDirty ) ;
a_NumInLightingQueue = ( int ) m_Lighting . GetQueueLength ( ) ;
}
2012-10-13 04:56:12 -04:00
2013-09-16 03:25:23 -04:00
void cWorld : : TickQueuedBlocks ( void )
2012-07-15 16:36:34 -04:00
{
2012-10-13 04:56:12 -04:00
if ( m_BlockTickQueue . empty ( ) )
{
2012-07-15 16:36:34 -04:00
return ;
2012-10-13 04:56:12 -04:00
}
2012-07-15 16:36:34 -04:00
m_BlockTickQueueCopy . clear ( ) ;
m_BlockTickQueue . swap ( m_BlockTickQueueCopy ) ;
2014-04-18 15:09:44 -04:00
for ( std : : vector < BlockTickQueueItem * > : : iterator itr = m_BlockTickQueueCopy . begin ( ) ; itr ! = m_BlockTickQueueCopy . end ( ) ; + + itr )
2012-07-15 16:36:34 -04:00
{
2013-11-30 09:58:27 -05:00
BlockTickQueueItem * Block = ( * itr ) ;
2013-09-16 03:25:23 -04:00
Block - > TicksToWait - = 1 ;
if ( Block - > TicksToWait < = 0 )
2012-07-15 16:36:34 -04:00
{
2013-09-16 03:25:23 -04:00
// TODO: Handle the case when the chunk is already unloaded
2013-11-30 09:58:27 -05:00
m_ChunkMap - > TickBlock ( Block - > X , Block - > Y , Block - > Z ) ;
2014-07-17 16:15:34 -04:00
delete Block ; // We don't have to remove it from the vector, this will happen automatically on the next tick
2012-10-13 04:56:12 -04:00
}
else
{
2014-07-17 10:33:09 -04:00
m_BlockTickQueue . push_back ( Block ) ; // Keep the block in the queue
2012-07-15 16:36:34 -04:00
}
2012-10-13 04:56:12 -04:00
} // for itr - m_BlockTickQueueCopy[]
2012-07-15 16:36:34 -04:00
}
2012-10-13 04:56:12 -04:00
2013-09-16 03:25:23 -04:00
void cWorld : : QueueBlockForTick ( int a_BlockX , int a_BlockY , int a_BlockZ , int a_TicksToWait )
2012-07-15 16:36:34 -04:00
{
2012-10-13 04:56:12 -04:00
BlockTickQueueItem * Block = new BlockTickQueueItem ;
Block - > X = a_BlockX ;
Block - > Y = a_BlockY ;
Block - > Z = a_BlockZ ;
2013-09-16 03:25:23 -04:00
Block - > TicksToWait = a_TicksToWait ;
2012-07-15 16:36:34 -04:00
m_BlockTickQueue . push_back ( Block ) ;
}
2012-10-13 04:56:12 -04:00
bool cWorld : : IsBlockDirectlyWatered ( int a_BlockX , int a_BlockY , int a_BlockZ )
2012-07-15 16:36:34 -04:00
{
2012-10-13 04:56:12 -04:00
return (
IsBlockWater ( GetBlock ( a_BlockX - 1 , a_BlockY , a_BlockZ ) ) | |
IsBlockWater ( GetBlock ( a_BlockX + 1 , a_BlockY , a_BlockZ ) ) | |
IsBlockWater ( GetBlock ( a_BlockX , a_BlockY , a_BlockZ - 1 ) ) | |
IsBlockWater ( GetBlock ( a_BlockX , a_BlockY , a_BlockZ + 1 ) )
) ;
}
2013-08-16 04:48:19 -04:00
int cWorld : : SpawnMob ( double a_PosX , double a_PosY , double a_PosZ , cMonster : : eType a_MonsterType )
2012-10-28 10:57:35 -04:00
{
cMonster * Monster = NULL ;
2013-09-07 20:47:02 -04:00
2013-10-20 07:25:56 -04:00
Monster = cMonster : : NewMonsterFromType ( a_MonsterType ) ;
if ( Monster ! = NULL )
{
2013-10-14 13:12:12 -04:00
Monster - > SetPosition ( a_PosX , a_PosY , a_PosZ ) ;
2013-10-20 07:25:56 -04:00
}
2013-11-10 15:48:12 -05:00
2013-09-07 20:47:02 -04:00
return SpawnMobFinalize ( Monster ) ;
}
2013-10-20 07:25:56 -04:00
int cWorld : : SpawnMobFinalize ( cMonster * a_Monster )
2013-09-07 20:47:02 -04:00
{
2014-07-24 06:15:48 -04:00
// Invalid cMonster object. Bail out.
2013-10-14 13:12:12 -04:00
if ( ! a_Monster )
2014-07-24 06:15:48 -04:00
{
2013-10-14 13:12:12 -04:00
return - 1 ;
2014-07-24 06:15:48 -04:00
}
// Give the mob full health.
2013-09-07 20:47:02 -04:00
a_Monster - > SetHealth ( a_Monster - > GetMaxHealth ( ) ) ;
2014-07-24 06:15:48 -04:00
// A plugin doesn't agree with the spawn. bail out.
2013-09-07 20:47:02 -04:00
if ( cPluginManager : : Get ( ) - > CallHookSpawningMonster ( * this , * a_Monster ) )
2013-08-08 03:13:13 -04:00
{
2013-09-07 20:47:02 -04:00
delete a_Monster ;
2014-06-19 04:49:56 -04:00
a_Monster = NULL ;
2013-08-08 03:13:13 -04:00
return - 1 ;
}
2014-07-24 06:15:48 -04:00
// Initialize the monster into the current world.
2014-06-08 15:58:08 -04:00
if ( ! a_Monster - > Initialize ( * this ) )
2013-08-08 03:13:13 -04:00
{
2013-09-07 20:47:02 -04:00
delete a_Monster ;
2014-06-19 04:49:56 -04:00
a_Monster = NULL ;
2013-08-08 03:13:13 -04:00
return - 1 ;
}
2014-07-24 06:15:48 -04:00
2013-09-07 20:47:02 -04:00
BroadcastSpawnEntity ( * a_Monster ) ;
cPluginManager : : Get ( ) - > CallHookSpawnedMonster ( * this , * a_Monster ) ;
2013-10-08 14:20:49 -04:00
2013-09-07 20:47:02 -04:00
return a_Monster - > GetUniqueID ( ) ;
2012-10-28 10:57:35 -04:00
}
2014-07-13 09:09:08 -04:00
int cWorld : : CreateProjectile ( double a_PosX , double a_PosY , double a_PosZ , cProjectileEntity : : eKind a_Kind , cEntity * a_Creator , const cItem * a_Item , const Vector3d * a_Speed )
2013-08-22 02:55:58 -04:00
{
2014-02-26 18:29:14 -05:00
cProjectileEntity * Projectile = cProjectileEntity : : Create ( a_Kind , a_Creator , a_PosX , a_PosY , a_PosZ , a_Item , a_Speed ) ;
2013-08-22 02:55:58 -04:00
if ( Projectile = = NULL )
{
return - 1 ;
}
2014-06-08 15:58:08 -04:00
if ( ! Projectile - > Initialize ( * this ) )
2013-08-22 02:55:58 -04:00
{
delete Projectile ;
2014-06-19 04:49:56 -04:00
Projectile = NULL ;
2013-08-22 02:55:58 -04:00
return - 1 ;
}
return Projectile - > GetUniqueID ( ) ;
}
2013-07-30 16:48:59 -04:00
void cWorld : : TabCompleteUserName ( const AString & a_Text , AStringVector & a_Results )
{
2014-08-01 17:15:14 -04:00
typedef std : : pair < AString : : size_type , AString > pair_t ;
size_t LastSpace = a_Text . find_last_of ( " " ) ; // Find the position of the last space
AString LastWord = a_Text . substr ( LastSpace + 1 , a_Text . length ( ) ) ; // Find the last word
if ( LastWord . empty ( ) )
{
return ;
}
std : : vector < pair_t > UsernamesByWeight ;
2013-07-31 05:16:11 -04:00
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = m_Players . begin ( ) , end = m_Players . end ( ) ; itr ! = end ; + + itr )
{
2014-03-01 16:25:27 -05:00
AString PlayerName ( ( * itr ) - > GetName ( ) ) ;
2014-08-01 17:15:14 -04:00
AString : : size_type Found = PlayerName . find ( LastWord ) ; // Try to find last word in playername
2013-08-18 09:52:38 -04:00
2014-03-01 16:25:27 -05:00
if ( Found = = AString : : npos )
2013-07-31 05:16:11 -04:00
{
2014-07-17 13:13:23 -04:00
continue ; // No match
2013-07-31 05:16:11 -04:00
}
2013-08-18 09:52:38 -04:00
2014-08-01 17:15:14 -04:00
UsernamesByWeight . push_back ( std : : make_pair ( Found , PlayerName ) ) ; // Match! Store it with the position of the match as a weight
}
Lock . Unlock ( ) ;
std : : sort ( UsernamesByWeight . begin ( ) , UsernamesByWeight . end ( ) ) ; // Sort lexicographically (by the first value, then second), so higher weights (usernames with match closer to start) come first (#1274)
/* TODO: Uncomment once migrated to C++11
std : : transform (
UsernamesByWeight . begin ( ) ,
UsernamesByWeight . end ( ) ,
std : : back_inserter ( a_Results ) ,
[ ] ( const pair_t & p ) { return p . first ; }
) ;
*/
a_Results . reserve ( UsernamesByWeight . size ( ) ) ;
for ( std : : vector < pair_t > : : const_iterator itr = UsernamesByWeight . begin ( ) ; itr ! = UsernamesByWeight . end ( ) ; + + itr )
{
a_Results . push_back ( itr - > second ) ;
2013-07-31 05:16:11 -04:00
}
2013-07-30 16:48:59 -04:00
}
2014-07-10 12:18:32 -04:00
void cWorld : : SetChunkAlwaysTicked ( int a_ChunkX , int a_ChunkZ , bool a_AlwaysTicked )
{
m_ChunkMap - > SetChunkAlwaysTicked ( a_ChunkX , a_ChunkZ , a_AlwaysTicked ) ;
}
2014-02-07 16:59:08 -05:00
cRedstoneSimulator * cWorld : : InitializeRedstoneSimulator ( cIniFile & a_IniFile )
2014-02-07 16:13:55 -05:00
{
2014-07-31 17:11:51 -04:00
AString SimulatorName = a_IniFile . GetValueSet ( " Physics " , " RedstoneSimulator " , " Incremental " ) ;
2014-02-07 16:13:55 -05:00
if ( SimulatorName . empty ( ) )
{
2014-07-31 17:11:51 -04:00
LOGWARNING ( " [Physics] RedstoneSimulator not present or empty in %s, using the default of \" Incremental \" . " , GetIniFileName ( ) . c_str ( ) ) ;
SimulatorName = " Incremental " ;
2014-02-07 16:13:55 -05:00
}
2014-02-07 16:59:08 -05:00
cRedstoneSimulator * res = NULL ;
2014-02-07 16:13:55 -05:00
2014-07-31 17:11:51 -04:00
if ( NoCaseCompare ( SimulatorName , " Incremental " ) = = 0 )
2014-02-07 16:13:55 -05:00
{
2014-02-07 16:59:08 -05:00
res = new cIncrementalRedstoneSimulator ( * this ) ;
2014-02-07 16:13:55 -05:00
}
2014-02-07 16:59:08 -05:00
else if ( NoCaseCompare ( SimulatorName , " noop " ) = = 0 )
2014-02-07 16:13:55 -05:00
{
res = new cRedstoneNoopSimulator ( * this ) ;
}
m_SimulatorManager - > RegisterSimulator ( res , 1 ) ;
return res ;
}
2012-10-13 05:53:28 -04:00
cFluidSimulator * cWorld : : InitializeFluidSimulator ( cIniFile & a_IniFile , const char * a_FluidName , BLOCKTYPE a_SimulateBlock , BLOCKTYPE a_StationaryBlock )
{
AString SimulatorNameKey ;
Printf ( SimulatorNameKey , " %sSimulator " , a_FluidName ) ;
AString SimulatorSectionName ;
Printf ( SimulatorSectionName , " %sSimulator " , a_FluidName ) ;
2014-07-31 12:21:45 -04:00
AString SimulatorName = a_IniFile . GetValueSet ( " Physics " , SimulatorNameKey , " Vanilla " ) ;
2012-10-13 05:53:28 -04:00
if ( SimulatorName . empty ( ) )
{
2014-03-05 08:54:38 -05:00
LOGWARNING ( " [Physics] %s not present or empty in %s, using the default of \" Vanilla \" . " , SimulatorNameKey . c_str ( ) , GetIniFileName ( ) . c_str ( ) ) ;
SimulatorName = " Vanilla " ;
2012-10-13 05:53:28 -04:00
}
cFluidSimulator * res = NULL ;
2012-10-14 16:10:03 -04:00
bool IsWater = ( strcmp ( a_FluidName , " Water " ) = = 0 ) ; // Used for defaults
2012-10-15 16:16:43 -04:00
int Rate = 1 ;
2013-03-14 16:46:40 -04:00
if (
2013-03-14 15:44:27 -04:00
( NoCaseCompare ( SimulatorName , " vaporize " ) = = 0 ) | |
( NoCaseCompare ( SimulatorName , " vaporise " ) = = 0 )
)
{
res = new cVaporizeFluidSimulator ( * this , a_SimulateBlock , a_StationaryBlock ) ;
}
2013-03-14 16:03:42 -04:00
else if (
( NoCaseCompare ( SimulatorName , " noop " ) = = 0 ) | |
( NoCaseCompare ( SimulatorName , " nop " ) = = 0 ) | |
( NoCaseCompare ( SimulatorName , " null " ) = = 0 ) | |
( NoCaseCompare ( SimulatorName , " nil " ) = = 0 )
)
{
res = new cNoopFluidSimulator ( * this , a_SimulateBlock , a_StationaryBlock ) ;
}
2012-10-13 05:53:28 -04:00
else
{
2013-03-14 16:46:40 -04:00
int Falloff = a_IniFile . GetValueSetI ( SimulatorSectionName , " Falloff " , IsWater ? 1 : 2 ) ;
int TickDelay = a_IniFile . GetValueSetI ( SimulatorSectionName , " TickDelay " , IsWater ? 5 : 30 ) ;
int NumNeighborsForSource = a_IniFile . GetValueSetI ( SimulatorSectionName , " NumNeighborsForSource " , IsWater ? 2 : - 1 ) ;
2014-03-05 08:54:38 -05:00
if ( NoCaseCompare ( SimulatorName , " floody " ) = = 0 )
{
res = new cFloodyFluidSimulator ( * this , a_SimulateBlock , a_StationaryBlock , Falloff , TickDelay , NumNeighborsForSource ) ;
}
else if ( NoCaseCompare ( SimulatorName , " vanilla " ) = = 0 )
{
res = new cVanillaFluidSimulator ( * this , a_SimulateBlock , a_StationaryBlock , Falloff , TickDelay , NumNeighborsForSource ) ;
}
else
{
// The simulator name doesn't match anything we have, issue a warning:
LOGWARNING ( " %s [Physics]:%s specifies an unknown simulator, using the default \" Vanilla \" . " , GetIniFileName ( ) . c_str ( ) , SimulatorNameKey . c_str ( ) ) ;
res = new cVanillaFluidSimulator ( * this , a_SimulateBlock , a_StationaryBlock , Falloff , TickDelay , NumNeighborsForSource ) ;
}
2012-10-13 05:53:28 -04:00
}
2012-10-15 16:16:43 -04:00
m_SimulatorManager - > RegisterSimulator ( res , Rate ) ;
2012-10-13 05:53:28 -04:00
return res ;
}
2013-08-11 15:05:44 -04:00
2014-02-11 14:38:28 -05:00
2014-02-13 14:36:24 -05:00
2014-06-08 15:58:08 -04:00
void cWorld : : AddQueuedPlayers ( void )
{
ASSERT ( m_TickThread . IsCurrentThread ( ) ) ;
// Grab the list of players to add, it has to be locked to access it:
cPlayerList PlayersToAdd ;
{
cCSLock Lock ( m_CSPlayersToAdd ) ;
std : : swap ( PlayersToAdd , m_PlayersToAdd ) ;
}
// Add all the players in the grabbed list:
{
cCSLock Lock ( m_CSPlayers ) ;
for ( cPlayerList : : iterator itr = PlayersToAdd . begin ( ) , end = PlayersToAdd . end ( ) ; itr ! = end ; + + itr )
{
2014-08-13 19:03:30 -04:00
ASSERT ( std : : find ( m_Players . begin ( ) , m_Players . end ( ) , * itr ) = = m_Players . end ( ) ) ; // Is it already in the list? HOW?
2014-06-12 10:21:07 -04:00
LOGD ( " Adding player %s to world \" %s \" . " , ( * itr ) - > GetName ( ) . c_str ( ) , m_WorldName . c_str ( ) ) ;
2014-07-22 12:26:48 -04:00
2014-06-08 15:58:08 -04:00
m_Players . push_back ( * itr ) ;
( * itr ) - > SetWorld ( this ) ;
// Add to chunkmap, if not already there (Spawn vs MoveToWorld):
2014-06-10 12:25:53 -04:00
m_ChunkMap - > AddEntityIfNotPresent ( * itr ) ;
2014-06-08 15:58:08 -04:00
} // for itr - PlayersToAdd[]
} // Lock(m_CSPlayers)
// Add all the players' clienthandles:
{
cCSLock Lock ( m_CSClients ) ;
for ( cPlayerList : : iterator itr = PlayersToAdd . begin ( ) , end = PlayersToAdd . end ( ) ; itr ! = end ; + + itr )
{
cClientHandle * Client = ( * itr ) - > GetClientHandle ( ) ;
if ( Client ! = NULL )
{
m_Clients . push_back ( Client ) ;
}
} // for itr - PlayersToAdd[]
} // Lock(m_CSClients)
// Stream chunks to all eligible clients:
for ( cPlayerList : : iterator itr = PlayersToAdd . begin ( ) , end = PlayersToAdd . end ( ) ; itr ! = end ; + + itr )
{
cClientHandle * Client = ( * itr ) - > GetClientHandle ( ) ;
if ( Client ! = NULL )
{
Client - > StreamChunks ( ) ;
2014-06-12 10:21:07 -04:00
Client - > SendPlayerMoveLook ( ) ;
Client - > SendHealth ( ) ;
Client - > SendWholeInventory ( * ( * itr ) - > GetWindow ( ) ) ;
2014-06-08 15:58:08 -04:00
}
} // for itr - PlayersToAdd[]
}
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2013-08-11 15:05:44 -04:00
// cWorld::cTaskSaveAllChunks:
void cWorld : : cTaskSaveAllChunks : : Run ( cWorld & a_World )
{
a_World . SaveAllChunks ( ) ;
}
2013-10-29 12:44:51 -04:00
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2014-02-10 20:00:07 -05:00
// cWorld::cTaskUnloadUnusedChunks
2013-08-11 15:05:44 -04:00
2014-02-10 20:00:07 -05:00
void cWorld : : cTaskUnloadUnusedChunks : : Run ( cWorld & a_World )
{
a_World . UnloadUnusedChunks ( ) ;
}
2013-08-11 15:05:44 -04:00
2013-10-29 12:44:51 -04:00
2014-02-11 14:38:28 -05:00
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2014-05-25 08:46:34 -04:00
// cWorld::cTaskSendBlockTo
2014-05-29 06:57:06 -04:00
cWorld : : cTaskSendBlockToAllPlayers : : cTaskSendBlockToAllPlayers ( std : : vector < Vector3i > & a_SendQueue ) :
m_SendQueue ( a_SendQueue )
2014-05-25 08:46:34 -04:00
{
}
void cWorld : : cTaskSendBlockToAllPlayers : : Run ( cWorld & a_World )
{
class cPlayerCallback :
public cPlayerListCallback
{
public :
2014-05-29 06:57:06 -04:00
cPlayerCallback ( std : : vector < Vector3i > & a_SendQueue , cWorld & a_World ) :
m_SendQueue ( a_SendQueue ) ,
2014-05-25 08:46:34 -04:00
m_World ( a_World )
{
}
virtual bool Item ( cPlayer * a_Player )
{
2014-05-29 06:57:06 -04:00
for ( std : : vector < Vector3i > : : const_iterator itr = m_SendQueue . begin ( ) ; itr ! = m_SendQueue . end ( ) ; + + itr )
{
m_World . SendBlockTo ( itr - > x , itr - > y , itr - > z , a_Player ) ;
}
2014-05-25 08:46:34 -04:00
return false ;
}
private :
2014-05-29 06:57:06 -04:00
std : : vector < Vector3i > m_SendQueue ;
2014-05-25 08:46:34 -04:00
cWorld & m_World ;
2014-05-29 06:57:06 -04:00
} PlayerCallback ( m_SendQueue , a_World ) ;
2014-05-25 08:46:34 -04:00
a_World . ForEachPlayer ( PlayerCallback ) ;
}
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2014-01-10 16:22:54 -05:00
// cWorld::cChunkGeneratorCallbacks:
cWorld : : cChunkGeneratorCallbacks : : cChunkGeneratorCallbacks ( cWorld & a_World ) :
m_World ( & a_World )
{
}
void cWorld : : cChunkGeneratorCallbacks : : OnChunkGenerated ( cChunkDesc & a_ChunkDesc )
{
cChunkDef : : BlockNibbles BlockMetas ;
a_ChunkDesc . CompressBlockMetas ( BlockMetas ) ;
2014-08-29 12:19:27 -04:00
cSetChunkDataPtr SetChunkData ( new cSetChunkData (
2014-01-10 16:22:54 -05:00
a_ChunkDesc . GetChunkX ( ) , a_ChunkDesc . GetChunkZ ( ) ,
a_ChunkDesc . GetBlockTypes ( ) , BlockMetas ,
NULL , NULL , // We don't have lighting, chunk will be lighted when needed
& a_ChunkDesc . GetHeightMap ( ) , & a_ChunkDesc . GetBiomeMap ( ) ,
a_ChunkDesc . GetEntities ( ) , a_ChunkDesc . GetBlockEntities ( ) ,
true
2014-08-29 12:19:27 -04:00
) ) ;
SetChunkData - > RemoveInvalidBlockEntities ( ) ;
m_World - > QueueSetChunkData ( SetChunkData ) ;
2014-01-10 16:22:54 -05:00
}
bool cWorld : : cChunkGeneratorCallbacks : : IsChunkValid ( int a_ChunkX , int a_ChunkZ )
{
return m_World - > IsChunkValid ( a_ChunkX , a_ChunkZ ) ;
}
2014-09-05 16:16:48 -04:00
bool cWorld : : cChunkGeneratorCallbacks : : IsChunkQueued ( int a_ChunkX , int a_ChunkZ )
{
return m_World - > IsChunkQueued ( a_ChunkX , a_ChunkZ ) ;
}
2014-01-10 16:22:54 -05:00
bool cWorld : : cChunkGeneratorCallbacks : : HasChunkAnyClients ( int a_ChunkX , int a_ChunkZ )
{
return m_World - > HasChunkAnyClients ( a_ChunkX , a_ChunkZ ) ;
}
void cWorld : : cChunkGeneratorCallbacks : : CallHookChunkGenerating ( cChunkDesc & a_ChunkDesc )
{
cPluginManager : : Get ( ) - > CallHookChunkGenerating (
m_World , a_ChunkDesc . GetChunkX ( ) , a_ChunkDesc . GetChunkZ ( ) , & a_ChunkDesc
) ;
}
void cWorld : : cChunkGeneratorCallbacks : : CallHookChunkGenerated ( cChunkDesc & a_ChunkDesc )
{
cPluginManager : : Get ( ) - > CallHookChunkGenerated (
m_World , a_ChunkDesc . GetChunkX ( ) , a_ChunkDesc . GetChunkZ ( ) , & a_ChunkDesc
) ;
}