diff options
author | Alexander Harkness <bearbin@gmail.com> | 2013-11-24 15:19:41 +0100 |
---|---|---|
committer | Alexander Harkness <bearbin@gmail.com> | 2013-11-24 15:19:41 +0100 |
commit | 675b4aa878f16291ce33fced48a2bc7425f635ae (patch) | |
tree | 409914df27a98f65adf866da669429c4de141b6f /source/BlockEntities/HopperEntity.cpp | |
parent | LineBlockTracer: Using the coord-based block faces. (diff) | |
download | cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.tar cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.tar.gz cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.tar.bz2 cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.tar.lz cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.tar.xz cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.tar.zst cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.zip |
Diffstat (limited to 'source/BlockEntities/HopperEntity.cpp')
-rw-r--r-- | source/BlockEntities/HopperEntity.cpp | 566 |
1 files changed, 0 insertions, 566 deletions
diff --git a/source/BlockEntities/HopperEntity.cpp b/source/BlockEntities/HopperEntity.cpp deleted file mode 100644 index 41849b1b3..000000000 --- a/source/BlockEntities/HopperEntity.cpp +++ /dev/null @@ -1,566 +0,0 @@ - -// HopperEntity.cpp - -// Implements the cHopperEntity representing a hopper block entity - -#include "Globals.h" -#include "HopperEntity.h" -#include "../Chunk.h" -#include "../Entities/Player.h" -#include "../PluginManager.h" -#include "ChestEntity.h" -#include "DropSpenserEntity.h" -#include "FurnaceEntity.h" - - - - - -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), - m_LastMoveItemsInTick(0), - m_LastMoveItemsOutTick(0) -{ -} - - - - - -/** Returns the block coords of the block receiving the output items, based on the meta -Returns false if unattached -*/ -bool cHopperEntity::GetOutputBlockPos(NIBBLETYPE a_BlockMeta, int & a_OutputX, int & a_OutputY, int & a_OutputZ) -{ - a_OutputX = m_PosX; - a_OutputY = m_PosY; - a_OutputZ = m_PosZ; - switch (a_BlockMeta) - { - case E_META_HOPPER_FACING_XM: a_OutputX--; return true; - case E_META_HOPPER_FACING_XP: a_OutputX++; return true; - case E_META_HOPPER_FACING_YM: a_OutputY--; return true; - case E_META_HOPPER_FACING_ZM: a_OutputZ--; return true; - case E_META_HOPPER_FACING_ZP: a_OutputZ++; return true; - default: - { - // Not attached - return false; - } - } -} - - - - - -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_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: - { - // Chests have special handling because of double-chests - res = MoveItemsFromChest(a_Chunk); - break; - } - case E_BLOCK_LIT_FURNACE: - case E_BLOCK_FURNACE: - { - // Furnaces have special handling because only the output and leftover fuel buckets shall be moved - res = MoveItemsFromFurnace(a_Chunk); - break; - } - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - case E_BLOCK_HOPPER: - { - res = MoveItemsFromGrid(*(cBlockEntityWithItems *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ)); - 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; - } - - int bx, by, bz; - NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ); - if (!GetOutputBlockPos(Meta, bx, by, bz)) - { - // Not attached to another container - return false; - } - if (by < 0) - { - // Cannot output below the zero-th block level - return false; - } - - // Convert coords to relative: - int rx = bx - a_Chunk.GetPosX() * cChunkDef::Width; - int rz = bz - a_Chunk.GetPosZ() * cChunkDef::Width; - cChunk * DestChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(rx, rz); - if (DestChunk == NULL) - { - // The destination chunk has been unloaded, don't tick - return false; - } - - // Call proper moving function, based on the blocktype present at the coords: - bool res = false; - switch (DestChunk->GetBlock(rx, by, rz)) - { - case E_BLOCK_CHEST: - { - // Chests have special handling because of double-chests - res = MoveItemsToChest(*DestChunk, bx, by, bz); - break; - } - case E_BLOCK_LIT_FURNACE: - case E_BLOCK_FURNACE: - { - // Furnaces have special handling because of the direction-to-slot relation - res = MoveItemsToFurnace(*DestChunk, bx, by, bz, Meta); - break; - } - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - case E_BLOCK_HOPPER: - { - res = MoveItemsToGrid(*(cBlockEntityWithItems *)DestChunk->GetBlockEntity(bx, by, bz)); - break; - } - } - - // If the item has been moved, reset the last tick: - if (res) - { - m_LastMoveItemsOutTick = a_CurrentTick; - } - - return res; -} - - - - - -/// 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))) - { - // 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))) - { - 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) -{ - cFurnaceEntity * Furnace = (cFurnaceEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ); - ASSERT(Furnace != NULL); - - // Try move from the output slot: - if (MoveItemsFromSlot(*Furnace, cFurnaceEntity::fsOutput, true)) - { - cItem NewOutput(Furnace->GetOutputSlot()); - Furnace->SetOutputSlot(NewOutput.AddCount(-1)); - return true; - } - - // No output moved, check if we can move an empty bucket out of the fuel slot: - if (Furnace->GetFuelSlot().m_ItemType == E_ITEM_BUCKET) - { - if (MoveItemsFromSlot(*Furnace, cFurnaceEntity::fsFuel, true)) - { - Furnace->SetFuelSlot(cItem()); - return true; - } - } - - // Nothing can be moved - return false; -} - - - - - -bool cHopperEntity::MoveItemsFromGrid(cBlockEntityWithItems & a_Entity) -{ - cItemGrid & Grid = a_Entity.GetContents(); - int NumSlots = Grid.GetNumSlots(); - - // First try adding items of types already in the hopper: - for (int i = 0; i < NumSlots; i++) - { - if (Grid.IsSlotEmpty(i)) - { - continue; - } - if (MoveItemsFromSlot(a_Entity, i, false)) - { - 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 (Grid.IsSlotEmpty(i)) - { - continue; - } - if (MoveItemsFromSlot(a_Entity, i, true)) - { - Grid.ChangeSlotCount(i, -1); - return true; - } - } - return false; -} - - - - - -/// Moves one piece of the specified a_Entity's slot itemstack into this hopper. Returns true if contents have changed. Doesn't change the itemstack. -bool cHopperEntity::MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_SlotNum, bool a_AllowNewStacks) -{ - cItem One(a_Entity.GetSlot(a_SlotNum).CopyOne()); - for (int i = 0; i < ContentsWidth * ContentsHeight; i++) - { - if (m_Contents.IsSlotEmpty(i)) - { - if (a_AllowNewStacks) - { - if (cPluginManager::Get()->CallHookHopperPullingItem(*m_World, *this, i, a_Entity, a_SlotNum)) - { - // Plugin disagrees with the move - continue; - } - } - m_Contents.SetSlot(i, One); - return true; - } - else if (m_Contents.GetSlot(i).IsStackableWith(One)) - { - if (cPluginManager::Get()->CallHookHopperPullingItem(*m_World, *this, i, a_Entity, a_SlotNum)) - { - // Plugin disagrees with the move - continue; - } - - m_Contents.ChangeSlotCount(i, 1); - return true; - } - } - return false; -} - - - - - -/// Moves items to the chest at the specified coords. Returns true if contents have changed -bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_BlockY, int a_BlockZ) -{ - // Try the chest directly connected to the hopper: - if (MoveItemsToGrid(*(cChestEntity *)a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ))) - { - return true; - } - - // Check if the chest is a double-chest, if so, try to move into the other half: - 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 (MoveItemsToGrid(*(cChestEntity *)Neighbor->GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ))) - { - return true; - } - return false; - } - - // The chest was single and nothing could be moved - return false; -} - - - - - -/// Moves items to the furnace at the specified coords. Returns true if contents have changed -bool cHopperEntity::MoveItemsToFurnace(cChunk & a_Chunk, int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_HopperMeta) -{ - cFurnaceEntity * Furnace = (cFurnaceEntity *)a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ); - if (a_HopperMeta == E_META_HOPPER_FACING_YM) - { - // Feed the input slot of the furnace - return MoveItemsToSlot(*Furnace, cFurnaceEntity::fsInput); - } - else - { - // Feed the fuel slot of the furnace - return MoveItemsToSlot(*Furnace, cFurnaceEntity::fsFuel); - } - return false; -} - - - - - -bool cHopperEntity::MoveItemsToGrid(cBlockEntityWithItems & a_Entity) -{ - // Iterate through our slots, try to move from each one: - int NumSlots = a_Entity.GetContents().GetNumSlots(); - for (int i = 0; i < NumSlots; i++) - { - if (MoveItemsToSlot(a_Entity, i)) - { - return true; - } - } - return false; -} - - - - - -bool cHopperEntity::MoveItemsToSlot(cBlockEntityWithItems & a_Entity, int a_DstSlotNum) -{ - cItemGrid & Grid = a_Entity.GetContents(); - if (Grid.IsSlotEmpty(a_DstSlotNum)) - { - // The slot is empty, move the first non-empty slot from our contents: - for (int i = 0; i < ContentsWidth * ContentsHeight; i++) - { - if (!m_Contents.IsSlotEmpty(i)) - { - if (cPluginManager::Get()->CallHookHopperPushingItem(*m_World, *this, i, a_Entity, a_DstSlotNum)) - { - // A plugin disagrees with the move - continue; - } - Grid.SetSlot(a_DstSlotNum, m_Contents.GetSlot(i).CopyOne()); - m_Contents.ChangeSlotCount(i, -1); - return true; - } - } - return false; - } - else - { - // The slot is taken, try to top it up: - const cItem & DestSlot = Grid.GetSlot(a_DstSlotNum); - if (DestSlot.IsFullStack()) - { - return false; - } - for (int i = 0; i < ContentsWidth * ContentsHeight; i++) - { - if (m_Contents.GetSlot(i).IsStackableWith(DestSlot)) - { - if (cPluginManager::Get()->CallHookHopperPushingItem(*m_World, *this, i, a_Entity, a_DstSlotNum)) - { - // A plugin disagrees with the move - continue; - } - Grid.ChangeSlotCount(a_DstSlotNum, 1); - m_Contents.ChangeSlotCount(i, -1); - return true; - } - } - return false; - } -} - - - - |