Effect: Introduce a bunch of static getters, change a bunch of API to use objects

This introduces static getters for every currently-known effect type. At some point in the near future, the magic number constants (which are really network IDs, by the way) will disappear.

Migrating:
- If you used constants (like any sensible person would): for the most part it's just a case of adding a () anywhere you used an Effect constant.
- If you hardcoded magic numbers: ... well, have fun fixing your code, and I reserve the right to say "I told you so" :)

This achieves multiple goals:
1) creating an EffectInstance for application is much less verbose (see diff for examples, especially the Potion class)
2) plugin devs cannot use magic numbers to apply effects anymore and are forced to use type-safe objects. :)

This is a warning shot for plugin devs who use magic numbers. More changes like this are coming in the not-too-distant future.
This commit is contained in:
Dylan K. Taylor 2019-02-20 12:03:10 +00:00
parent 15d4201c3a
commit 646fea5a4e
14 changed files with 190 additions and 78 deletions

View File

@ -2341,7 +2341,7 @@ class Player extends Human implements CommandSender, ChunkLoader, ChunkListener,
}
$ev->setModifier($meleeEnchantmentDamage, EntityDamageEvent::MODIFIER_WEAPON_ENCHANTMENTS);
if(!$this->isSprinting() and !$this->isFlying() and $this->fallDistance > 0 and !$this->hasEffect(Effect::BLINDNESS) and !$this->isUnderwater()){
if(!$this->isSprinting() and !$this->isFlying() and $this->fallDistance > 0 and !$this->hasEffect(Effect::BLINDNESS()) and !$this->isUnderwater()){
$ev->setModifier($ev->getFinalDamage() / 2, EntityDamageEvent::MODIFIER_CRITICAL);
}

View File

@ -62,7 +62,7 @@ class EffectCommand extends VanillaCommand{
if(strtolower($args[1]) === "clear"){
foreach($player->getEffects() as $effect){
$player->removeEffect($effect->getId());
$player->removeEffect($effect->getType());
}
$sender->sendMessage(new TranslationContainer("commands.effect.success.removed.all", [$player->getDisplayName()]));
@ -107,7 +107,7 @@ class EffectCommand extends VanillaCommand{
}
if($duration === 0){
if(!$player->hasEffect($effect->getId())){
if(!$player->hasEffect($effect)){
if(count($player->getEffects()) === 0){
$sender->sendMessage(new TranslationContainer("commands.effect.failure.notActive.all", [$player->getDisplayName()]));
}else{
@ -116,7 +116,7 @@ class EffectCommand extends VanillaCommand{
return true;
}
$player->removeEffect($effect->getId());
$player->removeEffect($effect);
$sender->sendMessage(new TranslationContainer("commands.effect.success.removed", [$effect->getName(), $player->getDisplayName()]));
}else{
$instance = new EffectInstance($effect, $duration, $amplification, $visible);

View File

@ -765,9 +765,9 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
if($totemModifier < 0){ //Totem prevented death
$this->removeAllEffects();
$this->addEffect(new EffectInstance(Effect::getEffect(Effect::REGENERATION), 40 * 20, 1));
$this->addEffect(new EffectInstance(Effect::getEffect(Effect::FIRE_RESISTANCE), 40 * 20, 1));
$this->addEffect(new EffectInstance(Effect::getEffect(Effect::ABSORPTION), 5 * 20, 1));
$this->addEffect(new EffectInstance(Effect::REGENERATION(), 40 * 20, 1));
$this->addEffect(new EffectInstance(Effect::FIRE_RESISTANCE(), 40 * 20, 1));
$this->addEffect(new EffectInstance(Effect::ABSORPTION(), 5 * 20, 1));
$this->broadcastEntityEvent(EntityEventPacket::CONSUME_TOTEM);
$this->level->broadcastLevelEvent($this->add(0, $this->eyeHeight, 0), LevelEventPacket::EVENT_SOUND_TOTEM);

View File

@ -65,6 +65,7 @@ use function max;
use function min;
use function mt_getrandmax;
use function mt_rand;
use function spl_object_id;
use function sqrt;
use const M_PI;
@ -212,18 +213,19 @@ abstract class Living extends Entity implements Damageable{
*/
public function removeAllEffects() : void{
foreach($this->effects as $effect){
$this->removeEffect($effect->getId());
$this->removeEffect($effect->getType());
}
}
/**
* Removes the effect with the specified ID from the mob.
*
* @param int $effectId
* @param Effect $effectType
*/
public function removeEffect(int $effectId) : void{
if(isset($this->effects[$effectId])){
$effect = $this->effects[$effectId];
public function removeEffect(Effect $effectType) : void{
$index = spl_object_id($effectType);
if(isset($this->effects[$index])){
$effect = $this->effects[$index];
$hasExpired = $effect->hasExpired();
$ev = new EntityEffectRemoveEvent($this, $effect);
$ev->call();
@ -234,7 +236,7 @@ abstract class Living extends Entity implements Damageable{
return;
}
unset($this->effects[$effectId]);
unset($this->effects[$index]);
$effect->getType()->remove($this, $effect);
$this->sendEffectRemove($effect);
@ -246,23 +248,23 @@ abstract class Living extends Entity implements Damageable{
* Returns the effect instance active on this entity with the specified ID, or null if the mob does not have the
* effect.
*
* @param int $effectId
* @param Effect $effect
*
* @return EffectInstance|null
*/
public function getEffect(int $effectId) : ?EffectInstance{
return $this->effects[$effectId] ?? null;
public function getEffect(Effect $effect) : ?EffectInstance{
return $this->effects[spl_object_id($effect)] ?? null;
}
/**
* Returns whether the specified effect is active on the mob.
*
* @param int $effectId
* @param Effect $effect
*
* @return bool
*/
public function hasEffect(int $effectId) : bool{
return isset($this->effects[$effectId]);
public function hasEffect(Effect $effect) : bool{
return isset($this->effects[spl_object_id($effect)]);
}
/**
@ -286,8 +288,10 @@ abstract class Living extends Entity implements Damageable{
$oldEffect = null;
$cancelled = false;
if(isset($this->effects[$effect->getId()])){
$oldEffect = $this->effects[$effect->getId()];
$type = $effect->getType();
$index = spl_object_id($type);
if(isset($this->effects[$index])){
$oldEffect = $this->effects[$index];
if(
abs($effect->getAmplifier()) < $oldEffect->getAmplifier()
or (abs($effect->getAmplifier()) === abs($oldEffect->getAmplifier()) and $effect->getDuration() < $oldEffect->getDuration())
@ -311,7 +315,7 @@ abstract class Living extends Entity implements Damageable{
$effect->getType()->add($this, $effect);
$this->sendEffectAdd($effect, $oldEffect !== null);
$this->effects[$effect->getId()] = $effect;
$this->effects[$index] = $effect;
$this->recalculateEffectColor();
@ -398,7 +402,7 @@ abstract class Living extends Entity implements Damageable{
* @return float
*/
public function getJumpVelocity() : float{
return $this->jumpVelocity + ($this->hasEffect(Effect::JUMP) ? ($this->getEffect(Effect::JUMP)->getEffectLevel() / 10) : 0);
return $this->jumpVelocity + ($this->hasEffect(Effect::JUMP_BOOST()) ? ($this->getEffect(Effect::JUMP_BOOST())->getEffectLevel() / 10) : 0);
}
/**
@ -411,7 +415,7 @@ abstract class Living extends Entity implements Damageable{
}
public function fall(float $fallDistance) : void{
$damage = ceil($fallDistance - 3 - ($this->hasEffect(Effect::JUMP) ? $this->getEffect(Effect::JUMP)->getEffectLevel() : 0));
$damage = ceil($fallDistance - 3 - ($this->hasEffect(Effect::JUMP_BOOST()) ? $this->getEffect(Effect::JUMP_BOOST())->getEffectLevel() : 0));
if($damage > 0){
$ev = new EntityDamageEvent($this, EntityDamageEvent::CAUSE_FALL, $damage);
$this->attack($ev);
@ -474,8 +478,8 @@ abstract class Living extends Entity implements Damageable{
}
$cause = $source->getCause();
if($this->hasEffect(Effect::DAMAGE_RESISTANCE) and $cause !== EntityDamageEvent::CAUSE_VOID and $cause !== EntityDamageEvent::CAUSE_SUICIDE){
$source->setModifier(-$source->getFinalDamage() * min(1, 0.2 * $this->getEffect(Effect::DAMAGE_RESISTANCE)->getEffectLevel()), EntityDamageEvent::MODIFIER_RESISTANCE);
if($this->hasEffect(Effect::RESISTANCE()) and $cause !== EntityDamageEvent::CAUSE_VOID and $cause !== EntityDamageEvent::CAUSE_SUICIDE){
$source->setModifier(-$source->getFinalDamage() * min(1, 0.2 * $this->getEffect(Effect::RESISTANCE())->getEffectLevel()), EntityDamageEvent::MODIFIER_RESISTANCE);
}
$totalEpf = 0;
@ -555,7 +559,7 @@ abstract class Living extends Entity implements Damageable{
}
}
if($this->hasEffect(Effect::FIRE_RESISTANCE) and (
if($this->hasEffect(Effect::FIRE_RESISTANCE()) and (
$source->getCause() === EntityDamageEvent::CAUSE_FIRE
or $source->getCause() === EntityDamageEvent::CAUSE_FIRE_TICK
or $source->getCause() === EntityDamageEvent::CAUSE_LAVA
@ -714,7 +718,7 @@ abstract class Living extends Entity implements Damageable{
}
$instance->decreaseDuration($tickDiff);
if($instance->hasExpired()){
$this->removeEffect($instance->getId());
$this->removeEffect($instance->getType());
}
}
@ -765,7 +769,7 @@ abstract class Living extends Entity implements Damageable{
* @return bool
*/
public function canBreathe() : bool{
return $this->hasEffect(Effect::WATER_BREATHING) or $this->hasEffect(Effect::CONDUIT_POWER) or !$this->isUnderwater();
return $this->hasEffect(Effect::WATER_BREATHING()) or $this->hasEffect(Effect::CONDUIT_POWER()) or !$this->isUnderwater();
}
/**

View File

@ -31,6 +31,8 @@ use function defined;
use function strtoupper;
class Effect{
//TODO: remove our dependence on these magic numbers
public const SPEED = 1;
public const SLOWNESS = 2;
public const HASTE = 3;
@ -90,6 +92,112 @@ class Effect{
self::registerEffect(new Effect(Effect::CONDUIT_POWER, "%potion.conduitPower", new Color(0x1d, 0xc2, 0xd1)));
}
/* auto-generated code */
public static function ABSORPTION() : Effect{
return self::getEffect(Effect::ABSORPTION);
}
public static function BLINDNESS() : Effect{
return self::getEffect(Effect::BLINDNESS);
}
public static function CONDUIT_POWER() : Effect{
return self::getEffect(Effect::CONDUIT_POWER);
}
public static function FATAL_POISON() : Effect{
return self::getEffect(Effect::FATAL_POISON);
}
public static function FIRE_RESISTANCE() : Effect{
return self::getEffect(Effect::FIRE_RESISTANCE);
}
public static function HASTE() : Effect{
return self::getEffect(Effect::HASTE);
}
public static function HEALTH_BOOST() : Effect{
return self::getEffect(Effect::HEALTH_BOOST);
}
public static function HUNGER() : Effect{
return self::getEffect(Effect::HUNGER);
}
public static function INSTANT_DAMAGE() : Effect{
return self::getEffect(Effect::INSTANT_DAMAGE);
}
public static function INSTANT_HEALTH() : Effect{
return self::getEffect(Effect::INSTANT_HEALTH);
}
public static function INVISIBILITY() : Effect{
return self::getEffect(Effect::INVISIBILITY);
}
public static function JUMP_BOOST() : Effect{
return self::getEffect(Effect::JUMP_BOOST);
}
public static function LEVITATION() : Effect{
return self::getEffect(Effect::LEVITATION);
}
public static function MINING_FATIGUE() : Effect{
return self::getEffect(Effect::MINING_FATIGUE);
}
public static function NAUSEA() : Effect{
return self::getEffect(Effect::NAUSEA);
}
public static function NIGHT_VISION() : Effect{
return self::getEffect(Effect::NIGHT_VISION);
}
public static function POISON() : Effect{
return self::getEffect(Effect::POISON);
}
public static function REGENERATION() : Effect{
return self::getEffect(Effect::REGENERATION);
}
public static function RESISTANCE() : Effect{
return self::getEffect(Effect::RESISTANCE);
}
public static function SATURATION() : Effect{
return self::getEffect(Effect::SATURATION);
}
public static function SLOWNESS() : Effect{
return self::getEffect(Effect::SLOWNESS);
}
public static function SPEED() : Effect{
return self::getEffect(Effect::SPEED);
}
public static function STRENGTH() : Effect{
return self::getEffect(Effect::STRENGTH);
}
public static function WATER_BREATHING() : Effect{
return self::getEffect(Effect::WATER_BREATHING);
}
public static function WEAKNESS() : Effect{
return self::getEffect(Effect::WEAKNESS);
}
public static function WITHER() : Effect{
return self::getEffect(Effect::WITHER);
}
/**
* @param Effect $effect
*/

View File

@ -53,12 +53,12 @@ class EntityDamageByEntityEvent extends EntityDamageEvent{
protected function addAttackerModifiers(Entity $damager) : void{
if($damager instanceof Living){ //TODO: move this to entity classes
if($damager->hasEffect(Effect::STRENGTH)){
$this->setModifier($this->getBaseDamage() * 0.3 * $damager->getEffect(Effect::STRENGTH)->getEffectLevel(), self::MODIFIER_STRENGTH);
if($damager->hasEffect(Effect::STRENGTH())){
$this->setModifier($this->getBaseDamage() * 0.3 * $damager->getEffect(Effect::STRENGTH())->getEffectLevel(), self::MODIFIER_STRENGTH);
}
if($damager->hasEffect(Effect::WEAKNESS)){
$this->setModifier(-($this->getBaseDamage() * 0.2 * $damager->getEffect(Effect::WEAKNESS)->getEffectLevel()), self::MODIFIER_WEAKNESS);
if($damager->hasEffect(Effect::WEAKNESS())){
$this->setModifier(-($this->getBaseDamage() * 0.2 * $damager->getEffect(Effect::WEAKNESS())->getEffectLevel()), self::MODIFIER_WEAKNESS);
}
}
}

View File

@ -46,8 +46,8 @@ class GoldenApple extends Food{
public function getAdditionalEffects() : array{
return [
new EffectInstance(Effect::getEffect(Effect::REGENERATION), 100, 1),
new EffectInstance(Effect::getEffect(Effect::ABSORPTION), 2400)
new EffectInstance(Effect::REGENERATION(), 100, 1),
new EffectInstance(Effect::ABSORPTION(), 2400)
];
}
}

View File

@ -34,10 +34,10 @@ class GoldenAppleEnchanted extends GoldenApple{
public function getAdditionalEffects() : array{
return [
new EffectInstance(Effect::getEffect(Effect::REGENERATION), 600, 4),
new EffectInstance(Effect::getEffect(Effect::ABSORPTION), 2400, 3),
new EffectInstance(Effect::getEffect(Effect::RESISTANCE), 6000),
new EffectInstance(Effect::getEffect(Effect::FIRE_RESISTANCE), 6000)
new EffectInstance(Effect::REGENERATION(), 600, 4),
new EffectInstance(Effect::ABSORPTION(), 2400, 3),
new EffectInstance(Effect::RESISTANCE(), 6000),
new EffectInstance(Effect::FIRE_RESISTANCE(), 6000)
];
}
}

View File

@ -43,7 +43,7 @@ class PoisonousPotato extends Food{
public function getAdditionalEffects() : array{
if(mt_rand(0, 100) > 40){
return [
new EffectInstance(Effect::getEffect(Effect::POISON), 100)
new EffectInstance(Effect::POISON(), 100)
];
}
return [];

View File

@ -124,131 +124,131 @@ class Potion extends Item implements Consumable{
return [];
case self::NIGHT_VISION:
return [
new EffectInstance(Effect::getEffect(Effect::NIGHT_VISION), 3600)
new EffectInstance(Effect::NIGHT_VISION(), 3600)
];
case self::LONG_NIGHT_VISION:
return [
new EffectInstance(Effect::getEffect(Effect::NIGHT_VISION), 9600)
new EffectInstance(Effect::NIGHT_VISION(), 9600)
];
case self::INVISIBILITY:
return [
new EffectInstance(Effect::getEffect(Effect::INVISIBILITY), 3600)
new EffectInstance(Effect::INVISIBILITY(), 3600)
];
case self::LONG_INVISIBILITY:
return [
new EffectInstance(Effect::getEffect(Effect::INVISIBILITY), 9600)
new EffectInstance(Effect::INVISIBILITY(), 9600)
];
case self::LEAPING:
return [
new EffectInstance(Effect::getEffect(Effect::JUMP_BOOST), 3600)
new EffectInstance(Effect::JUMP_BOOST(), 3600)
];
case self::LONG_LEAPING:
return [
new EffectInstance(Effect::getEffect(Effect::JUMP_BOOST), 9600)
new EffectInstance(Effect::JUMP_BOOST(), 9600)
];
case self::STRONG_LEAPING:
return [
new EffectInstance(Effect::getEffect(Effect::JUMP_BOOST), 1800, 1)
new EffectInstance(Effect::JUMP_BOOST(), 1800, 1)
];
case self::FIRE_RESISTANCE:
return [
new EffectInstance(Effect::getEffect(Effect::FIRE_RESISTANCE), 3600)
new EffectInstance(Effect::FIRE_RESISTANCE(), 3600)
];
case self::LONG_FIRE_RESISTANCE:
return [
new EffectInstance(Effect::getEffect(Effect::FIRE_RESISTANCE), 9600)
new EffectInstance(Effect::FIRE_RESISTANCE(), 9600)
];
case self::SWIFTNESS:
return [
new EffectInstance(Effect::getEffect(Effect::SPEED), 3600)
new EffectInstance(Effect::SPEED(), 3600)
];
case self::LONG_SWIFTNESS:
return [
new EffectInstance(Effect::getEffect(Effect::SPEED), 9600)
new EffectInstance(Effect::SPEED(), 9600)
];
case self::STRONG_SWIFTNESS:
return [
new EffectInstance(Effect::getEffect(Effect::SPEED), 1800, 1)
new EffectInstance(Effect::SPEED(), 1800, 1)
];
case self::SLOWNESS:
return [
new EffectInstance(Effect::getEffect(Effect::SLOWNESS), 1800)
new EffectInstance(Effect::SLOWNESS(), 1800)
];
case self::LONG_SLOWNESS:
return [
new EffectInstance(Effect::getEffect(Effect::SLOWNESS), 4800)
new EffectInstance(Effect::SLOWNESS(), 4800)
];
case self::WATER_BREATHING:
return [
new EffectInstance(Effect::getEffect(Effect::WATER_BREATHING), 3600)
new EffectInstance(Effect::WATER_BREATHING(), 3600)
];
case self::LONG_WATER_BREATHING:
return [
new EffectInstance(Effect::getEffect(Effect::WATER_BREATHING), 9600)
new EffectInstance(Effect::WATER_BREATHING(), 9600)
];
case self::HEALING:
return [
new EffectInstance(Effect::getEffect(Effect::INSTANT_HEALTH))
new EffectInstance(Effect::INSTANT_HEALTH())
];
case self::STRONG_HEALING:
return [
new EffectInstance(Effect::getEffect(Effect::INSTANT_HEALTH), null, 1)
new EffectInstance(Effect::INSTANT_HEALTH(), null, 1)
];
case self::HARMING:
return [
new EffectInstance(Effect::getEffect(Effect::INSTANT_DAMAGE))
new EffectInstance(Effect::INSTANT_DAMAGE())
];
case self::STRONG_HARMING:
return [
new EffectInstance(Effect::getEffect(Effect::INSTANT_DAMAGE), null, 1)
new EffectInstance(Effect::INSTANT_DAMAGE(), null, 1)
];
case self::POISON:
return [
new EffectInstance(Effect::getEffect(Effect::POISON), 900)
new EffectInstance(Effect::POISON(), 900)
];
case self::LONG_POISON:
return [
new EffectInstance(Effect::getEffect(Effect::POISON), 2400)
new EffectInstance(Effect::POISON(), 2400)
];
case self::STRONG_POISON:
return [
new EffectInstance(Effect::getEffect(Effect::POISON), 440, 1)
new EffectInstance(Effect::POISON(), 440, 1)
];
case self::REGENERATION:
return [
new EffectInstance(Effect::getEffect(Effect::REGENERATION), 900)
new EffectInstance(Effect::REGENERATION(), 900)
];
case self::LONG_REGENERATION:
return [
new EffectInstance(Effect::getEffect(Effect::REGENERATION), 2400)
new EffectInstance(Effect::REGENERATION(), 2400)
];
case self::STRONG_REGENERATION:
return [
new EffectInstance(Effect::getEffect(Effect::REGENERATION), 440, 1)
new EffectInstance(Effect::REGENERATION(), 440, 1)
];
case self::STRENGTH:
return [
new EffectInstance(Effect::getEffect(Effect::STRENGTH), 3600)
new EffectInstance(Effect::STRENGTH(), 3600)
];
case self::LONG_STRENGTH:
return [
new EffectInstance(Effect::getEffect(Effect::STRENGTH), 9600)
new EffectInstance(Effect::STRENGTH(), 9600)
];
case self::STRONG_STRENGTH:
return [
new EffectInstance(Effect::getEffect(Effect::STRENGTH), 1800, 1)
new EffectInstance(Effect::STRENGTH(), 1800, 1)
];
case self::WEAKNESS:
return [
new EffectInstance(Effect::getEffect(Effect::WEAKNESS), 1800)
new EffectInstance(Effect::WEAKNESS(), 1800)
];
case self::LONG_WEAKNESS:
return [
new EffectInstance(Effect::getEffect(Effect::WEAKNESS), 4800)
new EffectInstance(Effect::WEAKNESS(), 4800)
];
case self::WITHER:
return [
new EffectInstance(Effect::getEffect(Effect::WITHER), 800, 1)
new EffectInstance(Effect::WITHER(), 800, 1)
];
}

View File

@ -41,9 +41,9 @@ class Pufferfish extends Food{
public function getAdditionalEffects() : array{
return [
new EffectInstance(Effect::getEffect(Effect::HUNGER), 300, 2),
new EffectInstance(Effect::getEffect(Effect::POISON), 1200, 3),
new EffectInstance(Effect::getEffect(Effect::NAUSEA), 300, 1)
new EffectInstance(Effect::HUNGER(), 300, 2),
new EffectInstance(Effect::POISON(), 1200, 3),
new EffectInstance(Effect::NAUSEA(), 300, 1)
];
}
}

View File

@ -41,6 +41,6 @@ class RawChicken extends Food{
}
public function getAdditionalEffects() : array{
return mt_rand(0, 9) < 3 ? [new EffectInstance(Effect::getEffect(Effect::HUNGER), 600)] : [];
return mt_rand(0, 9) < 3 ? [new EffectInstance(Effect::HUNGER(), 600)] : [];
}
}

View File

@ -44,7 +44,7 @@ class RottenFlesh extends Food{
public function getAdditionalEffects() : array{
if(lcg_value() <= 0.8){
return [
new EffectInstance(Effect::getEffect(Effect::HUNGER), 600)
new EffectInstance(Effect::HUNGER(), 600)
];
}

View File

@ -40,6 +40,6 @@ class SpiderEye extends Food{
}
public function getAdditionalEffects() : array{
return [new EffectInstance(Effect::getEffect(Effect::POISON), 80)];
return [new EffectInstance(Effect::POISON(), 80)];
}
}