mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-04-20 16:00:20 +00:00
Moved bow functionality out of Player
This commit is contained in:
parent
6d5620606e
commit
a5f5502380
@ -38,7 +38,6 @@ use pocketmine\entity\Projectile;
|
||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||
use pocketmine\event\entity\EntityDamageEvent;
|
||||
use pocketmine\event\entity\EntityShootBowEvent;
|
||||
use pocketmine\event\entity\ProjectileLaunchEvent;
|
||||
use pocketmine\event\inventory\CraftItemEvent;
|
||||
use pocketmine\event\inventory\InventoryCloseEvent;
|
||||
@ -103,7 +102,6 @@ use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\nbt\tag\IntTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\LongTag;
|
||||
use pocketmine\nbt\tag\ShortTag;
|
||||
use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\network\mcpe\PlayerNetworkSessionAdapter;
|
||||
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
|
||||
@ -760,6 +758,29 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
return $this->inAirTicks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the player is currently using an item (right-click and hold).
|
||||
* @return bool
|
||||
*/
|
||||
public function isUsingItem() : bool{
|
||||
return $this->getGenericFlag(self::DATA_FLAG_ACTION) and $this->startAction > -1;
|
||||
}
|
||||
|
||||
public function setUsingItem(bool $value){
|
||||
$this->startAction = $value ? $this->server->getTick() : -1;
|
||||
$this->setGenericFlag(self::DATA_FLAG_ACTION, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how long the player has been using their currently-held item for. Used for determining arrow shoot force
|
||||
* for bows.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getItemUseDuration() : int{
|
||||
return $this->startAction === -1 ? -1 : ($this->server->getTick() - $this->startAction);
|
||||
}
|
||||
|
||||
protected function switchLevel(Level $targetLevel) : bool{
|
||||
$oldLevel = $this->level;
|
||||
if(parent::switchLevel($targetLevel)){
|
||||
@ -2470,72 +2491,10 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
||||
$this->level->broadcastLevelEvent($pos, LevelEventPacket::EVENT_BLOCK_STOP_BREAK);
|
||||
break;
|
||||
case PlayerActionPacket::ACTION_RELEASE_ITEM:
|
||||
if($this->startAction > -1 and $this->getGenericFlag(self::DATA_FLAG_ACTION)){
|
||||
if($this->inventory->getItemInHand()->getId() === Item::BOW){
|
||||
$bow = $this->inventory->getItemInHand();
|
||||
if($this->isSurvival() and !$this->inventory->contains(ItemFactory::get(Item::ARROW, 0, 1))){
|
||||
$this->inventory->sendContents($this);
|
||||
break;
|
||||
}
|
||||
|
||||
$nbt = new CompoundTag("", [
|
||||
new ListTag("Pos", [
|
||||
new DoubleTag("", $this->x),
|
||||
new DoubleTag("", $this->y + $this->getEyeHeight()),
|
||||
new DoubleTag("", $this->z)
|
||||
]),
|
||||
new ListTag("Motion", [
|
||||
new DoubleTag("", -sin($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI)),
|
||||
new DoubleTag("", -sin($this->pitch / 180 * M_PI)),
|
||||
new DoubleTag("", cos($this->yaw / 180 * M_PI) * cos($this->pitch / 180 * M_PI))
|
||||
]),
|
||||
new ListTag("Rotation", [
|
||||
//yaw/pitch for arrows taken crosswise, not along the arrow shaft.
|
||||
new FloatTag("", ($this->yaw > 180 ? 360 : 0) - $this->yaw), //arrow yaw must range from -180 to +180
|
||||
new FloatTag("", -$this->pitch)
|
||||
]),
|
||||
new ShortTag("Fire", $this->isOnFire() ? 45 * 60 : 0)
|
||||
]);
|
||||
|
||||
$diff = ($this->server->getTick() - $this->startAction);
|
||||
$p = $diff / 20;
|
||||
$f = min((($p ** 2) + $p * 2) / 3, 1) * 2;
|
||||
$ev = new EntityShootBowEvent($this, $bow, Entity::createEntity("Arrow", $this->getLevel(), $nbt, $this, $f == 2), $f);
|
||||
|
||||
if($f < 0.1 or $diff < 5){
|
||||
$ev->setCancelled();
|
||||
}
|
||||
|
||||
$this->server->getPluginManager()->callEvent($ev);
|
||||
|
||||
if($ev->isCancelled()){
|
||||
$ev->getProjectile()->kill();
|
||||
$this->inventory->sendContents($this);
|
||||
}else{
|
||||
$ev->getProjectile()->setMotion($ev->getProjectile()->getMotion()->multiply($ev->getForce()));
|
||||
if($this->isSurvival()){
|
||||
$this->inventory->removeItem(ItemFactory::get(Item::ARROW, 0, 1));
|
||||
$bow->setDamage($bow->getDamage() + 1);
|
||||
if($bow->getDamage() >= 385){
|
||||
$this->inventory->setItemInHand(ItemFactory::get(Item::AIR, 0, 0));
|
||||
}else{
|
||||
$this->inventory->setItemInHand($bow);
|
||||
}
|
||||
}
|
||||
|
||||
$projectile = $ev->getProjectile();
|
||||
if($projectile instanceof Projectile){
|
||||
$this->server->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($projectile));
|
||||
if($projectileEv->isCancelled()){
|
||||
$ev->getProjectile()->kill();
|
||||
}else{
|
||||
$ev->getProjectile()->spawnToAll();
|
||||
$this->level->addSound(new LaunchSound($this), $this->getViewers());
|
||||
}
|
||||
}else{
|
||||
$ev->getProjectile()->spawnToAll();
|
||||
}
|
||||
}
|
||||
if($this->isUsingItem()){
|
||||
$item = $this->inventory->getItemInHand();
|
||||
if($item->onReleaseUsing($this)){
|
||||
$this->inventory->setItemInHand($item);
|
||||
}
|
||||
}elseif($this->inventory->getItemInHand()->getId() === Item::BUCKET and $this->inventory->getItemInHand()->getDamage() === 1){ //Milk!
|
||||
$this->server->getPluginManager()->callEvent($ev = new PlayerItemConsumeEvent($this, $this->inventory->getItemInHand()));
|
||||
|
@ -23,6 +23,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\entity\Entity;
|
||||
use pocketmine\entity\Projectile;
|
||||
use pocketmine\event\entity\EntityShootBowEvent;
|
||||
use pocketmine\event\entity\ProjectileLaunchEvent;
|
||||
use pocketmine\level\sound\LaunchSound;
|
||||
use pocketmine\nbt\tag\CompoundTag;
|
||||
use pocketmine\nbt\tag\DoubleTag;
|
||||
use pocketmine\nbt\tag\FloatTag;
|
||||
use pocketmine\nbt\tag\ListTag;
|
||||
use pocketmine\nbt\tag\ShortTag;
|
||||
use pocketmine\Player;
|
||||
|
||||
class Bow extends Tool{
|
||||
public function __construct(int $meta = 0){
|
||||
@ -36,4 +47,79 @@ class Bow extends Tool{
|
||||
public function getMaxDurability(){
|
||||
return 385;
|
||||
}
|
||||
|
||||
public function onReleaseUsing(Player $player) : bool{
|
||||
if($player->isSurvival() and !$player->getInventory()->contains(ItemFactory::get(Item::ARROW, 0, 1))){
|
||||
$player->getInventory()->sendContents($player);
|
||||
}
|
||||
|
||||
$nbt = new CompoundTag("", [
|
||||
new ListTag("Pos", [
|
||||
new DoubleTag("", $player->x),
|
||||
new DoubleTag("", $player->y + $player->getEyeHeight()),
|
||||
new DoubleTag("", $player->z)
|
||||
]),
|
||||
new ListTag("Motion", [
|
||||
new DoubleTag("", -sin($player->yaw / 180 * M_PI) * cos($player->pitch / 180 * M_PI)),
|
||||
new DoubleTag("", -sin($player->pitch / 180 * M_PI)),
|
||||
new DoubleTag("", cos($player->yaw / 180 * M_PI) * cos($player->pitch / 180 * M_PI))
|
||||
]),
|
||||
new ListTag("Rotation", [
|
||||
//yaw/pitch for arrows taken crosswise, not along the arrow shaft.
|
||||
new FloatTag("", ($player->yaw > 180 ? 360 : 0) - $player->yaw), //arrow yaw must range from -180 to +180
|
||||
new FloatTag("", -$player->pitch)
|
||||
]),
|
||||
new ShortTag("Fire", $player->isOnFire() ? 45 * 60 : 0)
|
||||
]);
|
||||
|
||||
$diff = $player->getItemUseDuration();
|
||||
$p = $diff / 20;
|
||||
$force = min((($p ** 2) + $p * 2) / 3, 1) * 2;
|
||||
|
||||
|
||||
$entity = Entity::createEntity("Arrow", $player->getLevel(), $nbt, $player, $force == 2);
|
||||
if($entity instanceof Projectile){
|
||||
$ev = new EntityShootBowEvent($player, $this, $entity, $force);
|
||||
|
||||
if($force < 0.1 or $diff < 5){
|
||||
$ev->setCancelled();
|
||||
}
|
||||
|
||||
$player->getServer()->getPluginManager()->callEvent($ev);
|
||||
|
||||
$entity = $ev->getProjectile(); //This might have been changed by plugins
|
||||
|
||||
if($ev->isCancelled()){
|
||||
$entity->kill();
|
||||
$player->getInventory()->sendContents($player);
|
||||
}else{
|
||||
$entity->setMotion($entity->getMotion()->multiply($ev->getForce()));
|
||||
if($player->isSurvival()){
|
||||
$player->getInventory()->removeItem(ItemFactory::get(Item::ARROW, 0, 1));
|
||||
$this->setDamage($this->getDamage() + 1);
|
||||
if($this->getDamage() >= $this->getMaxDurability()){
|
||||
$player->getInventory()->setItemInHand(ItemFactory::get(Item::AIR, 0, 0));
|
||||
}else{
|
||||
$player->getInventory()->setItemInHand($this);
|
||||
}
|
||||
}
|
||||
|
||||
if($entity instanceof Projectile){
|
||||
$player->getServer()->getPluginManager()->callEvent($projectileEv = new ProjectileLaunchEvent($entity));
|
||||
if($projectileEv->isCancelled()){
|
||||
$ev->getProjectile()->kill();
|
||||
}else{
|
||||
$ev->getProjectile()->spawnToAll();
|
||||
$player->level->addSound(new LaunchSound($player), $player->getViewers());
|
||||
}
|
||||
}else{
|
||||
$entity->spawnToAll();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$entity->spawnToAll();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -829,6 +829,16 @@ class Item implements ItemIds, \JsonSerializable{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a player is using this item and releases it. Used to handle bow shoot actions.
|
||||
*
|
||||
* @param Player $player
|
||||
* @return bool
|
||||
*/
|
||||
public function onReleaseUsing(Player $player) : bool{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares an Item to this Item and check if they match.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user