New fire simulator, fully rewritten to the new scheme of things, directly accessing chunk data.
http://forum.mc-server.org/showthread.php?tid=617&pid=6626#pid6626 git-svn-id: http://mc-server.googlecode.com/svn/trunk@1233 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
parent
d636875fc0
commit
011e11af2c
@ -434,6 +434,9 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
|
|||||||
|
|
||||||
CheckBlocks();
|
CheckBlocks();
|
||||||
|
|
||||||
|
// Tick simulators:
|
||||||
|
m_World->GetSimulatorManager()->SimulateChunk(a_Dt, m_PosX, m_PosZ, this);
|
||||||
|
|
||||||
TickBlocks(a_TickRandom);
|
TickBlocks(a_TickRandom);
|
||||||
|
|
||||||
// Tick block entities (furnaces)
|
// Tick block entities (furnaces)
|
||||||
@ -1208,7 +1211,7 @@ void cChunk::QueueTickBlockNeighbors(int a_RelX, int a_RelY, int a_RelZ)
|
|||||||
} ;
|
} ;
|
||||||
for (int i = 0; i < ARRAYCOUNT(Coords); i++)
|
for (int i = 0; i < ARRAYCOUNT(Coords); i++)
|
||||||
{
|
{
|
||||||
cChunk * ch = GetRelNeighborChunk(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z);
|
cChunk * ch = GetRelNeighborChunk(a_RelX + Coords[i].x, a_RelZ + Coords[i].z);
|
||||||
if (ch != NULL)
|
if (ch != NULL)
|
||||||
{
|
{
|
||||||
ch->QueueTickBlock(a_RelX + Coords[i].x, a_RelY + Coords[i].y, a_RelZ + Coords[i].z);
|
ch->QueueTickBlock(a_RelX + Coords[i].x, a_RelY + Coords[i].y, a_RelZ + Coords[i].z);
|
||||||
@ -1320,14 +1323,14 @@ void cChunk::AddBlockEntity( cBlockEntity* a_BlockEntity )
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
cBlockEntity * cChunk::GetBlockEntity(int a_X, int a_Y, int a_Z)
|
cBlockEntity * cChunk::GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||||
{
|
{
|
||||||
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
|
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
((*itr)->GetPosX() == a_X) &&
|
((*itr)->GetPosX() == a_BlockX) &&
|
||||||
((*itr)->GetPosY() == a_Y) &&
|
((*itr)->GetPosY() == a_BlockY) &&
|
||||||
((*itr)->GetPosZ() == a_Z)
|
((*itr)->GetPosZ() == a_BlockZ)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return *itr;
|
return *itr;
|
||||||
@ -1803,26 +1806,26 @@ void cChunk::GetBlockInfo(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_Bloc
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
cChunk * cChunk::GetNeighborChunk(int a_BlockX, int a_BlockY, int a_BlockZ)
|
cChunk * cChunk::GetNeighborChunk(int a_BlockX, int a_BlockZ)
|
||||||
{
|
{
|
||||||
// Convert coords to relative, then call the relative version:
|
// Convert coords to relative, then call the relative version:
|
||||||
a_BlockX -= m_PosX * cChunkDef::Width;
|
a_BlockX -= m_PosX * cChunkDef::Width;
|
||||||
a_BlockZ -= m_PosZ * cChunkDef::Width;
|
a_BlockZ -= m_PosZ * cChunkDef::Width;
|
||||||
return GetRelNeighborChunk(a_BlockX, a_BlockY, a_BlockZ);
|
return GetRelNeighborChunk(a_BlockX, a_BlockZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelY, int a_RelZ)
|
cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ)
|
||||||
{
|
{
|
||||||
bool ReturnThis = true;
|
bool ReturnThis = true;
|
||||||
if (a_RelX < 0)
|
if (a_RelX < 0)
|
||||||
{
|
{
|
||||||
if (m_NeighborXM != NULL)
|
if (m_NeighborXM != NULL)
|
||||||
{
|
{
|
||||||
cChunk * Candidate = m_NeighborXM->GetRelNeighborChunk(a_RelX + cChunkDef::Width, a_RelY, a_RelZ);
|
cChunk * Candidate = m_NeighborXM->GetRelNeighborChunk(a_RelX + cChunkDef::Width, a_RelZ);
|
||||||
if (Candidate != NULL)
|
if (Candidate != NULL)
|
||||||
{
|
{
|
||||||
return Candidate;
|
return Candidate;
|
||||||
@ -1835,7 +1838,7 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelY, int a_RelZ)
|
|||||||
{
|
{
|
||||||
if (m_NeighborXP != NULL)
|
if (m_NeighborXP != NULL)
|
||||||
{
|
{
|
||||||
cChunk * Candidate = m_NeighborXP->GetRelNeighborChunk(a_RelX - cChunkDef::Width, a_RelY, a_RelZ);
|
cChunk * Candidate = m_NeighborXP->GetRelNeighborChunk(a_RelX - cChunkDef::Width, a_RelZ);
|
||||||
if (Candidate != NULL)
|
if (Candidate != NULL)
|
||||||
{
|
{
|
||||||
return Candidate;
|
return Candidate;
|
||||||
@ -1849,7 +1852,7 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelY, int a_RelZ)
|
|||||||
{
|
{
|
||||||
if (m_NeighborZM != NULL)
|
if (m_NeighborZM != NULL)
|
||||||
{
|
{
|
||||||
return m_NeighborZM->GetRelNeighborChunk(a_RelX, a_RelY, a_RelZ + cChunkDef::Width);
|
return m_NeighborZM->GetRelNeighborChunk(a_RelX, a_RelZ + cChunkDef::Width);
|
||||||
// For requests crossing both X and Z, the X-first way has been already tried
|
// For requests crossing both X and Z, the X-first way has been already tried
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1858,7 +1861,7 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelY, int a_RelZ)
|
|||||||
{
|
{
|
||||||
if (m_NeighborZP != NULL)
|
if (m_NeighborZP != NULL)
|
||||||
{
|
{
|
||||||
return m_NeighborZP->GetRelNeighborChunk(a_RelX, a_RelY, a_RelZ - cChunkDef::Width);
|
return m_NeighborZP->GetRelNeighborChunk(a_RelX, a_RelZ - cChunkDef::Width);
|
||||||
// For requests crossing both X and Z, the X-first way has been already tried
|
// For requests crossing both X and Z, the X-first way has been already tried
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
#include "ChunkDef.h"
|
#include "ChunkDef.h"
|
||||||
|
|
||||||
|
#include "Simulator/FireSimulator.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -147,13 +149,13 @@ public:
|
|||||||
/** Returns the chunk into which the specified block belongs, by walking the neighbors.
|
/** Returns the chunk into which the specified block belongs, by walking the neighbors.
|
||||||
Will return self if appropriate. Returns NULL if not reachable through neighbors.
|
Will return self if appropriate. Returns NULL if not reachable through neighbors.
|
||||||
*/
|
*/
|
||||||
cChunk * GetNeighborChunk(int a_BlockX, int a_BlockY, int a_BlockZ);
|
cChunk * GetNeighborChunk(int a_BlockX, int a_BlockZ);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns the chunk into which the relatively-specified block belongs, by walking the neighbors.
|
Returns the chunk into which the relatively-specified block belongs, by walking the neighbors.
|
||||||
Will return self if appropriate. Returns NULL if not reachable through neighbors.
|
Will return self if appropriate. Returns NULL if not reachable through neighbors.
|
||||||
*/
|
*/
|
||||||
cChunk * GetRelNeighborChunk(int a_RelX, int a_RelY, int a_RelZ);
|
cChunk * GetRelNeighborChunk(int a_RelX, int a_RelZ);
|
||||||
|
|
||||||
EMCSBiome GetBiomeAt(int a_RelX, int a_RelZ) const {return cChunkDef::GetBiome(m_BiomeMap, a_RelX, a_RelZ); }
|
EMCSBiome GetBiomeAt(int a_RelX, int a_RelZ) const {return cChunkDef::GetBiome(m_BiomeMap, a_RelX, a_RelZ); }
|
||||||
|
|
||||||
@ -250,10 +252,23 @@ public:
|
|||||||
inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); }
|
inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); }
|
||||||
inline NIBBLETYPE GetMeta(int a_BlockIdx) {return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); }
|
inline NIBBLETYPE GetMeta(int a_BlockIdx) {return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); }
|
||||||
inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_Meta); }
|
inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_Meta); }
|
||||||
|
inline void SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_BlockIdx, a_Meta); }
|
||||||
|
|
||||||
inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); }
|
inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); }
|
||||||
inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ); }
|
inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ); }
|
||||||
|
|
||||||
|
/// Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick()
|
||||||
|
bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
|
||||||
|
|
||||||
|
/// Same as SetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick()
|
||||||
|
bool UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||||
|
|
||||||
|
/// Same as FastSetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick()
|
||||||
|
bool UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
||||||
|
|
||||||
|
// Simulator data:
|
||||||
|
cFireSimulatorChunkData & GetFireSimulatorData(void) { return m_FireSimulatorData; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class cChunkMap;
|
friend class cChunkMap;
|
||||||
@ -297,9 +312,12 @@ private:
|
|||||||
cChunk * m_NeighborZM; // Neighbor at [X, Z - 1]
|
cChunk * m_NeighborZM; // Neighbor at [X, Z - 1]
|
||||||
cChunk * m_NeighborZP; // Neighbor at [X, Z + 1]
|
cChunk * m_NeighborZP; // Neighbor at [X, Z + 1]
|
||||||
|
|
||||||
|
cFireSimulatorChunkData m_FireSimulatorData;
|
||||||
|
|
||||||
|
|
||||||
void RemoveBlockEntity(cBlockEntity * a_BlockEntity);
|
void RemoveBlockEntity(cBlockEntity * a_BlockEntity);
|
||||||
void AddBlockEntity (cBlockEntity * a_BlockEntity);
|
void AddBlockEntity (cBlockEntity * a_BlockEntity);
|
||||||
cBlockEntity * GetBlockEntity( int a_X, int a_Y, int a_Z );
|
cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
cBlockEntity * GetBlockEntity(const Vector3i & a_BlockPos) { return GetBlockEntity(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); }
|
cBlockEntity * GetBlockEntity(const Vector3i & a_BlockPos) { return GetBlockEntity(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); }
|
||||||
|
|
||||||
void SpreadLightOfBlock(NIBBLETYPE * a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff);
|
void SpreadLightOfBlock(NIBBLETYPE * a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff);
|
||||||
@ -331,15 +349,6 @@ private:
|
|||||||
|
|
||||||
/// Checks if a leaves block at the specified coords has a log up to 4 blocks away connected by other leaves blocks (false if no log)
|
/// Checks if a leaves block at the specified coords has a log up to 4 blocks away connected by other leaves blocks (false if no log)
|
||||||
bool HasNearLog(cBlockArea & a_Area, int a_BlockX, int a_BlockY, int a_BlockZ);
|
bool HasNearLog(cBlockArea & a_Area, int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
|
|
||||||
/// Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick()
|
|
||||||
bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
|
|
||||||
|
|
||||||
/// Same as SetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick()
|
|
||||||
bool UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
|
||||||
|
|
||||||
/// Same as FastSetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick()
|
|
||||||
bool UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef cChunk * cChunkPtr;
|
typedef cChunk * cChunkPtr;
|
||||||
|
@ -516,3 +516,31 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Generic template that can store any kind of data together with a triplet of 3 coords:
|
||||||
|
template <typename X> class cCoordWithData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int z;
|
||||||
|
X Data;
|
||||||
|
|
||||||
|
cCoordWithData<typename X>(int a_X, int a_Y, int a_Z) :
|
||||||
|
x(a_X), y(a_Y), z(a_Z)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cCoordWithData<typename X>(int a_X, int a_Y, int a_Z, const X & a_Data) :
|
||||||
|
x(a_X), y(a_Y), z(a_Z), Data(a_Data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
// Illegal in C++03: typedef std::list< cCoordWithData<X> > cCoordWithDataList<X>;
|
||||||
|
typedef cCoordWithData<int> cCoordWithInt;
|
||||||
|
typedef std::list<cCoordWithInt> cCoordWithIntList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,17 +5,73 @@
|
|||||||
#include "../World.h"
|
#include "../World.h"
|
||||||
#include "../BlockID.h"
|
#include "../BlockID.h"
|
||||||
#include "../Defines.h"
|
#include "../Defines.h"
|
||||||
|
#include "../Chunk.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cFireSimulator::cFireSimulator(cWorld & a_World)
|
// Easy switch for turning on debugging logging:
|
||||||
: cSimulator(a_World)
|
#if 0
|
||||||
, m_Blocks(new BlockList)
|
#define FLOG LOGD
|
||||||
, m_Buffer(new BlockList)
|
#else
|
||||||
, m_BurningBlocks(new BlockList)
|
#define FLOG(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_CHANCE_REPLACE_FUEL 100000
|
||||||
|
#define MAX_CHANCE_FLAMMABILITY 100000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const struct
|
||||||
{
|
{
|
||||||
|
int x, y, z;
|
||||||
|
} gCrossCoords[] =
|
||||||
|
{
|
||||||
|
{ 1, 0, 0},
|
||||||
|
{-1, 0, 0},
|
||||||
|
{ 0, 0, 1},
|
||||||
|
{ 0, 0, -1},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
int x, y, z;
|
||||||
|
} gNeighborCoords[] =
|
||||||
|
{
|
||||||
|
{ 1, 0, 0},
|
||||||
|
{-1, 0, 0},
|
||||||
|
{ 0, 1, 0},
|
||||||
|
{ 0, -1, 0},
|
||||||
|
{ 0, 0, 1},
|
||||||
|
{ 0, 0, -1},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cFireSimulator:
|
||||||
|
|
||||||
|
cFireSimulator::cFireSimulator(cWorld & a_World, cIniFile & a_IniFile) :
|
||||||
|
cSimulator(a_World)
|
||||||
|
{
|
||||||
|
// Read params from the ini file:
|
||||||
|
m_BurnStepTimeFuel = a_IniFile.GetValueSetI("FireSimulator", "BurnStepTimeFuel", 500);
|
||||||
|
m_BurnStepTimeNonfuel = a_IniFile.GetValueSetI("FireSimulator", "BurnStepTimeNonfuel", 100);
|
||||||
|
m_Flammability = a_IniFile.GetValueSetI("FireSimulator", "Flammability", 50);
|
||||||
|
m_ReplaceFuelChance = a_IniFile.GetValueSetI("FireSimulator", "ReplaceFuelChance", 50000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -24,43 +80,64 @@ cFireSimulator::cFireSimulator(cWorld & a_World)
|
|||||||
|
|
||||||
cFireSimulator::~cFireSimulator()
|
cFireSimulator::~cFireSimulator()
|
||||||
{
|
{
|
||||||
delete m_Buffer;
|
|
||||||
delete m_Blocks;
|
|
||||||
delete m_BurningBlocks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFireSimulator::Simulate(float a_Dt)
|
void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
|
||||||
{
|
{
|
||||||
m_Buffer->clear();
|
cCoordWithIntList & Data = a_Chunk->GetFireSimulatorData();
|
||||||
std::swap(m_Blocks, m_Buffer);
|
|
||||||
|
|
||||||
for (BlockList::iterator itr = m_Buffer->begin(); itr != m_Buffer->end(); ++itr)
|
int NumMSecs = (int)a_Dt;
|
||||||
|
for (cCoordWithIntList::iterator itr = Data.begin(); itr != Data.end();)
|
||||||
{
|
{
|
||||||
Vector3i Pos = *itr;
|
int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z);
|
||||||
|
BLOCKTYPE BlockType = a_Chunk->GetBlock(idx);
|
||||||
|
|
||||||
BLOCKTYPE BlockID = m_World.GetBlock(Pos.x, Pos.y, Pos.z);
|
if (!IsAllowedBlock(BlockType))
|
||||||
|
|
||||||
if (!IsAllowedBlock(BlockID)) // Check wheather the block is still burning
|
|
||||||
{
|
{
|
||||||
|
// The block is no longer eligible (not a fire block anymore; a player probably placed a block over the fire)
|
||||||
|
FLOG("FS: Removing block {%d, %d, %d}",
|
||||||
|
itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width
|
||||||
|
);
|
||||||
|
itr = Data.erase(itr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BurnBlockAround(Pos.x, Pos.y, Pos.z)) //Burn single block and if there was one -> next time again
|
// Try to spread the fire:
|
||||||
|
TrySpreadFire(a_Chunk, itr->x, itr->y, itr->z);
|
||||||
|
|
||||||
|
itr->Data -= NumMSecs;
|
||||||
|
if (itr->Data >= 0)
|
||||||
{
|
{
|
||||||
m_Blocks->push_back(Pos);
|
// Not yet, wait for it longer
|
||||||
|
++itr;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Burn out the fire one step by increasing the meta:
|
||||||
|
/*
|
||||||
|
FLOG("FS: Fire at {%d, %d, %d} is stepping",
|
||||||
|
itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
NIBBLETYPE BlockMeta = a_Chunk->GetMeta(idx);
|
||||||
|
if (BlockMeta == 0x0f)
|
||||||
{
|
{
|
||||||
if (!IsForeverBurnable(m_World.GetBlock(Pos.x, Pos.y - 1, Pos.z)) && !FiresForever(BlockID))
|
// The fire burnt out completely
|
||||||
{
|
FLOG("FS: Fire at {%d, %d, %d} burnt out, removing the fire block",
|
||||||
m_World.SetBlock(Pos.x, Pos.y, Pos.z, E_BLOCK_AIR, 0);
|
itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width
|
||||||
|
);
|
||||||
|
a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0);
|
||||||
|
RemoveFuelNeighbors(a_Chunk, itr->x, itr->y, itr->z);
|
||||||
|
itr = Data.erase(itr);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
a_Chunk->SetMeta(idx, BlockMeta + 1);
|
||||||
} // for itr - m_Buffer[]
|
itr->Data = GetBurnStepTime(a_Chunk, itr->x, itr->y, itr->z); // TODO: Add some randomness into this
|
||||||
|
} // for itr - Data[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -69,7 +146,39 @@ void cFireSimulator::Simulate(float a_Dt)
|
|||||||
|
|
||||||
bool cFireSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType)
|
bool cFireSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType)
|
||||||
{
|
{
|
||||||
return (a_BlockType == E_BLOCK_FIRE) || IsBlockLava(a_BlockType);
|
return (a_BlockType == E_BLOCK_FIRE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cFireSimulator::IsFuel(BLOCKTYPE a_BlockType)
|
||||||
|
{
|
||||||
|
switch (a_BlockType)
|
||||||
|
{
|
||||||
|
case E_BLOCK_PLANKS:
|
||||||
|
case E_BLOCK_LEAVES:
|
||||||
|
case E_BLOCK_LOG:
|
||||||
|
case E_BLOCK_WOOL:
|
||||||
|
case E_BLOCK_BOOKCASE:
|
||||||
|
case E_BLOCK_FENCE:
|
||||||
|
case E_BLOCK_TNT:
|
||||||
|
case E_BLOCK_VINES:
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cFireSimulator::IsForever(BLOCKTYPE a_BlockType)
|
||||||
|
{
|
||||||
|
return (a_BlockType == E_BLOCK_NETHERRACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -78,97 +187,173 @@ bool cFireSimulator::IsAllowedBlock(BLOCKTYPE a_BlockType)
|
|||||||
|
|
||||||
void cFireSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
|
void cFireSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
|
||||||
{
|
{
|
||||||
// TODO: This can be optimized
|
int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
|
||||||
BLOCKTYPE BlockType = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
|
||||||
|
BLOCKTYPE BlockType = a_Chunk->GetBlock(RelX, a_BlockY, RelZ);
|
||||||
if (!IsAllowedBlock(BlockType))
|
if (!IsAllowedBlock(BlockType))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicates:
|
// Check for duplicates:
|
||||||
for (BlockList::iterator itr = m_Blocks->begin(); itr != m_Blocks->end(); ++itr )
|
cFireSimulatorChunkData & ChunkData = a_Chunk->GetFireSimulatorData();
|
||||||
|
for (cCoordWithIntList::iterator itr = ChunkData.begin(), end = ChunkData.end(); itr != end; ++itr)
|
||||||
{
|
{
|
||||||
Vector3i Pos = *itr;
|
if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ))
|
||||||
if ((Pos.x == a_BlockX) && (Pos.y == a_BlockY) && (Pos.z == a_BlockZ))
|
|
||||||
{
|
{
|
||||||
|
// Already present, skip adding
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
} // for itr - ChunkData[]
|
||||||
|
|
||||||
m_Blocks->push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
|
FLOG("FS: Adding block {%d, %d, %d}", a_BlockX, a_BlockY, a_BlockZ);
|
||||||
|
ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ, 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cFireSimulator::IsForeverBurnable( BLOCKTYPE a_BlockType )
|
int cFireSimulator::GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
|
||||||
{
|
{
|
||||||
return a_BlockType == E_BLOCK_NETHERRACK;
|
if (a_RelY > 0)
|
||||||
|
{
|
||||||
|
BLOCKTYPE BlockBelow = a_Chunk->GetBlock(a_RelX, a_RelY - 1, a_RelZ);
|
||||||
|
if (IsForever(BlockBelow))
|
||||||
|
{
|
||||||
|
// Is burning atop of netherrack, burn forever (re-check in 10 sec)
|
||||||
|
return 10000;
|
||||||
|
}
|
||||||
|
if (IsFuel(BlockBelow))
|
||||||
|
{
|
||||||
|
return m_BurnStepTimeFuel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((a_RelY < cChunkDef::Height - 1) && IsFuel(a_Chunk->GetBlock(a_RelX, a_RelY - 1, a_RelZ)))
|
||||||
|
{
|
||||||
|
return m_BurnStepTimeFuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
|
||||||
|
{
|
||||||
|
BLOCKTYPE BlockType;
|
||||||
|
NIBBLETYPE BlockMeta;
|
||||||
|
if (a_Chunk->UnboundedRelGetBlock(a_RelX + gCrossCoords[i].x, a_RelY, a_RelZ + gCrossCoords[i].z, BlockType, BlockMeta))
|
||||||
|
{
|
||||||
|
if (IsFuel(BlockType))
|
||||||
|
{
|
||||||
|
return m_BurnStepTimeFuel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // for i - gCrossCoords[]
|
||||||
|
return m_BurnStepTimeNonfuel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cFireSimulator::IsBurnable( BLOCKTYPE a_BlockType )
|
void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
|
||||||
{
|
{
|
||||||
return a_BlockType == E_BLOCK_PLANKS
|
/*
|
||||||
|| a_BlockType == E_BLOCK_LEAVES
|
if (m_World.GetTickRandomNumber(10000) > 100)
|
||||||
|| a_BlockType == E_BLOCK_LOG
|
{
|
||||||
|| a_BlockType == E_BLOCK_WOOL
|
// Make the chance to spread 100x smaller
|
||||||
|| a_BlockType == E_BLOCK_BOOKCASE
|
return;
|
||||||
|| a_BlockType == E_BLOCK_FENCE
|
}
|
||||||
|| a_BlockType == E_BLOCK_TNT
|
*/
|
||||||
|| a_BlockType == E_BLOCK_VINES;
|
|
||||||
|
for (int x = a_RelX - 1; x <= a_RelX + 1; x++)
|
||||||
|
{
|
||||||
|
for (int z = a_RelZ - 1; z <= a_RelZ + 1; z++)
|
||||||
|
{
|
||||||
|
for (int y = a_RelY - 1; y <= a_RelY + 2; y++) // flames spread up one more block than around
|
||||||
|
{
|
||||||
|
// No need to check the coords for equality with the parent block,
|
||||||
|
// it cannot catch fire anyway (because it's not an air block)
|
||||||
|
|
||||||
|
if (m_World.GetTickRandomNumber(MAX_CHANCE_FLAMMABILITY) > m_Flammability)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the fire in the neighbor {x, y, z}
|
||||||
|
/*
|
||||||
|
FLOG("FS: Trying to start fire at {%d, %d, %d}.",
|
||||||
|
x + a_Chunk->GetPosX() * cChunkDef::Width, y, z + a_Chunk->GetPosZ() * cChunkDef::Width
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
if (CanStartFireInBlock(a_Chunk, x, y, z))
|
||||||
|
{
|
||||||
|
FLOG("FS: Starting new fire at {%d, %d, %d}.",
|
||||||
|
x + a_Chunk->GetPosX() * cChunkDef::Width, y, z + a_Chunk->GetPosZ() * cChunkDef::Width
|
||||||
|
);
|
||||||
|
a_Chunk->UnboundedRelSetBlock(x, y, z, E_BLOCK_FIRE, 0);
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
} // for z
|
||||||
|
} // for x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cFireSimulator::FiresForever( BLOCKTYPE a_BlockType )
|
void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
|
||||||
{
|
{
|
||||||
return a_BlockType != E_BLOCK_FIRE;
|
for (int i = 0; i < ARRAYCOUNT(gNeighborCoords); i++)
|
||||||
|
{
|
||||||
|
BLOCKTYPE BlockType;
|
||||||
|
NIBBLETYPE BlockMeta;
|
||||||
|
if (!a_Chunk->UnboundedRelGetBlock(a_RelX + gNeighborCoords[i].x, a_RelY + gNeighborCoords[i].y, a_RelZ + gNeighborCoords[i].z, BlockType, BlockMeta))
|
||||||
|
{
|
||||||
|
// Neighbor not accessible, ignore it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!IsFuel(BlockType))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool ShouldReplaceFuel = (m_World.GetTickRandomNumber(MAX_CHANCE_REPLACE_FUEL) < m_ReplaceFuelChance);
|
||||||
|
a_Chunk->UnboundedRelSetBlock(
|
||||||
|
a_RelX + gNeighborCoords[i].x, a_RelY + gNeighborCoords[i].y, a_RelZ + gNeighborCoords[i].z,
|
||||||
|
ShouldReplaceFuel ? E_BLOCK_FIRE : E_BLOCK_AIR, 0
|
||||||
|
);
|
||||||
|
} // for i - Coords[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cFireSimulator::BurnBlockAround(int a_X, int a_Y, int a_Z)
|
bool cFireSimulator::CanStartFireInBlock(cChunk * a_NearChunk, int a_RelX, int a_RelY, int a_RelZ)
|
||||||
{
|
{
|
||||||
return BurnBlock(a_X + 1, a_Y, a_Z)
|
BLOCKTYPE BlockType;
|
||||||
|| BurnBlock(a_X - 1, a_Y, a_Z)
|
NIBBLETYPE BlockMeta;
|
||||||
|| BurnBlock(a_X, a_Y + 1, a_Z)
|
if (!a_NearChunk->UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta))
|
||||||
|| BurnBlock(a_X, a_Y - 1, a_Z)
|
|
||||||
|| BurnBlock(a_X, a_Y, a_Z + 1)
|
|
||||||
|| BurnBlock(a_X, a_Y, a_Z - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cFireSimulator::BurnBlock(int a_X, int a_Y, int a_Z)
|
|
||||||
{
|
{
|
||||||
BLOCKTYPE BlockID = m_World.GetBlock(a_X, a_Y, a_Z);
|
// The chunk is not accessible
|
||||||
if (IsBurnable(BlockID))
|
|
||||||
{
|
|
||||||
m_World.SetBlock(a_X, a_Y, a_Z, E_BLOCK_FIRE, 0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (IsForeverBurnable(BlockID))
|
|
||||||
{
|
|
||||||
BLOCKTYPE BlockAbove = m_World.GetBlock(a_X, a_Y + 1, a_Z);
|
|
||||||
if (BlockAbove == E_BLOCK_AIR)
|
|
||||||
{
|
|
||||||
m_World.SetBlock(a_X, a_Y + 1, a_Z, E_BLOCK_FIRE, 0); //Doesn´t notify the simulator so it won´t go off
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (BlockType != E_BLOCK_AIR)
|
||||||
|
{
|
||||||
|
// Only an air block can be replaced by a fire block
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < ARRAYCOUNT(gNeighborCoords); i++)
|
||||||
|
{
|
||||||
|
if (!a_NearChunk->UnboundedRelGetBlock(a_RelX + gNeighborCoords[i].x, a_RelY + gNeighborCoords[i].y, a_RelZ + gNeighborCoords[i].z, BlockType, BlockMeta))
|
||||||
|
{
|
||||||
|
// Neighbor inaccessible, skip it while evaluating
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (IsFuel(BlockType))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // for i - Coords[]
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,32 +8,68 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cFireSimulator : public cSimulator
|
/** The fire simulator takes care of the fire blocks.
|
||||||
|
It periodically increases their meta ("steps") until they "burn out"; it also supports the forever burning netherrack.
|
||||||
|
Each individual fire block gets stored in per-chunk data; that list is then used for fast retrieval.
|
||||||
|
The data value associated with each coord is used as the number of msec that the fire takes until
|
||||||
|
it progresses to the next step (blockmeta++). This value is updated if a neighbor is changed.
|
||||||
|
The simulator reads its parameters from the ini file given to the constructor.
|
||||||
|
*/
|
||||||
|
class cFireSimulator :
|
||||||
|
public cSimulator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cFireSimulator(cWorld & a_World);
|
cFireSimulator(cWorld & a_World, cIniFile & a_IniFile);
|
||||||
~cFireSimulator();
|
~cFireSimulator();
|
||||||
|
|
||||||
virtual void Simulate( float a_Dt ) override;
|
virtual void Simulate(float a_Dt) override {} // not used
|
||||||
|
virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override;
|
||||||
|
|
||||||
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override;
|
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override;
|
||||||
|
|
||||||
virtual bool IsBurnable( BLOCKTYPE a_BlockType );
|
bool IsFuel (BLOCKTYPE a_BlockType);
|
||||||
virtual bool IsForeverBurnable( BLOCKTYPE a_BlockType );
|
bool IsForever(BLOCKTYPE a_BlockType);
|
||||||
virtual bool FiresForever( BLOCKTYPE a_BlockType );
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/// Time (in msec) that a fire block takes to burn with a fuel block into the next step
|
||||||
|
unsigned m_BurnStepTimeFuel;
|
||||||
|
|
||||||
|
/// Time (in msec) that a fire block takes to burn without a fuel block into the next step
|
||||||
|
unsigned m_BurnStepTimeNonfuel;
|
||||||
|
|
||||||
|
/// Chance [0..100000] of an adjacent fuel to catch fire on each tick
|
||||||
|
unsigned m_Flammability;
|
||||||
|
|
||||||
|
/// Chance [0..100000] of a fuel burning out being replaced by a new fire block instead of an air block
|
||||||
|
unsigned m_ReplaceFuelChance;
|
||||||
|
|
||||||
|
|
||||||
virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override;
|
virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override;
|
||||||
virtual bool BurnBlockAround(int a_X, int a_Y, int a_Z);
|
|
||||||
virtual bool BurnBlock(int a_X, int a_Y, int a_Z);
|
|
||||||
|
|
||||||
typedef std::list <Vector3i> BlockList;
|
/// Returns the time [msec] after which the specified fire block is stepped again; based on surrounding fuels
|
||||||
BlockList *m_Blocks;
|
int GetBurnStepTime(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ);
|
||||||
BlockList *m_Buffer;
|
|
||||||
|
|
||||||
BlockList *m_BurningBlocks;
|
/// Tries to spread fire to a neighborhood of the specified block
|
||||||
|
void TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ);
|
||||||
|
|
||||||
|
/// Removes all burnable blocks neighboring the specified block
|
||||||
|
void RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ);
|
||||||
|
|
||||||
|
/** Returns true if a fire can be started in the specified block,
|
||||||
|
that is, it is an air block and has fuel next to it.
|
||||||
|
Note that a_NearChunk may be a chunk neighbor to the block specified!
|
||||||
|
The coords are relative to a_NearChunk but not necessarily in it.
|
||||||
|
*/
|
||||||
|
bool CanStartFireInBlock(cChunk * a_NearChunk, int a_RelX, int a_RelY, int a_RelZ);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Stores individual fire blocks in the chunk; the int data is used as the time [msec] the fire takes to step to another stage (blockmeta++)
|
||||||
|
typedef cCoordWithIntList cFireSimulatorChunkData;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,10 +34,10 @@ void cSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chu
|
|||||||
AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
|
AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
|
||||||
AddBlock(a_BlockX, a_BlockY - 1, a_BlockZ, a_Chunk);
|
AddBlock(a_BlockX, a_BlockY - 1, a_BlockZ, a_Chunk);
|
||||||
AddBlock(a_BlockX, a_BlockY + 1, a_BlockZ, a_Chunk);
|
AddBlock(a_BlockX, a_BlockY + 1, a_BlockZ, a_Chunk);
|
||||||
AddBlock(a_BlockX - 1, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 1, a_BlockY, a_BlockZ));
|
AddBlock(a_BlockX - 1, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 1, a_BlockZ));
|
||||||
AddBlock(a_BlockX + 1, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 1, a_BlockY, a_BlockZ));
|
AddBlock(a_BlockX + 1, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 1, a_BlockZ));
|
||||||
AddBlock(a_BlockX, a_BlockY, a_BlockZ - 1, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockY, a_BlockZ - 1));
|
AddBlock(a_BlockX, a_BlockY, a_BlockZ - 1, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 1));
|
||||||
AddBlock(a_BlockX, a_BlockY, a_BlockZ + 1, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockY, a_BlockZ + 1));
|
AddBlock(a_BlockX, a_BlockY, a_BlockZ + 1, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Vector3i.h"
|
#include "../Vector3i.h"
|
||||||
|
#include "../../iniFile/iniFile.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -254,12 +254,12 @@ cWorld::cWorld(const AString & a_WorldName) :
|
|||||||
m_WaterSimulator = InitializeFluidSimulator(IniFile, "Water", E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER);
|
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_LavaSimulator = InitializeFluidSimulator(IniFile, "Lava", E_BLOCK_LAVA, E_BLOCK_STATIONARY_LAVA);
|
||||||
m_SandSimulator = new cSandSimulator(*this);
|
m_SandSimulator = new cSandSimulator(*this);
|
||||||
m_FireSimulator = new cFireSimulator(*this);
|
m_FireSimulator = new cFireSimulator(*this, IniFile);
|
||||||
m_RedstoneSimulator = new cRedstoneSimulator(*this);
|
m_RedstoneSimulator = new cRedstoneSimulator(*this);
|
||||||
|
|
||||||
// Water and Lava simulators get registered in InitializeFluidSimulator()
|
// Water and Lava simulators get registered in InitializeFluidSimulator()
|
||||||
m_SimulatorManager->RegisterSimulator(m_SandSimulator, 1);
|
m_SimulatorManager->RegisterSimulator(m_SandSimulator, 1);
|
||||||
m_SimulatorManager->RegisterSimulator(m_FireSimulator, 10);
|
m_SimulatorManager->RegisterSimulator(m_FireSimulator, 1);
|
||||||
m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1);
|
m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1);
|
||||||
|
|
||||||
// Save any changes that the defaults may have done to the ini file:
|
// Save any changes that the defaults may have done to the ini file:
|
||||||
|
@ -451,6 +451,9 @@ public:
|
|||||||
/// Spawns a mob of the specified entity type. Returns the mob's EntityID if recognized and spawned, <0 otherwise
|
/// Spawns a mob of the specified entity type. Returns the mob's EntityID if recognized and spawned, <0 otherwise
|
||||||
int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, int a_EntityType); // tolua_export
|
int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, int a_EntityType); // tolua_export
|
||||||
|
|
||||||
|
/// Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread!
|
||||||
|
unsigned GetTickRandomNumber(unsigned a_Range) { return m_TickRand.randInt(a_Range); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class cRoot;
|
friend class cRoot;
|
||||||
|
Loading…
Reference in New Issue
Block a user