Proper fix for FS #347. Also unification of ticking block entities.

git-svn-id: http://mc-server.googlecode.com/svn/trunk@1348 0a769ca7-a7f5-676a-18bf-c427514a06d6
master
madmaxoft@gmail.com 2013-04-01 20:56:25 +00:00
parent 47b9f6d941
commit 578560d213
8 changed files with 44 additions and 141 deletions

View File

@ -43,18 +43,18 @@ protected:
{}
public:
virtual ~cBlockEntity() {};
virtual void Destroy() {};
virtual void Destroy(void) {};
// Position, in absolute block coordinates:
int GetPosX() { return m_PosX; }
int GetPosY() { return m_PosY; }
int GetPosZ() { return m_PosZ; }
int GetPosX(void) const { return m_PosX; }
int GetPosY(void) const { return m_PosY; }
int GetPosZ(void) const { return m_PosZ; }
ENUM_BLOCK_ID GetBlockType() { return m_BlockType; }
ENUM_BLOCK_ID GetBlockType(void) const { return m_BlockType; }
cWorld * GetWorld(void) const {return m_World; }
virtual void SaveToJson (Json::Value & a_Value ) = 0;
virtual void SaveToJson (Json::Value & a_Value) = 0;
virtual void UsedBy( cPlayer * a_Player ) = 0;
@ -62,6 +62,9 @@ public:
To send to all eligible clients, use cWorld::BroadcastBlockEntity()
*/
virtual void SendTo(cClientHandle & a_Client) = 0;
/// Ticks the entity; returns true if the chunk should be marked as dirty as a result of this ticking. By default does nothing.
virtual bool Tick(float a_Dt) { return false; }
protected:
int m_PosX; // Position in absolute block coordinates

View File

