-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Implement Trident #4547
base: minor-next
Are you sure you want to change the base?
Implement Trident #4547
Changes from 8 commits
910de73
d32129a
e01c31e
3aeb4e6
55bbdce
d55a3fc
1728f0f
b559dc7
2b67630
18c2194
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
<?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\entity\projectile; | ||
|
||
use pocketmine\block\Block; | ||
use pocketmine\entity\Entity; | ||
use pocketmine\entity\EntitySizeInfo; | ||
use pocketmine\entity\Location; | ||
use pocketmine\event\entity\EntityItemPickupEvent; | ||
use pocketmine\item\Trident as TridentItem; | ||
use pocketmine\math\RayTraceResult; | ||
use pocketmine\math\Vector3; | ||
use pocketmine\nbt\tag\CompoundTag; | ||
use pocketmine\network\mcpe\EntityEventBroadcaster; | ||
use pocketmine\network\mcpe\NetworkBroadcastUtils; | ||
use pocketmine\network\mcpe\protocol\types\entity\EntityIds; | ||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataCollection; | ||
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags; | ||
use pocketmine\player\Player; | ||
use pocketmine\world\sound\TridentHitEntitySound; | ||
use pocketmine\world\sound\TridentHitGroundSound; | ||
|
||
class Trident extends Projectile{ | ||
|
||
public const TAG_ITEM = "Trident"; //TAG_Compound | ||
protected const TAG_SPAWNED_IN_CREATIVE = "isCreative"; //TAG_Byte | ||
|
||
public static function getNetworkTypeId() : string{ return EntityIds::THROWN_TRIDENT; } | ||
|
||
protected float $damage = 8.0; | ||
|
||
protected bool $canCollide = true; | ||
|
||
protected bool $spawnedInCreative = false; | ||
|
||
public function __construct( | ||
Location $location, | ||
protected TridentItem $item, | ||
?Entity $shootingEntity, | ||
?CompoundTag $nbt = null | ||
){ | ||
if($item->isNull()){ | ||
throw new \InvalidArgumentException("Trident must have a count of at least 1"); | ||
} | ||
parent::__construct($location, $shootingEntity, $nbt); | ||
} | ||
|
||
protected function getInitialSizeInfo() : EntitySizeInfo{ return new EntitySizeInfo(0.35, 0.25); } | ||
|
||
protected function getInitialDragMultiplier() : float{ return 0.01; } | ||
|
||
protected function getInitialGravity() : float{ return 0.1; } | ||
|
||
protected function initEntity(CompoundTag $nbt) : void{ | ||
parent::initEntity($nbt); | ||
|
||
$this->spawnedInCreative = $nbt->getByte(self::TAG_SPAWNED_IN_CREATIVE, 0) === 1; | ||
} | ||
|
||
public function saveNBT() : CompoundTag{ | ||
$nbt = parent::saveNBT(); | ||
$nbt->setTag(self::TAG_ITEM, $this->item->nbtSerialize()); | ||
$nbt->setByte(self::TAG_SPAWNED_IN_CREATIVE, $this->spawnedInCreative ? 1 : 0); | ||
return $nbt; | ||
} | ||
|
||
protected function onFirstUpdate(int $currentTick) : void{ | ||
$owner = $this->getOwningEntity(); | ||
$this->spawnedInCreative = $owner instanceof Player && $owner->isCreative(); | ||
|
||
parent::onFirstUpdate($currentTick); | ||
} | ||
|
||
protected function entityBaseTick(int $tickDiff = 1) : bool{ | ||
if($this->closed){ | ||
return false; | ||
} | ||
//TODO: Loyalty enchantment. | ||
|
||
return parent::entityBaseTick($tickDiff); | ||
} | ||
|
||
protected function despawnsOnEntityHit() : bool{ | ||
return false; | ||
} | ||
|
||
protected function onHitEntity(Entity $entityHit, RayTraceResult $hitResult) : void{ | ||
parent::onHitEntity($entityHit, $hitResult); | ||
|
||
$this->canCollide = false; | ||
$this->broadcastSound(new TridentHitEntitySound()); | ||
$this->setMotion(new Vector3($this->motion->x * -0.01, $this->motion->y * -0.1, $this->motion->z * -0.01)); | ||
} | ||
|
||
protected function onHitBlock(Block $blockHit, RayTraceResult $hitResult) : void{ | ||
parent::onHitBlock($blockHit, $hitResult); | ||
$this->canCollide = true; | ||
$this->broadcastSound(new TridentHitGroundSound()); | ||
} | ||
|
||
public function getItem() : TridentItem{ | ||
return clone $this->item; | ||
} | ||
|
||
public function setItem(TridentItem $item) : void{ | ||
if($item->isNull()){ | ||
throw new \InvalidArgumentException("Trident must have a count of at least 1"); | ||
} | ||
if($this->item->hasEnchantments() !== $item->hasEnchantments()){ | ||
$this->networkPropertiesDirty = true; | ||
} | ||
$this->item = clone $item; | ||
} | ||
|
||
public function canCollideWith(Entity $entity) : bool{ | ||
return $this->canCollide && $entity->getId() !== $this->ownerId && parent::canCollideWith($entity); | ||
} | ||
|
||
public function onCollideWithPlayer(Player $player) : void{ | ||
if($this->blockHit !== null){ | ||
$this->pickup($player); | ||
} | ||
} | ||
|
||
private function pickup(Player $player) : void{ | ||
$shouldDespawn = false; | ||
|
||
$playerInventory = $player->getInventory(); | ||
$ev = new EntityItemPickupEvent($player, $this, $this->getItem(), $playerInventory); | ||
if($player->hasFiniteResources() && !$playerInventory->canAddItem($ev->getItem())){ | ||
$ev->cancel(); | ||
} | ||
if($this->spawnedInCreative){ | ||
$ev->cancel(); | ||
$shouldDespawn = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is going to despawn tridents thrown by creative players if a survival player tries to pick them up, even though no item will be received. Doesn't seem right to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's the expected behavior There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Expected by who? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm pretty sure this is a bug in Bedrock. No other items behave like this. Also, from the wiki:
I would expect this to work the same way arrows do, with modes NONE/ANY/CREATIVE pickup modes. |
||
} | ||
|
||
$ev->call(); | ||
if(!$ev->isCancelled()){ | ||
$ev->getInventory()?->addItem($ev->getItem()); | ||
$shouldDespawn = true; | ||
} | ||
|
||
if($shouldDespawn){ | ||
//even if the item was not actually picked up, the animation must be displayed. | ||
NetworkBroadcastUtils::broadcastEntityEvent( | ||
$this->getViewers(), | ||
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onPickUpItem($recipients, $player, $this) | ||
); | ||
$this->flagForDespawn(); | ||
} | ||
} | ||
|
||
protected function syncNetworkData(EntityMetadataCollection $properties) : void{ | ||
parent::syncNetworkData($properties); | ||
|
||
$properties->setGenericFlag(EntityMetadataFlags::ENCHANTED, $this->item->hasEnchantments()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to require this to be a TridentItem? It doesn't look like it needs any specific methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consistency, if I do
TridentEntity->getItem()
I would expect aTridentItem
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It just seems like an unnecessary constraint to me, considering there's no special methods on
TridentItem
.