PocketMine-MP 5.19.1 git-5cc1068cd43264d3363295eb8d6901e02f467897
EffectManager.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\entity\effect;
25
31use function abs;
32use function count;
33use function spl_object_id;
34
37 protected array $effects = [];
38
39 protected Color $bubbleColor;
40 protected bool $onlyAmbientEffects = false;
41
46 protected ObjectSet $effectAddHooks;
51 protected ObjectSet $effectRemoveHooks;
52
53 public function __construct(
54 private Living $entity
55 ){
56 $this->bubbleColor = new Color(0, 0, 0, 0);
57 $this->effectAddHooks = new ObjectSet();
58 $this->effectRemoveHooks = new ObjectSet();
59 }
60
65 public function all() : array{
66 return $this->effects;
67 }
68
72 public function clear() : void{
73 foreach($this->effects as $effect){
74 $this->remove($effect->getType());
75 }
76 }
77
81 public function remove(Effect $effectType) : void{
82 $index = spl_object_id($effectType);
83 if(isset($this->effects[$index])){
84 $effect = $this->effects[$index];
85 $ev = new EntityEffectRemoveEvent($this->entity, $effect);
86 $ev->call();
87 if($ev->isCancelled()){
88 foreach($this->effectAddHooks as $hook){
89 $hook($ev->getEffect(), true);
90 }
91 return;
92 }
93
94 unset($this->effects[$index]);
95 $effect->getType()->remove($this->entity, $effect);
96 foreach($this->effectRemoveHooks as $hook){
97 $hook($effect);
98 }
99
100 $this->recalculateEffectColor();
101 }
102 }
103
108 public function get(Effect $effect) : ?EffectInstance{
109 return $this->effects[spl_object_id($effect)] ?? null;
110 }
111
115 public function has(Effect $effect) : bool{
116 return isset($this->effects[spl_object_id($effect)]);
117 }
118
126 public function add(EffectInstance $effect) : bool{
127 $oldEffect = null;
128 $cancelled = false;
129
130 $index = spl_object_id($effect->getType());
131 if(isset($this->effects[$index])){
132 $oldEffect = $this->effects[$index];
133 if(
134 abs($effect->getAmplifier()) < $oldEffect->getAmplifier()
135 || (abs($effect->getAmplifier()) === abs($oldEffect->getAmplifier()) && $effect->getDuration() < $oldEffect->getDuration())
136 ){
137 $cancelled = true;
138 }
139 }
140
141 $ev = new EntityEffectAddEvent($this->entity, $effect, $oldEffect);
142 if($cancelled){
143 $ev->cancel();
144 }
145
146 $ev->call();
147 if($ev->isCancelled()){
148 return false;
149 }
150
151 if($oldEffect !== null){
152 $oldEffect->getType()->remove($this->entity, $oldEffect);
153 }
154
155 $effect->getType()->add($this->entity, $effect);
156 foreach($this->effectAddHooks as $hook){
157 $hook($effect, $oldEffect !== null);
158 }
159
160 $this->effects[$index] = $effect;
161
162 $this->recalculateEffectColor();
163
164 return true;
165 }
166
170 protected function recalculateEffectColor() : void{
172 $colors = [];
173 $ambient = true;
174 foreach($this->effects as $effect){
175 if($effect->isVisible() && $effect->getType()->hasBubbles()){
176 $level = $effect->getEffectLevel();
177 $color = $effect->getColor();
178 for($i = 0; $i < $level; ++$i){
179 $colors[] = $color;
180 }
181
182 if(!$effect->isAmbient()){
183 $ambient = false;
184 }
185 }
186 }
187
188 if(count($colors) > 0){
189 $this->bubbleColor = Color::mix(...$colors);
190 $this->onlyAmbientEffects = $ambient;
191 }else{
192 $this->bubbleColor = new Color(0, 0, 0, 0);
193 $this->onlyAmbientEffects = false;
194 }
195 }
196
197 public function getBubbleColor() : Color{
198 return $this->bubbleColor;
199 }
200
201 public function hasOnlyAmbientEffects() : bool{
202 return $this->onlyAmbientEffects;
203 }
204
205 public function tick(int $tickDiff = 1) : bool{
206 foreach($this->effects as $instance){
207 $type = $instance->getType();
208 if($type->canTick($instance)){
209 $type->applyEffect($this->entity, $instance);
210 }
211 $instance->decreaseDuration($tickDiff);
212 if($instance->hasExpired()){
213 $this->remove($instance->getType());
214 }
215 }
216
217 return count($this->effects) > 0;
218 }
219
224 public function getEffectAddHooks() : ObjectSet{
225 return $this->effectAddHooks;
226 }
227
232 public function getEffectRemoveHooks() : ObjectSet{
233 return $this->effectRemoveHooks;
234 }
235}