Cuberite
A lightweight, fast and extensible game server for Minecraft
Window.cpp
Go to the documentation of this file.
1 #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2 
3 #include "Window.h"
4 #include "WindowOwner.h"
5 #include "SlotArea.h"
6 #include "../Item.h"
7 #include "../ClientHandle.h"
8 #include "../Entities/Player.h"
9 #include "../Entities/Pickup.h"
10 #include "../Inventory.h"
11 #include "../Items/ItemHandler.h"
12 #include "../BlockEntities/BeaconEntity.h"
13 #include "../BlockEntities/ChestEntity.h"
14 #include "../BlockEntities/DropSpenserEntity.h"
15 #include "../BlockEntities/EnderChestEntity.h"
16 #include "../BlockEntities/HopperEntity.h"
17 #include "../Entities/Minecart.h"
18 #include "../Root.h"
19 #include "../Bindings/PluginManager.h"
20 
21 
22 
23 
25 
26 
27 
28 
29 
30 cWindow::cWindow(WindowType a_WindowType, const AString & a_WindowTitle) :
31  m_WindowID(static_cast<char>((++m_WindowIDCounter) % 127)),
32  m_WindowType(a_WindowType),
33  m_WindowTitle(a_WindowTitle),
34  m_IsDestroyed(false),
35  m_Owner(nullptr)
36 {
37  // The window ID is signed in protocol 1.7, unsigned in protocol 1.8. Keep out of trouble by using only 7 bits:
38  // Ref.: https://forum.cuberite.org/thread-1876.html
39  ASSERT((m_WindowID >= 0) && (m_WindowID < 127));
40 
41  if (a_WindowType == wtInventory)
42  {
43  m_WindowID = 0;
44  }
45 }
46 
47 
48 
49 
50 
52 {
53  for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
54  {
55  delete *itr;
56  }
57  m_SlotAreas.clear();
58 }
59 
60 
61 
62 
63 
65 {
66  switch (m_WindowType)
67  {
68  case wtChest: return "minecraft:chest";
69  case wtWorkbench: return "minecraft:crafting_table";
70  case wtFurnace: return "minecraft:furnace";
71  case wtDropSpenser: return "minecraft:dispenser";
72  case wtEnchantment: return "minecraft:enchanting_table";
73  case wtBrewery: return "minecraft:brewing_stand";
74  case wtNPCTrade: return "minecraft:villager";
75  case wtBeacon: return "minecraft:beacon";
76  case wtAnvil: return "minecraft:anvil";
77  case wtHopper: return "minecraft:hopper";
78  case wtDropper: return "minecraft:dropper";
79  case wtAnimalChest: return "EntityHorse";
80  default:
81  {
82  ASSERT(!"Unknown inventory type!");
83  return "";
84  }
85  }
86 }
87 
88 
89 
90 
91 
92 int cWindow::GetNumSlots(void) const
93 {
94  int res = 0;
95  for (const auto & itr : m_SlotAreas)
96  {
97  res += itr->GetNumSlots();
98  } // for itr - m_SlotAreas[]
99  return res;
100 }
101 
102 
103 
104 
105 
106 const cItem * cWindow::GetSlot(cPlayer & a_Player, int a_SlotNum) const
107 {
108  // Return the item at the specified slot for the specified player
109  int LocalSlotNum = 0;
110  const cSlotArea * Area = GetSlotArea(a_SlotNum, LocalSlotNum);
111  if (Area == nullptr)
112  {
113  LOGWARNING("%s: requesting item from an invalid SlotArea (SlotNum %d), returning nullptr.", __FUNCTION__, a_SlotNum);
114  return nullptr;
115  }
116  return Area->GetSlot(LocalSlotNum, a_Player);
117 }
118 
119 
120 
121 
122 
123 void cWindow::SetSlot(cPlayer & a_Player, int a_SlotNum, const cItem & a_Item)
124 {
125  // Set the item to the specified slot for the specified player
126  int LocalSlotNum = 0;
127  cSlotArea * Area = GetSlotArea(a_SlotNum, LocalSlotNum);
128  if (Area == nullptr)
129  {
130  LOGWARNING("%s: requesting write to an invalid SlotArea (SlotNum %d), ignoring.", __FUNCTION__, a_SlotNum);
131  return;
132  }
133  Area->SetSlot(LocalSlotNum, a_Player, a_Item);
134 }
135 
136 
137 
138 
139 
140 bool cWindow::IsSlotInPlayerMainInventory(int a_SlotNum) const
141 {
142  // Returns true if the specified slot is in the Player Main Inventory slotarea
143  // The player main inventory is always 27 slots, 9 slots from the end of the inventory
144  return ((a_SlotNum >= GetNumSlots() - 36) && (a_SlotNum < GetNumSlots() - 9));
145 }
146 
147 
148 
149 
150 
151 bool cWindow::IsSlotInPlayerHotbar(int a_SlotNum) const
152 {
153  // Returns true if the specified slot is in the Player Hotbar slotarea
154  // The hotbar is always the last 9 slots
155  return ((a_SlotNum >= GetNumSlots() - 9) && (a_SlotNum < GetNumSlots()));
156 }
157 
158 
159 
160 
161 
162 bool cWindow::IsSlotInPlayerInventory(int a_SlotNum) const
163 {
164  // Returns true if the specified slot is in the Player Main Inventory or Hotbar slotareas. Note that returns false for Armor.
165  // The player combined inventory is always the last 36 slots
166  return ((a_SlotNum >= GetNumSlots() - 36) && (a_SlotNum < GetNumSlots()));
167 }
168 
169 
170 
171 
172 
173 void cWindow::GetSlots(cPlayer & a_Player, cItems & a_Slots) const
174 {
175  a_Slots.clear();
176  a_Slots.reserve(static_cast<size_t>(GetNumSlots()));
177  for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
178  {
179  int NumSlots = (*itr)->GetNumSlots();
180  for (int i = 0; i < NumSlots; i++)
181  {
182  const cItem * Item = (*itr)->GetSlot(i, a_Player);
183  if (Item == nullptr)
184  {
185  a_Slots.push_back(cItem());
186  }
187  else
188  {
189  a_Slots.push_back(*Item);
190  }
191  }
192  } // for itr - m_SlotAreas[]
193 }
194 
195 
196 
197 
198 
200  cPlayer & a_Player,
201  int a_WindowID, short a_SlotNum, eClickAction a_ClickAction,
202  const cItem & a_ClickedItem
203 )
204 {
206  if (a_WindowID != m_WindowID)
207  {
208  LOGWARNING("%s: Wrong window ID (exp %d, got %d) received from \"%s\"; ignoring click.", __FUNCTION__, m_WindowID, a_WindowID, a_Player.GetName().c_str());
209  return;
210  }
211 
212  switch (a_ClickAction)
213  {
214  case caLeftClickOutside:
215  case caRightClickOutside:
216  {
217  if (PlgMgr->CallHookPlayerTossingItem(a_Player))
218  {
219  // A plugin doesn't agree with the tossing. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
220  return;
221  }
222  if (a_Player.IsGameModeCreative())
223  {
224  a_Player.TossPickup(a_ClickedItem);
225  }
226 
227  if (a_ClickAction == caLeftClickOutside)
228  {
229  // Toss all dragged items:
230  a_Player.TossHeldItem(a_Player.GetDraggingItem().m_ItemCount);
231  }
232  else
233  {
234  // Toss one of the dragged items:
235  a_Player.TossHeldItem();
236  }
237  return;
238  }
241  {
242  // Nothing needed
243  return;
244  }
245  case caLeftPaintBegin: OnPaintBegin (a_Player); return;
246  case caRightPaintBegin: OnPaintBegin (a_Player); return;
247  case caMiddlePaintBegin: OnPaintBegin (a_Player); return;
248  case caLeftPaintProgress: OnPaintProgress (a_Player, a_SlotNum); return;
249  case caRightPaintProgress: OnPaintProgress (a_Player, a_SlotNum); return;
250  case caMiddlePaintProgress: OnPaintProgress (a_Player, a_SlotNum); return;
251  case caLeftPaintEnd: OnLeftPaintEnd (a_Player); return;
252  case caRightPaintEnd: OnRightPaintEnd (a_Player); return;
253  case caMiddlePaintEnd: OnMiddlePaintEnd(a_Player); return;
254  default:
255  {
256  break;
257  }
258  }
259 
260  if (a_SlotNum < 0)
261  {
262  // TODO: Other click actions with irrelevant slot number (FS #371)
263  return;
264  }
265 
266  int LocalSlotNum = a_SlotNum;
267  for (const auto & itr : m_SlotAreas)
268  {
269  if (LocalSlotNum < itr->GetNumSlots())
270  {
271  itr->Clicked(a_Player, LocalSlotNum, a_ClickAction, a_ClickedItem);
272  return;
273  }
274  LocalSlotNum -= itr->GetNumSlots();
275  }
276 
277  LOGWARNING("Slot number higher than available window slots: %d, max %d received from \"%s\"; ignoring.",
278  a_SlotNum, GetNumSlots(), a_Player.GetName().c_str()
279  );
280 }
281 
282 
283 
284 
285 
287 {
288  {
289  cCSLock Lock(m_CS);
290  // If player is already in OpenedBy remove player first
291  m_OpenedBy.remove(&a_Player);
292  // Then add player
293  m_OpenedBy.push_back(&a_Player);
294 
295  for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
296  {
297  (*itr)->OnPlayerAdded(a_Player);
298  } // for itr - m_SlotAreas[]
299  }
300 
301  a_Player.GetClientHandle()->SendWindowOpen(*this);
302 }
303 
304 
305 
306 
307 
308 bool cWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
309 {
310  // Checks whether the player is still holding an item
311  if (!a_Player.GetDraggingItem().IsEmpty())
312  {
313  LOGD("Player is holding an item while closing their window, dropping it as a pickup...");
314  a_Player.TossHeldItem(a_Player.GetDraggingItem().m_ItemCount);
315  }
316 
317  cClientHandle * ClientHandle = a_Player.GetClientHandle();
318  if (ClientHandle != nullptr)
319  {
320  ClientHandle->SendWindowClose(*this);
321  }
322 
323  {
324  cCSLock Lock(m_CS);
325 
326  for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
327  {
328  (*itr)->OnPlayerRemoved(a_Player);
329  } // for itr - m_SlotAreas[]
330 
331  if (m_WindowType != wtInventory)
332  {
333  m_OpenedBy.remove(&a_Player);
334  if (m_OpenedBy.empty())
335  {
336  Destroy();
337  }
338  }
339  }
340  if (m_IsDestroyed)
341  {
342  delete this;
343  }
344 
345  return true;
346 }
347 
348 
349 
350 
351 
353 {
354  m_Owner = nullptr;
355  // Close window for each player. Note that the last one needs special handling
356  while (m_OpenedBy.size() > 1)
357  {
358  (*m_OpenedBy.begin())->CloseWindow();
359  }
360  (*m_OpenedBy.begin())->CloseWindow();
361 }
362 
363 
364 
365 
366 
368 {
369  cCSLock Lock(m_CS);
370  for (auto & Player : m_OpenedBy)
371  {
372  if (a_Callback(*Player))
373  {
374  return false;
375  }
376  } // for itr - m_OpenedBy[]
377  return true;
378 }
379 
380 
381 
382 
383 
385 {
386  cCSLock Lock(m_CS);
387  for (auto & Player : m_OpenedBy)
388  {
389  if (a_Callback(*Player->GetClientHandle()))
390  {
391  return false;
392  }
393  } // for itr - m_OpenedBy[]
394  return true;
395 }
396 
397 
398 
399 
400 
401 void cWindow::DistributeStackToAreas(cItem & a_ItemStack, cPlayer & a_Player, cSlotAreas & a_AreasInOrder, bool a_ShouldApply, bool a_BackFill)
402 {
403  /* Ask each slot area to take as much of the stack as it can.
404  First ask only slots that already have the same kind of item
405  Then ask any remaining slots */
406  for (size_t Pass = 0; Pass < 2; Pass++)
407  {
408  for (auto SlotArea : a_AreasInOrder)
409  {
410  SlotArea->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0), a_BackFill);
411  if (a_ItemStack.IsEmpty())
412  {
413  // Distributed it all
414  return;
415  }
416  }
417  }
418 }
419 
420 
421 
422 
423 
424 bool cWindow::CollectItemsToHand(cItem & a_Dragging, cSlotArea & a_Area, cPlayer & a_Player, bool a_CollectFullStacks)
425 {
426  // Ask to collect items from each slot area in order:
427  for (auto Area : m_SlotAreas)
428  {
429  if (Area->CollectItemsToHand(a_Dragging, a_Player, a_CollectFullStacks))
430  {
431  return true; // a_Dragging is full
432  }
433  }
434  return false; // All areas processed
435 }
436 
437 
438 
439 
440 
441 void cWindow::SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum)
442 {
443  int SlotBase = 0;
444  bool Found = false;
445  for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
446  {
447  if (*itr == a_SlotArea)
448  {
449  Found = true;
450  break;
451  }
452  SlotBase += (*itr)->GetNumSlots();
453  } // for itr - m_SlotAreas[]
454  if (!Found)
455  {
456  LOGERROR("cWindow::SendSlot(): unknown a_SlotArea");
457  ASSERT(!"cWindow::SendSlot(): unknown a_SlotArea");
458  return;
459  }
460 
462  m_WindowID, static_cast<short>(a_RelativeSlotNum + SlotBase), *(a_SlotArea->GetSlot(a_RelativeSlotNum, a_Player))
463  );
464 }
465 
466 
467 
468 
469 
471 {
472  if (m_Owner != nullptr)
473  {
474  m_Owner->CloseWindow();
475  m_Owner = nullptr;
476  }
477  m_IsDestroyed = true;
478 }
479 
480 
481 
482 
483 
484 cSlotArea * cWindow::GetSlotArea(int a_GlobalSlotNum, int & a_LocalSlotNum)
485 {
486  if ((a_GlobalSlotNum < 0) || (a_GlobalSlotNum >= GetNumSlots()))
487  {
488  LOGWARNING("%s: requesting an invalid SlotNum: %d out of %d slots", __FUNCTION__, a_GlobalSlotNum, GetNumSlots() - 1);
489  ASSERT(!"Invalid SlotNum");
490  return nullptr;
491  }
492 
493  // Iterate through all the SlotAreas, find the correct one
494  int LocalSlotNum = a_GlobalSlotNum;
495  for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
496  {
497  if (LocalSlotNum < (*itr)->GetNumSlots())
498  {
499  a_LocalSlotNum = LocalSlotNum;
500  return *itr;
501  }
502  LocalSlotNum -= (*itr)->GetNumSlots();
503  } // for itr - m_SlotAreas[]
504 
505  // We shouldn't be here - the check at the beginnning should prevent this. Log and assert
506  LOGWARNING("%s: GetNumSlots() is out of sync: %d; LocalSlotNum = %d", __FUNCTION__, GetNumSlots(), LocalSlotNum);
507  ASSERT(!"Invalid GetNumSlots");
508  return nullptr;
509 }
510 
511 
512 
513 
514 
515 const cSlotArea * cWindow::GetSlotArea(int a_GlobalSlotNum, int & a_LocalSlotNum) const
516 {
517  if ((a_GlobalSlotNum < 0) || (a_GlobalSlotNum >= GetNumSlots()))
518  {
519  LOGWARNING("%s: requesting an invalid SlotNum: %d out of %d slots", __FUNCTION__, a_GlobalSlotNum, GetNumSlots() - 1);
520  ASSERT(!"Invalid SlotNum");
521  return nullptr;
522  }
523 
524  // Iterate through all the SlotAreas, find the correct one
525  int LocalSlotNum = a_GlobalSlotNum;
526  for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
527  {
528  if (LocalSlotNum < (*itr)->GetNumSlots())
529  {
530  a_LocalSlotNum = LocalSlotNum;
531  return *itr;
532  }
533  LocalSlotNum -= (*itr)->GetNumSlots();
534  } // for itr - m_SlotAreas[]
535 
536  // We shouldn't be here - the check at the beginnning should prevent this. Log and assert
537  LOGWARNING("%s: GetNumSlots() is out of sync: %d; LocalSlotNum = %d", __FUNCTION__, GetNumSlots(), LocalSlotNum);
538  ASSERT(!"Invalid GetNumSlots");
539  return nullptr;
540 }
541 
542 
543 
544 
545 
547 {
548  // Prepares the internal structures for inventory painting from the specified player
549  a_Player.ClearInventoryPaintSlots();
550 }
551 
552 
553 
554 
555 
556 void cWindow::OnPaintProgress(cPlayer & a_Player, int a_SlotNum)
557 {
558  // Add the slot to the internal structures for inventory painting by the specified player
559  a_Player.AddInventoryPaintSlot(a_SlotNum);
560 }
561 
562 
563 
564 
565 
567 {
568  // Process the entire action stored in the internal structures for inventory painting
569  // distribute as many items as possible
570 
571  const cSlotNums & SlotNums = a_Player.GetInventoryPaintSlots();
572  cItem ToDistribute(a_Player.GetDraggingItem());
573  int ToEachSlot = static_cast<int>(ToDistribute.m_ItemCount) / static_cast<int>(SlotNums.size());
574 
575  int NumDistributed = DistributeItemToSlots(a_Player, ToDistribute, ToEachSlot, SlotNums);
576 
577  // Remove the items distributed from the dragging item:
578  a_Player.GetDraggingItem().m_ItemCount -= NumDistributed;
579  if (a_Player.GetDraggingItem().m_ItemCount == 0)
580  {
581  a_Player.GetDraggingItem().Empty();
582  }
583 
584  SendWholeWindow(*a_Player.GetClientHandle());
585 
586  // To fix #2345 (custom recipes don't work when inventory-painting), we send the result slot explicitly once again
587  // This is a fix for what seems like a client-side bug
588  a_Player.GetClientHandle()->SendInventorySlot(m_WindowID, 0, *GetSlot(a_Player, 0));
589 }
590 
591 
592 
593 
594 
596 {
597  // Process the entire action stored in the internal structures for inventory painting
598  // distribute one item into each slot
599 
600  const cSlotNums & SlotNums = a_Player.GetInventoryPaintSlots();
601  cItem ToDistribute(a_Player.GetDraggingItem());
602 
603  int NumDistributed = DistributeItemToSlots(a_Player, ToDistribute, 1, SlotNums);
604 
605  // Remove the items distributed from the dragging item:
606  a_Player.GetDraggingItem().m_ItemCount -= NumDistributed;
607  if (a_Player.GetDraggingItem().m_ItemCount == 0)
608  {
609  a_Player.GetDraggingItem().Empty();
610  }
611 
612  SendWholeWindow(*a_Player.GetClientHandle());
613 
614  // To fix #2345 (custom recipes don't work when inventory-painting), we send the result slot explicitly once again
615  // This is a fix for what seems like a client-side bug
616  a_Player.GetClientHandle()->SendInventorySlot(m_WindowID, 0, *GetSlot(a_Player, 0));
617 }
618 
619 
620 
621 
622 
624 {
625  if (!a_Player.IsGameModeCreative())
626  {
627  // Midle click paint is only valid for creative mode
628  return;
629  }
630 
631  // Fill available slots with full stacks of the dragging item
632  const auto & DraggingItem = a_Player.GetDraggingItem();
633  auto StackSize = ItemHandler(DraggingItem.m_ItemType)->GetMaxStackSize();
634  if (0 < DistributeItemToSlots(a_Player, DraggingItem, StackSize, a_Player.GetInventoryPaintSlots(), false))
635  {
636  // If any items were distibuted, set dragging item empty
637  a_Player.GetDraggingItem().Empty();
638  }
639 
640  SendWholeWindow(*a_Player.GetClientHandle());
641 }
642 
643 
644 
645 
646 
647 int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int a_NumToEachSlot, const cSlotNums & a_SlotNums, bool a_LimitItems)
648 {
649  if (a_LimitItems && (static_cast<size_t>(a_Item.m_ItemCount) < a_SlotNums.size()))
650  {
651  LOGWARNING("%s: Distributing less items (%d) than slots (%zu)", __FUNCTION__, static_cast<int>(a_Item.m_ItemCount), a_SlotNums.size());
652  // This doesn't seem to happen with the 1.5.1 client, so we don't worry about it for now
653  return 0;
654  }
655 
656  // Distribute to individual slots, keep track of how many items were actually distributed (full stacks etc.)
657  int NumDistributed = 0;
658  for (cSlotNums::const_iterator itr = a_SlotNums.begin(), end = a_SlotNums.end(); itr != end; ++itr)
659  {
660  int LocalSlotNum = 0;
661  cSlotArea * Area = GetSlotArea(*itr, LocalSlotNum);
662  if (Area == nullptr)
663  {
664  LOGWARNING("%s: Bad SlotArea for slot %d", __FUNCTION__, *itr);
665  continue;
666  }
667 
668  // Modify the item at the slot
669  cItem AtSlot(*Area->GetSlot(LocalSlotNum, a_Player));
670  int MaxStack = AtSlot.GetMaxStackSize();
671  if (AtSlot.IsEmpty())
672  {
673  // Empty, just move all of it there:
674  cItem ToStore(a_Item);
675  ToStore.m_ItemCount = static_cast<char>(std::min(a_NumToEachSlot, static_cast<int>(MaxStack)));
676  Area->SetSlot(LocalSlotNum, a_Player, ToStore);
677  NumDistributed += ToStore.m_ItemCount;
678  }
679  else if (AtSlot.IsEqual(a_Item))
680  {
681  // Occupied, add and cap at MaxStack:
682  int CanStore = std::min(a_NumToEachSlot, static_cast<int>(MaxStack) - AtSlot.m_ItemCount);
683  AtSlot.m_ItemCount += CanStore;
684  Area->SetSlot(LocalSlotNum, a_Player, AtSlot);
685  NumDistributed += CanStore;
686  }
687  } // for itr - SlotNums[]
688  return NumDistributed;
689 }
690 
691 
692 
693 
694 
695 void cWindow::BroadcastSlot(cSlotArea * a_Area, int a_LocalSlotNum)
696 {
697  // Translate local slot num into global slot num:
698  int SlotNum = 0;
699  bool HasFound = false;
700  for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
701  {
702  if (a_Area == *itr)
703  {
704  SlotNum += a_LocalSlotNum;
705  HasFound = true;
706  break;
707  }
708  SlotNum += (*itr)->GetNumSlots();
709  } // for itr - m_SlotAreas[]
710  if (!HasFound)
711  {
712  LOGWARNING("%s: Invalid slot area parameter", __FUNCTION__);
713  ASSERT(!"Invalid slot area");
714  return;
715  }
716 
717  // Broadcast the update packet:
718  cCSLock Lock(m_CS);
719  for (cPlayerList::iterator itr = m_OpenedBy.begin(); itr != m_OpenedBy.end(); ++itr)
720  {
721  (*itr)->GetClientHandle()->SendInventorySlot(m_WindowID, static_cast<short>(SlotNum), *a_Area->GetSlot(a_LocalSlotNum, **itr));
722  } // for itr - m_OpenedBy[]
723 }
724 
725 
726 
727 
728 
730 {
731  a_Client.SendWholeInventory(*this);
732 }
733 
734 
735 
736 
737 
739 {
740  cCSLock Lock(m_CS);
741  for (cPlayerList::iterator itr = m_OpenedBy.begin(); itr != m_OpenedBy.end(); ++itr)
742  {
743  SendWholeWindow(*(*itr)->GetClientHandle());
744  } // for itr - m_OpenedBy[]
745 }
746 
747 
748 
749 
750 
751 void cWindow::SetProperty(short a_Property, short a_Value)
752 {
753  cCSLock Lock(m_CS);
754  for (cPlayerList::iterator itr = m_OpenedBy.begin(), end = m_OpenedBy.end(); itr != end; ++itr)
755  {
756  (*itr)->GetClientHandle()->SendWindowProperty(*this, a_Property, a_Value);
757  } // for itr - m_OpenedBy[]
758 }
759 
760 
761 
762 
763 
764 void cWindow::SetProperty(short a_Property, short a_Value, cPlayer & a_Player)
765 {
766  a_Player.GetClientHandle()->SendWindowProperty(*this, a_Property, a_Value);
767 }
768 
769 
770 
771 
void SendSlot(cPlayer &a_Player, cSlotArea *a_SlotArea, int a_RelativeSlotNum)
Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative...
Definition: Window.cpp:441
void BroadcastSlot(cSlotArea *a_Area, int a_LocalSlotNum)
Sends the specified slot&#39;s contents to all clients of this window; the slot is specified as local in ...
Definition: Window.cpp:695
bool IsSlotInPlayerMainInventory(int a_SlotNum) const
Returns true if the specified slot is in the Player Main Inventory slotarea.
Definition: Window.cpp:140
char m_WindowID
Definition: Window.h:184
bool ForEachClient(cClientHandleCallback a_Callback)
Calls the callback safely for each client that has this window open; returns true if all clients have...
Definition: Window.cpp:384
bool IsSlotInPlayerInventory(int a_SlotNum) const
Returns true if the specified slot is in the Player Main Inventory or Hotbar slotareas.
Definition: Window.cpp:162
virtual void Clicked(cPlayer &a_Player, int a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem)
Handles a click event from a player.
Definition: Window.cpp:199
const AString GetWindowTypeName(void) const
Returns the textual representation of the window&#39;s type, such as "minecraft:chest".
Definition: Window.cpp:64
cCriticalSection m_CS
Definition: Window.h:188
void CloseWindow(void)
Definition: WindowOwner.h:29
void GetSlots(cPlayer &a_Player, cItems &a_Slots) const
Fills a_Slots with the slots read from m_SlotAreas[], for the specified player.
Definition: Window.cpp:173
virtual char GetMaxStackSize(void)
Returns the maximum stack size for a given item.
Definition: Player.h:27
void SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem &a_Item)
cItem & GetDraggingItem(void)
In UI windows, get the item that the player is dragging.
Definition: Player.h:437
bool IsEmpty(void) const
Definition: Item.h:116
void OwnerDestroyed(void)
Definition: Window.cpp:352
void TossHeldItem(char a_Amount=1)
tosses the item held in hand (when in UI windows)
Definition: Player.cpp:1948
void DistributeStackToAreas(cItem &a_ItemStack, cPlayer &a_Player, cSlotAreas &a_AreasInOrder, bool a_ShouldApply, bool a_BackFill)
Called from DistributeStack() to distribute the stack into a_AreasInOrder; Modifies a_ItemStack as it...
Definition: Window.cpp:401
void SendWholeInventory(const cWindow &a_Window)
const AString & GetName(void) const
Definition: Player.h:277
void SendWindowProperty(const cWindow &a_Window, short a_Property, short a_Value)
void LOGERROR(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:183
static Byte m_WindowIDCounter
Definition: Window.h:195
bool m_IsDestroyed
Definition: Window.h:191
void AddInventoryPaintSlot(int a_SlotNum)
Adds a slot to the list for inventory painting.
Definition: Player.cpp:783
bool CollectItemsToHand(cItem &a_Dragging, cSlotArea &a_Area, cPlayer &a_Player, bool a_CollectFullStacks)
Called on DblClicking to collect all stackable items from all areas into hand.
Definition: Window.cpp:424
eClickAction
Individual actions sent in the WindowClick packet.
Definition: Defines.h:73
const cSlotNums & GetInventoryPaintSlots(void) const
Returns the list of slots currently stored for inventory painting.
Definition: Player.cpp:793
virtual ~cWindow()
Definition: Window.cpp:51
cWindowOwner * m_Owner
Definition: Window.h:193
void OnPaintBegin(cPlayer &a_Player)
Prepares the internal structures for inventory painting from the specified player.
Definition: Window.cpp:546
std::vector< cSlotArea * > cSlotAreas
Definition: Window.h:34
virtual void OpenedByPlayer(cPlayer &a_Player)
Definition: Window.cpp:286
char m_ItemCount
Definition: Item.h:210
bool CallHookPlayerTossingItem(cPlayer &a_Player)
#define ASSERT(x)
Definition: Globals.h:335
void LOGWARNING(const char *a_Format, fmt::ArgList a_ArgList)
Definition: Logger.cpp:174
#define LOGD(...)
Definition: LoggerSimple.h:40
void Empty(void)
Definition: Item.h:92
bool ForEachPlayer(cPlayerListCallback a_Callback)
Calls the callback safely for each player that has this window open; returns true if all players have...
Definition: Window.cpp:367
cPlayerList m_OpenedBy
Definition: Window.h:189
void SendWindowOpen(const cWindow &a_Window)
int GetNumSlots(void) const
Returns the total number of slots.
Definition: Window.cpp:92
void ClearInventoryPaintSlots(void)
Clears the list of slots that are being inventory-painted.
Definition: Player.cpp:773
void OnRightPaintEnd(cPlayer &a_Player)
Processes the entire action stored in the internal structures for inventory painting; distributes one...
Definition: Window.cpp:595
void SendWholeWindow(cClientHandle &a_Client)
Sends the contents of the whole window to the specified client.
Definition: Window.cpp:729
virtual bool ClosedByPlayer(cPlayer &a_Player, bool a_CanRefuse)
Called when a player closes this window; notifies all slot areas.
Definition: Window.cpp:308
int DistributeItemToSlots(cPlayer &a_Player, const cItem &a_Item, int a_NumToEachSlot, const cSlotNums &a_SlotNums, bool a_LimitItems=true)
Distributes a_NumToEachSlot items into the slots specified in a_SlotNums; returns the total number of...
Definition: Window.cpp:647
void OnPaintProgress(cPlayer &a_Player, int a_SlotNum)
Adds the slot to the internal structures for inventory painting by the specified player.
Definition: Window.cpp:556
std::string AString
Definition: StringUtils.h:13
int m_WindowType
Definition: Window.h:185
virtual void SetProperty(short a_Property, short a_Value)
Updates a numerical property associated with the window.
Definition: Window.cpp:751
char GetMaxStackSize(void) const
Returns the maximum amount of stacked items of this type.
Definition: Item.cpp:128
void TossPickup(const cItem &a_Item)
tosses a pickup newly created from a_Item
Definition: Player.cpp:1975
static cRoot * Get()
Definition: Root.h:51
bool IsSlotInPlayerHotbar(int a_SlotNum) const
Returns true if the specified slot is in the Player Hotbar slotarea.
Definition: Window.cpp:151
RAII for cCriticalSection - locks the CS on creation, unlocks on destruction.
void SendWindowClose(const cWindow &a_Window)
cWindow(WindowType a_WindowType, const AString &a_WindowTitle)
Definition: Window.cpp:30
virtual const cItem * GetSlot(int a_SlotNum, cPlayer &a_Player) const =0
Called to retrieve an item in the specified slot for the specified player.
cSlotAreas m_SlotAreas
Definition: Window.h:182
cSlotArea * GetSlotArea(int a_GlobalSlotNum, int &a_LocalSlotNum)
Returns the correct slot area for the specified window-global SlotNum Also returns the area-local Slo...
Definition: Window.cpp:484
unsigned char Byte
Definition: Globals.h:117
virtual void Destroy(void)
Sets the internal flag as "destroyed"; notifies the owner that the window is destroying.
Definition: Window.cpp:470
bool IsGameModeCreative(void) const
Returns true if the player is in Creative mode, either explicitly, or by inheriting from current worl...
Definition: Player.cpp:1260
virtual void SetSlot(int a_SlotNum, cPlayer &a_Player, const cItem &a_Item)=0
Called to set an item in the specified slot for the specified player.
const cItem * GetSlot(cPlayer &a_Player, int a_SlotNum) const
Returns the item at the specified slot for the specified player.
Definition: Window.cpp:106
void OnMiddlePaintEnd(cPlayer &a_Player)
Processes the entire action stored in the internal structures for inventory painting; distributes a f...
Definition: Window.cpp:623
WindowType
Definition: Window.h:56
void SetSlot(cPlayer &a_Player, int a_SlotNum, const cItem &a_Item)
Sets the item to the specified slot for the specified player.
Definition: Window.cpp:123
Definition: Item.h:36
cItemHandler * ItemHandler(int a_ItemType)
Definition: ItemHandler.h:174
cClientHandle * GetClientHandle(void) const
Returns the raw client handle associated with the player.
Definition: Player.h:254
This class bridges a vector of cItem for safe access via Lua.
Definition: Item.h:234
void OnLeftPaintEnd(cPlayer &a_Player)
Processes the entire action stored in the internal structures for inventory painting; distributes as ...
Definition: Window.cpp:566
cPluginManager * GetPluginManager(void)
Definition: Root.h:114
std::vector< int > cSlotNums
List of slot numbers, used for inventory-painting.
Definition: Defines.h:9
void BroadcastWholeWindow(void)
Sends the contents of the whole window to all clients of this window.
Definition: Window.cpp:738