1
0

Added hopper entity, it can suck items out of chests, dispensers, droppers and other hopppers above it.

git-svn-id: http://mc-server.googlecode.com/svn/trunk@1587 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
madmaxoft@gmail.com 2013-06-13 07:36:43 +00:00
parent 732190e9f9
commit 03c6bb9f85
14 changed files with 630 additions and 81 deletions

View File

@ -2356,6 +2356,14 @@
RelativePath="..\source\BlockEntities\FurnaceEntity.h" RelativePath="..\source\BlockEntities\FurnaceEntity.h"
> >
</File> </File>
<File
RelativePath="..\source\BlockEntities\HopperEntity.cpp"
>
</File>
<File
RelativePath="..\source\BlockEntities\HopperEntity.h"
>
</File>
<File <File
RelativePath="..\source\BlockEntities\JukeboxEntity.cpp" RelativePath="..\source\BlockEntities\JukeboxEntity.cpp"
> >

View File

@ -0,0 +1,291 @@
// HopperEntity.cpp
// Implements the cHopperEntity representing a hopper block entity
#include "Globals.h"
#include "HopperEntity.h"
#include "../Chunk.h"
#include "../Player.h"
#include "ChestEntity.h"
#include "DropSpenserEntity.h"
cHopperEntity::cHopperEntity(int a_BlockX, int a_BlockY, int a_BlockZ) :
super(E_BLOCK_HOPPER, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, NULL)
{
}
cHopperEntity::cHopperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
super(E_BLOCK_HOPPER, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World)
{
}
bool cHopperEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
Int64 CurrentTick = a_Chunk.GetWorld()->GetWorldAge();
bool res = false;
res = MoveItemsIn (a_Chunk, CurrentTick) || res;
res = MovePickupsIn(a_Chunk, CurrentTick) || res;
res = MoveItemsOut (a_Chunk, CurrentTick) || res;
return res;
}
void cHopperEntity::SaveToJson(Json::Value & a_Value)
{
// TODO
LOGWARNING("%s: Not implemented yet", __FUNCTION__);
}
void cHopperEntity::SendTo(cClientHandle & a_Client)
{
// The hopper entity doesn't need anything sent to the client when it's created / gets in the viewdistance
// All the actual handling is in the cWindow UI code that gets called when the hopper is rclked
UNUSED(a_Client);
}
void cHopperEntity::UsedBy(cPlayer * a_Player)
{
// If the window is not created, open it anew:
cWindow * Window = GetWindow();
if (Window == NULL)
{
OpenNewWindow();
Window = GetWindow();
}
// Open the window for the player:
if (Window != NULL)
{
if (a_Player->GetWindow() != Window)
{
a_Player->OpenWindow(Window);
}
}
// This is rather a hack
// Instead of marking the chunk as dirty upon chest contents change, we mark it dirty now
// We cannot properly detect contents change, but such a change doesn't happen without a player opening the chest first.
// The few false positives aren't much to worry about
int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(m_PosX, m_PosY, m_PosZ, ChunkX, ChunkZ);
m_World->MarkChunkDirty(ChunkX, ChunkZ);
}
/// Opens a new window UI for this hopper
void cHopperEntity::OpenNewWindow(void)
{
OpenWindow(new cHopperWindow(m_PosX, m_PosY, m_PosZ, this));
}
/// Moves items from the container above it into this hopper. Returns true if the contents have changed.
bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
{
if (m_PosY >= cChunkDef::Height)
{
// This hopper is at the top of the world, no more blocks above
return false;
}
if (a_CurrentTick - m_LastMoveItemsInTick < TICKS_PER_TRANSFER)
{
// Too early after the previous transfer
return false;
}
// Try moving an item in:
bool res = false;
switch (a_Chunk.GetBlock(m_RelX, m_PosY + 1, m_RelZ))
{
case E_BLOCK_CHEST: res = MoveItemsFromChest(a_Chunk); break;
case E_BLOCK_FURNACE: res = MoveItemsFromFurnace(a_Chunk); break;
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER: res = MoveItemsFromGrid(((cDropSpenserEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ))->GetContents()); break;
case E_BLOCK_HOPPER: res = MoveItemsFromGrid(((cHopperEntity *) a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ))->GetContents()); break;
}
// If the item has been moved, reset the last tick:
if (res)
{
m_LastMoveItemsInTick = a_CurrentTick;
}
return res;
}
/// Moves pickups from above this hopper into it. Returns true if the contents have changed.
bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
{
// TODO
return false;
}
/// Moves items out from this hopper into the destination. Returns true if the contents have changed.
bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
{
if (a_CurrentTick - m_LastMoveItemsOutTick < TICKS_PER_TRANSFER)
{
// Too early after the previous transfer
return false;
}
// TODO
return false;
}
/// Moves items from a chest (dblchest) above the hopper into this hopper. Returns true if contents have changed.
bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
{
if (MoveItemsFromGrid(((cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ))->GetContents()))
{
// Moved the item from the chest directly above the hopper
return true;
}
// Check if the chest is a double-chest, if so, try to move from there:
static const struct
{
int x, z;
}
Coords [] =
{
{1, 0},
{-1, 0},
{0, 1},
{0, -1},
} ;
for (int i = 0; i < ARRAYCOUNT(Coords); i++)
{
int x = m_RelX + Coords[i].x;
int z = m_RelZ + Coords[i].z;
cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
if (
(Neighbor == NULL) ||
(Neighbor->GetBlock(x, m_PosY + 1, z) != E_BLOCK_CHEST)
)
{
continue;
}
if (MoveItemsFromGrid(((cChestEntity *)Neighbor->GetBlockEntity(x, m_PosY, z))->GetContents()))
{
return true;
}
return false;
}
// The chest was single and nothing could be moved
return false;
}
/// Moves items from a furnace above the hopper into this hopper. Returns true if contents have changed.
bool cHopperEntity::MoveItemsFromFurnace(cChunk & a_Chunk)
{
// TODO
return false;
}
/// Moves items from the specified ItemGrid into this hopper. Returns true if contents have changed.
bool cHopperEntity::MoveItemsFromGrid(cItemGrid & a_Grid)
{
int NumSlots = a_Grid.GetNumSlots();
// First try adding items of types already in the hopper:
for (int i = 0; i < NumSlots; i++)
{
if (a_Grid.IsSlotEmpty(i))
{
continue;
}
if (MoveItemsFromSlot(a_Grid.GetSlot(i), false))
{
a_Grid.ChangeSlotCount(i, -1);
return true;
}
}
// No already existing stack can be topped up, try again with allowing new stacks:
for (int i = 0; i < NumSlots; i++)
{
if (a_Grid.IsSlotEmpty(i))
{
continue;
}
if (MoveItemsFromSlot(a_Grid.GetSlot(i), true))
{
a_Grid.ChangeSlotCount(i, -1);
return true;
}
}
return false;
}
/// Moves one of the specified itemstack into this hopper. Returns true if contents have changed. Doesn't change the itemstack.
bool cHopperEntity::MoveItemsFromSlot(const cItem & a_ItemStack, bool a_AllowNewStacks)
{
if (m_Contents.AddItem(a_ItemStack.CopyOne(), a_AllowNewStacks) > 0)
{
return true;
}
return false;
}

