diff --git a/plugins/fancyholograms-v2/api/src/main/java/de/oliver/fancyholograms/api/data/HologramData.java b/plugins/fancyholograms-v2/api/src/main/java/de/oliver/fancyholograms/api/data/HologramData.java index 3c14aa36..2cd84b08 100644 --- a/plugins/fancyholograms-v2/api/src/main/java/de/oliver/fancyholograms/api/data/HologramData.java +++ b/plugins/fancyholograms-v2/api/src/main/java/de/oliver/fancyholograms/api/data/HologramData.java @@ -12,6 +12,7 @@ import java.util.Objects; import java.util.Optional; +import java.util.regex.Pattern; public class HologramData implements YamlData { @@ -28,6 +29,7 @@ public class HologramData implements YamlData { private Visibility visibility = DEFAULT_VISIBILITY; private boolean persistent = DEFAULT_PERSISTENCE; private String linkedNpcName; + private String worldPattern; /** * @param name Name of hologram @@ -134,6 +136,23 @@ public HologramData setLinkedNpcName(String linkedNpcName) { return this; } + public String getWorldPattern() { + return worldPattern; + } + + public HologramData setWorldPattern(String worldPattern) { + this.worldPattern = worldPattern; + return this; + } + + public boolean matchesWorld(World world) { + if (worldPattern == null || !worldPattern.contains("*") && !worldPattern.contains("?") && !worldPattern.contains("[") && !worldPattern.contains("{")) { + return location.getWorld().equals(world); + } + Pattern pattern = Pattern.compile(worldPattern.replace("*", ".*").replace("?", ".")); + return pattern.matcher(world.getName()).matches(); + } + @Override public boolean read(ConfigurationSection section, String name) { String worldName = section.getString("location.world", "world"); @@ -143,13 +162,30 @@ public boolean read(ConfigurationSection section, String name) { float yaw = (float) section.getDouble("location.yaw", 0); float pitch = (float) section.getDouble("location.pitch", 0); - World world = Bukkit.getWorld(worldName); - if (world == null) { - FancyHologramsPlugin.get().getFancyLogger().warn("Could not load hologram '" + name + "', because the world '" + worldName + "' is not loaded"); - return false; + if (worldName.contains("*") || worldName.contains("?") || worldName.contains("[") || worldName.contains("{")) { + this.worldPattern = worldName; + World firstMatchingWorld = null; + Pattern pattern = Pattern.compile(worldName.replace("*", ".*").replace("?", ".")); + for (World w : Bukkit.getWorlds()) { + if (pattern.matcher(w.getName()).matches()) { + firstMatchingWorld = w; + break; + } + } + if (firstMatchingWorld == null) { + FancyHologramsPlugin.get().getFancyLogger().warn("Could not load hologram '" + name + "', because no world matching pattern '" + worldName + "' is loaded"); + return false; + } + location = new Location(firstMatchingWorld, x, y, z, yaw, pitch); + } else { + World world = Bukkit.getWorld(worldName); + if (world == null) { + FancyHologramsPlugin.get().getFancyLogger().warn("Could not load hologram '" + name + "', because the world '" + worldName + "' is not loaded"); + return false; + } + location = new Location(world, x, y, z, yaw, pitch); } - location = new Location(world, x, y, z, yaw, pitch); visibilityDistance = section.getInt("visibility_distance", DEFAULT_VISIBILITY_DISTANCE); visibility = Optional.ofNullable(section.getString("visibility")) .flatMap(Visibility::byString) @@ -165,7 +201,7 @@ public boolean read(ConfigurationSection section, String name) { @Override public boolean write(ConfigurationSection section, String name) { section.set("type", type.name()); - section.set("location.world", location.getWorld().getName()); + section.set("location.world", worldPattern != null ? worldPattern : location.getWorld().getName()); section.set("location.x", location.x()); section.set("location.y", location.y()); section.set("location.z", location.z()); @@ -185,6 +221,7 @@ public HologramData copy(String name) { .setVisibilityDistance(this.getVisibilityDistance()) .setVisibility(this.getVisibility()) .setPersistent(this.isPersistent()) - .setLinkedNpcName(this.getLinkedNpcName()); + .setLinkedNpcName(this.getLinkedNpcName()) + .setWorldPattern(this.getWorldPattern()); } } diff --git a/plugins/fancyholograms-v2/api/src/main/java/de/oliver/fancyholograms/api/hologram/Hologram.java b/plugins/fancyholograms-v2/api/src/main/java/de/oliver/fancyholograms/api/hologram/Hologram.java index 48cacb90..d65f2d3d 100644 --- a/plugins/fancyholograms-v2/api/src/main/java/de/oliver/fancyholograms/api/hologram/Hologram.java +++ b/plugins/fancyholograms-v2/api/src/main/java/de/oliver/fancyholograms/api/hologram/Hologram.java @@ -273,11 +273,11 @@ public boolean meetsVisibilityConditions(@NotNull final Player player) { } public boolean isWithinVisibilityDistance(@NotNull final Player player) { - final var location = getData().getLocation(); - if (!location.getWorld().equals(player.getWorld())) { + if (!data.matchesWorld(player.getWorld())) { return false; } + final var location = getData().getLocation(); int visibilityDistance = data.getVisibilityDistance(); double distanceSquared = location.distanceSquared(player.getLocation()); diff --git a/plugins/fancyholograms-v2/src/main/java/de/oliver/fancyholograms/hologram/version/HologramImpl.java b/plugins/fancyholograms-v2/src/main/java/de/oliver/fancyholograms/hologram/version/HologramImpl.java index 20325f56..40b079e4 100644 --- a/plugins/fancyholograms-v2/src/main/java/de/oliver/fancyholograms/hologram/version/HologramImpl.java +++ b/plugins/fancyholograms-v2/src/main/java/de/oliver/fancyholograms/hologram/version/HologramImpl.java @@ -142,7 +142,7 @@ public boolean show(@NotNull final Player player) { return false; // could not be created, nothing to show } - if (!data.getLocation().getWorld().getName().equals(player.getLocation().getWorld().getName())) { + if (!data.matchesWorld(player.getWorld())) { return false; } diff --git a/plugins/fancynpcs/src/main/java/de/oliver/fancynpcs/NpcManagerImpl.java b/plugins/fancynpcs/src/main/java/de/oliver/fancynpcs/NpcManagerImpl.java index 63062333..35537efb 100644 --- a/plugins/fancynpcs/src/main/java/de/oliver/fancynpcs/NpcManagerImpl.java +++ b/plugins/fancynpcs/src/main/java/de/oliver/fancynpcs/NpcManagerImpl.java @@ -32,6 +32,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; +import java.util.regex.Pattern; public class NpcManagerImpl implements NpcManager { @@ -248,28 +249,6 @@ public void loadNpcs() { logger.warn("Could not load location for npc '" + id + "'"); } - if (location == null) { - String worldName = npcConfig.getString("npcs." + id + ".location.world"); - World world = Bukkit.getWorld(worldName); - - if (world == null) { - world = (!ServerSoftware.isFolia()) ? new WorldCreator(worldName).createWorld() : null; - } - - if (world == null) { - logger.info("Could not load npc '" + id + "', because the world '" + worldName + "' is not loaded"); - continue; - } - - double x = npcConfig.getDouble("npcs." + id + ".location.x"); - double y = npcConfig.getDouble("npcs." + id + ".location.y"); - double z = npcConfig.getDouble("npcs." + id + ".location.z"); - float yaw = (float) npcConfig.getDouble("npcs." + id + ".location.yaw"); - float pitch = (float) npcConfig.getDouble("npcs." + id + ".location.pitch"); - - location = new Location(world, x, y, z, yaw, pitch); - } - SkinData skin = null; String skinIdentifier = npcConfig.getString("npcs." + id + ".skin.identifier", npcConfig.getString("npcs." + id + ".skin.uuid", "")); String skinVariantStr = npcConfig.getString("npcs." + id + ".skin.variant", SkinData.SkinVariant.AUTO.name()); @@ -310,6 +289,89 @@ public void loadNpcs() { boolean turnToPlayer = npcConfig.getBoolean("npcs." + id + ".turnToPlayer"); int turnToPlayerDistance = npcConfig.getInt("npcs." + id + ".turnToPlayerDistance", -1); + if (location == null) { + String worldName = npcConfig.getString("npcs." + id + ".location.world"); + + List matchingWorlds = new ArrayList<>(); + if (worldName.contains("*") || worldName.contains("?") || worldName.contains("[") || worldName.contains("{")) { + Pattern worldPattern = Pattern.compile(worldName.replace("*", ".*").replace("?", ".")); + for (World w : Bukkit.getWorlds()) { + if (worldPattern.matcher(w.getName()).matches()) { + matchingWorlds.add(w); + } + } + } else { + World world = Bukkit.getWorld(worldName); + if (world == null) { + world = (!ServerSoftware.isFolia()) ? new WorldCreator(worldName).createWorld() : null; + } + if (world != null) { + matchingWorlds.add(world); + } + } + + if (matchingWorlds.isEmpty()) { + logger.info("Could not load npc '" + id + "', because no world matching '" + worldName + "' is loaded"); + continue; + } + + double x = npcConfig.getDouble("npcs." + id + ".location.x"); + double y = npcConfig.getDouble("npcs." + id + ".location.y"); + double z = npcConfig.getDouble("npcs." + id + ".location.z"); + float yaw = (float) npcConfig.getDouble("npcs." + id + ".location.yaw"); + float pitch = (float) npcConfig.getDouble("npcs." + id + ".location.pitch"); + + for (World world : matchingWorlds) { + Location loc = new Location(world, x, y, z, yaw, pitch); + + Map> actionsForWorld = new ConcurrentHashMap<>(); + for (Map.Entry> entry : actions.entrySet()) { + actionsForWorld.put(entry.getKey(), new ArrayList<>(entry.getValue())); + } + + Map attributesForWorld = new HashMap<>(attributes); + + NpcData data = new NpcData( + matchingWorlds.size() > 1 ? id + "_" + world.getName() : id, + name, + creator, + displayName, + skin, + loc, + showInTab, + spawnEntity, + collidable, + glowing, + glowingColor, + type, + new HashMap<>(), + turnToPlayer, + turnToPlayerDistance, + null, + actionsForWorld, + interactionCooldown, + scale, + visibilityDistance, + attributesForWorld, + mirrorSkin + ); + + Npc npc = npcAdapter.apply(data); + + if (npcConfig.isConfigurationSection("npcs." + id + ".equipment")) { + for (String equipmentSlotStr : npcConfig.getConfigurationSection("npcs." + id + ".equipment").getKeys(false)) { + NpcEquipmentSlot equipmentSlot = NpcEquipmentSlot.parse(equipmentSlotStr); + ItemStack item = npcConfig.getItemStack("npcs." + id + ".equipment." + equipmentSlotStr); + npc.getData().addEquipment(equipmentSlot, item); + } + } + + npc.create(); + registerNpc(npc); + } + continue; + } + Map> actions = new ConcurrentHashMap<>(); //TODO: remove these fields next version