mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-28 14:19:53 +00:00
Merge branch 'master' into api3/network
This commit is contained in:
commit
6c5dbd7359
@ -16,7 +16,7 @@ If you don't find what you're looking for there, [talk to a human](#discussion).
|
|||||||
There are a very wide range of already-written plugins available which you can use to customise your server. Check out the [old plugin repository](http://plugins.pocketmine.net/), [Poggit](https://poggit.pmmp.io) or just search GitHub.
|
There are a very wide range of already-written plugins available which you can use to customise your server. Check out the [old plugin repository](http://plugins.pocketmine.net/), [Poggit](https://poggit.pmmp.io) or just search GitHub.
|
||||||
|
|
||||||
### For developers
|
### For developers
|
||||||
* [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP%20Docs/doxygen/) - Doxygen documentation generated from development
|
* [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP-doc/doxygen/) - Doxygen documentation generated from development
|
||||||
* [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - A development tools plugin for creating plugins.
|
* [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - A development tools plugin for creating plugins.
|
||||||
|
|
||||||
### Can I contribute?
|
### Can I contribute?
|
||||||
|
@ -207,9 +207,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
|||||||
const SPECTATOR = 3;
|
const SPECTATOR = 3;
|
||||||
const VIEW = Player::SPECTATOR;
|
const VIEW = Player::SPECTATOR;
|
||||||
|
|
||||||
const SURVIVAL_SLOTS = 36;
|
|
||||||
const CREATIVE_SLOTS = 112;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks a supplied username and checks it is valid.
|
* Checks a supplied username and checks it is valid.
|
||||||
* @param string $name
|
* @param string $name
|
||||||
@ -881,6 +878,7 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
|||||||
$this->sendData($this);
|
$this->sendData($this);
|
||||||
$this->inventory->sendContents($this);
|
$this->inventory->sendContents($this);
|
||||||
$this->inventory->sendArmorContents($this);
|
$this->inventory->sendArmorContents($this);
|
||||||
|
$this->inventory->sendHeldItem($this);
|
||||||
|
|
||||||
$pk = new SetTimePacket();
|
$pk = new SetTimePacket();
|
||||||
$pk->time = $this->level->getTime();
|
$pk->time = $this->level->getTime();
|
||||||
@ -1809,12 +1807,6 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->isCreative()){
|
|
||||||
$this->inventory->setHeldItemSlot(0);
|
|
||||||
}else{
|
|
||||||
$this->inventory->setHeldItemSlot($this->inventory->getHotbarSlotIndex(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!$this->hasValidSpawnPosition() and isset($this->namedtag->SpawnLevel) and ($level = $this->server->getLevelByName($this->namedtag["SpawnLevel"])) instanceof Level){
|
if(!$this->hasValidSpawnPosition() and isset($this->namedtag->SpawnLevel) and ($level = $this->server->getLevelByName($this->namedtag["SpawnLevel"])) instanceof Level){
|
||||||
$this->spawnPosition = new WeakPosition($this->namedtag["SpawnX"], $this->namedtag["SpawnY"], $this->namedtag["SpawnZ"], $level);
|
$this->spawnPosition = new WeakPosition($this->namedtag["SpawnX"], $this->namedtag["SpawnY"], $this->namedtag["SpawnZ"], $level);
|
||||||
}
|
}
|
||||||
@ -2251,64 +2243,20 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($packet->slot === 0x28 or $packet->slot === 0 or $packet->slot === 255){ //0 for 0.8.0 compatibility
|
if($packet->inventorySlot === 255){
|
||||||
$packet->slot = -1; //Air
|
$packet->inventorySlot = -1; //Cleared slot
|
||||||
}else{
|
}else{
|
||||||
$packet->slot -= 9; //Get real block slot
|
$packet->inventorySlot -= 9; //Get real inventory slot
|
||||||
}
|
$item = $this->inventory->getItem($packet->inventorySlot);
|
||||||
|
|
||||||
/** @var Item $item */
|
if(!$item->equals($packet->item)){
|
||||||
$item = null;
|
|
||||||
|
|
||||||
if($this->isCreative()){ //Creative mode match
|
|
||||||
$item = $packet->item;
|
|
||||||
$slot = Item::getCreativeItemIndex($item);
|
|
||||||
}else{
|
|
||||||
$item = $this->inventory->getItem($packet->slot);
|
|
||||||
$slot = $packet->slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($packet->slot === -1){ //Air
|
|
||||||
if($this->isCreative()){
|
|
||||||
$found = false;
|
|
||||||
for($i = 0; $i < $this->inventory->getHotbarSize(); ++$i){
|
|
||||||
if($this->inventory->getHotbarSlotIndex($i) === -1){
|
|
||||||
$this->inventory->setHeldItemIndex($i);
|
|
||||||
$found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!$found){ //couldn't find a empty slot (error)
|
|
||||||
$this->inventory->sendContents($this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
if($packet->selectedSlot >= 0 and $packet->selectedSlot < 9){
|
|
||||||
$this->inventory->setHeldItemIndex($packet->selectedSlot, false);
|
|
||||||
$this->inventory->setHeldItemSlot($packet->slot);
|
|
||||||
}else{
|
|
||||||
$this->inventory->sendContents($this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}elseif($item === null or $slot === -1 or !$item->deepEquals($packet->item)){ // packet error or not implemented
|
|
||||||
$this->inventory->sendContents($this);
|
|
||||||
return true;
|
|
||||||
}elseif($this->isCreative()){
|
|
||||||
$this->inventory->setHeldItemIndex($packet->selectedSlot, false);
|
|
||||||
$this->inventory->setItem($packet->selectedSlot, $item);
|
|
||||||
$this->inventory->setHeldItemSlot($packet->selectedSlot);
|
|
||||||
}else{
|
|
||||||
if($packet->selectedSlot >= 0 and $packet->selectedSlot < $this->inventory->getHotbarSize()){
|
|
||||||
$this->inventory->setHeldItemIndex($packet->selectedSlot, false);
|
|
||||||
$this->inventory->setHeldItemSlot($slot);
|
|
||||||
}else{
|
|
||||||
$this->inventory->sendContents($this);
|
$this->inventory->sendContents($this);
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->inventory->equipItem($packet->hotbarSlot, $packet->inventorySlot);
|
||||||
|
|
||||||
$this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
|
$this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_ACTION, false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -2890,29 +2838,34 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($packet->windowid === 0){ //Our inventory
|
switch($packet->windowid){
|
||||||
if($packet->slot >= $this->inventory->getSize()){
|
case ContainerSetContentPacket::SPECIAL_INVENTORY: //Normal inventory change
|
||||||
return false;
|
if($packet->slot >= $this->inventory->getSize()){
|
||||||
}
|
return false;
|
||||||
if($this->isCreative()){
|
|
||||||
if(Item::getCreativeItemIndex($packet->item) !== -1){
|
|
||||||
$this->inventory->setItem($packet->slot, $packet->item);
|
|
||||||
$this->inventory->setHotbarSlotIndex($packet->slot, $packet->slot); //links $hotbar[$packet->slot] to $slots[$packet->slot]
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
$transaction = new BaseTransaction($this->inventory, $packet->slot, $this->inventory->getItem($packet->slot), $packet->item);
|
|
||||||
}elseif($packet->windowid === ContainerSetContentPacket::SPECIAL_ARMOR){ //Our armor
|
|
||||||
if($packet->slot >= 4){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$transaction = new BaseTransaction($this->inventory, $packet->slot + $this->inventory->getSize(), $this->inventory->getArmorItem($packet->slot), $packet->item);
|
$transaction = new BaseTransaction($this->inventory, $packet->slot, $this->inventory->getItem($packet->slot), $packet->item);
|
||||||
}elseif(isset($this->windowIndex[$packet->windowid])){
|
break;
|
||||||
$this->craftingType = 0;
|
case ContainerSetContentPacket::SPECIAL_ARMOR: //Armour change
|
||||||
$inv = $this->windowIndex[$packet->windowid];
|
if($packet->slot >= 4){
|
||||||
$transaction = new BaseTransaction($inv, $packet->slot, $inv->getItem($packet->slot), $packet->item);
|
return false;
|
||||||
}else{
|
}
|
||||||
return false;
|
|
||||||
|
$transaction = new BaseTransaction($this->inventory, $packet->slot + $this->inventory->getSize(), $this->inventory->getArmorItem($packet->slot), $packet->item);
|
||||||
|
break;
|
||||||
|
case ContainerSetContentPacket::SPECIAL_HOTBAR: //Hotbar link update
|
||||||
|
//hotbarSlot 0-8, slot 9-44
|
||||||
|
$this->inventory->setHotbarSlotIndex($packet->hotbarSlot, $packet->slot - 9);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
if(!isset($this->windowIndex[$packet->windowid])){
|
||||||
|
return false; //unknown windowID and/or not matching any open windows
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->craftingType = 0;
|
||||||
|
$inv = $this->windowIndex[$packet->windowid];
|
||||||
|
$transaction = new BaseTransaction($inv, $packet->slot, $inv->getItem($packet->slot), $packet->item);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($transaction->getSourceItem()->deepEquals($transaction->getTargetItem()) and $transaction->getTargetItem()->getCount() === $transaction->getSourceItem()->getCount()){ //No changes!
|
if($transaction->getSourceItem()->deepEquals($transaction->getTargetItem()) and $transaction->getTargetItem()->getCount() === $transaction->getSourceItem()->getCount()){ //No changes!
|
||||||
@ -3758,6 +3711,8 @@ class Player extends Human implements CommandSender, InventoryHolder, ChunkLoade
|
|||||||
|
|
||||||
if($this->inventory !== null){
|
if($this->inventory !== null){
|
||||||
$this->inventory->clearAll();
|
$this->inventory->clearAll();
|
||||||
|
$this->inventory->setHeldItemIndex(0);
|
||||||
|
$this->inventory->resetHotbar(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ class Attribute{
|
|||||||
return $this->currentValue;
|
return $this->currentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setValue($value, $fit = false){
|
public function setValue($value, $fit = false, bool $forceSend = false){
|
||||||
if($value > $this->getMaxValue() or $value < $this->getMinValue()){
|
if($value > $this->getMaxValue() or $value < $this->getMinValue()){
|
||||||
if(!$fit){
|
if(!$fit){
|
||||||
throw new \InvalidArgumentException("Value $value exceeds the range!");
|
throw new \InvalidArgumentException("Value $value exceeds the range!");
|
||||||
@ -180,7 +180,10 @@ class Attribute{
|
|||||||
if($this->currentValue != $value){
|
if($this->currentValue != $value){
|
||||||
$this->desynchronized = true;
|
$this->desynchronized = true;
|
||||||
$this->currentValue = $value;
|
$this->currentValue = $value;
|
||||||
|
}elseif($forceSend){
|
||||||
|
$this->desynchronized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ class Effect{
|
|||||||
$speed = $attr->getValue();
|
$speed = $attr->getValue();
|
||||||
}
|
}
|
||||||
$speed *= (1 - 0.15 * $this->amplifier);
|
$speed *= (1 - 0.15 * $this->amplifier);
|
||||||
$attr->setValue($speed);
|
$attr->setValue($speed, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,7 +423,7 @@ abstract class Entity extends Location implements Metadatable{
|
|||||||
if($value !== $this->isSprinting()){
|
if($value !== $this->isSprinting()){
|
||||||
$this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_SPRINTING, (bool) $value);
|
$this->setDataFlag(self::DATA_FLAGS, self::DATA_FLAG_SPRINTING, (bool) $value);
|
||||||
$attr = $this->attributeMap->getAttribute(Attribute::MOVEMENT_SPEED);
|
$attr = $this->attributeMap->getAttribute(Attribute::MOVEMENT_SPEED);
|
||||||
$attr->setValue($value ? ($attr->getValue() * 1.3) : ($attr->getValue() / 1.3));
|
$attr->setValue($value ? ($attr->getValue() * 1.3) : ($attr->getValue() / 1.3), false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1643,10 +1643,15 @@ abstract class Entity extends Location implements Metadatable{
|
|||||||
$this->despawnFromAll();
|
$this->despawnFromAll();
|
||||||
if($this->chunk !== null){
|
if($this->chunk !== null){
|
||||||
$this->chunk->removeEntity($this);
|
$this->chunk->removeEntity($this);
|
||||||
|
$this->chunk = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->getLevel() !== null){
|
if($this->getLevel() !== null){
|
||||||
$this->getLevel()->removeEntity($this);
|
$this->getLevel()->removeEntity($this);
|
||||||
|
$this->setLevel(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->namedtag = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,6 +285,12 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isset($this->namedtag->SelectedInventorySlot) and $this->namedtag->SelectedInventorySlot instanceof IntTag){
|
||||||
|
$this->inventory->setHeldItemIndex($this->namedtag->SelectedInventorySlot->getValue(), false);
|
||||||
|
}else{
|
||||||
|
$this->inventory->setHeldItemIndex(0, false);
|
||||||
|
}
|
||||||
|
|
||||||
parent::initEntity();
|
parent::initEntity();
|
||||||
|
|
||||||
if(!isset($this->namedtag->foodLevel) or !($this->namedtag->foodLevel instanceof IntTag)){
|
if(!isset($this->namedtag->foodLevel) or !($this->namedtag->foodLevel instanceof IntTag)){
|
||||||
@ -428,9 +434,8 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Normal inventory
|
//Normal inventory
|
||||||
$slotCount = Player::SURVIVAL_SLOTS + 9;
|
$slotCount = $this->inventory->getSize() + $this->inventory->getHotbarSize();
|
||||||
//$slotCount = (($this instanceof Player and ($this->gamemode & 0x01) === 1) ? Player::CREATIVE_SLOTS : Player::SURVIVAL_SLOTS) + 9;
|
for($slot = $this->inventory->getHotbarSize(); $slot < $slotCount; ++$slot){
|
||||||
for($slot = 9; $slot < $slotCount; ++$slot){
|
|
||||||
$item = $this->inventory->getItem($slot - 9);
|
$item = $this->inventory->getItem($slot - 9);
|
||||||
$this->namedtag->Inventory[$slot] = $item->nbtSerialize($slot);
|
$this->namedtag->Inventory[$slot] = $item->nbtSerialize($slot);
|
||||||
}
|
}
|
||||||
@ -442,6 +447,8 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
$this->namedtag->Inventory[$slot] = $item->nbtSerialize($slot);
|
$this->namedtag->Inventory[$slot] = $item->nbtSerialize($slot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->namedtag->SelectedInventorySlot = new IntTag("SelectedInventorySlot", $this->inventory->getHeldItemIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strlen($this->getSkinData()) > 0){
|
if(strlen($this->getSkinData()) > 0){
|
||||||
|
@ -40,7 +40,7 @@ class PlayerInventory extends BaseInventory{
|
|||||||
protected $hotbar;
|
protected $hotbar;
|
||||||
|
|
||||||
public function __construct(Human $player){
|
public function __construct(Human $player){
|
||||||
$this->hotbar = range(0, $this->getHotbarSize() - 1, 1);
|
$this->resetHotbar(false);
|
||||||
parent::__construct($player, InventoryType::get(InventoryType::PLAYER));
|
parent::__construct($player, InventoryType::get(InventoryType::PLAYER));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,20 +53,93 @@ class PlayerInventory extends BaseInventory{
|
|||||||
$this->sendContents($this->getViewers());
|
$this->sendContents($this->getViewers());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHotbarSlotIndex($index){
|
/**
|
||||||
return ($index >= 0 and $index < $this->getHotbarSize()) ? $this->hotbar[$index] : -1;
|
* Called when a client equips a hotbar slot. This method should not be used by plugins.
|
||||||
|
* This method will call PlayerItemHeldEvent.
|
||||||
|
*
|
||||||
|
* @param int $hotbarSlot Number of the hotbar slot to equip.
|
||||||
|
* @param int|null $inventorySlot Inventory slot to map to the specified hotbar slot. Supply null to make no change to the link.
|
||||||
|
*
|
||||||
|
* @return bool if the equipment change was successful, false if not.
|
||||||
|
*/
|
||||||
|
public function equipItem(int $hotbarSlot, $inventorySlot = null) : bool{
|
||||||
|
if($inventorySlot === null){
|
||||||
|
$inventorySlot = $this->getHotbarSlotIndex($this->getHeldItemIndex());
|
||||||
|
}
|
||||||
|
if($hotbarSlot < 0 or $hotbarSlot >= $this->getHotbarSize() or $inventorySlot < -1 or $inventorySlot >= $this->getSize()){
|
||||||
|
$this->sendContents($this->getHolder());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getHolder()->getLevel()->getServer()->getPluginManager()->callEvent($ev = new PlayerItemHeldEvent($this->getHolder(), $this->getItem($inventorySlot), $inventorySlot, $hotbarSlot));
|
||||||
|
if($ev->isCancelled()){
|
||||||
|
$this->sendContents($this->getHolder());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setHotbarSlotIndex($hotbarSlot, $inventorySlot);
|
||||||
|
$this->setHeldItemIndex($hotbarSlot, false);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setHotbarSlotIndex($index, $slot){
|
/**
|
||||||
if($index >= 0 and $index < $this->getHotbarSize() and $slot >= -1 and $slot < $this->getSize()){
|
* Returns the index of the inventory slot mapped to the specified hotbar slot, or -1 if the hotbar slot does not exist.
|
||||||
$this->hotbar[$index] = $slot;
|
* @param int $index
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getHotbarSlotIndex($index){
|
||||||
|
return $this->hotbar[$index] ?? -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal This method is intended for use in network interaction with clients only.
|
||||||
|
* @deprecated Do not change hotbar slot mapping with plugins, this will cause myriad client-sided bugs, especially with desktop GUI clients.
|
||||||
|
*
|
||||||
|
* @param int $hotbarSlot
|
||||||
|
* @param int $inventorySlot
|
||||||
|
*/
|
||||||
|
public function setHotbarSlotIndex($hotbarSlot, $inventorySlot){
|
||||||
|
if($hotbarSlot >= 0 and $hotbarSlot < $this->getHotbarSize() and $inventorySlot >= -1 and $inventorySlot < $this->getSize()){
|
||||||
|
if($inventorySlot !== -1 and ($alreadyEquippedIndex = array_search($inventorySlot, $this->hotbar)) !== false){
|
||||||
|
/* Swap the slots
|
||||||
|
* This assumes that the equipped slot can only be equipped in one other slot
|
||||||
|
* it will not account for ancient bugs where the same slot ended up linked to several hotbar slots.
|
||||||
|
* Such bugs will require a hotbar reset to default.
|
||||||
|
*/
|
||||||
|
$this->hotbar[$alreadyEquippedIndex] = $this->hotbar[$hotbarSlot];
|
||||||
|
}
|
||||||
|
$this->hotbar[$hotbarSlot] = $inventorySlot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets hotbar links to their original defaults.
|
||||||
|
* @param bool $send Whether to send changes to the holder.
|
||||||
|
*/
|
||||||
|
public function resetHotbar(bool $send = true){
|
||||||
|
$this->hotbar = range(0, $this->getHotbarSize() - 1, 1);
|
||||||
|
if($send){
|
||||||
|
$this->sendContents($this->getHolder());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hotbar slot number the holder is currently holding.
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
public function getHeldItemIndex(){
|
public function getHeldItemIndex(){
|
||||||
return $this->itemInHandIndex;
|
return $this->itemInHandIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets which hotbar slot the player is currently loading.
|
||||||
|
*
|
||||||
|
* @param int $index 0-8 index of the hotbar slot to hold
|
||||||
|
* @param bool $send Whether to send updates back to the inventory holder. This should usually be true for plugin calls.
|
||||||
|
* It should only be false to prevent feedback loops of equipment packets between client and server.
|
||||||
|
*/
|
||||||
public function setHeldItemIndex($index, $send = true){
|
public function setHeldItemIndex($index, $send = true){
|
||||||
if($index >= 0 and $index < $this->getHotbarSize()){
|
if($index >= 0 and $index < $this->getHotbarSize()){
|
||||||
$this->itemInHandIndex = $index;
|
$this->itemInHandIndex = $index;
|
||||||
@ -79,6 +152,11 @@ class PlayerInventory extends BaseInventory{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently-held item.
|
||||||
|
*
|
||||||
|
* @return Item
|
||||||
|
*/
|
||||||
public function getItemInHand(){
|
public function getItemInHand(){
|
||||||
$item = $this->getItem($this->getHeldItemSlot());
|
$item = $this->getItem($this->getHeldItemSlot());
|
||||||
if($item instanceof Item){
|
if($item instanceof Item){
|
||||||
@ -89,6 +167,7 @@ class PlayerInventory extends BaseInventory{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Sets the item in the currently-held slot to the specified item.
|
||||||
* @param Item $item
|
* @param Item $item
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
@ -97,29 +176,29 @@ class PlayerInventory extends BaseInventory{
|
|||||||
return $this->setItem($this->getHeldItemSlot(), $item);
|
return $this->setItem($this->getHeldItemSlot(), $item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hotbar slot number currently held.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
public function getHeldItemSlot(){
|
public function getHeldItemSlot(){
|
||||||
return $this->getHotbarSlotIndex($this->itemInHandIndex);
|
return $this->getHotbarSlotIndex($this->itemInHandIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hotbar slot link of the currently-held hotbar slot.
|
||||||
|
* @deprecated Do not change hotbar slot mapping with plugins, this will cause myriad client-sided bugs, especially with desktop GUI clients.
|
||||||
|
*
|
||||||
|
* @param int $slot
|
||||||
|
*/
|
||||||
public function setHeldItemSlot($slot){
|
public function setHeldItemSlot($slot){
|
||||||
if($slot >= -1 and $slot < $this->getSize()){
|
if($slot >= -1 and $slot < $this->getSize()){
|
||||||
$item = $this->getItem($slot);
|
$this->setHotbarSlotIndex($this->getHeldItemIndex(), $slot);
|
||||||
|
|
||||||
$itemIndex = $this->getHeldItemIndex();
|
|
||||||
|
|
||||||
if($this->getHolder() instanceof Player){
|
|
||||||
Server::getInstance()->getPluginManager()->callEvent($ev = new PlayerItemHeldEvent($this->getHolder(), $item, $slot, $itemIndex));
|
|
||||||
if($ev->isCancelled()){
|
|
||||||
$this->sendContents($this->getHolder());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->setHotbarSlotIndex($itemIndex, $slot);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Sends the currently-held item to specified targets.
|
||||||
* @param Player|Player[] $target
|
* @param Player|Player[] $target
|
||||||
*/
|
*/
|
||||||
public function sendHeldItem($target){
|
public function sendHeldItem($target){
|
||||||
@ -128,8 +207,8 @@ class PlayerInventory extends BaseInventory{
|
|||||||
$pk = new MobEquipmentPacket();
|
$pk = new MobEquipmentPacket();
|
||||||
$pk->eid = $this->getHolder()->getId();
|
$pk->eid = $this->getHolder()->getId();
|
||||||
$pk->item = $item;
|
$pk->item = $item;
|
||||||
$pk->slot = $this->getHeldItemSlot();
|
$pk->inventorySlot = $this->getHeldItemSlot();
|
||||||
$pk->selectedSlot = $this->getHeldItemIndex();
|
$pk->hotbarSlot = $this->getHeldItemIndex();
|
||||||
|
|
||||||
if(!is_array($target)){
|
if(!is_array($target)){
|
||||||
$target->dataPacket($pk);
|
$target->dataPacket($pk);
|
||||||
@ -161,6 +240,10 @@ class PlayerInventory extends BaseInventory{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of slots in the hotbar.
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
public function getHotbarSize(){
|
public function getHotbarSize(){
|
||||||
return 9;
|
return 9;
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,21 @@ class SimpleTransactionGroup implements TransactionGroup{
|
|||||||
$haveItems = [];
|
$haveItems = [];
|
||||||
$needItems = [];
|
$needItems = [];
|
||||||
|
|
||||||
return $this->matchItems($haveItems, $needItems) and count($haveItems) === 0 and count($needItems) === 0 and count($this->transactions) > 0;
|
if($this->matchItems($needItems, $haveItems) and count($this->transactions) > 0){
|
||||||
|
if(count($haveItems) === 0 and count($needItems) === 0){
|
||||||
|
return true;
|
||||||
|
}elseif($this->source->isCreative(true) and count($needItems) > 0){ //Added items from creative inventory
|
||||||
|
foreach($needItems as $item){
|
||||||
|
if(Item::getCreativeItemIndex($item) === -1 and $item->getId() !== Item::AIR){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute(){
|
public function execute(){
|
||||||
|
@ -34,14 +34,14 @@ class ContainerSetSlotPacket extends DataPacket{
|
|||||||
public $hotbarSlot;
|
public $hotbarSlot;
|
||||||
/** @var Item */
|
/** @var Item */
|
||||||
public $item;
|
public $item;
|
||||||
public $unknown;
|
public $selectSlot;
|
||||||
|
|
||||||
public function decode(){
|
public function decode(){
|
||||||
$this->windowid = $this->getByte();
|
$this->windowid = $this->getByte();
|
||||||
$this->slot = $this->getVarInt();
|
$this->slot = $this->getVarInt();
|
||||||
$this->hotbarSlot = $this->getVarInt();
|
$this->hotbarSlot = $this->getVarInt();
|
||||||
$this->item = $this->getSlot();
|
$this->item = $this->getSlot();
|
||||||
$this->unknown = $this->getByte();
|
$this->selectSlot = $this->getByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function encode(){
|
public function encode(){
|
||||||
@ -50,7 +50,7 @@ class ContainerSetSlotPacket extends DataPacket{
|
|||||||
$this->putVarInt($this->slot);
|
$this->putVarInt($this->slot);
|
||||||
$this->putVarInt($this->hotbarSlot);
|
$this->putVarInt($this->hotbarSlot);
|
||||||
$this->putSlot($this->item);
|
$this->putSlot($this->item);
|
||||||
$this->putByte($this->unknown);
|
$this->putByte($this->selectSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle(NetworkSession $session) : bool{
|
public function handle(NetworkSession $session) : bool{
|
||||||
|
@ -31,15 +31,15 @@ class MobEquipmentPacket extends DataPacket{
|
|||||||
|
|
||||||
public $eid;
|
public $eid;
|
||||||
public $item;
|
public $item;
|
||||||
public $slot;
|
public $inventorySlot;
|
||||||
public $selectedSlot;
|
public $hotbarSlot;
|
||||||
public $unknownByte;
|
public $unknownByte;
|
||||||
|
|
||||||
public function decode(){
|
public function decode(){
|
||||||
$this->eid = $this->getEntityRuntimeId();
|
$this->eid = $this->getEntityRuntimeId();
|
||||||
$this->item = $this->getSlot();
|
$this->item = $this->getSlot();
|
||||||
$this->slot = $this->getByte();
|
$this->inventorySlot = $this->getByte();
|
||||||
$this->selectedSlot = $this->getByte();
|
$this->hotbarSlot = $this->getByte();
|
||||||
$this->unknownByte = $this->getByte();
|
$this->unknownByte = $this->getByte();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,8 +47,8 @@ class MobEquipmentPacket extends DataPacket{
|
|||||||
$this->reset();
|
$this->reset();
|
||||||
$this->putEntityRuntimeId($this->eid);
|
$this->putEntityRuntimeId($this->eid);
|
||||||
$this->putSlot($this->item);
|
$this->putSlot($this->item);
|
||||||
$this->putByte($this->slot);
|
$this->putByte($this->inventorySlot);
|
||||||
$this->putByte($this->selectedSlot);
|
$this->putByte($this->hotbarSlot);
|
||||||
$this->putByte($this->unknownByte);
|
$this->putByte($this->unknownByte);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user