View File

@ -0,0 +1,81 @@
// HopperEntity.h
// Declares the cHopperEntity representing a hopper block entity
#pragma once
#include "BlockEntityWithItems.h"
#include "../UI/WindowOwner.h"
class cHopperEntity : // tolua_export
public cBlockEntityWindowOwner,
// tolua_begin
public cBlockEntityWithItems
{
typedef cBlockEntityWithItems super;
public:
enum {
ContentsHeight = 1,
ContentsWidth = 5,
TICKS_PER_TRANSFER = 8, ///< How many ticks at minimum between two item transfers to or from the hopper
} ;
/// Constructor used while generating a chunk; sets m_World to NULL
cHopperEntity(int a_BlockX, int a_BlockY, int a_BlockZ);
// tolua_end
/// Constructor used for normal operation
cHopperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
static const char * GetClassStatic(void) { return "cHopperEntity"; }
protected:
Int64 m_LastMoveItemsInTick;
Int64 m_LastMoveItemsOutTick;
// cBlockEntity overrides:
virtual bool Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void SaveToJson(Json::Value & a_Value) override;
virtual void SendTo(cClientHandle & a_Client) override;
virtual void UsedBy(cPlayer * a_Player) override;
/// Opens a new chest window for this chest. Scans for neighbors to open a double chest window, if appropriate.
void OpenNewWindow(void);
/// Moves items from the container above it into this hopper. Returns true if the contents have changed.
bool MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick);
/// Moves pickups from above this hopper into it. Returns true if the contents have changed.
bool MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick);
/// Moves items out from this hopper into the destination. Returns true if the contents have changed.
bool MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick);
/// Moves items from a chest (dblchest) above the hopper into this hopper. Returns true if contents have changed.
bool MoveItemsFromChest(cChunk & a_Chunk);
/// Moves items from a furnace above the hopper into this hopper. Returns true if contents have changed.
bool MoveItemsFromFurnace(cChunk & a_Chunk);
/// Moves items from the specified ItemGrid into this hopper. Returns true if contents have changed.
bool MoveItemsFromGrid(cItemGrid & a_Grid);
/// Moves one of the specified itemstack into this hopper. Returns true if contents have changed. Doesn't change the itemstack.
bool MoveItemsFromSlot(const cItem & a_ItemStack, bool a_AllowNewStacks);
} ;

