Cuberite
A lightweight, fast and extensible game server for Minecraft
HopperEntity.cpp
Go to the documentation of this file.
1 
2 // HopperEntity.cpp
3 
4 // Implements the cHopperEntity representing a hopper block entity
5 
6 #include "Globals.h"
7 #include "HopperEntity.h"
8 #include "../Chunk.h"
9 #include "../Entities/Player.h"
10 #include "../Entities/Pickup.h"
11 #include "../Bindings/PluginManager.h"
12 #include "../UI/HopperWindow.h"
13 #include "ChestEntity.h"
14 #include "FurnaceEntity.h"
15 
16 
17 
18 
19 
20 cHopperEntity::cHopperEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld * a_World):
21  super(a_BlockType, a_BlockMeta, a_Pos, ContentsWidth, ContentsHeight, a_World),
22  m_LastMoveItemsInTick(0),
23  m_LastMoveItemsOutTick(0)
24 {
25  ASSERT(a_BlockType == E_BLOCK_HOPPER);
26 }
27 
28 
29 
30 
31 
32 std::pair<bool, Vector3i> cHopperEntity::GetOutputBlockPos(NIBBLETYPE a_BlockMeta)
33 {
34  auto pos = GetPos();
35  switch (a_BlockMeta)
36  {
37  case E_META_HOPPER_FACING_XM: return {true, pos.addedX(-1)};
38  case E_META_HOPPER_FACING_XP: return {true, pos.addedX( 1)};
39  case E_META_HOPPER_FACING_YM: return {true, pos.addedY(-1)};
40  case E_META_HOPPER_FACING_ZM: return {true, pos.addedZ(-1)};
41  case E_META_HOPPER_FACING_ZP: return {true, pos.addedZ( 1)};
42  default:
43  {
44  // Not attached
45  return {false, pos};
46  }
47  }
48 }
49 
50 
51 
52 
53 
55 {
56  super::CopyFrom(a_Src);
57  auto & src = static_cast<const cHopperEntity &>(a_Src);
58  m_LastMoveItemsInTick = src.m_LastMoveItemsInTick;
59  m_LastMoveItemsOutTick = src.m_LastMoveItemsOutTick;
60 }
61 
62 
63 
64 
65 
66 bool cHopperEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
67 {
68  UNUSED(a_Dt);
69  Int64 CurrentTick = a_Chunk.GetWorld()->GetWorldAge();
70 
71  bool isDirty = false;
72  isDirty = MoveItemsIn (a_Chunk, CurrentTick) || isDirty;
73  isDirty = MovePickupsIn(a_Chunk, CurrentTick) || isDirty;
74  isDirty = MoveItemsOut (a_Chunk, CurrentTick) || isDirty;
75  return isDirty;
76 }
77 
78 
79 
80 
81 
83 {
84  // The hopper entity doesn't need anything sent to the client when it's created / gets in the viewdistance
85  // All the actual handling is in the cWindow UI code that gets called when the hopper is rclked
86 
87  UNUSED(a_Client);
88 }
89 
90 
91 
92 
93 
95 {
96  // If the window is not created, open it anew:
97  cWindow * Window = GetWindow();
98  if (Window == nullptr)
99  {
100  OpenNewWindow();
101  Window = GetWindow();
102  }
103 
104  // Open the window for the player:
105  if (Window != nullptr)
106  {
107  if (a_Player->GetWindow() != Window)
108  {
109  a_Player->OpenWindow(*Window);
110  }
111  }
112 
113  // This is rather a hack
114  // Instead of marking the chunk as dirty upon chest contents change, we mark it dirty now
115  // We cannot properly detect contents change, but such a change doesn't happen without a player opening the chest first.
116  // The few false positives aren't much to worry about
118  m_World->MarkChunkDirty(ChunkPos.m_ChunkX, ChunkPos.m_ChunkZ);
119  return true;
120 }
121 
122 
123 
124 
125 
127 {
128  OpenWindow(new cHopperWindow(this));
129 }
130 
131 
132 
133 
134 
135 bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
136 {
137  if (m_Pos.y >= cChunkDef::Height)
138  {
139  // This hopper is at the top of the world, no more blocks above
140  return false;
141  }
142 
143  if (a_CurrentTick - m_LastMoveItemsInTick < TICKS_PER_TRANSFER)
144  {
145  // Too early after the previous transfer
146  return false;
147  }
148 
149  // Try moving an item in:
150  bool res = false;
151  switch (a_Chunk.GetBlock(GetRelPos().addedY(1)))
152  {
154  case E_BLOCK_CHEST:
155  {
156  // Chests have special handling because of double-chests
157  res = MoveItemsFromChest(a_Chunk);
158  break;
159  }
160  case E_BLOCK_LIT_FURNACE:
161  case E_BLOCK_FURNACE:
162  {
163  // Furnaces have special handling because only the output and leftover fuel buckets shall be moved
164  res = MoveItemsFromFurnace(a_Chunk);
165  break;
166  }
167  case E_BLOCK_DISPENSER:
168  case E_BLOCK_DROPPER:
169  case E_BLOCK_HOPPER:
170  {
171  res = MoveItemsFromGrid(*static_cast<cBlockEntityWithItems *>(a_Chunk.GetBlockEntity(this->GetPos().addedY(1))));
172  break;
173  }
174  }
175 
176  // If the item has been moved, reset the last tick:
177  if (res)
178  {
179  m_LastMoveItemsInTick = a_CurrentTick;
180  }
181 
182  return res;
183 }
184 
185 
186 
187 
188 
189 bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
190 {
191  UNUSED(a_CurrentTick);
192 
193  class cHopperPickupSearchCallback
194  {
195  public:
196  cHopperPickupSearchCallback(Vector3i a_Pos, cItemGrid & a_Contents) :
197  m_Pos(a_Pos),
198  m_bFoundPickupsAbove(false),
199  m_Contents(a_Contents)
200  {
201  }
202 
203  bool operator () (cEntity & a_Entity)
204  {
205  if (!a_Entity.IsPickup())
206  {
207  return false;
208  }
209 
210  Vector3f EntityPos = a_Entity.GetPosition();
211  Vector3f BlockPos(m_Pos.x + 0.5f, static_cast<float>(m_Pos.y) + 1, m_Pos.z + 0.5f); // One block above hopper, and search from center outwards
212  double Distance = (EntityPos - BlockPos).Length();
213 
214  if (Distance < 0.5)
215  {
216  if (TrySuckPickupIn(static_cast<cPickup &>(a_Entity)))
217  {
218  return false;
219  }
220  }
221 
222  return false;
223  }
224 
225  bool TrySuckPickupIn(cPickup & a_Pickup)
226  {
227  cItem & Item = a_Pickup.GetItem();
228 
229  for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
230  {
231  if (m_Contents.IsSlotEmpty(i))
232  {
233  m_bFoundPickupsAbove = true;
234  m_Contents.SetSlot(i, Item);
235  a_Pickup.Destroy(); // Kill pickup
236 
237  return true;
238  }
239  else if (m_Contents.GetSlot(i).IsEqual(Item) && !m_Contents.GetSlot(i).IsFullStack())
240  {
241  m_bFoundPickupsAbove = true;
242 
243  int PreviousCount = m_Contents.GetSlot(i).m_ItemCount;
244 
245  Item.m_ItemCount -= m_Contents.ChangeSlotCount(i, Item.m_ItemCount) - PreviousCount; // Set count to however many items were added
246 
247  if (Item.IsEmpty())
248  {
249  a_Pickup.Destroy(); // Kill pickup if all items were added
250  }
251  return true;
252  }
253  }
254  return false;
255  }
256 
257  bool FoundPickupsAbove(void) const
258  {
259  return m_bFoundPickupsAbove;
260  }
261 
262  protected:
263  Vector3i m_Pos;
264  bool m_bFoundPickupsAbove;
266  };
267 
268  cHopperPickupSearchCallback HopperPickupSearchCallback(Vector3i(GetPosX(), GetPosY(), GetPosZ()), m_Contents);
269  a_Chunk.ForEachEntity(HopperPickupSearchCallback);
270 
271  return HopperPickupSearchCallback.FoundPickupsAbove();
272 }
273 
274 
275 
276 
277 
278 bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
279 {
280  if (a_CurrentTick - m_LastMoveItemsOutTick < TICKS_PER_TRANSFER)
281  {
282  // Too early after the previous transfer
283  return false;
284  }
285 
286  // Get the coords of the block where to output items:
287  auto meta = a_Chunk.GetMeta(GetRelPos());
288  auto out = GetOutputBlockPos(meta);
289  if (!out.first)
290  {
291  // Not attached to another container
292  return false;
293  }
294  if (out.second.y < 0)
295  {
296  // Cannot output below the zero-th block level
297  return false;
298  }
299 
300  // Convert coords to relative:
301  auto relCoord = a_Chunk.AbsoluteToRelative(out.second);
302  auto destChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(relCoord);
303  if (destChunk == nullptr)
304  {
305  // The destination chunk has been unloaded, don't tick
306  return false;
307  }
308 
309  // Call proper moving function, based on the blocktype present at the coords:
310  bool res = false;
311  auto absCoord = destChunk->RelativeToAbsolute(relCoord);
312  switch (destChunk->GetBlock(relCoord))
313  {
315  case E_BLOCK_CHEST:
316  {
317  // Chests have special handling because of double-chests
318  res = MoveItemsToChest(*destChunk, absCoord);
319  break;
320  }
321  case E_BLOCK_LIT_FURNACE:
322  case E_BLOCK_FURNACE:
323  {
324  // Furnaces have special handling because of the direction-to-slot relation
325  res = MoveItemsToFurnace(*destChunk, absCoord, meta);
326  break;
327  }
328  case E_BLOCK_DISPENSER:
329  case E_BLOCK_DROPPER:
330  case E_BLOCK_HOPPER:
331  {
332  auto blockEntity = static_cast<cBlockEntityWithItems *>(destChunk->GetBlockEntity(absCoord));
333  if (blockEntity == nullptr)
334  {
335  FLOGWARNING("{0}: A block entity was not found where expected at {1}", __FUNCTION__, absCoord);
336  return false;
337  }
338  res = MoveItemsToGrid(*blockEntity);
339  break;
340  }
341  }
342 
343  // If the item has been moved, reset the last tick:
344  if (res)
345  {
346  m_LastMoveItemsOutTick = a_CurrentTick;
347  }
348 
349  return res;
350 }
351 
352 
353 
354 
355 
357 {
358  auto chestPos = GetPos().addedY(1);
359  auto mainChest = static_cast<cChestEntity *>(a_Chunk.GetBlockEntity(chestPos));
360  if (mainChest == nullptr)
361  {
362  FLOGWARNING("{0}: A chest entity was not found where expected, at {1}", __FUNCTION__, chestPos);
363  return false;
364  }
365  if (MoveItemsFromGrid(*mainChest))
366  {
367  // Moved the item from the chest directly above the hopper
368  return true;
369  }
370 
371  // Check if the chest is a double-chest (chest directly above was empty), if so, try to move from there:
372  static const Vector3i neighborOfs[] =
373  {
374  { 1, 1, 0},
375  {-1, 1, 0},
376  { 0, 1, 1},
377  { 0, 1, -1},
378  } ;
379  for (const auto & ofs: neighborOfs)
380  {
381  auto neighborRelCoord = ofs.addedXZ(m_RelX, m_RelZ);
382  auto neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(neighborRelCoord);
383  if (neighbor == nullptr)
384  {
385  continue;
386  }
387 
388  BLOCKTYPE Block = neighbor->GetBlock(neighborRelCoord);
389  if (Block != mainChest->GetBlockType())
390  {
391  // Not the same kind of chest
392  continue;
393  }
394 
395  auto neighborAbsCoord = neighbor->RelativeToAbsolute(neighborRelCoord);
396  auto sideChest = static_cast<cChestEntity *>(neighbor->GetBlockEntity(neighborAbsCoord));
397  if (sideChest == nullptr)
398  {
399  FLOGWARNING("{0}: A chest entity was not found where expected, at {1}", __FUNCTION__, neighborAbsCoord);
400  }
401  else
402  {
403  if (MoveItemsFromGrid(*sideChest))
404  {
405  return true;
406  }
407  }
408  return false;
409  }
410 
411  // The chest was empty
412  return false;
413 }
414 
415 
416 
417 
418 
420 {
421  auto furnace = static_cast<cFurnaceEntity *>(a_Chunk.GetBlockEntity(m_Pos.addedY(1)));
422  if (furnace == nullptr)
423  {
424  FLOGWARNING("{0}: A furnace entity was not found where expected, at {1}", __FUNCTION__, m_Pos.addedY(1));
425  return false;
426  }
427 
428  // Try move from the output slot:
430  {
431  cItem NewOutput(furnace->GetOutputSlot());
432  furnace->SetOutputSlot(NewOutput.AddCount(-1));
433  return true;
434  }
435 
436  // No output moved, check if we can move an empty bucket out of the fuel slot:
437  if (furnace->GetFuelSlot().m_ItemType == E_ITEM_BUCKET)
438  {
440  {
441  furnace->SetFuelSlot(cItem());
442  return true;
443  }
444  }
445 
446  // Nothing can be moved
447  return false;
448 }
449 
450 
451 
452 
453 
455 {
456  auto & Grid = a_Entity.GetContents();
457  int NumSlots = Grid.GetNumSlots();
458 
459  for (int i = 0; i < NumSlots; i++)
460  {
461  if (Grid.IsSlotEmpty(i))
462  {
463  continue;
464  }
465  if (MoveItemsFromSlot(a_Entity, i))
466  {
467  Grid.ChangeSlotCount(i, -1);
468  return true;
469  }
470  }
471  return false;
472 }
473 
474 
475 
476 
477 
479 {
480  cItem One(a_Entity.GetSlot(a_SlotNum).CopyOne());
481  for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
482  {
483  if (m_Contents.IsSlotEmpty(i))
484  {
485  if (cPluginManager::Get()->CallHookHopperPullingItem(*m_World, *this, i, a_Entity, a_SlotNum))
486  {
487  // Plugin disagrees with the move
488  continue;
489  }
490 
491  m_Contents.SetSlot(i, One);
492  return true;
493  }
494  else if (m_Contents.GetSlot(i).IsEqual(One))
495  {
496  if (cPluginManager::Get()->CallHookHopperPullingItem(*m_World, *this, i, a_Entity, a_SlotNum))
497  {
498  // Plugin disagrees with the move
499  continue;
500  }
501 
502  auto PreviousCount = m_Contents.GetSlot(i).m_ItemCount;
504 
505  if (PreviousCount + 1 == m_Contents.GetSlot(i).m_ItemCount)
506  {
507  // Successfully added a new item. (Failure condition consistutes: stack full)
508  return true;
509  }
510  }
511  }
512  return false;
513 }
514 
515 
516 
517 
518 
520 {
521  // Try the chest directly connected to the hopper:
522  auto ConnectedChest = static_cast<cChestEntity *>(a_Chunk.GetBlockEntity(a_Coords));
523  if (ConnectedChest == nullptr)
524  {
525  FLOGWARNING("{0}: A chest entity was not found where expected, at {1}", __FUNCTION__, a_Coords);
526  return false;
527  }
528  if (MoveItemsToGrid(*ConnectedChest))
529  {
530  // Chest block directly connected was not full
531  return true;
532  }
533 
534  // Check if the chest is a double-chest (chest block directly connected was full), if so, try to move into the other half:
535  static const Vector3i neighborOfs [] =
536  {
537  { 1, 0, 0},
538  {-1, 0, 0},
539  { 0, 0, 1},
540  { 0, 0, -1},
541  } ;
542  auto relCoord = a_Chunk.AbsoluteToRelative(a_Coords);
543  for (const auto & ofs: neighborOfs)
544  {
545  auto otherHalfRelCoord = relCoord + ofs;
546  auto neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(otherHalfRelCoord);
547  if (neighbor == nullptr)
548  {
549  continue;
550  }
551 
552  auto Block = neighbor->GetBlock(otherHalfRelCoord);
553  if (Block != ConnectedChest->GetBlockType())
554  {
555  // Not the same kind of chest
556  continue;
557  }
558 
559  auto chest = static_cast<cChestEntity *>(neighbor->GetBlockEntity(a_Coords + ofs));
560  if (chest == nullptr)
561  {
562  FLOGWARNING("{0}: A chest entity was not found where expected, at {1} ({2}, {3}})", __FUNCTION__, a_Coords + ofs, ofs.x, ofs.z);
563  continue;
564  }
565  if (MoveItemsToGrid(*chest))
566  {
567  return true;
568  }
569  return false;
570  }
571 
572  // The chest was single and nothing could be moved
573  return false;
574 }
575 
576 
577 
578 
579 
580 bool cHopperEntity::MoveItemsToFurnace(cChunk & a_Chunk, Vector3i a_Coords, NIBBLETYPE a_HopperMeta)
581 {
582  auto furnace = static_cast<cFurnaceEntity *>(a_Chunk.GetBlockEntity(a_Coords));
583  if (a_HopperMeta == E_META_HOPPER_FACING_YM)
584  {
585  // Feed the input slot of the furnace
586  return MoveItemsToSlot(*furnace, cFurnaceEntity::fsInput);
587  }
588  else
589  {
590  // Feed the fuel slot of the furnace
591  return MoveItemsToSlot(*furnace, cFurnaceEntity::fsFuel);
592  }
593 }
594 
595 
596 
597 
598 
600 {
601  // Iterate through our slots, try to move from each one:
602  int NumSlots = a_Entity.GetContents().GetNumSlots();
603  for (int i = 0; i < NumSlots; i++)
604  {
605  if (MoveItemsToSlot(a_Entity, i))
606  {
607  return true;
608  }
609  }
610  return false;
611 }
612 
613 
614 
615 
616 
617 bool cHopperEntity::MoveItemsToSlot(cBlockEntityWithItems & a_Entity, int a_DstSlotNum)
618 {
619  cItemGrid & Grid = a_Entity.GetContents();
620  if (Grid.IsSlotEmpty(a_DstSlotNum))
621  {
622  // The slot is empty, move the first non-empty slot from our contents:
623  for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
624  {
625  if (!m_Contents.IsSlotEmpty(i))
626  {
627  if (cPluginManager::Get()->CallHookHopperPushingItem(*m_World, *this, i, a_Entity, a_DstSlotNum))
628  {
629  // A plugin disagrees with the move
630  continue;
631  }
632  Grid.SetSlot(a_DstSlotNum, m_Contents.GetSlot(i).CopyOne());
634  return true;
635  }
636  }
637  return false;
638  }
639  else
640  {
641  // The slot is taken, try to top it up:
642  const cItem & DestSlot = Grid.GetSlot(a_DstSlotNum);
643  if (DestSlot.IsFullStack())
644  {
645  return false;
646  }
647  for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
648  {
649  if (m_Contents.GetSlot(i).IsEqual(DestSlot))
650  {
651  if (cPluginManager::Get()->CallHookHopperPushingItem(*m_World, *this, i, a_Entity, a_DstSlotNum))
652  {
653  // A plugin disagrees with the move
654  continue;
655  }
656  Grid.ChangeSlotCount(a_DstSlotNum, 1);
658  return true;
659  }
660  }
661  return false;
662  }
663 }
664 
665 
666 
667 
cWorld * GetWorld(void) const
Definition: Chunk.h:153
T x
Definition: Vector3.h:17
cChunk * GetRelNeighborChunkAdjustCoords(Vector3i &a_RelPos) const
Returns the chunk into which the relatively-specified block belongs.
Definition: Chunk.cpp:2358
bool MoveItemsFromChest(cChunk &a_Chunk)
Moves items from a chest (dblchest) above the hopper into this hopper.
bool IsFullStack(void) const
Returns true if the item is stacked up to its maximum stacking.
Definition: Item.cpp:119
Int64 m_LastMoveItemsInTick
Definition: HopperEntity.h:50
std::pair< bool, Vector3i > GetOutputBlockPos(NIBBLETYPE a_BlockMeta)
Returns the block coords of the block receiving the output items, based on the meta Returns <false...
int GetPosY() const
Definition: BlockEntity.h:106
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:42
const cItem & GetSlot(int a_SlotNum) const
int m_RelX
Position relative to the chunk, used to speed up ticking.
Definition: BlockEntity.h:145
Vector3< T > addedXZ(T a_AddX, T a_AddZ) const
Returns a copy of this vector moved by the specified amount on the X and Z axes.
Definition: Vector3.h:311
cWindow * GetWindow(void)
Definition: Player.h:239
Vector3i RelativeToAbsolute(Vector3i a_RelBlockPosition)
Converts the coord relative to this chunk into an absolute coord.
Definition: Chunk.h:569
bool MoveItemsFromSlot(cBlockEntityWithItems &a_Entity, int a_SrcSlotNum)
Moves one piece from the specified itemstack into this hopper.
Definition: Player.h:27
virtual void CopyFrom(const cBlockEntity &a_Src) override
Copies all properties of a_Src into this entity, except for its m_World and location.
int ChangeSlotCount(int a_SlotNum, int a_AddToCount)
Adds (or subtracts, if a_AddToCount is negative) to the count of items in the specified slot...
Definition: ItemGrid.cpp:443
bool IsEmpty(void) const
Definition: Item.h:116
void OpenWindow(cWindow *a_Window)
Definition: WindowOwner.h:34
cItemGrid & GetContents(void)
Returns the ItemGrid used for storing the contents.
cHopperEntity(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Vector3i a_Pos, cWorld *a_World)
Constructor used for normal operation.
int GetPosX() const
Definition: BlockEntity.h:105
bool IsEqual(const cItem &a_Item) const
Definition: Item.h:123
int GetPosZ() const
Definition: BlockEntity.h:107
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:45
Definition: Pickup.h:18
bool CallHookHopperPushingItem(cWorld &a_World, cHopperEntity &a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems &a_DstEntity, int a_DstSlotNum)
static cPluginManager * Get(void)
Returns the instance of the Plugin Manager (there is only ever one)
Definition: Chunk.h:49
cItem CopyOne(void) const
Returns a copy of this item with m_ItemCount set to 1.
Definition: Item.cpp:15
bool MoveItemsToSlot(cBlockEntityWithItems &a_Entity, int a_DstSlotNum)
Moves one piece to the specified entity&#39;s contents&#39; slot.
T y
Definition: Vector3.h:17
cBlockEntity * GetBlockEntity(Vector3i a_AbsPos)
Returns the block entity at the specified (absolute) coords.
Definition: Chunk.cpp:1530
virtual void Destroy(bool a_ShouldBroadcast=true)
Destroys the entity and schedules it for memory freeing; if a_ShouldBroadcast is set to true...
Definition: Entity.cpp:219
cWorld * m_World
Definition: BlockEntity.h:155
bool IsSlotEmpty(int a_SlotNum) const
Returns true if the specified slot is empty or the slot doesn&#39;t exist.
Definition: ItemGrid.cpp:203
T z
Definition: Vector3.h:17
static const int Height
Definition: ChunkDef.h:135
Vector3< T > addedY(T a_AddY) const
Returns a copy of this vector moved by the specified amount on the y axis.
Definition: Vector3.h:299
static void BlockToChunk(int a_X, int a_Z, int &a_ChunkX, int &a_ChunkZ)
Converts absolute block coords to chunk coords:
Definition: ChunkDef.h:234
void MarkChunkDirty(int a_ChunkX, int a_ChunkZ)
Definition: World.cpp:2260
bool ForEachEntity(cEntityCallback a_Callback)
Calls the callback for each entity; returns true if all entities processed, false if the callback abo...
Definition: Chunk.cpp:1871
cWindow * GetWindow(void) const
Definition: WindowOwner.h:40
Vector3i GetPos() const
Definition: BlockEntity.h:104
Vector3i GetRelPos() const
Definition: BlockEntity.h:109
bool MoveItemsToChest(cChunk &a_Chunk, Vector3i a_Coords)
Moves items to the chest at the specified absolute coords.
Definition: World.h:65
NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:380
bool CallHookHopperPullingItem(cWorld &a_World, cHopperEntity &a_Hopper, int a_DstSlotNum, cBlockEntityWithItems &a_SrcEntity, int a_SrcSlotNum)
bool MoveItemsToGrid(cBlockEntityWithItems &a_Entity)
Moves items to the specified ItemGrid.
char m_ItemCount
Definition: Item.h:210
static void AbsoluteToRelative(int &a_X, int &a_Y, int &a_Z, int &a_ChunkX, int &a_ChunkZ)
Converts absolute block coords into relative (chunk + block) coords:
Definition: ChunkDef.h:163
virtual Int64 GetWorldAge(void) const override
Definition: World.h:109
bool MoveItemsToFurnace(cChunk &a_Chunk, Vector3i a_Coords, NIBBLETYPE a_HopperMeta)
Moves items to the furnace at the specified absolute coords.
#define ASSERT(x)
Definition: Globals.h:335
Int64 m_LastMoveItemsOutTick
Definition: HopperEntity.h:51
Vector3i m_Pos
Position in absolute block coordinates.
Definition: BlockEntity.h:142
bool MovePickupsIn(cChunk &a_Chunk, Int64 a_CurrentTick)
Moves pickups from above this hopper into it.
int m_ChunkZ
Definition: ChunkDef.h:60
bool MoveItemsFromFurnace(cChunk &a_Chunk)
Moves items from a furnace above the hopper into this hopper.
#define UNUSED
Definition: Globals.h:152
void FLOGWARNING(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:138
int m_ChunkX
Definition: ChunkDef.h:59
virtual bool Tick(std::chrono::milliseconds a_Dt, cChunk &a_Chunk) override
Ticks the entity; returns true if the chunk should be marked as dirty as a result of this ticking...
bool MoveItemsFromGrid(cBlockEntityWithItems &a_Entity)
Moves items from the specified a_Entity&#39;s Contents into this hopper.
How many ticks at minimum between two item transfers to or from the hopper.
Definition: HopperEntity.h:33
cItem & GetItem(void)
Definition: Pickup.h:31
BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:177
bool MoveItemsIn(cChunk &a_Chunk, Int64 a_CurrentTick)
Moves items from the container above it into this hopper.
Definition: Entity.h:73
virtual void CopyFrom(const cBlockEntity &a_Src) override
Copies all properties of a_Src into this entity, except for its m_World and location.
const Vector3d & GetPosition(void) const
Exported in ManualBindings.
Definition: Entity.h:307
bool IsPickup(void) const
Definition: Entity.h:172
Represents a UI window.
Definition: Window.h:53
Vector3< int > Vector3i
Definition: Vector3.h:447
virtual bool UsedBy(cPlayer *a_Player) override
Called when a player uses this entity; should open the UI window.
const cItem & GetSlot(int a_X, int a_Y) const
Definition: ItemGrid.cpp:96
bool MoveItemsOut(cChunk &a_Chunk, Int64 a_CurrentTick)
Moves items out from this hopper into the destination.
int GetNumSlots(void) const
Definition: ItemGrid.h:40
Definition: Item.h:36
signed long long Int64
Definition: Globals.h:107
void OpenNewWindow(void)
Opens a new chest window for this chest.
void OpenWindow(cWindow &a_Window)
Opens the specified window; closes the current one first using CloseWindow()
Definition: Player.cpp:1349
virtual void SendTo(cClientHandle &a_Client) override
Sends the packet defining the block entity to the client specified.
void SetSlot(int a_X, int a_Y, const cItem &a_Item)
Definition: ItemGrid.cpp:121