From c3a70e27edc2549b7bdc9a995e5c635090d65635 Mon Sep 17 00:00:00 2001 From: fullwall Date: Wed, 14 Jul 2021 21:23:55 +0800 Subject: [PATCH] Add workaround for spigot disable issue --- .../main/java/net/citizensnpcs/Citizens.java | 30 ++++++------ .../java/net/citizensnpcs/EventListen.java | 27 +++++++++++ .../citizensnpcs/commands/NPCCommands.java | 25 ++++++++++ .../npc/CitizensTraitFactory.java | 2 + .../net/citizensnpcs/trait/ShopTrait.java | 46 +++++++++++++++++++ 5 files changed, 117 insertions(+), 13 deletions(-) create mode 100644 main/src/main/java/net/citizensnpcs/trait/ShopTrait.java diff --git a/main/src/main/java/net/citizensnpcs/Citizens.java b/main/src/main/java/net/citizensnpcs/Citizens.java index 39d7c2440..09f7f8852 100644 --- a/main/src/main/java/net/citizensnpcs/Citizens.java +++ b/main/src/main/java/net/citizensnpcs/Citizens.java @@ -76,8 +76,8 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { private final List anonymousRegistries = Lists.newArrayList(); private final List citizensBackedRegistries = Lists.newArrayList(); private final CommandManager commands = new CommandManager(); - private boolean compatible; private Settings config; + private boolean loaded; private CitizensNPCRegistry npcRegistry; private NPCDataStore saves; private NPCSelector selector; @@ -145,6 +145,19 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { } } + public void disable() { + if (loaded) { + Bukkit.getPluginManager().callEvent(new CitizensDisableEvent()); + Editor.leaveAll(); + despawnNPCs(true); + npcRegistry = null; + NMS.shutdown(); + loaded = false; + } + + CitizensAPI.shutdown(); + } + private void enableSubPlugins() { File root = new File(getDataFolder(), Setting.SUBPLUGIN_FOLDER.asString()); if (!root.exists() || !root.isDirectory()) @@ -277,16 +290,7 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { @Override public void onDisable() { - Bukkit.getPluginManager().callEvent(new CitizensDisableEvent()); - Editor.leaveAll(); - - if (compatible) { - despawnNPCs(true); - npcRegistry = null; - NMS.shutdown(); - } - - CitizensAPI.shutdown(); + disable(); } @Override @@ -296,11 +300,11 @@ public class Citizens extends JavaPlugin implements CitizensPlugin { setupTranslator(); // Disable if the server is not using the compatible Minecraft version String mcVersion = Util.getMinecraftRevision(); - compatible = true; + loaded = true; try { NMS.loadBridge(mcVersion); } catch (Exception e) { - compatible = false; + loaded = false; if (Messaging.isDebugging()) { e.printStackTrace(); } diff --git a/main/src/main/java/net/citizensnpcs/EventListen.java b/main/src/main/java/net/citizensnpcs/EventListen.java index 06f1ce883..1176e268d 100644 --- a/main/src/main/java/net/citizensnpcs/EventListen.java +++ b/main/src/main/java/net/citizensnpcs/EventListen.java @@ -1,5 +1,6 @@ package net.citizensnpcs; +import java.lang.invoke.MethodHandle; import java.util.Collection; import java.util.List; import java.util.Map; @@ -42,6 +43,7 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.event.vehicle.VehicleDamageEvent; import org.bukkit.event.vehicle.VehicleDestroyEvent; import org.bukkit.event.vehicle.VehicleEnterEvent; @@ -51,6 +53,7 @@ import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; import org.bukkit.inventory.meta.SkullMeta; import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; import com.google.common.base.Predicates; @@ -228,6 +231,28 @@ public class EventListen implements Listener { checkCreationEvent(event); } + @EventHandler + public void onDisable(PluginDisableEvent event) { + // hack: Spigot now unloads plugin classes on disable in reverse order so prefer unloading at the start of + // plugin disable cycle + if (event.getPlugin() instanceof JavaPlugin) { + try { + MethodHandle field = CLASSES_FIELD == null + ? CLASSES_FIELD = NMS.getGetter(event.getPlugin().getPluginLoader().getClass(), "classes") + : CLASSES_FIELD; + Map> classes = (Map>) field + .invoke(event.getPlugin().getPluginLoader()); + if (classes.containsKey("net.citizensnpcs.api.CitizensAPI")) { + CitizensAPI.getPlugin().onDisable(); + } + } catch (Throwable e) { + CitizensAPI.getPlugin().onDisable(); + } + } else { + CitizensAPI.getPlugin().onDisable(); + } + } + /* * Entity events */ @@ -717,4 +742,6 @@ public class EventListen implements Listener { } return npc.spawn(spawn, SpawnReason.CHUNK_LOAD); } + + private static MethodHandle CLASSES_FIELD = null; } diff --git a/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java b/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java index d817571ae..27e7cc313 100644 --- a/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java +++ b/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java @@ -114,6 +114,8 @@ import net.citizensnpcs.trait.RabbitType; import net.citizensnpcs.trait.ScoreboardTrait; import net.citizensnpcs.trait.ScriptTrait; import net.citizensnpcs.trait.SheepTrait; +import net.citizensnpcs.trait.ShopTrait; +import net.citizensnpcs.trait.ShopTrait.NPCShop; import net.citizensnpcs.trait.SkinLayers; import net.citizensnpcs.trait.SkinLayers.Layer; import net.citizensnpcs.trait.SkinTrait; @@ -1919,6 +1921,29 @@ public class NPCCommands { } } + @Command( + aliases = { "npc" }, + usage = "shop (name) (editr)", + desc = "NPC shop edit/show", + modifiers = { "shop" }, + min = 1, + max = 3, + permission = "citizens.npc.shop") + public void shop(CommandContext args, Player sender, NPC npc) throws CommandException { + ShopTrait trait = npc.getOrAddTrait(ShopTrait.class); + if (args.argsLength() > 1) { + NPCShop shop = trait.getShop(args.getString(1)); + if (args.getString(1).equalsIgnoreCase("edit")) { + } else if (args.getString(1).equalsIgnoreCase("show") && args.argsLength() == 3) { + shop.display(sender); + } else { + throw new CommandUsageException(); + } + } else { + trait.getDefaultShop().display(sender); + } + } + @Command( aliases = { "npc" }, usage = "skin (-c -l(atest)) [name] (or --url [url] or -t [uuid/name] [data] [signature])", diff --git a/main/src/main/java/net/citizensnpcs/npc/CitizensTraitFactory.java b/main/src/main/java/net/citizensnpcs/npc/CitizensTraitFactory.java index be0bb4a8c..b34628330 100644 --- a/main/src/main/java/net/citizensnpcs/npc/CitizensTraitFactory.java +++ b/main/src/main/java/net/citizensnpcs/npc/CitizensTraitFactory.java @@ -46,6 +46,7 @@ import net.citizensnpcs.trait.Saddle; import net.citizensnpcs.trait.ScoreboardTrait; import net.citizensnpcs.trait.ScriptTrait; import net.citizensnpcs.trait.SheepTrait; +import net.citizensnpcs.trait.ShopTrait; import net.citizensnpcs.trait.SkinLayers; import net.citizensnpcs.trait.SkinTrait; import net.citizensnpcs.trait.SlimeSize; @@ -92,6 +93,7 @@ public class CitizensTraitFactory implements TraitFactory { registerTrait(TraitInfo.create(SkinTrait.class)); registerTrait(TraitInfo.create(MountTrait.class)); registerTrait(TraitInfo.create(SlimeSize.class)); + registerTrait(TraitInfo.create(ShopTrait.class)); registerTrait(TraitInfo.create(Spawned.class)); registerTrait(TraitInfo.create(Speech.class)); registerTrait(TraitInfo.create(Text.class)); diff --git a/main/src/main/java/net/citizensnpcs/trait/ShopTrait.java b/main/src/main/java/net/citizensnpcs/trait/ShopTrait.java new file mode 100644 index 000000000..be2f0656e --- /dev/null +++ b/main/src/main/java/net/citizensnpcs/trait/ShopTrait.java @@ -0,0 +1,46 @@ +package net.citizensnpcs.trait; + +import java.util.Map; + +import org.bukkit.entity.Player; + +import com.google.common.collect.Maps; + +import net.citizensnpcs.api.persistence.Persist; +import net.citizensnpcs.api.trait.Trait; +import net.citizensnpcs.api.trait.TraitName; + +/** + * Shop trait for NPC GUI shops. + */ +@TraitName("shop") +public class ShopTrait extends Trait { + public ShopTrait() { + super("shop"); + } + + public NPCShop getDefaultShop() { + return NPC_SHOPS.get(npc.getUniqueId().toString()); + } + + public NPCShop getShop(String name) { + return SHOPS.get(name); + } + + public static class NPCShop { + @Persist + String name; + + private NPCShop(String name) { + this.name = name; + } + + public void display(Player sender) { + } + } + + @Persist(value = "npcShops", namespace = "shopstrait") + private static Map NPC_SHOPS = Maps.newHashMap(); + @Persist(value = "namedShops", namespace = "shopstrait") + private static Map SHOPS = Maps.newHashMap(); +} \ No newline at end of file