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

Pm4 #11

Merged
merged 6 commits into from
Jan 8, 2022
Merged

Pm4 #11

Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions .poggit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
build-by-default: true
branches:
- master
- PM4
projects:
Shield:
path: ""
Expand Down
5 changes: 2 additions & 3 deletions plugin.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
name: Shield
depend: OffHand
main: JavierLeon9966\Shield\Shield
author: JavierLeon9966
version: 1.3.0
api: 3.7.0
version: 1.4.0
api: 4.0.0
mcpe-protocol: [340, 354, 361, 388, 389, 390, 407, 408, 419, 422, 428, 431, 440, 448, 465, 471, 475]
description: A PocketMine-MP plugin which adds functionable shields
131 changes: 79 additions & 52 deletions src/JavierLeon9966/Shield/Shield.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,83 +4,108 @@

namespace JavierLeon9966\Shield;

use alvin0319\Offhand\Offhand;
use JavierLeon9966\Shield\item\Shield as ShieldItem;
use JavierLeon9966\Shield\sound\ShieldBlockSound;

use pocketmine\block\BlockIds;
use pocketmine\entity\{Effect, Entity, Living};
use pocketmine\entity\effect\VanillaEffects;
use pocketmine\entity\{Entity, Living};
use pocketmine\event\Listener;
use pocketmine\event\entity\{EntityDamageEvent, EntityDamageByChildEntityEvent, EntityDamageByEntityEvent};
use pocketmine\event\player\{PlayerAnimationEvent, PlayerToggleSneakEvent};
use pocketmine\item\{Axe, Item, ItemFactory};
use pocketmine\event\entity\{EntityDamageByChildEntityEvent, EntityDamageEvent, EntityDamageByEntityEvent};
use pocketmine\event\server\DataPacketReceiveEvent;
use pocketmine\event\player\PlayerToggleSneakEvent;
use pocketmine\inventory\CreativeInventory;
use pocketmine\item\{ItemIdentifier, ItemIds, ItemFactory, StringToItemParser};
use pocketmine\player\Player;
use pocketmine\plugin\PluginBase;
use pocketmine\Player;
use pocketmine\network\mcpe\protocol\{AnimatePacket, LevelSoundEventPacket};
use pocketmine\network\mcpe\protocol\AnimatePacket;
use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataFlags;
use pocketmine\scheduler\ClosureTask;

use JavierLeon9966\Shield\item\Shield as ShieldItem;
use pocketmine\world\sound\ItemBreakSound;

