PocketMine-MP  1.4 - API 1.10.0
 All Classes Namespaces Functions Variables Pages
BaseInventory.php
1 <?php
2 
3 /*
4  *
5  * ____ _ _ __ __ _ __ __ ____
6  * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7  * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8  * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9  * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * @author PocketMine Team
17  * @link http://www.pocketmine.net/
18  *
19  *
20 */
21 
22 namespace pocketmine\inventory;
23 
32 
33 abstract class BaseInventory implements Inventory{
34 
36  protected $type;
38  protected $maxStackSize = Inventory::MAX_STACK;
40  protected $size;
42  protected $name;
44  protected $title;
46  protected $slots = [];
48  protected $viewers = [];
50  protected $holder;
51 
59  public function __construct(InventoryHolder $holder, InventoryType $type, array $items = [], $overrideSize = null, $overrideTitle = null){
60  $this->holder = $holder;
61 
62  $this->type = $type;
63  if($overrideSize !== null){
64  $this->size = (int) $overrideSize;
65  }else{
66  $this->size = $this->type->getDefaultSize();
67  }
68 
69  if($overrideTitle !== null){
70  $this->title = $overrideTitle;
71  }else{
72  $this->title = $this->type->getDefaultTitle();
73  }
74 
75  $this->name = $this->type->getDefaultTitle();
76 
77  $this->setContents($items);
78  }
79 
80  public function getSize(){
81  return $this->size;
82  }
83 
84  public function getMaxStackSize(){
85  return $this->maxStackSize;
86  }
87 
88  public function getName(){
89  return $this->name;
90  }
91 
92  public function getTitle(){
93  return $this->title;
94  }
95 
96  public function getItem($index){
97  return isset($this->slots[$index]) ? clone $this->slots[$index] : Item::get(Item::AIR, null, 0);
98  }
99 
100  public function getContents(){
101  return $this->slots;
102  }
103 
107  public function setContents(array $items){
108  if(count($items) > $this->size){
109  $items = array_slice($items, 0, $this->size, true);
110  }
111 
112  for($i = 0; $i < $this->size; ++$i){
113  if(!isset($items[$i])){
114  if(isset($this->slots[$i])){
115  $this->clear($i);
116  }
117  }else{
118  $this->setItem($i, $items[$i]);
119  }
120  }
121  }
122 
123  public function setItem($index, Item $item, $source = null){
124  $item = clone $item;
125  if($index < 0 or $index >= $this->size){
126  return false;
127  }elseif($item->getId() === 0 or $item->getCount() <= 0){
128  return $this->clear($index, $source);
129  }
130 
131  $holder = $this->getHolder();
132  if($holder instanceof Entity){
133  Server::getInstance()->getPluginManager()->callEvent($ev = new EntityInventoryChangeEvent($holder, $this->getItem($index), $item, $index));
134  if($ev->isCancelled()){
135  $this->sendSlot($index, $this->getViewers());
136  return false;
137  }
138  $item = $ev->getNewItem();
139  }
140 
141  $old = $this->getItem($index);
142  $this->slots[$index] = clone $item;
143  $this->onSlotChange($index, $old, $source);
144 
145  return true;
146  }
147 
148  public function contains(Item $item){
149  $count = max(1, $item->getCount());
150  $checkDamage = $item->getDamage() === null ? false : true;
151  foreach($this->getContents() as $i){
152  if($item->equals($i, $checkDamage)){
153  $count -= $i->getCount();
154  if($count <= 0){
155  return true;
156  }
157  }
158  }
159 
160  return false;
161  }
162 
163  public function all(Item $item){
164  $slots = [];
165  $checkDamage = $item->getDamage() === null ? false : true;
166  foreach($this->getContents() as $index => $i){
167  if($item->equals($i, $checkDamage)){
168  $slots[$index] = $i;
169  }
170  }
171 
172  return $slots;
173  }
174 
175  public function remove(Item $item){
176  $checkDamage = $item->getDamage() === null ? false : true;
177  foreach($this->getContents() as $index => $i){
178  if($item->equals($i, $checkDamage)){
179  $this->clear($index);
180  }
181  }
182  }
183 
184  public function first(Item $item){
185  $count = max(1, $item->getCount());
186  $checkDamage = $item->getDamage() === null ? false : true;
187  foreach($this->getContents() as $index => $i){
188  if($item->equals($i, $checkDamage) and $i->getCount() >= $count){
189  return $index;
190  }
191  }
192 
193  return -1;
194  }
195 
196  public function firstEmpty(){
197  for($i = 0; $i < $this->size; ++$i){
198  if($this->getItem($i)->getId() === Item::AIR){
199  return $i;
200  }
201  }
202 
203  return -1;
204  }
205 
206  public function canAddItem(Item $item){
207  $item = clone $item;
208  $checkDamage = $item->getDamage() === null ? false : true;
209  for($i = 0; $i < $this->getSize(); ++$i){
210  $slot = $this->getItem($i);
211  if($item->equals($slot, $checkDamage)){
212  if(($diff = $slot->getMaxStackSize() - $slot->getCount()) > 0){
213  $item->setCount($item->getCount() - $diff);
214  }
215  }elseif($slot->getId() === Item::AIR){
216  $item->setCount($item->getCount() - $this->getMaxStackSize());
217  }
218 
219  if($item->getCount() <= 0){
220  return true;
221  }
222  }
223 
224  return false;
225  }
226 
227  public function addItem(...$slots){
228  if(isset($slots[$end = count($slots) - 1]) and $slots[$end] instanceof Player){
230  $source = $slots[$end];
231  unset($slots[$end]);
232  }else{
233  $source = null;
234  }
235 
238  $itemSlots = [];
239  foreach($slots as $slot){
240  if($slot->getId() !== 0 and $slot->getCount() > 0){
241  $itemSlots[] = clone $slot;
242  }
243  }
244 
245  $emptySlots = [];
246 
247  for($i = 0; $i < $this->getSize(); ++$i){
248  $item = $this->getItem($i);
249  if($item->getId() === Item::AIR or $item->getCount() <= 0){
250  $emptySlots[] = $i;
251  }
252 
253  foreach($itemSlots as $index => $slot){
254  if($slot->equals($item, true) and $item->getCount() < $item->getMaxStackSize()){
255  $amount = min($item->getMaxStackSize() - $item->getCount(), $slot->getCount(), $this->getMaxStackSize());
256  if($amount > 0){
257  $slot->setCount($slot->getCount() - $amount);
258  $item->setCount($item->getCount() + $amount);
259  $this->setItem($i, $item, $source);
260  if($slot->getCount() <= 0){
261  unset($itemSlots[$index]);
262  }
263  }
264  }
265  }
266 
267  if(count($itemSlots) === 0){
268  break;
269  }
270  }
271 
272  if(count($itemSlots) > 0 and count($emptySlots) > 0){
273  foreach($emptySlots as $slotIndex){
274  foreach($itemSlots as $index => $slot){
275  $amount = min($slot->getMaxStackSize(), $slot->getCount(), $this->getMaxStackSize());
276  $slot->setCount($slot->getCount() - $amount);
277  $item = clone $slot;
278  $item->setCount($amount);
279  $this->setItem($slotIndex, $item, $source);
280  if($slot->getCount() <= 0){
281  unset($itemSlots[$index]);
282  }
283  break;
284  }
285  }
286  }
287 
288  return $itemSlots;
289  }
290 
291  public function removeItem(...$slots){
292  if(isset($slots[$end = count($slots) - 1]) and $slots[$end] instanceof Player){
294  $source = $slots[$end];
295  unset($slots[$end]);
296  }else{
297  $source = null;
298  }
299 
302  $itemSlots = [];
303  foreach($slots as $slot){
304  if($slot->getId() !== 0 and $slot->getCount() > 0){
305  $itemSlots[] = clone $slot;
306  }
307  }
308 
309  for($i = 0; $i < $this->getSize(); ++$i){
310  $item = $this->getItem($i);
311  if($item->getId() === Item::AIR or $item->getCount() <= 0){
312  continue;
313  }
314 
315  foreach($itemSlots as $index => $slot){
316  if($slot->equals($item, $slot->getDamage() === null ? false : true)){
317  $amount = min($item->getCount(), $slot->getCount());
318  $slot->setCount($slot->getCount() - $amount);
319  $item->setCount($item->getCount() - $amount);
320  $this->setItem($i, $item, $source);
321  if($slot->getCount() <= 0){
322  unset($itemSlots[$index]);
323  }
324  }
325  }
326 
327  if(count($itemSlots) === 0){
328  break;
329  }
330  }
331 
332  return $itemSlots;
333  }
334 
335  public function clear($index, $source = null){
336  if(isset($this->slots[$index])){
337  $item = Item::get(Item::AIR, null, 0);
338  $old = $this->slots[$index];
339  $holder = $this->getHolder();
340  if($holder instanceof Entity){
341  Server::getInstance()->getPluginManager()->callEvent($ev = new EntityInventoryChangeEvent($holder, $old, $item, $index));
342  if($ev->isCancelled()){
343  $this->sendSlot($index, $this->getViewers());
344  return false;
345  }
346  $item = $ev->getNewItem();
347  }
348  if($item->getId() !== Item::AIR){
349  $this->slots[$index] = clone $item;
350  }else{
351  unset($this->slots[$index]);
352  }
353 
354  $this->onSlotChange($index, $old, $source);
355  }
356 
357  return true;
358  }
359 
360  public function clearAll(){
361  foreach($this->getContents() as $index => $i){
362  $this->clear($index);
363  }
364  }
365 
371  public function getViewers($source = null){
372  $viewers = [];
373  foreach($this->viewers as $viewer){
374  if($viewer === $source){
375  continue;
376  }
377  $viewers[] = $viewer;
378  }
379 
380  return $viewers;
381  }
382 
383  public function getHolder(){
384  return $this->holder;
385  }
386 
387  public function setMaxStackSize($size){
388  $this->setMaxStackSize($size);
389  }
390 
391  public function open(Player $who){
392  $who->getServer()->getPluginManager()->callEvent($ev = new InventoryOpenEvent($this, $who));
393  if($ev->isCancelled()){
394  return false;
395  }
396  $this->onOpen($who);
397 
398  return true;
399  }
400 
401  public function close(Player $who){
402  $this->onClose($who);
403  }
404 
405  public function onOpen(Player $who){
406  $this->viewers[spl_object_hash($who)] = $who;
407  }
408 
409  public function onClose(Player $who){
410  unset($this->viewers[spl_object_hash($who)]);
411  }
412 
413  public function onSlotChange($index, $before, $source = null){
414  $this->sendSlot($index, $this->getViewers($source));
415  }
416 
417 
421  public function sendContents($target){
422  if($target instanceof Player){
423  $target = [$target];
424  }
425 
426  $pk = new ContainerSetContentPacket();
427  $pk->slots = [];
428  for($i = 0; $i < $this->getSize(); ++$i){
429  $pk->slots[$i] = $this->getItem($i);
430  }
431 
432  foreach($target as $player){
433  if(($id = $player->getWindowId($this)) === -1 or $player->spawned !== true){
434  $this->close($player);
435  continue;
436  }
437  $pk->windowid = $id;
438  $player->dataPacket($pk);
439  }
440  }
441 
446  public function sendSlot($index, $target){
447  if($target instanceof Player){
448  $target = [$target];
449  }
450 
451  $pk = new ContainerSetSlotPacket();
452  $pk->slot = $index;
453  $pk->item = clone $this->getItem($index);
454 
455  foreach($target as $player){
456  if(($id = $player->getWindowId($this)) === -1){
457  $this->close($player);
458  continue;
459  }
460  $pk->windowid = $id;
461  $player->dataPacket($pk);
462  }
463  }
464 
465  public function getType(){
466  return $this->type;
467  }
468 
469 }
__construct(InventoryHolder $holder, InventoryType $type, array $items=[], $overrideSize=null, $overrideTitle=null)
static getInstance()
Definition: Server.php:1444
setItem($index, Item $item, $source=null)
onSlotChange($index, $before, $source=null)