1
0
cuberite-2a/source/cFurnaceEntity.cpp
faketruth c2b43f33da Player data is saved and loaded as human readable JSON now.
cFileFormatUpdate will loop through old files and convert them to new files (should replace legacy old format loading code)
cItem has two new functions to load from Json and output Json, this will keep the items in Json standard
ChestEntity and FurnaceEntity use the new functions in cItem

git-svn-id: http://mc-server.googlecode.com/svn/trunk@35 0a769ca7-a7f5-676a-18bf-c427514a06d6
2011-10-31 21:30:14 +00:00

343 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");
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;
}