final class Shield extends PluginBase implements Listener{
private $cooldowns = [];
/**
* @var true[]
* @phpstan-var array<string, true>
*/
private array $cooldowns = [];

public function onEnable(): void{
ItemFactory::registerItem(new ShieldItem);
Item::addCreativeItem(Item::get(Item::SHIELD));
$shield = new ShieldItem(new ItemIdentifier(ItemIds::SHIELD, 0), 'Shield');
ItemFactory::getInstance()->register($shield);
CreativeInventory::getInstance()->add($shield);
StringToItemParser::getInstance()->register('shield', static fn() => clone $shield);
$this->getServer()->getPluginManager()->registerEvents($this, $this);
}

public function setCooldown(Player $player, int $ticks): void{
$player->getNetworkProperties()->setGenericFlag(EntityMetadataFlags::BLOCKING, false);
$this->cooldowns[$player->getUniqueId()->getBytes()] = true;

$this->getScheduler()->scheduleDelayedTask(new ClosureTask(fn() => $this->removeCooldown($player)), $ticks);
}

public function hasCooldown(Player $player): bool{
return isset($this->cooldowns[$player->getUniqueId()->getBytes()]);
}

public function removeCooldown(Player $player): void{
$player->getNetworkProperties()->setGenericFlag(EntityMetadataFlags::BLOCKING, $player->isSneaking());
unset($this->cooldowns[$player->getUniqueId()->getBytes()]);
}

/**
* @priority MONITOR
* @ignoreCancelled
*/
public function onPlayerAnimation(PlayerAnimationEvent $event): void{
$player = $event->getPlayer();
if($event->getAnimationType() == AnimatePacket::ACTION_SWING_ARM){
public function onDataPacketReceive(DataPacketReceiveEvent $event): void{
$player = $event->getOrigin()->getPlayer();
if(!$player instanceof Player) return;

$packet = $event->getPacket();
if($packet instanceof AnimatePacket and $packet->action === AnimatePacket::ACTION_SWING_ARM){
$ticks = 6;

if($player->hasEffect(Effect::HASTE) and $player->getEffect(Effect::HASTE)->getEffectLevel() > 1){
$ticks -= $player->getEffect(Effect::HASTE)->getEffectLevel();
}elseif($player->hasEffect(Effect::FATIGUE)){
$ticks += 2*$player->getEffect(Effect::FATIGUE)->getEffectLevel();
$effects = $player->getEffects();
if(($effectLevel = $effects->get(VanillaEffects::HASTE())?->getEffectLevel() ?? 0) > 1){
$ticks -= $effectLevel;
}else{
$ticks += 2*($effects->get(VanillaEffects::MINING_FATIGUE())?->getEffectLevel() ?? 0);
}

if($ticks <= 0) return;

$player->setGenericFlag(Entity::DATA_FLAG_BLOCKING, false);
$this->cooldowns[$player->getRawUniqueId()] = true;

$this->getScheduler()->scheduleDelayedTask(new ClosureTask(function() use($player): void{
$player->setGenericFlag(Entity::DATA_FLAG_BLOCKING, $player->isSneaking());
unset($this->cooldowns[$player->getRawUniqueId()]);
}), $ticks);
if($ticks > 0) $this->setCooldown($player, $ticks);
}
}

/**
* @priority MONITOR
* @ignoreCancelled
*/
public function onPlayerToggleSneak(PlayerToggleSneakEvent $event): void{
if(!isset($this->cooldowns[$event->getPlayer()->getRawUniqueId()])){
$event->getPlayer()->setGenericFlag(Entity::DATA_FLAG_BLOCKING, $event->isSneaking());
$player = $event->getPlayer();
if(!isset($this->cooldowns[$player->getUniqueId()->getBytes()])){
$player->getNetworkProperties()->setGenericFlag(EntityMetadataFlags::BLOCKING, $event->isSneaking());
}
}

/**
* @priority HIGHEST
* @ignoreCancelled
*/
public function onEntityDamageByEntity(EntityDamageByEntityEvent $event): void{
$entity = $event->getEntity();
$damager = $event->getDamager();
$entity = $event->getEntity();
if(!$entity instanceof Player) return;

$inventory = $entity->getInventory();
$offhandInventory = $entity->getOffHandInventory();

if(!$damager instanceof Entity) return;
if($entity instanceof Player
and $event->canBeReducedByArmor()
and $entity->getGenericFlag(Entity::DATA_FLAG_BLOCKING)
and ($entity->getInventory()->getItemInHand() instanceof ShieldItem
or Offhand::getInstance()->getOffhandInventory($entity)->getItem(0) instanceof ShieldItem)
and $entity->canInteract($event instanceof EntityDamageByChildEntityEvent ? $event->getChild() : $damager, 8, 0)

if($event->canBeReducedByArmor()
and !isset($this->cooldowns[$entity->getUniqueId()->getBytes()])
and $entity->isSneaking()
and ($inventory->getItemInHand() instanceof ShieldItem
or $offhandInventory->getItem(0) instanceof ShieldItem)
and $entity->canInteract(($event instanceof EntityDamageByChildEntityEvent ? $event->getChild() : $damager)->getPosition(), 8, 0)
){
$entity->getLevel()->broadcastLevelSoundEvent($entity, LevelSoundEventPacket::SOUND_ITEM_SHIELD_BLOCK);
$entity->broadcastSound(new ShieldBlockSound);

$damage = (int)(2*($event->getBaseDamage()+array_sum([
$event->getModifier(EntityDamageEvent::MODIFIER_STRENGTH),
Expand All @@ -89,29 +114,31 @@ public function onEntityDamageByEntity(EntityDamageByEntityEvent $event): void{
$event->getModifier(EntityDamageEvent::MODIFIER_WEAPON_ENCHANTMENTS)
])));

$shield = Offhand::getInstance()->getOffhandInventory($entity)->getItem(0);
$shield = $offhandInventory->getItem(0);
if($shield instanceof ShieldItem){
$shield->applyDamage($damage);
Offhand::getInstance()->getOffhandInventory($entity)->setItem(0, $shield);
$offhandInventory->setItem(0, $shield);
}else{
$shield = $entity->getInventory()->getItemInHand();
$shield = $inventory->getItemInHand();
if($shield instanceof ShieldItem){
$shield->applyDamage($damage);
$entity->getInventory()->setItemInHand($shield);
$inventory->setItemInHand($shield);
}
}

if($shield->isBroken()){
$entity->getLevel()->broadcastLevelSoundEvent($entity, LevelSoundEventPacket::SOUND_BREAK);
if($shield instanceof ShieldItem and $shield->isBroken()){
$entity->broadcastSound(new ItemBreakSound);
}

if(!$event instanceof EntityDamageByChildEntityEvent and $damager instanceof Living){
$deltaX = $damager->x - $entity->x;
$deltaZ = $damager->z - $entity->z;
$damager->knockBack($entity, 0, $deltaX, $deltaZ, 0.8);
$damagerPos = $damager->getPosition();
$entityPos = $entity->getPosition();
$deltaX = $damagerPos->x - $entityPos->x;
$deltaZ = $damagerPos->z - $entityPos->z;
$damager->knockBack($deltaX, $deltaZ, 0.8);
}

$event->setCancelled();
$event->cancel();
}
}
}
6 changes: 1 addition & 5 deletions src/JavierLeon9966/Shield/item/Shield.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@

class Shield extends Durable{

public function __construct(int $meta = 0){
parent::__construct(self::SHIELD, $meta, 'Shield');
}

public function getMaxStackSize(): int{
return 1;
}
Expand All @@ -22,7 +18,7 @@ public function getMaxDurability(): int{
}

public function onDestroyBlock(Block $block): bool{
if($block->getHardness() > 0){
if(!$block->getBreakInfo()->breaksInstantly()){
return $this->applyDamage(2);
}
return false;
Expand Down
17 changes: 17 additions & 0 deletions src/JavierLeon9966/Shield/sound/ShieldBlockSound.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types = 1);

namespace JavierLeon9966\Shield\sound;

use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\types\LevelSoundEvent;
use pocketmine\world\sound\Sound;

class ShieldBlockSound implements Sound{

public function encode(Vector3 $pos): array{
return [LevelSoundEventPacket::nonActorSound(LevelSoundEvent::ITEM_SHIELD_BLOCK, $pos, false)];
}
}