Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added entity middle-click feature #5397

Merged
merged 18 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/entity/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
use pocketmine\event\entity\EntityRegainHealthEvent;
use pocketmine\event\entity\EntitySpawnEvent;
use pocketmine\event\entity\EntityTeleportEvent;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
use pocketmine\math\Vector2;
Expand Down Expand Up @@ -497,6 +499,12 @@ public function saveNBT() : CompoundTag{
return $nbt;
}

public function getCleanedNBT() : CompoundTag{
$nbt = $this->saveNBT();
$nbt->removeTag("identifier", "Pos", "Motion", "Rotation", "FallDistance", "OnGround");
return $nbt;
}

protected function initEntity(CompoundTag $nbt) : void{
$this->fireTicks = $nbt->getShort("Fire", 0);

Expand Down Expand Up @@ -1535,6 +1543,25 @@ public function despawnFromAll() : void{
}
}

/**
* Returns the item that can be used to spawn this entity, by default it returns null if there isn't one
*/
public function getSpawnItem() : ?Item{
return VanillaItems::AIR();
}

/**
* Returns the item that players will equip when middle-clicking on this entity.
* If addUserData is true, additional data may be added, such as name tag, fire ticks, etc.
JavierLeon9966 marked this conversation as resolved.
Show resolved Hide resolved
*/
public function getPickedItem() : ?Item{
$item = $this->getSpawnItem();
if($item === null){
return null;
}
return $item;
JavierLeon9966 marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Flags the entity to be removed from the world on the next tick.
*/
Expand Down
5 changes: 5 additions & 0 deletions src/entity/Squid.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use pocketmine\entity\animation\SquidInkCloudAnimation;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
Expand Down Expand Up @@ -126,4 +127,8 @@ public function getDrops() : array{
VanillaItems::INK_SAC()->setCount(mt_rand(1, 3))
];
}

public function getSpawnItem() : ?Item{
return VanillaItems::SQUID_SPAWN_EGG();
}
}
6 changes: 6 additions & 0 deletions src/entity/Villager.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

namespace pocketmine\entity;

use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection;
Expand Down Expand Up @@ -85,6 +87,10 @@ public function isBaby() : bool{
return $this->baby;
}

public function getSpawnItem() : ?Item{
return VanillaItems::VILLAGER_SPAWN_EGG();
}

protected function syncNetworkData(EntityMetadataCollection $properties) : void{
parent::syncNetworkData($properties);
$properties->setGenericFlag(EntityMetadataFlags::BABY, $this->baby);
Expand Down
5 changes: 5 additions & 0 deletions src/entity/Zombie.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

namespace pocketmine\entity;

use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
use function mt_rand;
Expand Down Expand Up @@ -65,4 +66,8 @@ public function getXpDropAmount() : int{
//TODO: check for equipment and whether it's a baby
return 5;
}

public function getSpawnItem() : ?Item{
return VanillaItems::ZOMBIE_SPAWN_EGG();
}
}
5 changes: 5 additions & 0 deletions src/entity/object/FallingBlock.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use pocketmine\entity\Location;
use pocketmine\event\entity\EntityBlockChangeEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
Expand Down Expand Up @@ -144,6 +145,10 @@ public function saveNBT() : CompoundTag{
return $nbt;
}

public function getPickedItem() : ?Item{
return $this->block->asItem();
}

protected function syncNetworkData(EntityMetadataCollection $properties) : void{
parent::syncNetworkData($properties);

Expand Down
9 changes: 9 additions & 0 deletions src/entity/object/Painting.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use pocketmine\entity\EntitySizeInfo;
use pocketmine\entity\Location;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\AxisAlignedBB;
use pocketmine\math\Facing;
Expand Down Expand Up @@ -162,6 +163,14 @@ protected function sendSpawnPacket(Player $player) : void{
));
}

public function getSpawnItem() : ?Item{
return VanillaItems::PAINTING();
}

public function getPickedItem() : ?Item{
return $this->getSpawnItem();
}

/**
* Returns the painting motive (which image is displayed on the painting)
*/
Expand Down
10 changes: 10 additions & 0 deletions src/entity/object/PrimedTNT.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@

namespace pocketmine\entity\object;

use pocketmine\block\VanillaBlocks;
use pocketmine\entity\Entity;
use pocketmine\entity\EntitySizeInfo;
use pocketmine\entity\Explosive;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\ExplosionPrimeEvent;
use pocketmine\item\Item;
use pocketmine\math\Vector3;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\protocol\types\entity\EntityIds;
Expand Down Expand Up @@ -128,6 +130,14 @@ public function explode() : void{
}
}

public function getSpawnItem() : ?Item{
return VanillaBlocks::TNT()->setWorksUnderwater($this->worksUnderwater)->asItem();
}

public function getPickedItem() : ?Item{
return $this->getSpawnItem();
}

