PocketMine-MP 5.25.1 git-694aa17cc916a954b10fe12721c81b1dc73eecd5
Loading...
Searching...
No Matches
SurvivalBlockBreakHandler.php
1<?php
2
3/*
4 *
5 * ____ _ _ __ __ _ __ __ ____
6 * | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
7 * | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
8 * | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
9 * |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
10 *
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * @author PocketMine Team
17 * @link http://www.pocketmine.net/
18 *
19 *
20 */
21
22declare(strict_types=1);
23
24namespace pocketmine\player;
25
36use function abs;
37
39
40 public const DEFAULT_FX_INTERVAL_TICKS = 5;
41
42 private int $fxTicker = 0;
43 private float $breakSpeed;
44 private float $breakProgress = 0;
45
46 public function __construct(
47 private Player $player,
48 private Vector3 $blockPos,
49 private Block $block,
50 private int $targetedFace,
51 private int $maxPlayerDistance,
52 private int $fxTickInterval = self::DEFAULT_FX_INTERVAL_TICKS
53 ){
54 $this->breakSpeed = $this->calculateBreakProgressPerTick();
55 if($this->breakSpeed > 0){
56 $this->player->getWorld()->broadcastPacketToViewers(
57 $this->blockPos,
58 LevelEventPacket::create(LevelEvent::BLOCK_START_BREAK, (int) (65535 * $this->breakSpeed), $this->blockPos)
59 );
60 }
61 }
62
66 private function calculateBreakProgressPerTick() : float{
67 if(!$this->block->getBreakInfo()->isBreakable()){
68 return 0.0;
69 }
70 $breakTimePerTick = $this->block->getBreakInfo()->getBreakTime($this->player->getInventory()->getItemInHand()) * 20;
71 if(!$this->player->isOnGround() && !$this->player->isFlying()){
72 $breakTimePerTick *= 5;
73 }
74 if($this->player->isUnderwater() && !$this->player->getArmorInventory()->getHelmet()->hasEnchantment(VanillaEnchantments::AQUA_AFFINITY())){
75 $breakTimePerTick *= 5;
76 }
77 if($breakTimePerTick > 0){
78 $progressPerTick = 1 / $breakTimePerTick;
79
80 $haste = $this->player->getEffects()->get(VanillaEffects::HASTE());
81 if($haste !== null){
82 $hasteLevel = $haste->getEffectLevel();
83 $progressPerTick *= (1 + 0.2 * $hasteLevel) * (1.2 ** $hasteLevel);
84 }
85
86 $miningFatigue = $this->player->getEffects()->get(VanillaEffects::MINING_FATIGUE());
87 if($miningFatigue !== null){
88 $miningFatigueLevel = $miningFatigue->getEffectLevel();
89 $progressPerTick *= 0.21 ** $miningFatigueLevel;
90 }
91
92 return $progressPerTick;
93 }
94 return 1;
95 }
96
97 public function update() : bool{
98 if($this->player->getPosition()->distanceSquared($this->blockPos->add(0.5, 0.5, 0.5)) > $this->maxPlayerDistance ** 2){
99 return false;
100 }
101
102 $newBreakSpeed = $this->calculateBreakProgressPerTick();
103 if(abs($newBreakSpeed - $this->breakSpeed) > 0.0001){
104 $this->breakSpeed = $newBreakSpeed;
105 $this->player->getWorld()->broadcastPacketToViewers(
106 $this->blockPos,
107 LevelEventPacket::create(LevelEvent::BLOCK_BREAK_SPEED, (int) (65535 * $this->breakSpeed), $this->blockPos)
108 );
109 }
110
111 $this->breakProgress += $this->breakSpeed;
112
113 if(($this->fxTicker++ % $this->fxTickInterval) === 0 && $this->breakProgress < 1){
114 $this->player->getWorld()->addParticle($this->blockPos, new BlockPunchParticle($this->block, $this->targetedFace));
115 $this->player->getWorld()->addSound($this->blockPos, new BlockPunchSound($this->block));
116 $this->player->broadcastAnimation(new ArmSwingAnimation($this->player), $this->player->getViewers());
117 }
118
119 return $this->breakProgress < 1;
120 }
121
122 public function getBlockPos() : Vector3{
123 return $this->blockPos;
124 }
125
126 public function getTargetedFace() : int{
127 return $this->targetedFace;
128 }
129
130 public function setTargetedFace(int $face) : void{
131 Facing::validate($face);
132 $this->targetedFace = $face;
133 }
134
135 public function getBreakSpeed() : float{
136 return $this->breakSpeed;
137 }
138
139 public function getBreakProgress() : float{
140 return $this->breakProgress;
141 }
142
143 public function __destruct(){
144 if($this->player->getWorld()->isInLoadedTerrain($this->blockPos)){
145 $this->player->getWorld()->broadcastPacketToViewers(
146 $this->blockPos,
147 LevelEventPacket::create(LevelEvent::BLOCK_STOP_BREAK, 0, $this->blockPos)
148 );
149 }
150 }
151}
static create(int $eventId, int $eventData, ?Vector3 $position)