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
This commit is contained in:
parent
47b9f6d941
commit
578560d213
@ -43,14 +43,14 @@ 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; }
|
||||
|
||||
@ -63,6 +63,9 @@ public:
|
||||
*/
|
||||
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
|
||||
int m_PosY;
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -30,16 +30,12 @@ public:
|
||||
virtual ~cDispenserEntity();
|
||||
virtual void Destroy();
|
||||
|
||||
bool LoadFromFile(cFile & a_File); // deprecated format
|
||||
|
||||
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 bool Tick(float a_Dt) override;
|
||||
virtual void UsedBy(cPlayer * a_Player) override;
|
||||
|
||||
const cItem * GetSlot(int i) const { return &(m_Items[i]); }
|
||||
|
@ -280,50 +280,6 @@ 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)
|
||||
{
|
||||
m_PosX = a_Value.get("x", 0).asInt();
|
||||
|
@ -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);
|
||||
|
||||
// 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 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);
|
||||
|
@ -1599,11 +1599,6 @@ void cWorld::SetChunkData(
|
||||
m_Generator.GenerateBiomes(a_ChunkX, a_ChunkZ, BiomeMap);
|
||||
}
|
||||
|
||||
{
|
||||
// _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,
|
||||
@ -1611,6 +1606,11 @@ void cWorld::SetChunkData(
|
||||
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)
|
||||
{
|
||||
(*itr)->Initialize(this);
|
||||
}
|
||||
|
||||
// If a client is requesting this chunk, send it to them:
|
||||
|
Loading…
Reference in New Issue
Block a user