View File

@ -16,6 +16,7 @@
#include "BlockEntities/DispenserEntity.h" #include "BlockEntities/DispenserEntity.h"
#include "BlockEntities/DropperEntity.h" #include "BlockEntities/DropperEntity.h"
#include "BlockEntities/FurnaceEntity.h" #include "BlockEntities/FurnaceEntity.h"
#include "BlockEntities/HopperEntity.h"
#include "BlockEntities/JukeboxEntity.h" #include "BlockEntities/JukeboxEntity.h"
#include "BlockEntities/NoteEntity.h" #include "BlockEntities/NoteEntity.h"
#include "BlockEntities/SignEntity.h" #include "BlockEntities/SignEntity.h"
@ -1222,7 +1223,7 @@ void cChunk::CreateBlockEntities(void)
{ {
if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width)) if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width))
{ {
m_BlockEntities.push_back( new cChestEntity( x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World) ); m_BlockEntities.push_back(new cChestEntity(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World));
} }
break; break;
} }
@ -1231,7 +1232,7 @@ void cChunk::CreateBlockEntities(void)
{ {
if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width)) if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width))
{ {
m_BlockEntities.push_back( new cDispenserEntity( x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World) ); m_BlockEntities.push_back(new cDispenserEntity(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World));
} }
break; break;
} }
@ -1249,17 +1250,25 @@ void cChunk::CreateBlockEntities(void)
{ {
if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width)) if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width))
{ {
m_BlockEntities.push_back( new cFurnaceEntity( x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World) ); m_BlockEntities.push_back(new cFurnaceEntity(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World));
} }
break; break;
} }
case E_BLOCK_HOPPER:
{
if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width))
{
m_BlockEntities.push_back(new cHopperEntity(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World));
}
}
case E_BLOCK_SIGN_POST: case E_BLOCK_SIGN_POST:
case E_BLOCK_WALLSIGN: case E_BLOCK_WALLSIGN:
{ {
if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width)) if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width))
{ {
m_BlockEntities.push_back( new cSignEntity( BlockType, x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World) ); m_BlockEntities.push_back( new cSignEntity(BlockType, x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World));
} }
break; break;
} }
@ -1268,7 +1277,7 @@ void cChunk::CreateBlockEntities(void)
{ {
if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width)) if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width))
{ {
m_BlockEntities.push_back(new cNoteEntity(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World) ); m_BlockEntities.push_back(new cNoteEntity(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World));
} }
break; break;
} }
@ -1277,7 +1286,7 @@ void cChunk::CreateBlockEntities(void)
{ {
if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width)) if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width))
{ {
m_BlockEntities.push_back(new cJukeboxEntity(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World) ); m_BlockEntities.push_back(new cJukeboxEntity(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width, m_World));
} }
break; break;
} }
@ -1434,28 +1443,33 @@ void cChunk::SetBlock( int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType
{ {
case E_BLOCK_CHEST: case E_BLOCK_CHEST:
{ {
AddBlockEntity( new cChestEntity( WorldPos.x, WorldPos.y, WorldPos.z, m_World) ); AddBlockEntity(new cChestEntity( WorldPos.x, WorldPos.y, WorldPos.z, m_World));
break; break;
} }
case E_BLOCK_DISPENSER: case E_BLOCK_DISPENSER:
{ {
AddBlockEntity( new cDispenserEntity( WorldPos.x, WorldPos.y, WorldPos.z, m_World) ); AddBlockEntity(new cDispenserEntity( WorldPos.x, WorldPos.y, WorldPos.z, m_World));
break; break;
} }
case E_BLOCK_DROPPER: case E_BLOCK_DROPPER:
{ {
AddBlockEntity( new cDropperEntity( WorldPos.x, WorldPos.y, WorldPos.z, m_World) ); AddBlockEntity(new cDropperEntity( WorldPos.x, WorldPos.y, WorldPos.z, m_World));
break; break;
} }
case E_BLOCK_FURNACE: case E_BLOCK_FURNACE:
{ {
AddBlockEntity( new cFurnaceEntity( WorldPos.x, WorldPos.y, WorldPos.z, m_World) ); AddBlockEntity(new cFurnaceEntity( WorldPos.x, WorldPos.y, WorldPos.z, m_World));
break;
}
case E_BLOCK_HOPPER:
{
AddBlockEntity(new cHopperEntity( WorldPos.x, WorldPos.y, WorldPos.z, m_World));
break; break;
} }
case E_BLOCK_SIGN_POST: case E_BLOCK_SIGN_POST:
case E_BLOCK_WALLSIGN: case E_BLOCK_WALLSIGN:
{ {
AddBlockEntity( new cSignEntity( (ENUM_BLOCK_ID)a_BlockType, WorldPos.x, WorldPos.y, WorldPos.z, m_World) ); AddBlockEntity(new cSignEntity(a_BlockType, WorldPos.x, WorldPos.y, WorldPos.z, m_World));
break; break;
} }
case E_BLOCK_NOTE_BLOCK: case E_BLOCK_NOTE_BLOCK:

View File

@ -310,6 +310,9 @@ public:
cFluidSimulatorData * GetLavaSimulatorData (void) { return m_LavaSimulatorData; } cFluidSimulatorData * GetLavaSimulatorData (void) { return m_LavaSimulatorData; }
cSandSimulatorChunkData & GetSandSimulatorData (void) { return m_SandSimulatorData; } cSandSimulatorChunkData & GetSandSimulatorData (void) { return m_SandSimulatorData; }
cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * GetBlockEntity(const Vector3i & a_BlockPos) { return GetBlockEntity(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); }
private: private:
friend class cChunkMap; friend class cChunkMap;
@ -362,8 +365,6 @@ private:
void RemoveBlockEntity(cBlockEntity * a_BlockEntity); void RemoveBlockEntity(cBlockEntity * a_BlockEntity);
void AddBlockEntity (cBlockEntity * a_BlockEntity); void AddBlockEntity (cBlockEntity * a_BlockEntity);
cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * GetBlockEntity(const Vector3i & a_BlockPos) { return GetBlockEntity(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); }
void SpreadLightOfBlock(NIBBLETYPE * a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff); void SpreadLightOfBlock(NIBBLETYPE * a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff);

View File

@ -616,9 +616,13 @@ void cItemGrid::RemoveListener(cListener & a_Listener)
void cItemGrid::TriggerListeners(int a_SlotNum) void cItemGrid::TriggerListeners(int a_SlotNum)
{ {
cCSLock Lock(m_CSListeners); cListeners Listeners;
m_IsInTriggerListeners = true; {
for (cListeners::iterator itr = m_Listeners.begin(), end = m_Listeners.end(); itr != end; ++itr) cCSLock Lock(m_CSListeners);
m_IsInTriggerListeners = true;
Listeners = m_Listeners;
}
for (cListeners::iterator itr = Listeners.begin(), end = Listeners.end(); itr != end; ++itr)
{ {
(*itr)->OnSlotChanged(this, a_SlotNum); (*itr)->OnSlotChanged(this, a_SlotNum);
} // for itr - m_Listeners[] } // for itr - m_Listeners[]

View File

@ -665,6 +665,16 @@ cSlotAreaItemGrid::cSlotAreaItemGrid(cItemGrid & a_ItemGrid, cWindow & a_ParentW
super(a_ItemGrid.GetNumSlots(), a_ParentWindow), super(a_ItemGrid.GetNumSlots(), a_ParentWindow),
m_ItemGrid(a_ItemGrid) m_ItemGrid(a_ItemGrid)
{ {
m_ItemGrid.AddListener(*this);
}
cSlotAreaItemGrid::~cSlotAreaItemGrid()
{
m_ItemGrid.RemoveListener(*this);
} }
@ -689,6 +699,16 @@ void cSlotAreaItemGrid::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem &
void cSlotAreaItemGrid::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
{
ASSERT(a_ItemGrid == &m_ItemGrid);
m_ParentWindow.BroadcastSlot(this, a_SlotNum);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSlotAreaTemporary: // cSlotAreaTemporary:

View File

@ -143,18 +143,24 @@ public:
/// Handles any slot area that is representing a cItemGrid; same items for all the players /// Handles any slot area that is representing a cItemGrid; same items for all the players
class cSlotAreaItemGrid : class cSlotAreaItemGrid :
public cSlotArea public cSlotArea,
public cItemGrid::cListener
{ {
typedef cSlotArea super; typedef cSlotArea super;
public: public:
cSlotAreaItemGrid(cItemGrid & a_ItemGrid, cWindow & a_ParentWindow); cSlotAreaItemGrid(cItemGrid & a_ItemGrid, cWindow & a_ParentWindow);
virtual ~cSlotAreaItemGrid();
virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const override; virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const override;
virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override;
protected: protected:
cItemGrid & m_ItemGrid; cItemGrid & m_ItemGrid;
// cItemGrid::cListener overrides:
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override;
} ; } ;

View File

@ -11,6 +11,7 @@
#include "../Inventory.h" #include "../Inventory.h"
#include "../Items/ItemHandler.h" #include "../Items/ItemHandler.h"
#include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/HopperEntity.h"
@ -607,6 +608,40 @@ int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int
void cWindow::BroadcastSlot(cSlotArea * a_Area, int a_LocalSlotNum)
{
// Translate local slot num into global slot num:
int SlotNum = 0;
bool HasFound = false;
for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
{
if (a_Area == *itr)
{
SlotNum += a_LocalSlotNum;
HasFound = true;
break;
}
SlotNum += (*itr)->GetNumSlots();
} // for itr - m_SlotAreas[]
if (!HasFound)
{
LOGWARNING("%s: Invalid slot area parameter", __FUNCTION__);
ASSERT(!"Invalid slot area");
return;
}
// Broadcast the update packet:
cCSLock Lock(m_CS);
for (cPlayerList::iterator itr = m_OpenedBy.begin(); itr != m_OpenedBy.end(); ++itr)
{
(*itr)->GetClientHandle()->SendInventorySlot(m_WindowID, SlotNum, *a_Area->GetSlot(a_LocalSlotNum, **itr));
} // for itr - m_OpenedBy[]
}
void cWindow::SendWholeWindow(cClientHandle & a_Client) void cWindow::SendWholeWindow(cClientHandle & a_Client)
{ {
a_Client.SendWholeInventory(*this); a_Client.SendWholeInventory(*this);
@ -741,6 +776,7 @@ cChestWindow::~cChestWindow()
cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) : cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) :
cWindow(cWindow::DropSpenser, "MCS-DropSpenser") cWindow(cWindow::DropSpenser, "MCS-DropSpenser")
{ {
m_ShouldDistributeToHotbarFirst = false;
m_SlotAreas.push_back(new cSlotAreaDropSpenser(a_DropSpenser, *this)); m_SlotAreas.push_back(new cSlotAreaDropSpenser(a_DropSpenser, *this));
m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this));
m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
@ -750,12 +786,29 @@ cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cHopperWindow:
cHopperWindow::cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper) :
super(cWindow::Hopper, "MCS-Hopper")
{
m_ShouldDistributeToHotbarFirst = false;
m_SlotAreas.push_back(new cSlotAreaItemGrid(a_Hopper->GetContents(), *this));
m_SlotAreas.push_back(new cSlotAreaInventory(*this));
m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFurnaceWindow: // cFurnaceWindow:
cFurnaceWindow::cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace) : cFurnaceWindow::cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace) :
cWindow(cWindow::Furnace, "MCS-Furnace") cWindow(cWindow::Furnace, "MCS-Furnace")
{ {
m_ShouldDistributeToHotbarFirst = false;
m_SlotAreas.push_back(new cSlotAreaFurnace(a_Furnace, *this)); m_SlotAreas.push_back(new cSlotAreaFurnace(a_Furnace, *this));
m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this));
m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this));

View File

@ -21,6 +21,7 @@ class cClientHandle;
class cChestEntity; class cChestEntity;
class cDropSpenserEntity; class cDropSpenserEntity;
class cFurnaceEntity; class cFurnaceEntity;
class cHopperEntity;
class cSlotArea; class cSlotArea;
class cWorld; class cWorld;
@ -110,8 +111,16 @@ public:
/// Called when a player closes this window; notifies all slot areas. Returns true if close accepted /// Called when a player closes this window; notifies all slot areas. Returns true if close accepted
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse); virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse);
/// Sends the specified slot's contents to all clients of this window; the slot is specified as local in an area
void BroadcastSlot(cSlotArea * a_Area, int a_LocalSlotNum);
/// Sends the contents of the whole window to the specified client
void SendWholeWindow(cClientHandle & a_Client); void SendWholeWindow(cClientHandle & a_Client);
/// Sends the contents of the whole window to all clients of this window.
void BroadcastWholeWindow(void); void BroadcastWholeWindow(void);
/// Sends the progressbar to all clients of this window
void BroadcastInventoryProgress(short a_Progressbar, short a_Value); void BroadcastInventoryProgress(short a_Progressbar, short a_Value);
// tolua_begin // tolua_begin
@ -194,6 +203,7 @@ protected:
class cCraftingWindow : class cCraftingWindow :
public cWindow public cWindow
{ {
typedef cWindow super;
public: public:
cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ); cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
} ; } ;
@ -205,6 +215,7 @@ public:
class cFurnaceWindow : class cFurnaceWindow :
public cWindow public cWindow
{ {
typedef cWindow super;
public: public:
cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace); cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace);
} ; } ;
@ -216,6 +227,7 @@ public:
class cDropSpenserWindow : class cDropSpenserWindow :
public cWindow public cWindow
{ {
typedef cWindow super;
public: public:
cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_Dispenser); cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_Dispenser);
} ; } ;
@ -224,6 +236,18 @@ public:
class cHopperWindow :
public cWindow
{
typedef cWindow super;
public:
cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper);
} ;
class cChestWindow : class cChestWindow :
public cWindow public cWindow
{ {

View File

@ -9,6 +9,7 @@
#include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DispenserEntity.h"
#include "../BlockEntities/DropperEntity.h" #include "../BlockEntities/DropperEntity.h"
#include "../BlockEntities/FurnaceEntity.h" #include "../BlockEntities/FurnaceEntity.h"
#include "../BlockEntities/HopperEntity.h"
#include "../BlockEntities/JukeboxEntity.h" #include "../BlockEntities/JukeboxEntity.h"
#include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h" #include "../BlockEntities/SignEntity.h"
@ -175,14 +176,25 @@ void cNBTChunkSerializer::AddFurnaceEntity(cFurnaceEntity * a_Furnace)
void cNBTChunkSerializer::AddSignEntity(cSignEntity * a_Sign) void cNBTChunkSerializer::AddHopperEntity(cHopperEntity * a_Entity)
{ {
m_Writer.BeginCompound(""); m_Writer.BeginCompound("");
AddBasicTileEntity(a_Sign, "Sign"); AddBasicTileEntity(a_Entity, "Hopper");
m_Writer.AddString("Text1", a_Sign->GetLine(0)); m_Writer.BeginList("Items", TAG_Compound);
m_Writer.AddString("Text2", a_Sign->GetLine(1)); AddItemGrid(a_Entity->GetContents());
m_Writer.AddString("Text3", a_Sign->GetLine(2)); m_Writer.EndList();
m_Writer.AddString("Text4", a_Sign->GetLine(3)); m_Writer.EndCompound();
}
void cNBTChunkSerializer::AddJukeboxEntity(cJukeboxEntity * a_Jukebox)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Jukebox, "RecordPlayer");
m_Writer.AddInt("Record", a_Jukebox->GetRecord());
m_Writer.EndCompound(); m_Writer.EndCompound();
} }
@ -202,11 +214,14 @@ void cNBTChunkSerializer::AddNoteEntity(cNoteEntity * a_Note)
void cNBTChunkSerializer::AddJukeboxEntity(cJukeboxEntity * a_Jukebox) void cNBTChunkSerializer::AddSignEntity(cSignEntity * a_Sign)
{ {
m_Writer.BeginCompound(""); m_Writer.BeginCompound("");
AddBasicTileEntity(a_Jukebox, "RecordPlayer"); AddBasicTileEntity(a_Sign, "Sign");
m_Writer.AddInt("Record", a_Jukebox->GetRecord()); m_Writer.AddString("Text1", a_Sign->GetLine(0));
m_Writer.AddString("Text2", a_Sign->GetLine(1));
m_Writer.AddString("Text3", a_Sign->GetLine(2));
m_Writer.AddString("Text4", a_Sign->GetLine(3));
m_Writer.EndCompound(); m_Writer.EndCompound();
} }
@ -428,6 +443,7 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity)
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break; case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break; case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break;
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break; case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break;
case E_BLOCK_SIGN_POST: case E_BLOCK_SIGN_POST:
case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break; case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break;
case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break; case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break;