@ -296,14 +296,8 @@ void cChunk::SetAllData(
CalculateHeightmap();
}
// Initialize incoming entities:
for (cEntityList::iterator itr = a_Entities.begin(), end = a_Entities.end(); itr != end; ++itr)
{
(*itr)->Initialize(m_World);
} // for itr - a_Entities[]
// Append entities to current entity list:
m_Entities.splice(m_Entities.end(), a_Entities);
m_Entities.insert(m_Entities.end(), a_Entities.begin(), a_Entities.end());
// Clear the block entities present - either the loader / saver has better, or we'll create empty ones:
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
@ -456,24 +450,13 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
TickBlocks(a_TickRandom);
// Tick block entities (furnaces)
// Tick all block entities in this chunk:
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
{
if ((*itr)->GetBlockType() == E_BLOCK_FURNACE)
{
m_IsDirty = ((cFurnaceEntity *)(*itr))->Tick( a_Dt ) | m_IsDirty;
}
m_IsDirty = (*itr)->Tick(a_Dt) | m_IsDirty;
}
// Tick block entities (dispensers)
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
{
if ((*itr)->GetBlockType() == E_BLOCK_DISPENSER)
{
m_IsDirty = ((cDispenserEntity *)(*itr))->Tick( a_Dt ) | m_IsDirty;
}
}
ApplyWeatherToTop(a_TickRandom);
ApplyWeatherToTop();
}
@ -570,10 +553,10 @@ void cChunk::TickBlocks(MTRand & a_TickRandom)
void cChunk::ApplyWeatherToTop(MTRand & a_TickRandom)
void cChunk::ApplyWeatherToTop()
{
if (
(a_TickRandom.randInt(100) != 0) ||
(m_World->GetTickRandomNumber(100) != 0) ||
(
(m_World->GetWeather() != eWeather_Rain) &&
(m_World->GetWeather() != eWeather_ThunderStorm)
@ -584,8 +567,8 @@ void cChunk::ApplyWeatherToTop(MTRand & a_TickRandom)
return;
}
int X = a_TickRandom.randInt(15);
int Z = a_TickRandom.randInt(15);
int X = m_World->GetTickRandomNumber(15);
int Z = m_World->GetTickRandomNumber(15);
switch (GetBiomeAt(X, Z))
{
case biTaiga:

View File

@ -355,7 +355,7 @@ private:
void TickBlocks (MTRand & a_TickRandom);
/// Adds snow to the top of snowy biomes and hydrates farmland / fills cauldrons in rainy biomes
void ApplyWeatherToTop(MTRand & a_TickRandom);
void ApplyWeatherToTop(void);
/// Grows sugarcane by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking)
void GrowSugarcane (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks);

View File

@ -261,37 +261,6 @@ void cDispenserEntity::SetSlot(int a_Slot, const cItem & a_Item)
#define READ(File, Var) \
if (File.Read(&Var, sizeof(Var)) != sizeof(Var)) \
{ \
LOGERROR("ERROR READING cDispenserEntity %s FROM FILE (line %d)", #Var, __LINE__); \
return false; \
}
bool cDispenserEntity::LoadFromFile(cFile & f)
{
READ(f, m_PosX);
READ(f, m_PosY);
READ(f, m_PosZ);
unsigned int NumSlots = 0;
READ(f, NumSlots);
m_Items = new cItem[ NumSlots ];
for(unsigned int i = 0; i < NumSlots; i++)
{
cItem & Item = m_Items[i];
READ(f, Item.m_ItemType);
READ(f, Item.m_ItemCount);
READ(f, Item.m_ItemDamage);
}
return true;
}
bool cDispenserEntity::LoadFromJson( const Json::Value& a_Value )
{
m_PosX = a_Value.get("x", 0).asInt();

View File

@ -30,17 +30,13 @@ public:
virtual ~cDispenserEntity();
virtual void Destroy();
bool LoadFromFile(cFile & a_File); // deprecated format
bool LoadFromJson(const Json::Value& a_Value );
virtual void SaveToJson(Json::Value& a_Value ) override;
bool LoadFromJson(const Json::Value & a_Value);
// cBlockEntity overrides:
virtual void SaveToJson(Json::Value & a_Value) override;
virtual void SendTo(cClientHandle & a_Client) override;
// Returns true if there's any change, forcing the chunk to go dirty.
bool Tick( float a_Dt );
virtual void UsedBy( cPlayer * a_Player ) override;
virtual bool Tick(float a_Dt) override;
virtual void UsedBy(cPlayer * a_Player) override;
const cItem * GetSlot(int i) const { return &(m_Items[i]); }

View File

@ -280,51 +280,7 @@ void cFurnaceEntity::SetSlot(int a_Slot, const cItem & a_Item)
#define READ(File, Var) \
if (File.Read(&Var, sizeof(Var)) != sizeof(Var)) \
{ \
LOGERROR("ERROR READING cFurnaceEntity %s FROM FILE (line %d)", #Var, __LINE__); \
return false; \
}
bool cFurnaceEntity::LoadFromFile(cFile & f)
{
READ(f, m_PosX);
READ(f, m_PosY);
READ(f, m_PosZ);
unsigned int NumSlots = 0;
READ(f, NumSlots);
m_Items = new cItem[ NumSlots ];
for(unsigned int i = 0; i < NumSlots; i++)
{
cItem & Item = m_Items[i];
READ(f, Item.m_ItemType);
READ(f, Item.m_ItemCount);
READ(f, Item.m_ItemDamage);
}
cItem CookingItem;
READ(f, CookingItem.m_ItemType);
READ(f, CookingItem.m_ItemCount);
READ(f, CookingItem.m_ItemDamage);
if (!CookingItem.IsEmpty())
{
m_CookingItem = new cItem(CookingItem);
}
READ(f, m_CookTime);
READ(f, m_TimeCooked);
READ(f, m_BurnTime);
READ(f, m_TimeBurned);
return true;
}
bool cFurnaceEntity::LoadFromJson( const Json::Value& a_Value )
bool cFurnaceEntity::LoadFromJson(const Json::Value & a_Value)
{
m_PosX = a_Value.get("x", 0).asInt();
m_PosY = a_Value.get("y", 0).asInt();

View File

@ -32,19 +32,15 @@ public:
static const char * GetClassStatic() { return "cFurnaceEntity"; }
bool LoadFromFile(cFile & a_File); // deprecated format
bool LoadFromJson(const Json::Value& a_Value );
virtual void SaveToJson(Json::Value& a_Value ) override;
bool LoadFromJson(const Json::Value & a_Value);
// cBlockEntity overrides:
virtual void SaveToJson(Json::Value & a_Value) override;
virtual void SendTo(cClientHandle & a_Client) override;
// Returns true if there's any change, forcing the chunk to go dirty.
bool Tick( float a_Dt );
virtual void UsedBy( cPlayer * a_Player ) override;
virtual bool Tick(float a_Dt) override;
virtual void UsedBy(cPlayer * a_Player) override;
bool StartCooking();
bool StartCooking(void);
/// Restarts cooking. Used after the furnace is loaded from storage to set up the internal variables so that cooking continues, if it was active. Returns true if cooking.
bool ContinueCooking(void);

View File

@ -1599,18 +1599,18 @@ void cWorld::SetChunkData(
m_Generator.GenerateBiomes(a_ChunkX, a_ChunkZ, BiomeMap);
}
m_ChunkMap->SetChunkData(
a_ChunkX, a_ChunkY, a_ChunkZ,
a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight,
a_HeightMap, *Biomes,
a_Entities, a_BlockEntities,
a_MarkDirty
);
// Initialize the entities (outside the m_ChunkMap's CS, to fix FS #347):
for (cEntityList::iterator itr = a_Entities.begin(), end = a_Entities.end(); itr != end; ++itr)
{
// _X: 2013_04_01: Hotfix for FS #347 - deadlock between the anvil loader thread and the tick thread
// By locking the entities here, we break one of the 3 conditions needed for the deadlock
cCSLock Lock(m_CSEntities);
m_ChunkMap->SetChunkData(
a_ChunkX, a_ChunkY, a_ChunkZ,
a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight,
a_HeightMap, *Biomes,
a_Entities, a_BlockEntities,
a_MarkDirty
);
(*itr)->Initialize(this);
}
// If a client is requesting this chunk, send it to them: