diff --git a/arena/src/main/java/eu/mhsl/craftattack/spawn/arena/appliances/arena/Arena.java b/arena/src/main/java/eu/mhsl/craftattack/spawn/arena/appliances/arena/Arena.java index fb72f05..6d3baa1 100644 --- a/arena/src/main/java/eu/mhsl/craftattack/spawn/arena/appliances/arena/Arena.java +++ b/arena/src/main/java/eu/mhsl/craftattack/spawn/arena/appliances/arena/Arena.java @@ -20,6 +20,7 @@ import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.World; import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.entity.Villager; import org.bukkit.event.Listener; @@ -104,6 +105,7 @@ public class Arena extends Appliance { else Main.logger().warning("Arena: pads are not set up, fights cannot be started"); this.syncRegions().forEach(region -> this.worlds.keepLoaded(region, Main.instance())); + this.removeStrayVillagers(); this.placeStarterPlatform(); this.syncAll(); @@ -178,6 +180,25 @@ public class Arena extends Appliance { .forEach(this::toTribune); } + /** + * Removes old copies of the return villager, for example after its position was changed in the config by hand. + */ + private void removeStrayVillagers() { + Region region = this.settings.syncRegion(); + if(region == null || this.villager == null) return; + UUID current = this.villager.getUniqueId(); + for(int cx = region.minChunkX(); cx <= region.maxChunkX(); cx++) { + for(int cz = region.minChunkZ(); cz <= region.maxChunkZ(); cz++) { + for(Entity entity : this.worlds.play().getChunkAt(cx, cz).getEntities()) { + if(!(entity instanceof Villager) || entity.getUniqueId().equals(current)) continue; + if(!entity.getScoreboardTags().contains(Displays.MANAGED_TAG)) continue; + entity.remove(); + Main.logger().info("Arena: removed a stray return villager at " + entity.getLocation().toVector()); + } + } + } + } + /** * A fresh, empty world gets a small platform at the tribune spawn, so the first visitors do not fall into the void. */ diff --git a/core/src/main/java/eu/mhsl/craftattack/spawn/core/util/entity/DisplayVillager.java b/core/src/main/java/eu/mhsl/craftattack/spawn/core/util/entity/DisplayVillager.java index 8970b21..e770052 100644 --- a/core/src/main/java/eu/mhsl/craftattack/spawn/core/util/entity/DisplayVillager.java +++ b/core/src/main/java/eu/mhsl/craftattack/spawn/core/util/entity/DisplayVillager.java @@ -8,6 +8,7 @@ import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.EntityType; import org.bukkit.entity.Villager; +import java.util.Arrays; import java.util.Objects; import java.util.UUID; import java.util.function.Consumer; @@ -19,11 +20,14 @@ public class DisplayVillager { public DisplayVillager(UUID uuid, Location location, Consumer villagerCreator) { this.location = location; - try { - ChunkUtils.loadChunkAtLocation(this.location); - this.villager = (Villager) this.location.getWorld().getEntity(uuid); - Objects.requireNonNull(this.villager); - } catch(NullPointerException | IllegalArgumentException e) { + // getEntities() waits for the chunk's entities; getEntity(uuid) misses them while they are still loading + this.villager = Arrays.stream(ChunkUtils.loadChunkAtLocation(this.location).getEntities()) + .filter(entity -> entity.getUniqueId().equals(uuid)) + .filter(Villager.class::isInstance) + .map(Villager.class::cast) + .findFirst() + .orElse(null); + if(this.villager == null) { this.villager = this.getBaseVillager(); villagerCreator.accept(this.villager); }