Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,20 @@ public void onEnvironmentalDamage(EntityDamageEvent event) {
&& runtime.byEntity(event.getEntity()) != null) event.setCancelled(true);
}

/** Owners cannot hurt their own pets: following pets end up inside area skills such as dashes. */
@EventHandler(priority = EventPriority.LOWEST)
public void onOwnerDamage(EntityDamageByEntityEvent event) {
Pet pet = runtime.byEntity(event.getEntity());
if (pet != null && pet.ownerId().equals(responsiblePlayer(event))) event.setCancelled(true);
}

private static UUID responsiblePlayer(EntityDamageByEntityEvent event) {
Entity cause = event.getDamageSource().getCausingEntity();
if (cause == null) cause = event.getDamager();
if (cause instanceof Projectile projectile && projectile.getShooter() instanceof Entity shooter) cause = shooter;
return cause instanceof Player player ? player.getUniqueId() : null;
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onVisualDamage(EntityDamageEvent event) {
if (event.getFinalDamage() <= 0) return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
assertNull(runtime.store().kennelOwner(PetStore.kennelKey(world.getName(), 3, 64, 0)));
}
private EntityDamageByEntityEvent attack(Entity attacker, Entity victim, double damage) {
return new EntityDamageByEntityEvent(attacker, victim, EntityDamageEvent.DamageCause.ENTITY_ATTACK, damage);

Check warning on line 168 in src/test/java/net/tfminecraft/companionpets/listen/PetListenerCoverageTest.java

View workflow job for this annotation

GitHub Actions / build

EntityDamageByEntityEvent(org.bukkit.entity.Entity,org.bukkit.entity.Entity,org.bukkit.event.entity.EntityDamageEvent.DamageCause,double) in org.bukkit.event.entity.EntityDamageByEntityEvent has been deprecated and marked for removal
}

@Test void previouslyCancelledBlockClickCannotPlaceOrConsumeKennel() {
Expand Down Expand Up @@ -253,15 +253,15 @@

@Test void highPriorityDamageCancellationPreservesMoodAndAnimations() {
atHigh(EntityDamageByEntityEvent.class, event -> event.setCancelled(true));
var event = fire(attack(owner, body, 2));
var event = fire(attack(server.addPlayer(), body, 2));
assertTrue(event.isCancelled());
assertEquals(80, pet.need(Need.MOOD));
assertTrue(animations.isEmpty());
assertTrue(cancelledAnimations.isEmpty());
}

@Test void zeroFinalDamageDoesNotCountAsBeingStruck() {
fire(attack(owner, body, 0));
fire(attack(server.addPlayer(), body, 0));
assertEquals(80, pet.need(Need.MOOD));
assertTrue(animations.isEmpty());
}
Expand Down Expand Up @@ -324,7 +324,7 @@
}

@Test void environmentalDamageHurtsWithoutAMoodPenaltyAndUnrelatedMobsStayUntouched() {
fire(new EntityDamageEvent(body, EntityDamageEvent.DamageCause.FALL, 2));

Check warning on line 327 in src/test/java/net/tfminecraft/companionpets/listen/PetListenerCoverageTest.java

View workflow job for this annotation

GitHub Actions / build

EntityDamageEvent(org.bukkit.entity.Entity,org.bukkit.event.entity.EntityDamageEvent.DamageCause,double) in org.bukkit.event.entity.EntityDamageEvent has been deprecated and marked for removal
assertEquals(List.of(body.getUniqueId() + ":HURT"), animations);
assertEquals(80, pet.need(Need.MOOD));
animations.clear();
Expand All @@ -342,7 +342,7 @@
(unused, event) -> observed.add(((EntityDamageEvent) event).isCancelled()), runtime.plugin());
double health = body.getHealth();
for (int tick = 0; tick < 40; tick++) {
var event = fire(new EntityDamageEvent(body, cause, 1_000));

Check warning on line 345 in src/test/java/net/tfminecraft/companionpets/listen/PetListenerCoverageTest.java

View workflow job for this annotation

GitHub Actions / build

EntityDamageEvent(org.bukkit.entity.Entity,org.bukkit.event.entity.EntityDamageEvent.DamageCause,double) in org.bukkit.event.entity.EntityDamageEvent has been deprecated and marked for removal
assertTrue(event.isCancelled());
if (!event.isCancelled()) body.setHealth(Math.max(0, body.getHealth() - event.getFinalDamage()));
}
Expand All @@ -350,10 +350,41 @@
assertEquals(health, body.getHealth()); assertFalse(body.isDead()); assertFalse(pet.dead());
assertSame(pet, runtime.store().get(pet.id())); assertFalse(runtime.store().isDeleted(pet.id()));
assertTrue(animations.isEmpty()); assertTrue(cancelledAnimations.isEmpty()); assertTrue(sounds.isEmpty());
var ordinary = fire(new EntityDamageEvent(wolf(owner.getLocation()), cause, 1));

Check warning on line 353 in src/test/java/net/tfminecraft/companionpets/listen/PetListenerCoverageTest.java

View workflow job for this annotation

GitHub Actions / build

EntityDamageEvent(org.bukkit.entity.Entity,org.bukkit.event.entity.EntityDamageEvent.DamageCause,double) in org.bukkit.event.entity.EntityDamageEvent has been deprecated and marked for removal
assertFalse(ordinary.isCancelled()); assertFalse(observed.getLast());
}

