From 1e80b0b217a11753d3fc6f7d569f38b9b7e96f1e Mon Sep 17 00:00:00 2001 From: Pyrbu Date: Tue, 28 May 2024 22:42:43 +0200 Subject: [PATCH] fix multiple null errors with unloaded worlds --- .../pyr/znpcsplus/commands/CloneCommand.java | 48 +++++++++++++++++++ .../pyr/znpcsplus/commands/MoveCommand.java | 3 +- .../pyr/znpcsplus/commands/NearCommand.java | 6 ++- .../java/lol/pyr/znpcsplus/npc/NpcImpl.java | 14 ++++-- .../pyr/znpcsplus/npc/NpcRegistryImpl.java | 34 +++++++++++++ 5 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 plugin/src/main/java/lol/pyr/znpcsplus/commands/CloneCommand.java diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/CloneCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/CloneCommand.java new file mode 100644 index 0000000..de1ceaa --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/CloneCommand.java @@ -0,0 +1,48 @@ +package lol.pyr.znpcsplus.commands; + +import lol.pyr.director.adventure.command.CommandContext; +import lol.pyr.director.adventure.command.CommandHandler; +import lol.pyr.director.common.command.CommandExecutionException; +import lol.pyr.znpcsplus.npc.NpcEntryImpl; +import lol.pyr.znpcsplus.npc.NpcRegistryImpl; +import lol.pyr.znpcsplus.npc.NpcTypeImpl; +import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl; +import lol.pyr.znpcsplus.util.NpcLocation; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; + +import java.util.Collections; +import java.util.List; + +public class CloneCommand implements CommandHandler { + private final NpcRegistryImpl npcRegistry; + private final NpcTypeRegistryImpl typeRegistry; + + public CloneCommand(NpcRegistryImpl npcRegistry, NpcTypeRegistryImpl typeRegistry) { + this.npcRegistry = npcRegistry; + this.typeRegistry = typeRegistry; + } + + @Override + public void run(CommandContext context) throws CommandExecutionException { + context.setUsage(context.getLabel() + " create "); + Player player = context.ensureSenderIsPlayer(); + + String id = context.popString(); + if (npcRegistry.getById(id) != null) context.halt(Component.text("NPC with that ID already exists.", NamedTextColor.RED)); + NpcTypeImpl type = context.parse(NpcTypeImpl.class); + + NpcEntryImpl entry = npcRegistry.create(id, player.getWorld(), type, new NpcLocation(player.getLocation())); + entry.enableEverything(); + + context.send(Component.text("Created a " + type.getName() + " NPC with ID " + id + ".", NamedTextColor.GREEN)); + } + + @Override + public List suggest(CommandContext context) throws CommandExecutionException { + if (context.argSize() == 1) return context.suggestCollection(npcRegistry.getModifiableIds()); + if (context.argSize() == 2) return context.suggestStream(typeRegistry.getAllImpl().stream().map(NpcTypeImpl::getName)); + return Collections.emptyList(); + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/MoveCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/MoveCommand.java index dc87abb..452cf44 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/commands/MoveCommand.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/MoveCommand.java @@ -13,6 +13,7 @@ import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; +import java.util.Objects; public class MoveCommand implements CommandHandler { private final NpcRegistryImpl npcRegistry; @@ -27,7 +28,7 @@ public class MoveCommand implements CommandHandler { Player player = context.ensureSenderIsPlayer(); NpcImpl npc = context.parse(NpcEntryImpl.class).getNpc(); npc.setLocation(new NpcLocation(player.getLocation())); - if (!npc.getWorld().equals(player.getWorld())) npc.setWorld(player.getWorld()); + if (!Objects.equals(npc.getWorld(), player.getWorld())) npc.setWorld(player.getWorld()); context.send(Component.text("NPC moved to your current location.", NamedTextColor.GREEN)); } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/commands/NearCommand.java b/plugin/src/main/java/lol/pyr/znpcsplus/commands/NearCommand.java index 1d62104..6f965f7 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/commands/NearCommand.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/commands/NearCommand.java @@ -10,6 +10,7 @@ import lol.pyr.znpcsplus.util.NpcLocation; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Location; import org.bukkit.entity.Player; import java.util.List; @@ -32,7 +33,10 @@ public class NearCommand implements CommandHandler { List entries = npcRegistry.getAllModifiable().stream() .filter(entry -> Objects.equals(entry.getNpc().getWorld(), player.getWorld())) - .filter(entry -> entry.getNpc().getBukkitLocation().distanceSquared(player.getLocation()) < radius) + .filter(entry -> { + Location loc = entry.getNpc().getBukkitLocation(); + return loc != null && loc.distanceSquared(player.getLocation()) < radius; + }) .collect(Collectors.toList()); if (entries.isEmpty()) context.halt(Component.text("There are no npcs within " + raw + " blocks around you.", NamedTextColor.RED)); diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcImpl.java index 7aa8539..6784dea 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcImpl.java @@ -20,6 +20,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.stream.Collectors; @@ -75,8 +76,10 @@ public class NpcImpl extends Viewable implements Npc { return location; } - public Location getBukkitLocation() { - return location.toBukkitLocation(getWorld()); + public @Nullable Location getBukkitLocation() { + World world = getWorld(); + if (world == null) return null; + return location.toBukkitLocation(world); } public void setLocation(NpcLocation location) { @@ -112,7 +115,7 @@ public class NpcImpl extends Viewable implements Npc { return uuid; } - public World getWorld() { + public @Nullable World getWorld() { return Bukkit.getWorld(worldName); } @@ -182,6 +185,11 @@ public class NpcImpl extends Viewable implements Npc { setProperty((EntityPropertyImpl) property, (T) value); } + @SuppressWarnings("unchecked") + public void UNSAFE_setProperty(EntityProperty property, Object value) { + setProperty((EntityPropertyImpl) property, (T) value); + } + public Set> getAllProperties() { return Collections.unmodifiableSet(propertyMap.keySet()); } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcRegistryImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcRegistryImpl.java index 3b760e6..bcdea13 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcRegistryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcRegistryImpl.java @@ -1,12 +1,17 @@ package lol.pyr.znpcsplus.npc; import lol.pyr.znpcsplus.ZNpcsPlus; +import lol.pyr.znpcsplus.api.entity.EntityProperty; import lol.pyr.znpcsplus.api.npc.NpcEntry; import lol.pyr.znpcsplus.api.npc.NpcRegistry; import lol.pyr.znpcsplus.api.npc.NpcType; import lol.pyr.znpcsplus.config.ConfigManager; import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; +import lol.pyr.znpcsplus.hologram.HologramItem; +import lol.pyr.znpcsplus.hologram.HologramLine; +import lol.pyr.znpcsplus.hologram.HologramText; import lol.pyr.znpcsplus.interaction.ActionRegistry; +import lol.pyr.znpcsplus.interaction.InteractionActionImpl; import lol.pyr.znpcsplus.packets.PacketFactory; import lol.pyr.znpcsplus.scheduling.TaskScheduler; import lol.pyr.znpcsplus.storage.NpcStorage; @@ -153,6 +158,35 @@ public class NpcRegistryImpl implements NpcRegistry { return entry; } + public NpcEntryImpl clone(String id, String newId, World newWorld, NpcLocation newLocation) { + NpcEntryImpl oldNpc = getById(id); + if (oldNpc == null) return null; + NpcEntryImpl newNpc = create(newId, newWorld, oldNpc.getNpc().getType(), newLocation); + newNpc.enableEverything(); + + for (EntityProperty property : oldNpc.getNpc().getAllProperties()) { + newNpc.getNpc().UNSAFE_setProperty(property, oldNpc.getNpc().getProperty(property)); + } + + for (InteractionActionImpl action : oldNpc.getNpc().getActions()) { + newNpc.getNpc().addAction(action); + } + + for (HologramLine line : oldNpc.getNpc().getHologram().getLines()) { + if (line instanceof HologramText) { + HologramText text = (HologramText) line; + newNpc.getNpc().getHologram().addTextLineComponent(text.getValue()); + } + else if (line instanceof HologramItem) { + HologramItem item = (HologramItem) line; + newNpc.getNpc().getHologram().addItemLinePEStack(item.getValue()); + } + else throw new IllegalArgumentException("Unknown hologram line type during clone"); + } + + return newNpc; + } + @Override public void delete(String id) { NpcEntryImpl entry = npcIdLookupMap.get(id.toLowerCase());