PocketMine-MP  1.4 - API 1.10.0
 All Classes Namespaces Functions Variables Pages
PlayerInventory.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 
35 
37 
38  protected $itemInHandIndex = 0;
40  protected $hotbar;
41 
42  public function __construct(Human $player){
43  $this->hotbar = array_fill(0, $this->getHotbarSize(), -1);
44  parent::__construct($player, InventoryType::get(InventoryType::PLAYER));
45  }
46 
47  public function getSize(){
48  return parent::getSize() - 4; //Remove armor slots
49  }
50 
51  public function getHotbarSlotIndex($index){
52  return ($index >= 0 and $index < $this->getHotbarSize()) ? $this->hotbar[$index] : -1;
53  }
54 
55  public function setHotbarSlotIndex($index, $slot){
56  if($index >= 0 and $index < $this->getHotbarSize() and $slot >= -1 and $slot < $this->getSize()){
57  $this->hotbar[$index] = $slot;
58  }
59  }
60 
61  public function getHeldItemIndex(){
62  return $this->itemInHandIndex;
63  }
64 
65  public function setHeldItemIndex($index){
66  if($index >= 0 and $index < $this->getHotbarSize()){
67  $this->itemInHandIndex = $index;
68  $item = $this->getItemInHand();
69 
70  $pk = new PlayerEquipmentPacket();
71  $pk->eid = $this->getHolder()->getId();
72  $pk->item = $item->getId();
73  $pk->meta = $item->getDamage();
74  $pk->slot = $this->getHeldItemIndex();
75 
77  }
78  }
79 
80  public function getItemInHand(){
81  $item = $this->getItem($this->getHeldItemSlot());
82  if($item instanceof Item){
83  return $item;
84  }else{
85  return Item::get(Item::AIR, 0, 0);
86  }
87  }
88 
95  public function setItemInHand(Item $item, $source = null){
96  return $this->setItem($this->getHeldItemSlot(), $item, $source);
97  }
98 
99  public function getHeldItemSlot(){
100  return $this->getHotbarSlotIndex($this->itemInHandIndex);
101  }
102 
103  public function setHeldItemSlot($slot){
104  if($slot >= -1 and $slot < $this->getSize()){
105  $item = $this->getItem($slot);
106 
107  $itemIndex = $this->getHeldItemIndex();
108 
109  for($i = 0; $i < $this->getHotbarSize(); ++$i){
110  if($this->getHotbarSlotIndex($i) === $slot){
111  $itemIndex = $i;
112  break;
113  }
114  }
115 
116  if($this->getHolder() instanceof Player){
117  Server::getInstance()->getPluginManager()->callEvent($ev = new PlayerItemHeldEvent($this->getHolder(), $item, $slot, $itemIndex));
118  if($ev->isCancelled()){
119  $this->sendHeldItem($this->getHolder());
120  return;
121  }
122  }
123 
124  $this->setHotbarSlotIndex($itemIndex, $slot);
125  $this->setHeldItemIndex($itemIndex);
126  }
127  }
128 
132  public function sendHeldItem($target){
133  if($target instanceof Player){
134  $target = [$target];
135  }
136 
137  $item = $this->getItemInHand();
138 
139  $pk = new PlayerEquipmentPacket();
140  $pk->eid = $this->getHolder()->getId();
141  $pk->item = $item->getId();
142  $pk->meta = $item->getDamage();
143  $pk->slot = 0;
144  $pk->isEncoded = true;
145  $pk->encode();
146 
147  foreach($target as $player){
148  if($player === $this->getHolder()){
149  //TODO: Check if Mojang enabled sending a single slot this
150  //$this->sendSlot($this->getHeldItemSlot());
151  $this->sendContents($player);
152  }else{
153  $player->dataPacket($pk);
154  }
155  }
156  }
157 
158  public function onSlotChange($index, $before, $source = null){
159  parent::onSlotChange($index, $before, $source);
160 
161  if($index >= $this->getSize()){
162  $this->sendArmorSlot($index, $this->getViewers($source));
163  $this->sendArmorSlot($index, $this->getHolder()->getViewers());
164  }
165  }
166 
167  public function getHotbarSize(){
168  return 9;
169  }
170 
171  public function getArmorItem($index){
172  return $this->getItem($this->getSize() + $index);
173  }
174 
175  public function setArmorItem($index, Item $item, $source = null){
176  return $this->setItem($this->getSize() + $index, $item, $source);
177  }
178 
179  public function getHelmet(){
180  return $this->getItem($this->getSize());
181  }
182 
183  public function getChestplate(){
184  return $this->getItem($this->getSize() + 1);
185  }
186 
187  public function getLeggings(){
188  return $this->getItem($this->getSize() + 2);
189  }
190 
191  public function getBoots(){
192  return $this->getItem($this->getSize() + 3);
193  }
194 
195  public function setHelmet(Item $helmet){
196  return $this->setItem($this->getSize(), $helmet);
197  }
198 
199  public function setChestplate(Item $chestplate){
200  return $this->setItem($this->getSize() + 1, $chestplate);
201  }
202 
203  public function setLeggings(Item $leggings){
204  return $this->setItem($this->getSize() + 2, $leggings);
205  }
206 
207  public function setBoots(Item $boots){
208  return $this->setItem($this->getSize() + 3, $boots);
209  }
210 
211  public function setItem($index, Item $item, $source = null){
212  if($index < 0 or $index >= $this->size){
213  return false;
214  }elseif($item->getId() === 0 or $item->getCount() <= 0){
215  return $this->clear($index, $source);
216  }
217 
218  if($index >= $this->getSize()){ //Armor change
219  Server::getInstance()->getPluginManager()->callEvent($ev = new EntityArmorChangeEvent($this->getHolder(), $this->getItem($index), $item, $index));
220  if($ev->isCancelled() and $this->getHolder() instanceof Player){
221  if($index >= $this->size){
222  $this->sendArmorSlot($index, $this->getViewers());
223  }else{
224  $this->sendSlot($index, $this->getViewers());
225  }
226  return false;
227  }
228  $item = $ev->getNewItem();
229  }else{
230  Server::getInstance()->getPluginManager()->callEvent($ev = new EntityInventoryChangeEvent($this->getHolder(), $this->getItem($index), $item, $index));
231  if($ev->isCancelled()){
232  if($index >= $this->size){
233  $this->sendArmorSlot($index, $this->getViewers());
234  }else{
235  $this->sendSlot($index, $this->getViewers());
236  }
237  return false;
238  }
239  $item = $ev->getNewItem();
240  }
241 
242 
243  $old = $this->getItem($index);
244  $this->slots[$index] = clone $item;
245  $this->onSlotChange($index, $old, $source);
246 
247  return true;
248  }
249 
250  public function clear($index, $source = null){
251  if(isset($this->slots[$index])){
252  $item = Item::get(Item::AIR, null, 0);
253  $old = $this->slots[$index];
254  if($index >= $this->getSize() and $index < $this->size){ //Armor change
255  Server::getInstance()->getPluginManager()->callEvent($ev = new EntityArmorChangeEvent($this->getHolder(), $old, $item, $index));
256  if($ev->isCancelled()){
257  if($index >= $this->size){
258  $this->sendArmorSlot($index, $this->getViewers());
259  }else{
260  $this->sendSlot($index, $this->getViewers());
261  }
262  return false;
263  }
264  $item = $ev->getNewItem();
265  }else{
266  Server::getInstance()->getPluginManager()->callEvent($ev = new EntityInventoryChangeEvent($this->getHolder(), $old, $item, $index));
267  if($ev->isCancelled()){
268  if($index >= $this->size){
269  $this->sendArmorSlot($index, $this->getViewers());
270  }else{
271  $this->sendSlot($index, $this->getViewers());
272  }
273  return false;
274  }
275  $item = $ev->getNewItem();
276  }
277  if($item->getId() !== Item::AIR){
278  $this->slots[$index] = clone $item;
279  }else{
280  unset($this->slots[$index]);
281  }
282 
283  $this->onSlotChange($index, $old, $source);
284  }
285 
286  return true;
287  }
288 
292  public function getArmorContents(){
293  $armor = [];
294 
295  for($i = 0; $i < 4; ++$i){
296  $armor[$i] = $this->getItem($this->getSize() + $i);
297  }
298 
299  return $armor;
300  }
301 
302  public function clearAll(){
303  $limit = $this->getSize() + 4;
304  for($index = 0; $index < $limit; ++$index){
305  $this->clear($index);
306  }
307  }
308 
312  public function sendArmorContents($target){
313  if($target instanceof Player){
314  $target = [$target];
315  }
316  $armor = $this->getArmorContents();
317  $slots = [];
318 
319  foreach($armor as $i => $slot){
320  if($slot->getId() === Item::AIR){
321  $slots[$i] = 255;
322  }else{
323  $slots[$i] = $slot->getId();
324  }
325  }
326 
327  $pk = new PlayerArmorEquipmentPacket();
328  $pk->eid = $this->getHolder()->getId();
329  $pk->slots = $slots;
330  $pk->encode();
331  $pk->isEncoded = true;
332 
333  foreach($target as $player){
334  if($player === $this->getHolder()){
336  //$pk2 = clone $pk;
337  //$pk2->eid = 0;
338 
339  $pk2 = new ContainerSetContentPacket();
340  $pk2->windowid = 0x78; //Armor window id constant
341  $pk2->slots = $armor;
342  $player->dataPacket($pk2);
343  }else{
344  $player->dataPacket($pk);
345  }
346  }
347  }
348 
352  public function setArmorContents(array $items){
353  for($i = 0; $i < 4; ++$i){
354  if(!isset($items[$i]) or !($items[$i] instanceof Item)){
355  $items[$i] = Item::get(Item::AIR, null, 0);
356  }
357 
358  if($items[$i]->getId() === Item::AIR){
359  $this->clear($this->getSize() + $i);
360  }else{
361  $this->setItem($this->getSize() + $i, $items[$i]);
362  }
363  }
364  }
365 
366 
371  public function sendArmorSlot($index, $target){
372  if($target instanceof Player){
373  $target = [$target];
374  }
375 
376  $armor = $this->getArmorContents();
377  $slots = [];
378 
379  foreach($armor as $i => $slot){
380  if($slot->getId() === Item::AIR){
381  $slots[$i] = 255;
382  }else{
383  $slots[$i] = $slot->getId();
384  }
385  }
386 
387  $pk = new PlayerArmorEquipmentPacket();
388  $pk->eid = $this->getHolder()->getId();
389  $pk->slots = $slots;
390  $pk->encode();
391  $pk->isEncoded = true;
392 
393  foreach($target as $player){
394  if($player === $this->getHolder()){
396  //$pk2 = clone $pk;
397  //$pk2->eid = 0;
398 
399  $pk2 = new ContainerSetSlotPacket();
400  $pk2->windowid = 0x78; //Armor window id constant
401  $pk2->slot = $index;
402  $pk2->item = $this->getItem($index);
403  $player->dataPacket($pk2);
404  }else{
405  $player->dataPacket($pk);
406  }
407  }
408  }
409 
413  public function sendContents($target){
414  if($target instanceof Player){
415  $target = [$target];
416  }
417 
418  $pk = new ContainerSetContentPacket();
419  $pk->slots = [];
420  for($i = 0; $i < $this->getSize(); ++$i){ //Do not send armor by error here
421  $pk->slots[$i] = $this->getItem($i);
422  }
423 
424  foreach($target as $player){
425  $pk->hotbar = [];
426  if($player === $this->getHolder()){
427  for($i = 0; $i < $this->getHotbarSize(); ++$i){
428  $index = $this->getHotbarSlotIndex($i);
429  $pk->hotbar[] = $index <= -1 ? -1 : $index + 9;
430  }
431  }
432  if(($id = $player->getWindowId($this)) === -1 or $player->spawned !== true){
433  $this->close($player);
434  continue;
435  }
436  $pk->windowid = $id;
437  $player->dataPacket(clone $pk);
438  }
439  }
440 
445  public function sendSlot($index, $target){
446  if($target instanceof Player){
447  $target = [$target];
448  }
449 
450  $pk = new ContainerSetSlotPacket();
451  $pk->slot = $index;
452  $pk->item = clone $this->getItem($index);
453 
454  foreach($target as $player){
455  if($player === $this->getHolder()){
457  $this->sendContents($player); //#blamemojang
458  }else{
459  if(($id = $player->getWindowId($this)) === -1){
460  $this->close($player);
461  continue;
462  }
463  $pk->windowid = $id;
464  $player->dataPacket(clone $pk);
465  }
466  }
467  }
468 
472  public function getHolder(){
473  return parent::getHolder();
474  }
475 
476 }
setItem($index, Item $item, $source=null)
setItemInHand(Item $item, $source=null)
onSlotChange($index, $before, $source=null)
static getInstance()
Definition: Server.php:1444
static broadcastPacket(array $players, DataPacket $packet)
Definition: Server.php:1725