View File

@ -20,12 +20,13 @@ class cFastNBTWriter;
class cEntity; class cEntity;
class cBlockEntity; class cBlockEntity;
class cChestEntity; class cChestEntity;
class cFurnaceEntity;
class cDispenserEntity; class cDispenserEntity;
class cDropperEntity; class cDropperEntity;
class cSignEntity; class cFurnaceEntity;
class cNoteEntity; class cHopperEntity;
class cJukeboxEntity; class cJukeboxEntity;
class cNoteEntity;
class cSignEntity;
class cFallingBlock; class cFallingBlock;
class cMinecart; class cMinecart;
class cMinecartWithChest; class cMinecartWithChest;
@ -78,17 +79,18 @@ protected:
void AddItemGrid(const cItemGrid & a_Grid, int a_BeginSlotNum = 0); void AddItemGrid(const cItemGrid & a_Grid, int a_BeginSlotNum = 0);
// Block entities: // Block entities:
void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID); void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID);
void AddChestEntity(cChestEntity * a_Entity); void AddChestEntity (cChestEntity * a_Entity);
void AddDispenserEntity(cDispenserEntity * a_Entity); void AddDispenserEntity(cDispenserEntity * a_Entity);
void AddDropperEntity(cDropperEntity * a_Entity); void AddDropperEntity (cDropperEntity * a_Entity);
void AddFurnaceEntity(cFurnaceEntity * a_Furnace); void AddFurnaceEntity (cFurnaceEntity * a_Furnace);
void AddSignEntity(cSignEntity * a_Sign); void AddHopperEntity (cHopperEntity * a_Entity);
void AddNoteEntity(cNoteEntity * a_Note); void AddJukeboxEntity (cJukeboxEntity * a_Jukebox);
void AddJukeboxEntity(cJukeboxEntity * a_Jukebox); void AddNoteEntity (cNoteEntity * a_Note);
void AddBasicEntity(cEntity * a_Entity, const AString & a_ClassName); void AddSignEntity (cSignEntity * a_Sign);
// Entities: // Entities:
void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName);
void AddFallingBlockEntity(cFallingBlock * a_FallingBlock); void AddFallingBlockEntity(cFallingBlock * a_FallingBlock);
void AddMinecartEntity (cMinecart * a_Minecart); void AddMinecartEntity (cMinecart * a_Minecart);
void AddMonsterEntity (cMonster * a_Monster); void AddMonsterEntity (cMonster * a_Monster);

