diff --git a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaLoader.java b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaLoader.java index afd475dbc..242de37ad 100644 --- a/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaLoader.java +++ b/bukkit/src/main/java/us/myles/ViaVersion/bukkit/platform/BukkitViaLoader.java @@ -1,10 +1,11 @@ package us.myles.ViaVersion.bukkit.platform; -import lombok.AllArgsConstructor; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.scheduler.BukkitTask; import us.myles.ViaVersion.ViaVersionPlugin; import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.data.UserConnection; @@ -21,43 +22,60 @@ import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTransla import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.HandItemProvider; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; -@AllArgsConstructor public class BukkitViaLoader implements ViaPlatformLoader { private ViaVersionPlugin plugin; + private Set listeners = new HashSet<>(); + private Set tasks = new HashSet<>(); + + public BukkitViaLoader(ViaVersionPlugin plugin) { + this.plugin = plugin; + } + + public void registerListener(Listener listener) { + Bukkit.getPluginManager().registerEvents(storeListener(listener), plugin); + } + + public T storeListener(T listener) { + listeners.add(listener); + return listener; + } + @Override public void load() { // Update Listener - Bukkit.getPluginManager().registerEvents(new UpdateListener(), plugin); + registerListener(new UpdateListener()); /* Base Protocol */ final ViaVersionPlugin plugin = (ViaVersionPlugin) Bukkit.getPluginManager().getPlugin("ViaVersion"); - Bukkit.getPluginManager().registerEvents(new Listener() { + registerListener(new Listener() { @EventHandler public void onPlayerQuit(PlayerQuitEvent e) { Via.getManager().removePortedClient(e.getPlayer().getUniqueId()); } - }, plugin); + }); /* 1.9 client to 1.8 server */ - new ArmorListener(plugin).register(); - new DeathListener(plugin).register(); - new BlockListener(plugin).register(); + storeListener(new ArmorListener(plugin)).register(); + storeListener(new DeathListener(plugin)).register(); + storeListener(new BlockListener(plugin)).register(); if (Bukkit.getVersion().toLowerCase().contains("paper") || Bukkit.getVersion().toLowerCase().contains("taco") || Bukkit.getVersion().toLowerCase().contains("torch")) { plugin.getLogger().info("Enabling PaperSpigot/TacoSpigot/Torch patch: Fixes block placement."); - new PaperPatch(plugin).register(); + storeListener(new PaperPatch(plugin)).register(); } if (plugin.getConf().isItemCache()) { - new HandItemCache().runTaskTimerAsynchronously(plugin, 2L, 2L); // Updates player's items :) + tasks.add(new HandItemCache().runTaskTimerAsynchronously(plugin, 2L, 2L)); // Updates player's items :) HandItemCache.CACHE = true; } @@ -95,4 +113,17 @@ public class BukkitViaLoader implements ViaPlatformLoader { }); } + + @Override + public void unload() { + // todo restore providers + for (Listener listener : listeners) { + HandlerList.unregisterAll(listener); + } + listeners.clear(); + for (BukkitTask task : tasks) { + task.cancel(); + } + tasks.clear(); + } } diff --git a/bungee/src/main/java/us/myles/ViaVersion/bungee/platform/BungeeViaLoader.java b/bungee/src/main/java/us/myles/ViaVersion/bungee/platform/BungeeViaLoader.java index 6635d2eca..428643bfe 100644 --- a/bungee/src/main/java/us/myles/ViaVersion/bungee/platform/BungeeViaLoader.java +++ b/bungee/src/main/java/us/myles/ViaVersion/bungee/platform/BungeeViaLoader.java @@ -1,7 +1,8 @@ package us.myles.ViaVersion.bungee.platform; -import lombok.AllArgsConstructor; import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.api.scheduler.ScheduledTask; import us.myles.ViaVersion.BungeePlugin; import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.platform.ViaPlatformLoader; @@ -19,20 +20,33 @@ import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BossBarProvider; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.EntityIdProvider; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.TimeUnit; -@AllArgsConstructor public class BungeeViaLoader implements ViaPlatformLoader { private BungeePlugin plugin; + private Set listeners = new HashSet<>(); + private Set tasks = new HashSet<>(); + + public BungeeViaLoader(BungeePlugin plugin) { + this.plugin = plugin; + } + + private void registerListener(Listener listener) { + listeners.add(listener); + ProxyServer.getInstance().getPluginManager().registerListener(plugin, listener); + } + @Override public void load() { // Listeners - ProxyServer.getInstance().getPluginManager().registerListener(plugin, plugin); - ProxyServer.getInstance().getPluginManager().registerListener(plugin, new UpdateListener()); - ProxyServer.getInstance().getPluginManager().registerListener(plugin, new BungeeServerHandler()); - ProxyServer.getInstance().getPluginManager().registerListener(plugin, new MainHandPatch()); - ProxyServer.getInstance().getPluginManager().registerListener(plugin, new ElytraPatch()); + registerListener(plugin); + registerListener(new UpdateListener()); + registerListener(new BungeeServerHandler()); + registerListener(new MainHandPatch()); + registerListener(new ElytraPatch()); // Providers Via.getManager().getProviders().use(MovementTransmitterProvider.class, new BungeeMovementTransmitter()); @@ -41,7 +55,24 @@ public class BungeeViaLoader implements ViaPlatformLoader { Via.getManager().getProviders().use(BossBarProvider.class, new BungeeBossBarProvider()); if (plugin.getConf().getBungeePingInterval() > 0) { - plugin.getProxy().getScheduler().schedule(plugin, new ProtocolDetectorService(plugin), 0, plugin.getConf().getBungeePingInterval(), TimeUnit.SECONDS); + tasks.add(plugin.getProxy().getScheduler().schedule( + plugin, + new ProtocolDetectorService(plugin), + 0, plugin.getConf().getBungeePingInterval(), + TimeUnit.SECONDS + )); } } + + @Override + public void unload() { + for (Listener listener : listeners) { + ProxyServer.getInstance().getPluginManager().unregisterListener(listener); + } + listeners.clear(); + for (ScheduledTask task : tasks) { + task.cancel(); + } + tasks.clear(); + } } diff --git a/common/src/main/java/us/myles/ViaVersion/ViaManager.java b/common/src/main/java/us/myles/ViaVersion/ViaManager.java index 8df0bf6aa..a733cbb94 100644 --- a/common/src/main/java/us/myles/ViaVersion/ViaManager.java +++ b/common/src/main/java/us/myles/ViaVersion/ViaManager.java @@ -102,6 +102,9 @@ public class ViaManager { getPlatform().getLogger().severe("ViaVersion failed to uninject:"); e.printStackTrace(); } + + // Unload + loader.unload(); } public void addPortedClient(UserConnection info) { diff --git a/common/src/main/java/us/myles/ViaVersion/api/platform/ViaPlatformLoader.java b/common/src/main/java/us/myles/ViaVersion/api/platform/ViaPlatformLoader.java index e8c4503bf..68930aebc 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/platform/ViaPlatformLoader.java +++ b/common/src/main/java/us/myles/ViaVersion/api/platform/ViaPlatformLoader.java @@ -5,4 +5,6 @@ public interface ViaPlatformLoader { * Initialise the loading for a platform, eg. registering listeners / providers / events etc. */ void load(); + + void unload(); } diff --git a/sponge/src/main/java/us/myles/ViaVersion/SpongePlugin.java b/sponge/src/main/java/us/myles/ViaVersion/SpongePlugin.java index b20365674..dd2ea5b66 100644 --- a/sponge/src/main/java/us/myles/ViaVersion/SpongePlugin.java +++ b/sponge/src/main/java/us/myles/ViaVersion/SpongePlugin.java @@ -2,14 +2,19 @@ package us.myles.ViaVersion; import com.google.gson.JsonObject; import com.google.inject.Inject; +import lombok.Getter; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.chat.ComponentSerializer; import org.spongepowered.api.Game; import org.spongepowered.api.config.DefaultConfig; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.game.state.GameAboutToStartServerEvent; +import org.spongepowered.api.event.game.state.GameInitializationEvent; +import org.spongepowered.api.event.game.state.GameStoppingServerEvent; import org.spongepowered.api.plugin.Plugin; import org.spongepowered.api.plugin.PluginContainer; -import org.spongepowered.api.scheduler.SpongeExecutorService; +import org.spongepowered.api.scheduler.Task; import org.spongepowered.api.text.serializer.TextSerializers; import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.ViaAPI; @@ -37,8 +42,7 @@ import java.util.logging.Logger; name = "ViaVersion", version = VersionInfo.VERSION, authors = {"_MylesC", "Matsv"}, - description = "Allow newer Minecraft versions to connect to an older server version.", - dependencies = {} + description = "Allow newer Minecraft versions to connect to an older server version." ) public class SpongePlugin implements ViaPlatform { @Inject @@ -52,22 +56,20 @@ public class SpongePlugin implements ViaPlatform { private File defaultConfig; private SpongeViaAPI api = new SpongeViaAPI(); - private SpongeExecutorService asyncExecutor; - private SpongeExecutorService syncExecutor; private SpongeConfigAPI conf; + + @Getter private Logger logger; @Listener - public void onServerStart(GameAboutToStartServerEvent event) { + public void onGameStart(GameInitializationEvent event) { // Setup Logger logger = new LoggerWrapper(container.getLogger()); // Setup Plugin conf = new SpongeConfigAPI(container, defaultConfig.getParentFile()); - syncExecutor = game.getScheduler().createSyncExecutor(this); - asyncExecutor = game.getScheduler().createAsyncExecutor(this); SpongeCommandHandler commandHandler = new SpongeCommandHandler(); - game.getCommandManager().register(this, commandHandler, Arrays.asList("viaversion", "viaver", "vvsponge")); - getLogger().info("ViaVersion " + getPluginVersion() + " is now loaded, injecting!"); + game.getCommandManager().register(this, commandHandler, "viaversion", "viaver", "vvsponge"); + getLogger().info("ViaVersion " + getPluginVersion() + " is now loaded!"); // Init platform Via.init(ViaManager.builder() .platform(this) @@ -75,14 +77,18 @@ public class SpongePlugin implements ViaPlatform { .injector(new SpongeViaInjector()) .loader(new SpongeViaLoader(this)) .build()); + } + @Listener + public void onServerStart(GameAboutToStartServerEvent event) { // Inject! + logger.info("ViaVersion is injecting!"); Via.getManager().init(); } - @Override - public Logger getLogger() { - return logger; + @Listener + public void onServerStop(GameStoppingServerEvent event) { + Via.getManager().destroy(); } @Override @@ -102,26 +108,41 @@ public class SpongePlugin implements ViaPlatform { @Override public TaskId runAsync(Runnable runnable) { - asyncExecutor.execute(runnable); - return new SpongeTaskId(null); + return new SpongeTaskId( + Task.builder() + .execute(runnable) + .async() + .submit(this) + ); } @Override public TaskId runSync(Runnable runnable) { - syncExecutor.execute(runnable); - return new SpongeTaskId(null); + return new SpongeTaskId( + Task.builder() + .execute(runnable) + .submit(this) + ); } @Override public TaskId runSync(Runnable runnable, Long ticks) { - Long delay = ticks * 50L; - return new SpongeTaskId(syncExecutor.schedule(runnable, delay, TimeUnit.MILLISECONDS).getTask()); + return new SpongeTaskId( + Task.builder() + .execute(runnable) + .delayTicks(ticks) + .submit(this) + ); } @Override public TaskId runRepeatingSync(Runnable runnable, Long ticks) { - Long time = ticks * 50L; - return new SpongeTaskId(syncExecutor.scheduleAtFixedRate(runnable, time, time, TimeUnit.MILLISECONDS).getTask()); + return new SpongeTaskId( + Task.builder() + .execute(runnable) + .intervalTicks(ticks) + .submit(this) + ); } @Override @@ -145,21 +166,24 @@ public class SpongePlugin implements ViaPlatform { @Override public void sendMessage(UUID uuid, String message) { - for (Player player : game.getServer().getOnlinePlayers()) { - if (player.getUniqueId().equals(uuid)) - player.sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(message)); - } + game.getServer().getPlayer(uuid) + .ifPresent(player -> + player.sendMessage( + TextSerializers.JSON.deserialize( + ComponentSerializer.toString( + TextComponent.fromLegacyText(message) // Hacky way to fix links + ) + ) + ) + ); } @Override public boolean kickPlayer(UUID uuid, String message) { - for (Player player : game.getServer().getOnlinePlayers()) { - if (player.getUniqueId().equals(uuid)) { - player.kick(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(message)); - return true; - } - } - return false; + return game.getServer().getPlayer(uuid).map(player -> { + player.kick(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(message)); + return true; + }).orElse(false); } @Override diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/commands/SpongeCommandSender.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/commands/SpongeCommandSender.java index b095c90bf..915b2841b 100644 --- a/sponge/src/main/java/us/myles/ViaVersion/sponge/commands/SpongeCommandSender.java +++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/commands/SpongeCommandSender.java @@ -1,9 +1,11 @@ package us.myles.ViaVersion.sponge.commands; import lombok.AllArgsConstructor; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.chat.ComponentSerializer; import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.serializer.TextSerializers; +import org.spongepowered.api.util.Identifiable; import us.myles.ViaVersion.api.command.ViaCommandSender; import java.util.UUID; @@ -19,16 +21,23 @@ public class SpongeCommandSender implements ViaCommandSender { @Override public void sendMessage(String msg) { - source.sendMessage(TextSerializers.LEGACY_FORMATTING_CODE.deserialize(msg)); + source.sendMessage( + TextSerializers.JSON.deserialize( + ComponentSerializer.toString( + TextComponent.fromLegacyText(msg) // Hacky way to fix links + ) + ) + ); } @Override public UUID getUUID() { - if (source instanceof Player) { - return ((Player) source).getUniqueId(); + if (source instanceof Identifiable) { + return ((Identifiable) source).getUniqueId(); } else { return UUID.fromString(getName()); } + } @Override diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/handlers/SpongeChannelInitializer.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/handlers/SpongeChannelInitializer.java index 319f9e26e..99eb3af6b 100644 --- a/sponge/src/main/java/us/myles/ViaVersion/sponge/handlers/SpongeChannelInitializer.java +++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/handlers/SpongeChannelInitializer.java @@ -5,18 +5,20 @@ import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.MessageToByteEncoder; +import lombok.Getter; import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.api.protocol.ProtocolPipeline; import us.myles.ViaVersion.api.protocol.ProtocolRegistry; import java.lang.reflect.Method; -public class SpongeChannelInitializer extends ChannelInitializer { +public class SpongeChannelInitializer extends ChannelInitializer { - private final ChannelInitializer original; + @Getter + private final ChannelInitializer original; private Method method; - public SpongeChannelInitializer(ChannelInitializer oldInit) { + public SpongeChannelInitializer(ChannelInitializer oldInit) { this.original = oldInit; try { this.method = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class); @@ -26,29 +28,27 @@ public class SpongeChannelInitializer extends ChannelInitializer } } - public ChannelInitializer getOriginal() { - return original; - } @Override - protected void initChannel(SocketChannel socketChannel) throws Exception { + protected void initChannel(Channel channel) throws Exception { // Ensure ViaVersion is loaded - if (ProtocolRegistry.SERVER_PROTOCOL != -1) { - UserConnection info = new UserConnection(socketChannel); + if (ProtocolRegistry.SERVER_PROTOCOL != -1 + && channel instanceof SocketChannel) { // channel can be LocalChannel on internal server + UserConnection info = new UserConnection((SocketChannel) channel); // init protocol new ProtocolPipeline(info); // Add originals - this.method.invoke(this.original, socketChannel); + this.method.invoke(this.original, channel); // Add our transformers - MessageToByteEncoder encoder = new SpongeEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder")); - ByteToMessageDecoder decoder = new SpongeDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder")); + MessageToByteEncoder encoder = new SpongeEncodeHandler(info, (MessageToByteEncoder) channel.pipeline().get("encoder")); + ByteToMessageDecoder decoder = new SpongeDecodeHandler(info, (ByteToMessageDecoder) channel.pipeline().get("decoder")); SpongePacketHandler chunkHandler = new SpongePacketHandler(info); - socketChannel.pipeline().replace("encoder", "encoder", encoder); - socketChannel.pipeline().replace("decoder", "decoder", decoder); - socketChannel.pipeline().addAfter("packet_handler", "viaversion_packet_handler", chunkHandler); + channel.pipeline().replace("encoder", "encoder", encoder); + channel.pipeline().replace("decoder", "decoder", decoder); + channel.pipeline().addAfter("packet_handler", "viaversion_packet_handler", chunkHandler); } else { - this.method.invoke(this.original, socketChannel); + this.method.invoke(this.original, channel); } } } diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/platform/SpongeViaInjector.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/platform/SpongeViaInjector.java index 530eefadf..0b0a00dc1 100644 --- a/sponge/src/main/java/us/myles/ViaVersion/sponge/platform/SpongeViaInjector.java +++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/platform/SpongeViaInjector.java @@ -1,9 +1,9 @@ package us.myles.ViaVersion.sponge.platform; +import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelInitializer; -import io.netty.channel.socket.SocketChannel; import org.spongepowered.api.MinecraftVersion; import org.spongepowered.api.Sponge; import us.myles.ViaVersion.api.Pair; @@ -86,7 +86,7 @@ public class SpongeViaInjector implements ViaInjector { bootstrapAcceptor = future.channel().pipeline().first(); } try { - ChannelInitializer oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class); + ChannelInitializer oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class); ChannelInitializer newInit = new SpongeChannelInitializer(oldInit); ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit); @@ -111,7 +111,7 @@ public class SpongeViaInjector implements ViaInjector { for (String name : names) { ChannelHandler handler = future.channel().pipeline().get(name); try { - ChannelInitializer oldInit = ReflectionUtil.get(handler, "childHandler", ChannelInitializer.class); + ChannelInitializer oldInit = ReflectionUtil.get(handler, "childHandler", ChannelInitializer.class); if (oldInit instanceof SpongeChannelInitializer) { bootstrapAcceptor = handler; } @@ -125,7 +125,7 @@ public class SpongeViaInjector implements ViaInjector { } try { - ChannelInitializer oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class); + ChannelInitializer oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class); if (oldInit instanceof SpongeChannelInitializer) { ReflectionUtil.set(bootstrapAcceptor, "childHandler", ((SpongeChannelInitializer) oldInit).getOriginal()); } diff --git a/sponge/src/main/java/us/myles/ViaVersion/sponge/platform/SpongeViaLoader.java b/sponge/src/main/java/us/myles/ViaVersion/sponge/platform/SpongeViaLoader.java index 2f6dc51c9..fe1f68756 100644 --- a/sponge/src/main/java/us/myles/ViaVersion/sponge/platform/SpongeViaLoader.java +++ b/sponge/src/main/java/us/myles/ViaVersion/sponge/platform/SpongeViaLoader.java @@ -1,11 +1,11 @@ package us.myles.ViaVersion.sponge.platform; -import lombok.AllArgsConstructor; import org.spongepowered.api.Sponge; import us.myles.ViaVersion.SpongePlugin; import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.api.minecraft.item.Item; +import us.myles.ViaVersion.api.platform.TaskId; import us.myles.ViaVersion.api.platform.ViaPlatformLoader; import us.myles.ViaVersion.protocols.base.ProtocolInfo; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider; @@ -21,28 +21,47 @@ import us.myles.ViaVersion.sponge.listeners.protocol1_9to1_8.sponge5.Sponge5Armo import us.myles.ViaVersion.sponge.providers.SpongeViaBulkChunkTranslator; import us.myles.ViaVersion.sponge.providers.SpongeViaMovementTransmitter; -@AllArgsConstructor +import java.util.HashSet; +import java.util.Set; + public class SpongeViaLoader implements ViaPlatformLoader { + private SpongePlugin plugin; + private Set listeners = new HashSet<>(); + private Set tasks = new HashSet<>(); + + public SpongeViaLoader(SpongePlugin plugin) { + this.plugin = plugin; + } + + private void registerListener(Object listener) { + Sponge.getEventManager().registerListeners(plugin, storeListener(listener)); + } + + private T storeListener(T listener) { + listeners.add(listener); + return listener; + } + @Override public void load() { // Update Listener - Sponge.getEventManager().registerListeners(plugin, new UpdateListener()); + registerListener(new UpdateListener()); /* Base Protocol */ - Sponge.getEventManager().registerListeners(plugin, new ClientLeaveListener()); + registerListener(new ClientLeaveListener()); /* 1.9 client to 1.8 server */ try { Class.forName("org.spongepowered.api.event.entity.DisplaceEntityEvent"); - new Sponge4ArmorListener().register(); + storeListener(new Sponge4ArmorListener()).register(); } catch (ClassNotFoundException e) { - new Sponge5ArmorListener(plugin).register(); + storeListener(new Sponge5ArmorListener(plugin)).register(); } - new DeathListener(plugin).register(); - new BlockListener(plugin).register(); + storeListener(new DeathListener(plugin)).register(); + storeListener(new BlockListener(plugin)).register(); if (plugin.getConf().isItemCache()) { - Via.getPlatform().runRepeatingSync(new HandItemCache(), 2L); // Updates players items :) + tasks.add(Via.getPlatform().runRepeatingSync(new HandItemCache(), 2L)); // Updates players items :) HandItemCache.CACHE = true; } @@ -60,4 +79,12 @@ public class SpongeViaLoader implements ViaPlatformLoader { } }); } -} + + public void unload() { + // todo restore providers + listeners.forEach(Sponge.getEventManager()::unregisterListeners); + listeners.clear(); + tasks.forEach(Via.getPlatform()::cancelTask); + tasks.clear(); + } +} \ No newline at end of file