c4f4ae5c71
- Beginnings of "Double Chest". All that's needed is detection when 2 chests get put next to each other, block other chests from then touching them on any side, load/save with the m_JoinedChest seeing each other and adding and making sure the left side is always the top rows. I'm not sure exactly at this moment how to do all of the detection and saving/loading of the double chest stuff so if you've any ideas feel free to point out some areas in the server code or implement it yourself. git-svn-id: http://mc-server.googlecode.com/svn/trunk@154 0a769ca7-a7f5-676a-18bf-c427514a06d6
344 lines
10 KiB
C++
344 lines
10 KiB
C++
#include "cFurnaceEntity.h"
|
|
#include "BlockID.h"
|
|
#include "cItem.h"
|
|
#include "cFurnaceWindow.h"
|
|
#include "cPlayer.h"
|
|
#include "cWorld.h"
|
|
#include "cChunk.h"
|
|
#include "cClientHandle.h"
|
|
#include "cFurnaceRecipe.h"
|
|
#include "cServer.h"
|
|
#include "cPickup.h"
|
|
#include "cRoot.h"
|
|
|
|
#include "packets/cPacket_InventoryProgressBar.h"
|
|
|
|
#include "cMCLogger.h"
|
|
|
|
#include <json/json.h>
|
|
|
|
cFurnaceEntity::cFurnaceEntity(int a_X, int a_Y, int a_Z, cChunk* a_Chunk)
|
|
: cBlockEntity( E_BLOCK_FURNACE, a_X, a_Y, a_Z, a_Chunk )
|
|
, m_Items( new cItem[3] )
|
|
, m_CookingItem( 0 )
|
|
, m_CookTime( 0 )
|
|
, m_TimeCooked( 0 )
|
|
, m_BurnTime( 0 )
|
|
, m_TimeBurned( 0 )
|
|
{
|
|
}
|
|
|
|
cFurnaceEntity::~cFurnaceEntity()
|
|
{
|
|
// Tell window its owner is destroyed
|
|
if( GetWindow() )
|
|
{
|
|
GetWindow()->OwnerDestroyed();
|
|
}
|
|
|
|
// Clean up items
|
|
if( m_Items )
|
|
{
|
|
delete [] m_Items;
|
|
}
|
|
}
|
|
|
|
void cFurnaceEntity::Destroy()
|
|
{
|
|
// Drop items
|
|
for( int i = 0; i < 3; i++)
|
|
{
|
|
if( !m_Items[i].IsEmpty() )
|
|
{
|
|
cPickup* Pickup = new cPickup( m_PosX*32 + 16, m_PosY*32 + 16, m_PosZ*32 + 16, m_Items[i], 0, 1.f, 0 );
|
|
Pickup->Initialize( m_Chunk->GetWorld() );
|
|
m_Items[i].Empty();
|
|
}
|
|
}
|
|
|
|
// Remove from tick list
|
|
GetChunk()->RemoveTickBlockEntity( this );
|
|
}
|
|
|
|
void cFurnaceEntity::UsedBy( cPlayer & a_Player )
|
|
{
|
|
LOG("Used a furnace");
|
|
|
|
if( !GetWindow() )
|
|
{
|
|
cWindow* Window = new cFurnaceWindow( this );
|
|
Window->SetSlots( m_Items, 3 );
|
|
Window->SetWindowTitle("UberFurnace");
|
|
Window->GetOwner()->SetEntity(this);
|
|
OpenWindow( Window );
|
|
}
|
|
if( GetWindow() )
|
|
{
|
|
if( a_Player.GetWindow() != GetWindow() )
|
|
{
|
|
a_Player.OpenWindow( GetWindow() );
|
|
|
|
GetWindow()->SendWholeWindow( a_Player.GetClientHandle() );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool cFurnaceEntity::Tick( float a_Dt )
|
|
{
|
|
//LOG("Time left: %0.1f Time burned: %0.1f Burn time: %0.1f", m_CookTime - m_TimeCooked, m_TimeBurned, m_BurnTime );
|
|
if( m_CookingItem && ( (m_TimeBurned < m_BurnTime) || (m_TimeCooked + a_Dt >= m_CookTime) ) )
|
|
{
|
|
if( m_CookingItem->Equals( m_Items[2] ) || m_Items[2].IsEmpty() )
|
|
{
|
|
m_TimeCooked += a_Dt;
|
|
if( m_TimeCooked >= m_CookTime )
|
|
{
|
|
m_Items[0].m_ItemCount--;
|
|
if( m_Items[0].IsEmpty() ) m_Items[0].Empty();
|
|
|
|
m_Items[2].m_ItemHealth = m_CookingItem->m_ItemHealth;
|
|
m_Items[2].m_ItemID = m_CookingItem->m_ItemID;
|
|
m_Items[2].m_ItemCount += m_CookingItem->m_ItemCount;
|
|
delete m_CookingItem;
|
|
m_CookingItem = 0;
|
|
|
|
cWindow* Window = GetWindow();
|
|
if( Window )
|
|
{
|
|
const std::list< cPlayer* > & OpenedBy = Window->GetOpenedBy();
|
|
for( std::list< cPlayer* >::const_iterator itr = OpenedBy.begin(); itr != OpenedBy.end(); ++itr )
|
|
{
|
|
Window->SendWholeWindow( (*itr)->GetClientHandle() );
|
|
}
|
|
}
|
|
|
|
m_TimeCooked = 0.f;
|
|
StartCooking();
|
|
}
|
|
cWindow* Window = GetWindow();
|
|
if( Window )
|
|
{
|
|
const std::list< cPlayer* > & OpenedBy = Window->GetOpenedBy();
|
|
for( std::list< cPlayer* >::const_iterator itr = OpenedBy.begin(); itr != OpenedBy.end(); ++itr )
|
|
{
|
|
cClientHandle* Client = (*itr)->GetClientHandle();
|
|
|
|
cPacket_InventoryProgressBar Progress;
|
|
Progress.m_ProgressBar = 0;
|
|
Progress.m_WindowID = (char)Window->GetWindowID();
|
|
Progress.m_Value = (short)( m_TimeCooked * (180.f/m_CookTime) );
|
|
if( Progress.m_Value > 180 ) Progress.m_Value = 180;
|
|
if( Progress.m_Value < 0 ) Progress.m_Value = 0;
|
|
Client->Send( Progress );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_TimeBurned += a_Dt;
|
|
|
|
cWindow* Window = GetWindow();
|
|
if( m_TimeBurned >= m_BurnTime )
|
|
{
|
|
m_TimeBurned -= m_BurnTime;
|
|
m_BurnTime = 0;
|
|
if( StartCooking() && Window )
|
|
{
|
|
const std::list< cPlayer* > & OpenedBy = Window->GetOpenedBy();
|
|
for( std::list< cPlayer* >::const_iterator itr = OpenedBy.begin(); itr != OpenedBy.end(); ++itr )
|
|
{
|
|
Window->SendWholeWindow( (*itr)->GetClientHandle() );
|
|
}
|
|
}
|
|
}
|
|
if( Window )
|
|
{
|
|
const std::list< cPlayer* > & OpenedBy = Window->GetOpenedBy();
|
|
for( std::list< cPlayer* >::const_iterator itr = OpenedBy.begin(); itr != OpenedBy.end(); ++itr )
|
|
{
|
|
cClientHandle* Client = (*itr)->GetClientHandle();
|
|
|
|
cPacket_InventoryProgressBar Progress;
|
|
Progress.m_WindowID = (char)Window->GetWindowID();
|
|
Progress.m_ProgressBar = 1;
|
|
|
|
if( m_BurnTime > 0.f ) Progress.m_Value = (short)( m_TimeBurned * (150.f/m_BurnTime) );
|
|
else Progress.m_Value = 0;
|
|
if( Progress.m_Value > 150 ) Progress.m_Value = 150;
|
|
if( Progress.m_Value < 0 ) Progress.m_Value = 0;
|
|
Client->Send( Progress );
|
|
}
|
|
}
|
|
return ((m_CookingItem != 0) || (m_TimeBurned < m_BurnTime)) && m_BurnTime > 0.f; // Keep on ticking, if there's more to cook, or if it's cooking
|
|
}
|
|
|
|
bool cFurnaceEntity::StartCooking()
|
|
{
|
|
cFurnaceRecipe* FR = cRoot::Get()->GetFurnaceRecipe();
|
|
float BurnTime = FR->GetBurnTime( m_Items[1] );
|
|
if( (m_TimeBurned < m_BurnTime) || BurnTime > 0.f ) // burnable material
|
|
{
|
|
const cFurnaceRecipe::Recipe* R = FR->GetRecipeFrom( m_Items[0] );
|
|
if( R ) // cook able ingredient
|
|
{
|
|
if( m_Items[2].Equals( *R->Out ) || m_Items[2].IsEmpty() )
|
|
{
|
|
// good to go
|
|
|
|
if( m_TimeBurned >= m_BurnTime ) // burn new material
|
|
{
|
|
m_Items[1].m_ItemCount--;
|
|
if( m_Items[1].m_ItemCount <= 0 ) m_Items[1].Empty();
|
|
m_TimeBurned = 0;
|
|
m_BurnTime = BurnTime;
|
|
}
|
|
|
|
if( !m_CookingItem ) // Only cook new item if not already cooking
|
|
{
|
|
m_CookingItem = new cItem( *R->Out ); // Resulting item
|
|
m_TimeCooked = 0.f;
|
|
m_CookTime = R->CookTime;
|
|
}
|
|
GetChunk()->AddTickBlockEntity( this );
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void cFurnaceEntity::ResetCookTimer()
|
|
{
|
|
if( m_CookingItem )
|
|
{
|
|
delete m_CookingItem;
|
|
m_CookingItem = 0;
|
|
}
|
|
m_TimeCooked = 0.f;
|
|
m_CookTime = 0.f;
|
|
}
|
|
|
|
void cFurnaceEntity::WriteToFile(FILE* a_File)
|
|
{
|
|
fwrite( &m_BlockType, sizeof( ENUM_BLOCK_ID ), 1, a_File );
|
|
fwrite( &m_PosX, sizeof( int ), 1, a_File );
|
|
fwrite( &m_PosY, sizeof( int ), 1, a_File );
|
|
fwrite( &m_PosZ, sizeof( int ), 1, a_File );
|
|
|
|
unsigned int NumSlots = 3;
|
|
fwrite( &NumSlots, sizeof(unsigned int), 1, a_File );
|
|
for(unsigned int i = 0; i < NumSlots; i++)
|
|
{
|
|
cItem* Item = &m_Items[i];
|
|
if( Item )
|
|
{
|
|
fwrite( &Item->m_ItemID, sizeof(Item->m_ItemID), 1, a_File );
|
|
fwrite( &Item->m_ItemCount, sizeof(Item->m_ItemCount), 1, a_File );
|
|
fwrite( &Item->m_ItemHealth, sizeof(Item->m_ItemHealth), 1, a_File );
|
|
}
|
|
}
|
|
cItem Item;
|
|
if( m_CookingItem ) Item = *m_CookingItem;
|
|
fwrite( &Item.m_ItemID, sizeof(Item.m_ItemID), 1, a_File );
|
|
fwrite( &Item.m_ItemCount, sizeof(Item.m_ItemCount), 1, a_File );
|
|
fwrite( &Item.m_ItemHealth, sizeof(Item.m_ItemHealth), 1, a_File );
|
|
|
|
fwrite( &m_CookTime, sizeof(float), 1, a_File );
|
|
fwrite( &m_TimeCooked, sizeof(float), 1, a_File );
|
|
fwrite( &m_BurnTime, sizeof(float), 1, a_File );
|
|
fwrite( &m_TimeBurned, sizeof(float), 1, a_File );
|
|
}
|
|
|
|
bool cFurnaceEntity::LoadFromFile(FILE* a_File)
|
|
{
|
|
if( fread( &m_PosX, sizeof(int), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
if( fread( &m_PosY, sizeof(int), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
if( fread( &m_PosZ, sizeof(int), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
|
|
unsigned int NumSlots = 0;
|
|
if( fread( &NumSlots, sizeof(unsigned int), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
m_Items = new cItem[ NumSlots ];
|
|
for(unsigned int i = 0; i < NumSlots; i++)
|
|
{
|
|
cItem & Item = m_Items[ i ];
|
|
if( fread( &Item.m_ItemID, sizeof(Item.m_ItemID), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
if( fread( &Item.m_ItemCount, sizeof(Item.m_ItemCount), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
if( fread( &Item.m_ItemHealth, sizeof(Item.m_ItemHealth), 1, a_File)!= 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
}
|
|
cItem Item;
|
|
if( fread( &Item.m_ItemID, sizeof(Item.m_ItemID), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
if( fread( &Item.m_ItemCount, sizeof(Item.m_ItemCount), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
if( fread( &Item.m_ItemHealth, sizeof(Item.m_ItemHealth), 1, a_File)!= 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
if( !Item.IsEmpty() ) m_CookingItem = new cItem( Item );
|
|
|
|
if( fread( &m_CookTime, sizeof(float), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
if( fread( &m_TimeCooked, sizeof(float), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
if( fread( &m_BurnTime, sizeof(float), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
if( fread( &m_TimeBurned, sizeof(float), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cFurnaceEntity::LoadFromJson( const Json::Value& a_Value )
|
|
{
|
|
m_PosX = a_Value.get("x", 0).asInt();
|
|
m_PosY = a_Value.get("y", 0).asInt();
|
|
m_PosZ = a_Value.get("z", 0).asInt();
|
|
|
|
Json::Value AllSlots = a_Value.get("Slots", 0);
|
|
int SlotIdx = 0;
|
|
for( Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr )
|
|
{
|
|
m_Items[ SlotIdx ].FromJson( *itr );
|
|
SlotIdx++;
|
|
}
|
|
|
|
// Get currently cooking item
|
|
Json::Value JsonItem = a_Value.get("Cooking", Json::nullValue );
|
|
if( !JsonItem.empty() )
|
|
{
|
|
cItem Item;
|
|
Item.FromJson( JsonItem );
|
|
if( !Item.IsEmpty() )
|
|
{
|
|
m_CookingItem = new cItem( Item );
|
|
GetChunk()->AddTickBlockEntity( this );
|
|
}
|
|
}
|
|
|
|
m_CookTime = (float)a_Value.get("CookTime", 0).asDouble();
|
|
m_TimeCooked = (float)a_Value.get("TimeCooked", 0).asDouble();
|
|
m_BurnTime = (float)a_Value.get("BurnTime", 0).asDouble();
|
|
m_TimeBurned = (float)a_Value.get("TimeBurned", 0).asDouble();
|
|
|
|
return true;
|
|
}
|
|
|
|
void cFurnaceEntity::SaveToJson( Json::Value& a_Value )
|
|
{
|
|
a_Value["x"] = m_PosX;
|
|
a_Value["y"] = m_PosY;
|
|
a_Value["z"] = m_PosZ;
|
|
|
|
Json::Value AllSlots;
|
|
for(unsigned int i = 0; i < 3; i++)
|
|
{
|
|
Json::Value Slot;
|
|
m_Items[ i ].GetJson( Slot );
|
|
AllSlots.append( Slot );
|
|
}
|
|
a_Value["Slots"] = AllSlots;
|
|
|
|
// Currently cooking item
|
|
if( m_CookingItem )
|
|
{
|
|
Json::Value JsonItem;
|
|
m_CookingItem->GetJson( JsonItem );
|
|
a_Value["Cooking"] = JsonItem;
|
|
}
|
|
|
|
a_Value["CookTime"] = m_CookTime;
|
|
a_Value["TimeCooked"] = m_TimeCooked;
|
|
a_Value["BurnTime"] = m_BurnTime;
|
|
a_Value["TimeBurned"] = m_TimeBurned;
|
|
} |