View File

@ -13,6 +13,7 @@
#include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DispenserEntity.h"
#include "../BlockEntities/DropperEntity.h" #include "../BlockEntities/DropperEntity.h"
#include "../BlockEntities/FurnaceEntity.h" #include "../BlockEntities/FurnaceEntity.h"
#include "../BlockEntities/HopperEntity.h"
#include "../BlockEntities/JukeboxEntity.h" #include "../BlockEntities/JukeboxEntity.h"
#include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h" #include "../BlockEntities/SignEntity.h"
@ -568,6 +569,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
{ {
LoadFurnaceFromNBT(a_BlockEntities, a_NBT, Child); LoadFurnaceFromNBT(a_BlockEntities, a_NBT, Child);
} }
else if (strncmp(a_NBT.GetData(sID), "Hopper", a_NBT.GetDataLength(sID)) == 0)
{
LoadHopperFromNBT(a_BlockEntities, a_NBT, Child);
}
else if (strncmp(a_NBT.GetData(sID), "Music", a_NBT.GetDataLength(sID)) == 0) else if (strncmp(a_NBT.GetData(sID), "Music", a_NBT.GetDataLength(sID)) == 0)
{ {
LoadNoteFromNBT(a_BlockEntities, a_NBT, Child); LoadNoteFromNBT(a_BlockEntities, a_NBT, Child);
@ -721,7 +726,7 @@ void cWSSAnvil::LoadDropperFromNBT(cBlockEntityList & a_BlockEntities, const cPa
int Items = a_NBT.FindChildByName(a_TagIdx, "Items"); int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List)) if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
{ {
return; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this return; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this
} }
std::auto_ptr<cDropperEntity> Dropper(new cDropperEntity(x, y, z, m_World)); std::auto_ptr<cDropperEntity> Dropper(new cDropperEntity(x, y, z, m_World));
LoadItemGridFromNBT(Dropper->GetContents(), a_NBT, Items); LoadItemGridFromNBT(Dropper->GetContents(), a_NBT, Items);
@ -781,6 +786,70 @@ void cWSSAnvil::LoadFurnaceFromNBT(cBlockEntityList & a_BlockEntities, const cPa
void cWSSAnvil::LoadHopperFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
{
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
int x, y, z;
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
{
return;
}
int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
{
return; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this
}
std::auto_ptr<cHopperEntity> Hopper(new cHopperEntity(x, y, z, m_World));
LoadItemGridFromNBT(Hopper->GetContents(), a_NBT, Items);
a_BlockEntities.push_back(Hopper.release());
}
void cWSSAnvil::LoadJukeboxFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
{
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
int x, y, z;
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
{
return;
}
std::auto_ptr<cJukeboxEntity> Jukebox(new cJukeboxEntity(x, y, z, m_World));
int Record = a_NBT.FindChildByName(a_TagIdx, "Record");
if (Record >= 0)
{
Jukebox->SetRecord(a_NBT.GetInt(Record));
}
a_BlockEntities.push_back(Jukebox.release());
}
void cWSSAnvil::LoadNoteFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
{
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
int x, y, z;
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
{
return;
}
std::auto_ptr<cNoteEntity> Note(new cNoteEntity(x, y, z, m_World));
int note = a_NBT.FindChildByName(a_TagIdx, "note");
if (note >= 0)
{
Note->SetPitch(a_NBT.GetByte(note));
}
a_BlockEntities.push_back(Note.release());
}
void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
{ {
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
@ -821,47 +890,6 @@ void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParse
void cWSSAnvil::LoadNoteFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
{
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
int x, y, z;
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
{
return;
}
std::auto_ptr<cNoteEntity> Note(new cNoteEntity(x, y, z, m_World));
int note = a_NBT.FindChildByName(a_TagIdx, "note");
if (note >= 0)
{
Note->SetPitch(a_NBT.GetByte(note));
}
a_BlockEntities.push_back(Note.release());
}
void cWSSAnvil::LoadJukeboxFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
{
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
int x, y, z;
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
{
return;
}
std::auto_ptr<cJukeboxEntity> Jukebox(new cJukeboxEntity(x, y, z, m_World));
int Record = a_NBT.FindChildByName(a_TagIdx, "Record");
if (Record >= 0)
{
Jukebox->SetRecord(a_NBT.GetInt(Record));
}
a_BlockEntities.push_back(Jukebox.release());
}
void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength) void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength)
{ {

View File

@ -131,9 +131,10 @@ protected:
void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadSignFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadHopperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadSignFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength); void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength);