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,18 +43,18 @@ protected:
|
|||||||
{}
|
{}
|
||||||
public:
|
public:
|
||||||
virtual ~cBlockEntity() {};
|
virtual ~cBlockEntity() {};
|
||||||
virtual void Destroy() {};
|
virtual void Destroy(void) {};
|
||||||
|
|
||||||
// Position, in absolute block coordinates:
|
// Position, in absolute block coordinates:
|
||||||
int GetPosX() { return m_PosX; }
|
int GetPosX(void) const { return m_PosX; }
|
||||||
int GetPosY() { return m_PosY; }
|
int GetPosY(void) const { return m_PosY; }
|
||||||
int GetPosZ() { return m_PosZ; }
|
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; }
|
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;
|
virtual void UsedBy( cPlayer * a_Player ) = 0;
|
||||||
|
|
||||||
@ -62,6 +62,9 @@ public:
|
|||||||
To send to all eligible clients, use cWorld::BroadcastBlockEntity()
|
To send to all eligible clients, use cWorld::BroadcastBlockEntity()
|
||||||
*/
|
*/
|
||||||
virtual void SendTo(cClientHandle & a_Client) = 0;
|
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:
|
protected:
|
||||||
int m_PosX; // Position in absolute block coordinates
|
int m_PosX; // Position in absolute block coordinates
|
||||||
|
@ -296,14 +296,8 @@ void cChunk::SetAllData(
|
|||||||
CalculateHeightmap();
|
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:
|
// 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:
|
// 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)
|
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);
|
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)
|
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
|
||||||
{
|
{
|
||||||
if ((*itr)->GetBlockType() == E_BLOCK_FURNACE)
|
m_IsDirty = (*itr)->Tick(a_Dt) | m_IsDirty;
|
||||||
{
|
|
||||||
m_IsDirty = ((cFurnaceEntity *)(*itr))->Tick( a_Dt ) | m_IsDirty;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tick block entities (dispensers)
|
ApplyWeatherToTop();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -570,10 +553,10 @@ void cChunk::TickBlocks(MTRand & a_TickRandom)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunk::ApplyWeatherToTop(MTRand & a_TickRandom)
|
void cChunk::ApplyWeatherToTop()
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
(a_TickRandom.randInt(100) != 0) ||
|
(m_World->GetTickRandomNumber(100) != 0) ||
|
||||||
(
|
(
|
||||||
(m_World->GetWeather() != eWeather_Rain) &&
|
(m_World->GetWeather() != eWeather_Rain) &&
|
||||||
(m_World->GetWeather() != eWeather_ThunderStorm)
|
(m_World->GetWeather() != eWeather_ThunderStorm)
|
||||||
@ -584,8 +567,8 @@ void cChunk::ApplyWeatherToTop(MTRand & a_TickRandom)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int X = a_TickRandom.randInt(15);
|
int X = m_World->GetTickRandomNumber(15);
|
||||||
int Z = a_TickRandom.randInt(15);
|
int Z = m_World->GetTickRandomNumber(15);
|
||||||
switch (GetBiomeAt(X, Z))
|
switch (GetBiomeAt(X, Z))
|
||||||
{
|
{
|
||||||
case biTaiga:
|
case biTaiga:
|
||||||
|
@ -355,7 +355,7 @@ private:
|
|||||||
void TickBlocks (MTRand & a_TickRandom);
|
void TickBlocks (MTRand & a_TickRandom);
|
||||||
|
|
||||||
/// Adds snow to the top of snowy biomes and hydrates farmland / fills cauldrons in rainy biomes
|
/// 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)
|
/// 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);
|
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 )
|
bool cDispenserEntity::LoadFromJson( const Json::Value& a_Value )
|
||||||
{
|
{
|
||||||
m_PosX = a_Value.get("x", 0).asInt();
|
m_PosX = a_Value.get("x", 0).asInt();
|
||||||
|
@ -30,17 +30,13 @@ public:
|
|||||||
virtual ~cDispenserEntity();
|
virtual ~cDispenserEntity();
|
||||||
virtual void Destroy();
|
virtual void Destroy();
|
||||||
|
|
||||||
bool LoadFromFile(cFile & a_File); // deprecated format
|
bool LoadFromJson(const Json::Value & a_Value);
|
||||||
|
|
||||||
bool LoadFromJson(const Json::Value& a_Value );
|
// cBlockEntity overrides:
|
||||||
virtual void SaveToJson(Json::Value& a_Value ) override;
|
virtual void SaveToJson(Json::Value & a_Value) override;
|
||||||
|
|
||||||
virtual void SendTo(cClientHandle & a_Client) override;
|
virtual void SendTo(cClientHandle & a_Client) override;
|
||||||
|
virtual bool Tick(float a_Dt) override;
|
||||||
// Returns true if there's any change, forcing the chunk to go dirty.
|
virtual void UsedBy(cPlayer * a_Player) override;
|
||||||
bool Tick( float a_Dt );
|
|
||||||
|
|
||||||
virtual void UsedBy( cPlayer * a_Player ) override;
|
|
||||||
|
|
||||||
const cItem * GetSlot(int i) const { return &(m_Items[i]); }
|
const cItem * GetSlot(int i) const { return &(m_Items[i]); }
|
||||||
|
|
||||||
|
@ -280,51 +280,7 @@ void cFurnaceEntity::SetSlot(int a_Slot, const cItem & a_Item)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define READ(File, Var) \
|
bool cFurnaceEntity::LoadFromJson(const Json::Value & a_Value)
|
||||||
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();
|
m_PosX = a_Value.get("x", 0).asInt();
|
||||||
m_PosY = a_Value.get("y", 0).asInt();
|
m_PosY = a_Value.get("y", 0).asInt();
|
||||||
|
@ -32,19 +32,15 @@ public:
|
|||||||
|
|
||||||
static const char * GetClassStatic() { return "cFurnaceEntity"; }
|
static const char * GetClassStatic() { return "cFurnaceEntity"; }
|
||||||
|
|
||||||
bool LoadFromFile(cFile & a_File); // deprecated format
|
bool LoadFromJson(const Json::Value & a_Value);
|
||||||
|
|
||||||
bool LoadFromJson(const Json::Value& a_Value );
|
// cBlockEntity overrides:
|
||||||
virtual void SaveToJson(Json::Value& a_Value ) override;
|
virtual void SaveToJson(Json::Value & a_Value) override;
|
||||||
|
|
||||||
virtual void SendTo(cClientHandle & a_Client) override;
|
virtual void SendTo(cClientHandle & a_Client) override;
|
||||||
|
virtual bool Tick(float a_Dt) override;
|
||||||
// Returns true if there's any change, forcing the chunk to go dirty.
|
virtual void UsedBy(cPlayer * a_Player) override;
|
||||||
bool Tick( float a_Dt );
|
|
||||||
|
|
||||||
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.
|
/// 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);
|
bool ContinueCooking(void);
|
||||||
|
@ -1599,18 +1599,18 @@ void cWorld::SetChunkData(
|
|||||||
m_Generator.GenerateBiomes(a_ChunkX, a_ChunkZ, BiomeMap);
|
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
|
(*itr)->Initialize(this);
|
||||||
// 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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a client is requesting this chunk, send it to them:
|
// If a client is requesting this chunk, send it to them:
|
||||||
|
Loading…
Reference in New Issue
Block a user