protected function syncNetworkData(EntityMetadataCollection $properties) : void{
parent::syncNetworkData($properties);

Expand Down
53 changes: 53 additions & 0 deletions src/event/player/PlayerEntityPickEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/

declare(strict_types=1);

namespace pocketmine\event\player;

use pocketmine\entity\Entity;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
use pocketmine\item\Item;
use pocketmine\player\Player;

/**
* Called when a player middle-clicks on a entity to get an item in creative mode.
ipad54 marked this conversation as resolved.
Show resolved Hide resolved
*/
class PlayerEntityPickEvent extends PlayerEvent implements Cancellable{
use CancellableTrait;

public function __construct(
Player $player,
private Entity $entityClicked,
private Item $resultItem
){
$this->player = $player;
}

public function getEntity() : Entity{
return $this->entityClicked;
}

public function getResultItem() : Item{
return $this->resultItem;
}
}
3 changes: 0 additions & 3 deletions src/item/SpawnEgg.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ abstract protected function createEntity(World $world, Vector3 $pos, float $yaw,
public function onInteractBlock(Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : ItemUseResult{
$entity = $this->createEntity($player->getWorld(), $blockReplace->getPosition()->add(0.5, 0, 0.5), lcg_value() * 360, 0);

if($this->hasCustomName()){
$entity->setNameTag($this->getCustomName());
}
$this->pop();
$entity->spawnToAll();
//TODO: what if the entity was marked for deletion?
Expand Down
2 changes: 1 addition & 1 deletion src/network/mcpe/handler/InGamePacketHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ public function handleBlockPickRequest(BlockPickRequestPacket $packet) : bool{
}

public function handleActorPickRequest(ActorPickRequestPacket $packet) : bool{
return false; //TODO
return $this->player->pickEntity($packet->actorUniqueId);
}

public function handlePlayerAction(PlayerActionPacket $packet) : bool{
Expand Down
66 changes: 48 additions & 18 deletions src/player/Player.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
use pocketmine\event\player\PlayerDisplayNameChangeEvent;
use pocketmine\event\player\PlayerEmoteEvent;
use pocketmine\event\player\PlayerEntityInteractEvent;
use pocketmine\event\player\PlayerEntityPickEvent;
use pocketmine\event\player\PlayerExhaustEvent;
use pocketmine\event\player\PlayerGameModeChangeEvent;
use pocketmine\event\player\PlayerInteractEvent;
Expand Down Expand Up @@ -1595,29 +1596,58 @@ public function pickBlock(Vector3 $pos, bool $addTileNBT) : bool{
$ev->call();

if(!$ev->isCancelled()){
if($existingSlot !== -1){
if($existingSlot < $this->inventory->getHotbarSize()){
$this->inventory->setHeldItemIndex($existingSlot);
}else{
$this->inventory->swap($this->inventory->getHeldItemIndex(), $existingSlot);
}
}else{
$firstEmpty = $this->inventory->firstEmpty();
if($firstEmpty === -1){ //full inventory
$this->inventory->setItemInHand($item);
}elseif($firstEmpty < $this->inventory->getHotbarSize()){
$this->inventory->setItem($firstEmpty, $item);
$this->inventory->setHeldItemIndex($firstEmpty);
}else{
$this->inventory->swap($this->inventory->getHeldItemIndex(), $firstEmpty);
$this->inventory->setItemInHand($item);
}
}
$this->equipOrAddPickedItem($existingSlot, $item);
}

return true;
}

public function pickEntity(int $entityId) : bool{
$entity = $this->getWorld()->getEntity($entityId);
if($entity === null){
return true;
}

$item = $entity->getPickedItem();
if($item === null){
return true;
}

$ev = new PlayerEntityPickEvent($this, $entity, $item);
$existingSlot = $this->inventory->first($item);
if($existingSlot === -1 && ($this->hasFiniteResources() || $this->isSpectator())){
$ev->cancel();
}
$ev->call();

if(!$ev->isCancelled()){
$this->equipOrAddPickedItem($existingSlot, $item);
}
JavierLeon9966 marked this conversation as resolved.
Show resolved Hide resolved

return true;
}

private function equipOrAddPickedItem(int $existingSlot, Item $item) : void{
if($existingSlot !== -1){
if($existingSlot < $this->inventory->getHotbarSize()){
$this->inventory->setHeldItemIndex($existingSlot);
}else{
$this->inventory->swap($this->inventory->getHeldItemIndex(), $existingSlot);
}
}else{
$firstEmpty = $this->inventory->firstEmpty();
if($firstEmpty === -1){ //full inventory
$this->inventory->setItemInHand($item);
}elseif($firstEmpty < $this->inventory->getHotbarSize()){
$this->inventory->setItem($firstEmpty, $item);
$this->inventory->setHeldItemIndex($firstEmpty);
}else{
$this->inventory->swap($this->inventory->getHeldItemIndex(), $firstEmpty);
$this->inventory->setItemInHand($item);
}
}
}

/**
* Performs a left-click (attack) action on the block.
*
Expand Down