mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-06-15 16:05:28 +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\EntityDamageByBlockEvent;
|
||||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
use pocketmine\event\entity\EntityDamageEvent;
|
||||||
use pocketmine\event\entity\EntityShootBowEvent;
|
|
||||||
use pocketmine\event\entity\ProjectileLaunchEvent;
|
use pocketmine\event\entity\ProjectileLaunchEvent;
|
||||||
use pocketmine\event\inventory\CraftItemEvent;
|
use pocketmine\event\inventory\CraftItemEvent;
|
||||||
use pocketmine\event\inventory\InventoryCloseEvent;
|
use pocketmine\event\inventory\InventoryCloseEvent;
|
||||||
@ -103,7 +102,6 @@ use pocketmine\nbt\tag\FloatTag;
|
|||||||
use pocketmine\nbt\tag\IntTag;
|
use pocketmine\nbt\tag\IntTag;
|
||||||
use pocketmine\nbt\tag\ListTag;
|
use pocketmine\nbt\tag\ListTag;
|
||||||
use pocketmine\nbt\tag\LongTag;
|
use pocketmine\nbt\tag\LongTag;
|
||||||
use pocketmine\nbt\tag\ShortTag;
|
|
||||||
use pocketmine\nbt\tag\StringTag;
|
use pocketmine\nbt\tag\StringTag;
|
||||||
use pocketmine\network\mcpe\PlayerNetworkSessionAdapter;
|
use pocketmine\network\mcpe\PlayerNetworkSessionAdapter;
|
||||||
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
|
use pocketmine\network\mcpe\protocol\AdventureSettingsPacket;
|
||||||
@ -760,6 +758,29 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
return $this->inAirTicks;
|
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{
|
protected function switchLevel(Level $targetLevel) : bool{
|
||||||
$oldLevel = $this->level;
|
$oldLevel = $this->level;
|
||||||
if(parent::switchLevel($targetLevel)){
|
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);
|
$this->level->broadcastLevelEvent($pos, LevelEventPacket::EVENT_BLOCK_STOP_BREAK);
|
||||||
break;
|
break;
|
||||||
case PlayerActionPacket::ACTION_RELEASE_ITEM:
|
case PlayerActionPacket::ACTION_RELEASE_ITEM:
|
||||||
if($this->startAction > -1 and $this->getGenericFlag(self::DATA_FLAG_ACTION)){
|
if($this->isUsingItem()){
|
||||||
if($this->inventory->getItemInHand()->getId() === Item::BOW){
|
$item = $this->inventory->getItemInHand();
|
||||||
$bow = $this->inventory->getItemInHand();
|
if($item->onReleaseUsing($this)){
|
||||||
if($this->isSurvival() and !$this->inventory->contains(ItemFactory::get(Item::ARROW, 0, 1))){
|
$this->inventory->setItemInHand($item);
|
||||||
$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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}elseif($this->inventory->getItemInHand()->getId() === Item::BUCKET and $this->inventory->getItemInHand()->getDamage() === 1){ //Milk!
|
}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()));
|
$this->server->getPluginManager()->callEvent($ev = new PlayerItemConsumeEvent($this, $this->inventory->getItemInHand()));
|
||||||
|
@ -23,6 +23,17 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\item;
|
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{
|
class Bow extends Tool{
|
||||||
public function __construct(int $meta = 0){
|
public function __construct(int $meta = 0){
|
||||||
@ -36,4 +47,79 @@ class Bow extends Tool{
|
|||||||
public function getMaxDurability(){
|
public function getMaxDurability(){
|
||||||
return 385;
|
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;
|
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.
|
* Compares an Item to this Item and check if they match.
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user