@Test void ownerDamageIsCancelledBeforeOtherPluginsWhetherMeleeProjectileOrSkill() {
var observed = new ArrayList<Boolean>();
server.getPluginManager().registerEvent(EntityDamageByEntityEvent.class, new Listener() { }, EventPriority.LOW,
(unused, event) -> observed.add(((EntityDamageEvent) event).isCancelled()), runtime.plugin());
Snowball shot = world.spawn(owner.getEyeLocation(), Snowball.class);
shot.setShooter(owner);
// Skill effects may hit through another entity while naming the caster as the cause.
Snowball effect = world.spawn(owner.getEyeLocation(), Snowball.class);
var skill = DamageSource.builder(DamageType.MAGIC).withCausingEntity(owner).withDirectEntity(effect).build();
for (var event : List.of(attack(owner, body, 10), attack(shot, body, 10),
new EntityDamageByEntityEvent(effect, body, EntityDamageEvent.DamageCause.MAGIC, skill, 10))) {

Check warning on line 367 in src/test/java/net/tfminecraft/companionpets/listen/PetListenerCoverageTest.java

View workflow job for this annotation

GitHub Actions / build

EntityDamageByEntityEvent(org.bukkit.entity.Entity,org.bukkit.entity.Entity,org.bukkit.event.entity.EntityDamageEvent.DamageCause,org.bukkit.damage.DamageSource,double) in org.bukkit.event.entity.EntityDamageByEntityEvent has been deprecated and marked for removal
assertTrue(fire(event).isCancelled());
}
assertEquals(List.of(true, true, true), observed);
assertEquals(80, pet.need(Need.MOOD));
assertTrue(animations.isEmpty());
assertTrue(cancelledAnimations.isEmpty());
}

@Test void ownerProtectionCoversOnlyTheirOwnPets() {
var stranger = server.addPlayer();
assertFalse(fire(attack(stranger, body, 2)).isCancelled());
assertEquals(80 - runtime.config().care().struckMoodPenalty(), pet.need(Need.MOOD));
var otherBody = wolf(owner.getLocation().add(2, 0, 0));
Pet other = net.tfminecraft.companionpets.testutil.OwnershipFixture.pet(UUID.randomUUID(), stranger.getUniqueId(), "wolf", "Luna", PetSex.FEMALE);
runtime.store().add(other);
runtime.remember(other, otherBody);
assertFalse(fire(attack(owner, otherBody, 2)).isCancelled());
assertFalse(fire(attack(owner, wolf(owner.getLocation()), 2)).isCancelled());
}

@Test void toyProjectileDamageIsCancelledBeforeMoodOrVisualEffects() {
Snowball toy = world.spawn(owner.getEyeLocation(), Snowball.class);
toy.getPersistentDataContainer().set(runtime.toyKey(), PersistentDataType.STRING, UUID.randomUUID().toString());
Expand All @@ -372,20 +403,20 @@
Snowball ball = world.getEntities().stream().filter(Snowball.class::isInstance).map(Snowball.class::cast).findFirst().orElseThrow();
assertNotNull(pet.fetch());
ball.teleport(new Location(world, 4, 64, 0));
fire(new ProjectileHitEvent(ball));

Check warning on line 406 in src/test/java/net/tfminecraft/companionpets/listen/PetListenerCoverageTest.java

View workflow job for this annotation

GitHub Actions / build

ProjectileHitEvent(org.bukkit.entity.Projectile) in org.bukkit.event.entity.ProjectileHitEvent has been deprecated and marked for removal
assertFalse(ball.isValid());
assertEquals(net.tfminecraft.companionpets.play.FetchPhase.GROUND, pet.fetch().phase());
Item item = (Item) Bukkit.getEntity(pet.fetch().itemId());
assertNotNull(item);
assertEquals(Material.STICK, item.getItemStack().getType());
assertTrue(fire(new PlayerAttemptPickupItemEvent(owner, item)).isCancelled());

Check warning on line 412 in src/test/java/net/tfminecraft/companionpets/listen/PetListenerCoverageTest.java

View workflow job for this annotation

GitHub Actions / build

PlayerAttemptPickupItemEvent(org.bukkit.entity.Player,org.bukkit.entity.Item) in org.bukkit.event.player.PlayerAttemptPickupItemEvent has been deprecated and marked for removal
assertTrue(fire(new EntityPickupItemEvent(body, item, 0)).isCancelled());
assertTrue(fire(new EntityPickupItemEvent(server.addPlayer(), item, 0)).isCancelled());
}

@Test void unrelatedProjectilesAndItemsKeepTheirNormalBehavior() {
Snowball snowball = world.spawn(owner.getEyeLocation(), Snowball.class);
fire(new ProjectileHitEvent(snowball));

Check warning on line 419 in src/test/java/net/tfminecraft/companionpets/listen/PetListenerCoverageTest.java

View workflow job for this annotation

GitHub Actions / build

ProjectileHitEvent(org.bukkit.entity.Projectile) in org.bukkit.event.entity.ProjectileHitEvent has been deprecated and marked for removal
assertTrue(snowball.isValid());
var arrow = world.spawn(owner.getEyeLocation(), Arrow.class);
fire(new ProjectileHitEvent(arrow));
Expand Down
Loading