From a27a26285818fef220d44e11fa6b5dab0d3ad11c Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 10 Oct 2020 00:29:21 +0200 Subject: [PATCH] LPInjector and mcchat fixes Fixed LPInjector registering to the Core Stop MCChatListener from having multiple active instances MinecraftChatModule.state instead of all the flags Showing MinecraftChatModule enable/disable on Discord /discord reset --> restart Wait for each shutdown message to send on shutdown (although it hasn't really been an issue so far) This means using Mono in a lot of places Also added a contract (IntelliJ) to warn if not subscribed Faking getOnlinePlayers() is unnecessary and causes too much trouble Today's work --- README.md | 2 +- .../discordplugin/ChromaBot.java | 10 +- .../discordplugin/DiscordConnectedPlayer.java | 78 +++++++++++++++- .../discordplugin/DiscordPlayer.java | 4 +- .../discordplugin/DiscordPlugin.java | 93 ++++++------------- .../announcer/AnnouncerModule.java | 2 + .../broadcaster/PlayerListWatcher.java | 2 +- .../discordplugin/listeners/MCListener.java | 7 +- .../discordplugin/mcchat/MCChatListener.java | 15 +-- .../discordplugin/mcchat/MCChatPrivate.java | 17 ++-- .../discordplugin/mcchat/MCChatUtils.java | 74 +++++++++------ .../discordplugin/mcchat/MCListener.java | 16 ++-- .../mcchat/MinecraftChatModule.java | 88 +++++++++++++++--- .../mccommands/DiscordMCCommand.java | 21 ++--- .../playerfaker/ServerWatcher.java | 8 +- .../playerfaker/perm/LPInjector.java | 25 ++--- .../discordplugin/util/DPState.java | 24 +++++ 17 files changed, 311 insertions(+), 175 deletions(-) create mode 100644 src/main/java/buttondevteam/discordplugin/util/DPState.java diff --git a/README.md b/README.md index f523f0c..7982e51 100755 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A plugin that provides Minecraft chat functionality and other features. ## Setup This plugin needs Chroma-Core to work. If you have that and this plugin, start the server, and follow the instructions. You'll need a Discord application made, and a bot account created for it. -You can restart the plugin using /discord reset without having to restart the whole server. +You can restart the plugin using /discord restart without having to restart the whole server. ## Building Maven is used to build this project with all of its dependencies. You will need Spigot 1.12.2 and 1.14.4 built using BuildTools. diff --git a/src/main/java/buttondevteam/discordplugin/ChromaBot.java b/src/main/java/buttondevteam/discordplugin/ChromaBot.java index e392fe8..92f0e9d 100755 --- a/src/main/java/buttondevteam/discordplugin/ChromaBot.java +++ b/src/main/java/buttondevteam/discordplugin/ChromaBot.java @@ -15,16 +15,12 @@ public class ChromaBot { * May be null if it's not initialized. Initialization happens after the server is done loading (using {@link BukkitScheduler#runTaskAsynchronously(org.bukkit.plugin.Plugin, Runnable)}) */ private static @Getter ChromaBot instance; - private DiscordPlugin dp; /** * This will set the instance field. - * - * @param dp The Discord plugin */ - ChromaBot(DiscordPlugin dp) { + ChromaBot() { instance = this; - this.dp = dp; } static void delete() { @@ -37,7 +33,7 @@ public class ChromaBot { * @param message The message to send, duh (use {@link MessageChannel#createMessage(String)}) */ public void sendMessage(Function, Mono> message) { - MCChatUtils.forAllMCChat(ch -> message.apply(ch).subscribe()); + MCChatUtils.forPublicPrivateChat(message::apply).subscribe(); } /** @@ -47,7 +43,7 @@ public class ChromaBot { * @param toggle The toggle type for channelcon */ public void sendMessageCustomAsWell(Function, Mono> message, @Nullable ChannelconBroadcast toggle) { - MCChatUtils.forCustomAndAllMCChat(ch -> message.apply(ch).subscribe(), toggle, false); + MCChatUtils.forCustomAndAllMCChat(message::apply, toggle, false).subscribe(); } public void updatePlayerList() { diff --git a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java index 2993126..a41f9fd 100644 --- a/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordConnectedPlayer.java @@ -8,6 +8,8 @@ import discord4j.core.object.entity.channel.MessageChannel; import lombok.Getter; import lombok.Setter; import lombok.experimental.Delegate; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.*; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; @@ -24,10 +26,8 @@ import org.mockito.MockSettings; import org.mockito.Mockito; import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.UUID; +import java.net.InetSocketAddress; +import java.util.*; import static org.mockito.Answers.RETURNS_DEFAULTS; @@ -160,6 +160,11 @@ public abstract class DiscordConnectedPlayer extends DiscordSenderBase implement location.getYaw(), location.getPitch()); } + @Override + public Location getEyeLocation() { + return getLocation(); + } + @Override @Deprecated public double getMaxHealth() { @@ -222,6 +227,71 @@ public abstract class DiscordConnectedPlayer extends DiscordSenderBase implement return GameMode.SPECTATOR; } + private final Player.Spigot spigot = new Player.Spigot() { + @Override + public InetSocketAddress getRawAddress() { + return null; + } + + @Override + public void playEffect(Location location, Effect effect, int id, int data, float offsetX, float offsetY, float offsetZ, float speed, int particleCount, int radius) { + } + + @Override + public boolean getCollidesWithEntities() { + return false; + } + + @Override + public void setCollidesWithEntities(boolean collides) { + } + + @Override + public void respawn() { + } + + @Override + public String getLocale() { + return "en_us"; + } + + @Override + public Set getHiddenPlayers() { + return Collections.emptySet(); + } + + @Override + public void sendMessage(BaseComponent component) { + DiscordConnectedPlayer.super.sendMessage(component.toPlainText()); + } + + @Override + public void sendMessage(BaseComponent... components) { + for (var component : components) + sendMessage(component); + } + + @Override + public void sendMessage(ChatMessageType position, BaseComponent component) { + sendMessage(component); //Ignore position + } + + @Override + public void sendMessage(ChatMessageType position, BaseComponent... components) { + sendMessage(components); //Ignore position + } + + @Override + public boolean isInvulnerable() { + return true; + } + }; + + @Override + public Player.Spigot spigot() { + return spigot; + } + public static DiscordConnectedPlayer create(User user, MessageChannel channel, UUID uuid, String mcname, MinecraftChatModule module) { return Mockito.mock(DiscordConnectedPlayer.class, diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java b/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java index d748433..99d84cf 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlayer.java @@ -3,6 +3,8 @@ package buttondevteam.discordplugin; import buttondevteam.discordplugin.mcchat.MCChatPrivate; import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.UserClass; +import discord4j.core.object.entity.User; +import discord4j.core.object.entity.channel.MessageChannel; @UserClass(foldername = "discord") public class DiscordPlayer extends ChromaGamerBase { @@ -20,7 +22,7 @@ public class DiscordPlayer extends ChromaGamerBase { /** * Returns true if player has the private Minecraft chat enabled. For setting the value, see - * {@link MCChatPrivate#privateMCChat(sx.blah.discord.handle.obj.MessageChannel, boolean, sx.blah.discord.handle.obj.User, DiscordPlayer)} + * {@link MCChatPrivate#privateMCChat(MessageChannel, boolean, User, DiscordPlayer)} */ public boolean isMinecraftChatEnabled() { return MCChatPrivate.isMinecraftChatEnabled(this); diff --git a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java index 22d6102..e234afc 100755 --- a/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java +++ b/src/main/java/buttondevteam/discordplugin/DiscordPlugin.java @@ -7,10 +7,10 @@ import buttondevteam.discordplugin.exceptions.ExceptionListenerModule; import buttondevteam.discordplugin.fun.FunModule; import buttondevteam.discordplugin.listeners.CommonListeners; import buttondevteam.discordplugin.listeners.MCListener; -import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.discordplugin.mcchat.MinecraftChatModule; import buttondevteam.discordplugin.mccommands.DiscordMCCommand; import buttondevteam.discordplugin.role.GameRoleModule; +import buttondevteam.discordplugin.util.DPState; import buttondevteam.discordplugin.util.Timings; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.ButtonPlugin; @@ -29,13 +29,10 @@ import discord4j.core.object.entity.Role; import discord4j.core.object.presence.Activity; import discord4j.core.object.presence.Presence; import discord4j.core.object.reaction.ReactionEmoji; -import discord4j.rest.util.Color; import discord4j.store.jdk.JdkStoreService; import lombok.Getter; import lombok.val; -import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; import org.mockito.internal.util.MockUtil; import reactor.core.publisher.Mono; @@ -43,7 +40,6 @@ import java.io.File; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; @ButtonPlugin.ConfigOpts(disableConfigGen = true) public class DiscordPlugin extends ButtonPlugin { @@ -118,7 +114,7 @@ public class DiscordPlugin extends ButtonPlugin { getLogger().info("Initializing..."); plugin = this; manager = new Command2DC(); - registerCommand(new DiscordMCCommand()); //Register so that the reset command works + registerCommand(new DiscordMCCommand()); //Register so that the restart command works String token; File tokenFile = new File("TBMC", "Token.txt"); if (tokenFile.exists()) //Legacy support @@ -132,7 +128,7 @@ public class DiscordPlugin extends ButtonPlugin { conf.set("token", "Token goes here"); conf.save(privateFile); - getLogger().severe("Token not found! Please set it in private.yml then do /discord reset"); + getLogger().severe("Token not found! Please set it in private.yml then do /discord restart"); getLogger().severe("You need to have a bot account to use with your server."); getLogger().severe("If you don't have one, go to https://discordapp.com/developers/applications/ and create an application, then create a bot for it and copy the bot token."); return; @@ -152,7 +148,7 @@ public class DiscordPlugin extends ButtonPlugin { }); /* All guilds have been received, client is fully connected */ } catch (Exception e) { TBMCCoreAPI.SendException("Failed to enable the Discord plugin!", e, this); - getLogger().severe("You may be able to reset the plugin using /discord reset"); + getLogger().severe("You may be able to restart the plugin using /discord restart"); } } @@ -168,7 +164,7 @@ public class DiscordPlugin extends ButtonPlugin { mainServer = mainServer().get().orElse(null); //Shouldn't change afterwards if (mainServer == null) { if (event.size() == 0) { - getLogger().severe("Main server not found! Invite the bot and do /discord reset"); + getLogger().severe("Main server not found! Invite the bot and do /discord restart"); dc.getApplicationInfo().subscribe(info -> getLogger().severe("Click here: https://discordapp.com/oauth2/authorize?client_id=" + info.getId().asString() + "&scope=bot&permissions=268509264")); saveConfig(); //Put default there @@ -182,40 +178,6 @@ public class DiscordPlugin extends ButtonPlugin { DPUtils.disableIfConfigErrorRes(null, commandChannel(), DPUtils.getMessageChannel(commandChannel())); //Won't disable, just prints the warning here - Component.registerComponent(this, new GeneralEventBroadcasterModule()); - Component.registerComponent(this, new MinecraftChatModule()); - Component.registerComponent(this, new ExceptionListenerModule()); - Component.registerComponent(this, new GameRoleModule()); //Needs the mainServer to be set - Component.registerComponent(this, new AnnouncerModule()); - Component.registerComponent(this, new FunModule()); - new ChromaBot(this).updatePlayerList(); //Initialize ChromaBot - The MCChatModule is tested to be enabled - - getManager().registerCommand(new VersionCommand()); - getManager().registerCommand(new UserinfoCommand()); - getManager().registerCommand(new HelpCommand()); - getManager().registerCommand(new DebugCommand()); - getManager().registerCommand(new ConnectCommand()); - if (DiscordMCCommand.resetting) //These will only execute if the chat is enabled - ChromaBot.getInstance().sendMessageCustomAsWell(chan -> chan.flatMap(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.CYAN) - .setTitle("Discord plugin restarted - chat connected."))), ChannelconBroadcast.RESTART); //Really important to note the chat, hmm - else if (getConfig().getBoolean("serverup", false)) { - ChromaBot.getInstance().sendMessageCustomAsWell(chan -> chan.flatMap(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.YELLOW) - .setTitle("Server recovered from a crash - chat connected."))), ChannelconBroadcast.RESTART); - val thr = new Throwable( - "The server shut down unexpectedly. See the log of the previous run for more details."); - thr.setStackTrace(new StackTraceElement[0]); - TBMCCoreAPI.SendException("The server crashed!", thr, this); - } else - ChromaBot.getInstance().sendMessageCustomAsWell(chan -> chan.flatMap(ch -> ch.createEmbed(ecs -> ecs.setColor(Color.GREEN) - .setTitle("Server started - chat connected."))), ChannelconBroadcast.RESTART); - - DiscordMCCommand.resetting = false; //This is the last event handling this flag - - getConfig().set("serverup", true); - saveConfig(); - TBMCCoreAPI.SendUnsentExceptions(); - TBMCCoreAPI.SendUnsentDebugMessages(); - CommonListeners.register(dc.getEventDispatcher()); TBMCCoreAPI.RegisterEventsForExceptions(new MCListener(), this); TBMCCoreAPI.RegisterUserClass(DiscordPlayer.class); @@ -223,6 +185,25 @@ public class DiscordPlugin extends ButtonPlugin { ? ((DiscordSenderBase) sender).getChromaUser() : null)); IHaveConfig.pregenConfig(this, null); + + var cb = new ChromaBot(); //Initialize ChromaBot + Component.registerComponent(this, new GeneralEventBroadcasterModule()); + Component.registerComponent(this, new MinecraftChatModule()); + Component.registerComponent(this, new ExceptionListenerModule()); + Component.registerComponent(this, new GameRoleModule()); //Needs the mainServer to be set + Component.registerComponent(this, new AnnouncerModule()); + Component.registerComponent(this, new FunModule()); + cb.updatePlayerList(); //The MCChatModule is tested to be enabled + + getManager().registerCommand(new VersionCommand()); + getManager().registerCommand(new UserinfoCommand()); + getManager().registerCommand(new HelpCommand()); + getManager().registerCommand(new DebugCommand()); + getManager().registerCommand(new ConnectCommand()); + + TBMCCoreAPI.SendUnsentExceptions(); + TBMCCoreAPI.SendUnsentDebugMessages(); + if (!TBMCCoreAPI.IsTestServer()) { dc.updatePresence(Presence.online(Activity.playing("Minecraft"))).subscribe(); } else { @@ -234,46 +215,24 @@ public class DiscordPlugin extends ButtonPlugin { } } - /** - * Always true, except when running "stop" from console - */ - public static boolean Restart; - @Override public void pluginPreDisable() { if (ChromaBot.getInstance() == null) return; //Failed to load Timings timings = new Timings(); timings.printElapsed("Disable start"); - MCChatUtils.forCustomAndAllMCChat(chan -> chan.flatMap(ch -> ch.createEmbed(ecs -> { - timings.printElapsed("Sending message to " + ch.getMention()); - if (DiscordMCCommand.resetting) - ecs.setColor(Color.ORANGE).setTitle("Discord plugin restarting"); - else - ecs.setColor(Restart ? Color.ORANGE : Color.RED) - .setTitle(Restart ? "Server restarting" : "Server stopping") - .setDescription( - Bukkit.getOnlinePlayers().size() > 0 - ? (DPUtils - .sanitizeString(Bukkit.getOnlinePlayers().stream() - .map(Player::getDisplayName).collect(Collectors.joining(", "))) - + (Bukkit.getOnlinePlayers().size() == 1 ? " was " : " were ") - + "thrown out") //TODO: Make configurable - : ""); //If 'restart' is disabled then this isn't shown even if joinleave is enabled - })).subscribe(), ChannelconBroadcast.RESTART, false); timings.printElapsed("Updating player list"); ChromaBot.getInstance().updatePlayerList(); timings.printElapsed("Done"); + if (MinecraftChatModule.state == DPState.RUNNING) + MinecraftChatModule.state = DPState.STOPPING_SERVER; } @Override public void pluginDisable() { Timings timings = new Timings(); timings.printElapsed("Actual disable start (logout)"); - timings.printElapsed("Config setup"); - getConfig().set("serverup", false); if (ChromaBot.getInstance() == null) return; //Failed to load - saveConfig(); try { SafeMode = true; // Stop interacting with Discord ChromaBot.delete(); diff --git a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java index e86b336..f41363c 100644 --- a/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java +++ b/src/main/java/buttondevteam/discordplugin/announcer/AnnouncerModule.java @@ -82,6 +82,7 @@ public class AnnouncerModule extends Component { while (!stop) { try { if (!isEnabled()) { + //noinspection BusyWait Thread.sleep(10000); continue; } @@ -135,6 +136,7 @@ public class AnnouncerModule extends Component { e.printStackTrace(); } try { + //noinspection BusyWait Thread.sleep(10000); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); diff --git a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java index ba218c4..5fd86d7 100755 --- a/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java +++ b/src/main/java/buttondevteam/discordplugin/broadcaster/PlayerListWatcher.java @@ -144,7 +144,7 @@ public class PlayerListWatcher { if (packet.getClass() == ppoc) { Field msgf = ppoc.getDeclaredField("a"); msgf.setAccessible(true); - MCChatUtils.forAllMCChat(MCChatUtils.send((String) toPlainText.invoke(msgf.get(packet)))); + MCChatUtils.forPublicPrivateChat(MCChatUtils.send((String) toPlainText.invoke(msgf.get(packet)))).subscribe(); } } catch (Exception e) { TBMCCoreAPI.SendException("Failed to broadcast message sent to all players - hacking failed.", e, module); diff --git a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java index e333941..7b57aa0 100755 --- a/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/listeners/MCListener.java @@ -3,6 +3,8 @@ package buttondevteam.discordplugin.listeners; import buttondevteam.discordplugin.DiscordPlayer; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.commands.ConnectCommand; +import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import buttondevteam.discordplugin.util.DPState; import buttondevteam.lib.TBMCCommandPreprocessEvent; import buttondevteam.lib.player.TBMCPlayerGetInfoEvent; import buttondevteam.lib.player.TBMCPlayerJoinEvent; @@ -53,6 +55,9 @@ public class MCListener implements Listener { @EventHandler public void onCommandPreprocess(TBMCCommandPreprocessEvent e) { - DiscordPlugin.Restart = !e.getMessage().equalsIgnoreCase("/stop"); // The variable is always true except if stopped + if (e.getMessage().equalsIgnoreCase("/stop")) + MinecraftChatModule.state = DPState.STOPPING_SERVER; + else + MinecraftChatModule.state = DPState.RESTARTING_SERVER; } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java index ade2fc7..46b0de5 100755 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatListener.java @@ -45,8 +45,9 @@ public class MCChatListener implements Listener { private BukkitTask sendtask; private final LinkedBlockingQueue> sendevents = new LinkedBlockingQueue<>(); private Runnable sendrunnable; - private static Thread sendthread; + private Thread sendthread; private final MinecraftChatModule module; + private boolean stop = false; //A new instance will be created on enable public MCChatListener(MinecraftChatModule minecraftChatModule) { module = minecraftChatModule; @@ -62,7 +63,7 @@ public class MCChatListener implements Listener { sendrunnable = () -> { sendthread = Thread.currentThread(); processMCToDiscord(); - if (DiscordPlugin.plugin.isEnabled()) //Don't run again if shutting down + if (DiscordPlugin.plugin.isEnabled() && !stop) //Don't run again if shutting down sendtask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, sendrunnable); }; sendtask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, sendrunnable); @@ -188,12 +189,14 @@ public class MCChatListener implements Listener { // The maps may not contain the senders for UnconnectedSenders /** - * Stop the listener. Any calls to onMCChat will restart it as long as we're not in safe mode. + * Stop the listener permanently. Enabling the module will create a new instance. * * @param wait Wait 5 seconds for the threads to stop */ - public static void stop(boolean wait) { + public void stop(boolean wait) { + stop = true; MCChatPrivate.logoutAll(); + MCChatUtils.LoggedInPlayers.clear(); if (sendthread != null) sendthread.interrupt(); if (recthread != null) recthread.interrupt(); try { @@ -221,7 +224,7 @@ public class MCChatListener implements Listener { private BukkitTask rectask; private final LinkedBlockingQueue recevents = new LinkedBlockingQueue<>(); private Runnable recrun; - private static Thread recthread; + private Thread recthread; // Discord public Mono handleDiscord(MessageCreateEvent ev) { @@ -257,7 +260,7 @@ public class MCChatListener implements Listener { recrun = () -> { //Don't return in a while loop next time recthread = Thread.currentThread(); processDiscordToMC(); - if (DiscordPlugin.plugin.isEnabled()) //Don't run again if shutting down + if (DiscordPlugin.plugin.isEnabled() && !stop) //Don't run again if shutting down rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Continue message processing }; rectask = Bukkit.getScheduler().runTaskAsynchronously(DiscordPlugin.plugin, recrun); //Start message processing diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java index 0f4cc71..647aa0d 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatPrivate.java @@ -3,6 +3,8 @@ package buttondevteam.discordplugin.mcchat; import buttondevteam.core.ComponentManager; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlayer; +import buttondevteam.discordplugin.DiscordPlugin; +import buttondevteam.discordplugin.DiscordSenderBase; import buttondevteam.lib.player.TBMCPlayer; import discord4j.core.object.entity.User; import discord4j.core.object.entity.channel.MessageChannel; @@ -35,11 +37,13 @@ public class MCChatPrivate { } else { val sender = MCChatUtils.removeSender(MCChatUtils.ConnectedSenders, channel.getId(), user); assert sender != null; - MCChatUtils.LoggedInPlayers.remove(sender.getUniqueId()); - if (p == null // Player is offline - If the player is online, that takes precedence - && sender.isLoggedIn()) //Don't call the quit event if login failed - MCChatUtils.callLogoutEvent(sender, true); - sender.setLoggedIn(false); + Bukkit.getScheduler().runTask(DiscordPlugin.plugin, () -> { + if ((p == null || p instanceof DiscordSenderBase) // Player is offline - If the player is online, that takes precedence + && sender.isLoggedIn()) //Don't call the quit event if login failed + MCChatUtils.callLogoutEvent(sender, false); //The next line has to run *after* this one, so can't use the needsSync parameter + MCChatUtils.LoggedInPlayers.remove(sender.getUniqueId()); + sender.setLoggedIn(false); + }); } } // ---- PermissionsEx warning is normal on logout ---- if (!start) @@ -65,8 +69,7 @@ public class MCChatPrivate { for (val entry : MCChatUtils.ConnectedSenders.entrySet()) for (val valueEntry : entry.getValue().entrySet()) if (MCChatUtils.getSender(MCChatUtils.OnlineSenders, valueEntry.getKey(), valueEntry.getValue().getUser()) == null) //If the player is online then the fake player was already logged out - MCChatUtils.callLogoutEvent(valueEntry.getValue(), false); //This is sync - MCChatUtils.ConnectedSenders.clear(); + MCChatUtils.callLogoutEvent(valueEntry.getValue(), !Bukkit.isPrimaryThread()); } } diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java index c6c026c..974fc11 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCChatUtils.java @@ -29,6 +29,7 @@ import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.plugin.AuthorNagException; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredListener; +import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; import javax.annotation.Nullable; @@ -37,6 +38,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; import java.util.logging.Level; import java.util.stream.Collectors; @@ -67,7 +69,7 @@ public class MCChatUtils { } private static boolean notEnabled() { - return getModule() == null; + return (module == null) || (!module.disabling && (getModule() == null)); //Allow using things while disabling the module } private static MinecraftChatModule getModule() { @@ -142,30 +144,34 @@ public class MCChatUtils { return null; } - public static void forAllMCChat(Consumer> action) { - if (notEnabled()) return; - action.accept(module.chatChannelMono()); + public static Mono forPublicPrivateChat(Function, Mono> action) { + if (notEnabled()) return Mono.empty(); + var list = new ArrayList>(); + list.add(action.apply(module.chatChannelMono())); for (LastMsgData data : MCChatPrivate.lastmsgPerUser) - action.accept(Mono.just(data.channel)); + list.add(action.apply(Mono.just(data.channel))); // lastmsgCustom.forEach(cc -> action.accept(cc.channel)); - Only send relevant messages to custom chat + return Mono.whenDelayError(list); } /** * For custom and all MC chat * - * @param action The action to act + * @param action The action to act (cannot complete empty) * @param toggle The toggle to check * @param hookmsg Whether the message is also sent from the hook */ - public static void forCustomAndAllMCChat(Consumer> action, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { - if (notEnabled()) return; + public static Mono forCustomAndAllMCChat(Function, Mono> action, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { + if (notEnabled()) return Mono.empty(); + var list = new ArrayList>(); if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg) - forAllMCChat(action); - final Consumer customLMDConsumer = cc -> action.accept(Mono.just(cc.channel)); + list.add(forPublicPrivateChat(action)); + final Function> customLMDFunction = cc -> action.apply(Mono.just(cc.channel)); if (toggle == null) - MCChatCustom.lastmsgCustom.forEach(customLMDConsumer); + MCChatCustom.lastmsgCustom.stream().map(customLMDFunction).forEach(list::add); else - MCChatCustom.lastmsgCustom.stream().filter(cc -> (cc.toggles & toggle.flag) != 0).forEach(customLMDConsumer); + MCChatCustom.lastmsgCustom.stream().filter(cc -> (cc.toggles & toggle.flag) != 0).map(customLMDFunction).forEach(list::add); + return Mono.whenDelayError(list); } /** @@ -175,16 +181,17 @@ public class MCChatUtils { * @param sender The sender to check perms of or null to send to all that has it toggled * @param toggle The toggle to check or null to send to all allowed */ - public static void forAllowedCustomMCChat(Consumer> action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle) { - if (notEnabled()) return; - MCChatCustom.lastmsgCustom.stream().filter(clmd -> { + public static Mono forAllowedCustomMCChat(Function, Mono> action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle) { + if (notEnabled()) return Mono.empty(); + Stream> st = MCChatCustom.lastmsgCustom.stream().filter(clmd -> { //new TBMCChannelConnectFakeEvent(sender, clmd.mcchannel).shouldSendTo(clmd.dcp) - Thought it was this simple hehe - Wait, it *should* be this simple if (toggle != null && (clmd.toggles & toggle.flag) == 0) return false; //If null then allow if (sender == null) return true; return clmd.groupID.equals(clmd.mcchannel.getGroupID(sender)); - }).forEach(cc -> action.accept(Mono.just(cc.channel))); //TODO: Send error messages on channel connect + }).map(cc -> action.apply(Mono.just(cc.channel))); //TODO: Send error messages on channel connect + return Mono.whenDelayError(st::iterator); //Can't convert as an iterator or inside the stream, but I can convert it as a stream } /** @@ -195,32 +202,35 @@ public class MCChatUtils { * @param toggle The toggle to check or null to send to all allowed * @param hookmsg Whether the message is also sent from the hook */ - public static void forAllowedCustomAndAllMCChat(Consumer> action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { - if (notEnabled()) return; + public static Mono forAllowedCustomAndAllMCChat(Function, Mono> action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle, boolean hookmsg) { + if (notEnabled()) return Mono.empty(); + var cc = forAllowedCustomMCChat(action, sender, toggle); if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg) - forAllMCChat(action); - forAllowedCustomMCChat(action, sender, toggle); + return Mono.whenDelayError(forPublicPrivateChat(action), cc); + return Mono.whenDelayError(cc); } - public static Consumer> send(String message) { + public static Function, Mono> send(String message) { return ch -> ch.flatMap(mc -> { resetLastMessage(mc); return mc.createMessage(DPUtils.sanitizeString(message)); - }).subscribe(); + }); } - public static void forAllowedMCChat(Consumer> action, TBMCSystemChatEvent event) { - if (notEnabled()) return; + public static Mono forAllowedMCChat(Function, Mono> action, TBMCSystemChatEvent event) { + if (notEnabled()) return Mono.empty(); + var list = new ArrayList>(); if (event.getChannel().isGlobal()) - action.accept(module.chatChannelMono()); + list.add(action.apply(module.chatChannelMono())); for (LastMsgData data : MCChatPrivate.lastmsgPerUser) if (event.shouldSendTo(getSender(data.channel.getId(), data.user))) - action.accept(Mono.just(data.channel)); //TODO: Only store ID? + list.add(action.apply(Mono.just(data.channel))); //TODO: Only store ID? MCChatCustom.lastmsgCustom.stream().filter(clmd -> { if (!clmd.brtoggles.contains(event.getTarget())) return false; return event.shouldSendTo(clmd.dcp); - }).map(clmd -> Mono.just(clmd.channel)).forEach(action); + }).map(clmd -> action.apply(Mono.just(clmd.channel))).forEach(list::add); + return Mono.whenDelayError(list); } /** @@ -357,8 +367,11 @@ public class MCChatUtils { } callEventExcludingSome(new PlayerJoinEvent(dcp, "")); dcp.setLoggedIn(true); - if (module != null) + if (module != null) { + if (module.serverWatcher != null) + module.serverWatcher.fakePlayers.add(dcp); module.log(dcp.getName() + " (" + dcp.getUniqueId() + ") logged in from Discord"); + } }); } @@ -374,8 +387,11 @@ public class MCChatUtils { if (needsSync) callEventSync(event); else callEventExcludingSome(event); dcp.setLoggedIn(false); - if (module != null) + if (module != null) { module.log(dcp.getName() + " (" + dcp.getUniqueId() + ") logged out from Discord"); + if (module.serverWatcher != null) + module.serverWatcher.fakePlayers.remove(dcp); + } } static void callEventSync(Event event) { diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java index 2049a61..30f7431 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MCListener.java @@ -63,7 +63,7 @@ class MCListener implements Listener { } final String message = e.getJoinMessage(); if (message != null && message.trim().length() > 0) - MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true).subscribe(); ChromaBot.getInstance().updatePlayerList(); }); } @@ -80,7 +80,7 @@ class MCListener implements Listener { ChromaBot.getInstance()::updatePlayerList, 5); final String message = e.getQuitMessage(); if (message != null && message.trim().length() > 0) - MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true); + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(message), e.getPlayer(), ChannelconBroadcast.JOINLEAVE, true).subscribe(); } @EventHandler(priority = EventPriority.HIGHEST) @@ -92,7 +92,7 @@ class MCListener implements Listener { @EventHandler(priority = EventPriority.LOW) public void onPlayerDeath(PlayerDeathEvent e) { - MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(e.getDeathMessage()), e.getEntity(), ChannelconBroadcast.DEATH, true); + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(e.getDeathMessage()), e.getEntity(), ChannelconBroadcast.DEATH, true).subscribe(); } @EventHandler @@ -102,7 +102,7 @@ class MCListener implements Listener { return; final String msg = base.getDisplayName() + " is " + (e.getValue() ? "now" : "no longer") + " AFK."; - MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(msg), base, ChannelconBroadcast.AFK, false); + MCChatUtils.forAllowedCustomAndAllMCChat(MCChatUtils.send(msg), base, ChannelconBroadcast.AFK, false).subscribe(); } private ConfigData> muteRole() { @@ -137,12 +137,12 @@ class MCListener implements Listener { @EventHandler public void onChatSystemMessage(TBMCSystemChatEvent event) { - MCChatUtils.forAllowedMCChat(MCChatUtils.send(event.getMessage()), event); + MCChatUtils.forAllowedMCChat(MCChatUtils.send(event.getMessage()), event).subscribe(); } @EventHandler public void onBroadcastMessage(BroadcastMessageEvent event) { - MCChatUtils.forCustomAndAllMCChat(MCChatUtils.send(event.getMessage()), ChannelconBroadcast.BROADCAST, false); + MCChatUtils.forCustomAndAllMCChat(MCChatUtils.send(event.getMessage()), ChannelconBroadcast.BROADCAST, false).subscribe(); } @EventHandler @@ -151,8 +151,8 @@ class MCListener implements Listener { : event.getSender().getName(); //Channel channel = ChromaGamerBase.getFromSender(event.getSender()).channel().get(); - TODO DiscordPlugin.mainServer.getEmojis().filter(e -> "YEEHAW".equals(e.getName())) - .take(1).singleOrEmpty().map(Optional::of).defaultIfEmpty(Optional.empty()).subscribe(yeehaw -> - MCChatUtils.forAllMCChat(MCChatUtils.send(name + (yeehaw.map(guildEmoji -> " <:YEEHAW:" + guildEmoji.getId().asString() + ">s").orElse(" YEEHAWs"))))); + .take(1).singleOrEmpty().map(Optional::of).defaultIfEmpty(Optional.empty()).flatMap(yeehaw -> + MCChatUtils.forPublicPrivateChat(MCChatUtils.send(name + (yeehaw.map(guildEmoji -> " <:YEEHAW:" + guildEmoji.getId().asString() + ">s").orElse(" YEEHAWs"))))).subscribe(); } @EventHandler diff --git a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java index b51d4b3..68813f7 100644 --- a/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java +++ b/src/main/java/buttondevteam/discordplugin/mcchat/MinecraftChatModule.java @@ -1,12 +1,13 @@ package buttondevteam.discordplugin.mcchat; -import buttondevteam.core.MainPlugin; import buttondevteam.core.component.channel.Channel; +import buttondevteam.discordplugin.ChannelconBroadcast; import buttondevteam.discordplugin.DPUtils; import buttondevteam.discordplugin.DiscordConnectedPlayer; import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.playerfaker.ServerWatcher; import buttondevteam.discordplugin.playerfaker.perm.LPInjector; +import buttondevteam.discordplugin.util.DPState; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.Component; @@ -15,10 +16,11 @@ import buttondevteam.lib.architecture.ReadOnlyConfigData; import com.google.common.collect.Lists; import discord4j.common.util.Snowflake; import discord4j.core.object.entity.channel.MessageChannel; +import discord4j.rest.util.Color; import lombok.Getter; import lombok.val; import org.bukkit.Bukkit; -import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.entity.Player; import reactor.core.publisher.Mono; import java.util.ArrayList; @@ -30,9 +32,11 @@ import java.util.stream.Collectors; * Provides Minecraft chat connection to Discord. Commands may be used either in a public chat (limited) or in a DM. */ public class MinecraftChatModule extends Component { + public static DPState state = DPState.RUNNING; private @Getter MCChatListener listener; - private ServerWatcher serverWatcher; + ServerWatcher serverWatcher; private LPInjector lpInjector; + boolean disabling = false; /** * A list of commands that can be used in public chats - Warning: Some plugins will treat players as OPs, always test before allowing a command! @@ -123,6 +127,11 @@ public class MinecraftChatModule extends Component { */ private final ConfigData addFakePlayersToBukkit = getConfig().getData("addFakePlayersToBukkit", true); + /** + * Set by the component to report crashes. + */ + private final ConfigData serverUp = getConfig().getData("serverUp", false); + @Override protected void enable() { if (DPUtils.disableIfConfigErrorRes(this, chatChannel(), chatChannelMono())) @@ -158,7 +167,7 @@ public class MinecraftChatModule extends Component { try { if (lpInjector == null) - lpInjector = new LPInjector(MainPlugin.Instance); + lpInjector = new LPInjector(DiscordPlugin.plugin); } catch (Exception e) { TBMCCoreAPI.SendException("Failed to init LuckPerms injector", e, this); } catch (NoClassDefFoundError e) { @@ -170,23 +179,68 @@ public class MinecraftChatModule extends Component { try { serverWatcher = new ServerWatcher(); serverWatcher.enableDisable(true); + log("Finished hooking into the server"); } catch (Exception e) { TBMCCoreAPI.SendException("Failed to hack the server (object)!", e, this); } } + + if (state == DPState.RESTARTING_PLUGIN) { //These will only execute if the chat is enabled + sendStateMessage(Color.CYAN, "Discord plugin restarted - chat connected."); //Really important to note the chat, hmm + state = DPState.RUNNING; + } else if (state == DPState.DISABLED_MCCHAT) { + sendStateMessage(Color.CYAN, "Minecraft chat enabled - chat connected."); + state = DPState.RUNNING; + } else if (serverUp.get()) { + sendStateMessage(Color.YELLOW, "Server started after a crash - chat connected."); + val thr = new Throwable("The server shut down unexpectedly. See the log of the previous run for more details."); + thr.setStackTrace(new StackTraceElement[0]); + TBMCCoreAPI.SendException("The server crashed!", thr, this); + } else + sendStateMessage(Color.GREEN, "Server started - chat connected."); + serverUp.set(true); } @Override protected void disable() { + disabling = true; + if (state == DPState.RESTARTING_PLUGIN) //These will only execute if the chat is enabled + sendStateMessage(Color.ORANGE, "Discord plugin restarting"); + else if (state == DPState.RUNNING) { + sendStateMessage(Color.ORANGE, "Minecraft chat disabled"); + state = DPState.DISABLED_MCCHAT; + } else { + String kickmsg = Bukkit.getOnlinePlayers().size() > 0 + ? (DPUtils + .sanitizeString(Bukkit.getOnlinePlayers().stream() + .map(Player::getDisplayName).collect(Collectors.joining(", "))) + + (Bukkit.getOnlinePlayers().size() == 1 ? " was " : " were ") + + "thrown out") //TODO: Make configurable + : ""; + if (state == DPState.RESTARTING_SERVER) + sendStateMessage(Color.ORANGE, "Server restarting", kickmsg); + else if (state == DPState.STOPPING_SERVER) + sendStateMessage(Color.RED, "Server stopping", kickmsg); + else + sendStateMessage(Color.GRAY, "Unknown state, please report."); + } //If 'restart' is disabled then this isn't shown even if joinleave is enabled + + serverUp.set(false); //Disable even if just the component is disabled because that way it won't falsely report crashes + try { //If it's not enabled it won't do anything - if (serverWatcher != null) + if (serverWatcher != null) { serverWatcher.enableDisable(false); - } catch (Exception e) { + log("Finished unhooking the server"); + } + } catch ( + Exception e) { TBMCCoreAPI.SendException("Failed to restore the server object!", e, this); } + val chcons = MCChatCustom.getCustomChats(); val chconsc = getConfig().getConfig().createSection("chcons"); - for (val chcon : chcons) { + for ( + val chcon : chcons) { val chconc = chconsc.createSection(chcon.channel.getId().asString()); chconc.set("mcchid", chcon.mcchannel.ID); chconc.set("chid", chcon.channel.getId().asLong()); @@ -197,11 +251,23 @@ public class MinecraftChatModule extends Component { chconc.set("toggles", chcon.toggles); chconc.set("brtoggles", chcon.brtoggles.stream().map(TBMCSystemChatEvent.BroadcastTarget::getName).collect(Collectors.toList())); } - MCChatListener.stop(true); + listener.stop(true); + disabling = false; } - @Override - protected void unregister(JavaPlugin plugin) { - lpInjector = null; //Plugin restart, events need to be registered again + /** + * It will block to make sure all messages are sent + */ + private void sendStateMessage(Color color, String message) { + MCChatUtils.forCustomAndAllMCChat(chan -> chan.flatMap(ch -> ch.createEmbed(ecs -> ecs.setColor(color) + .setTitle(message))), ChannelconBroadcast.RESTART, false).block(); + } + + /** + * It will block to make sure all messages are sent + */ + private void sendStateMessage(Color color, String message, String extra) { + MCChatUtils.forCustomAndAllMCChat(chan -> chan.flatMap(ch -> ch.createEmbed(ecs -> ecs.setColor(color) + .setTitle(message).setDescription(extra))), ChannelconBroadcast.RESTART, false).block(); } } diff --git a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java index 7d46b3a..a909765 100644 --- a/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java +++ b/src/main/java/buttondevteam/discordplugin/mccommands/DiscordMCCommand.java @@ -7,6 +7,8 @@ import buttondevteam.discordplugin.DiscordSenderBase; import buttondevteam.discordplugin.commands.ConnectCommand; import buttondevteam.discordplugin.commands.VersionCommand; import buttondevteam.discordplugin.mcchat.MCChatUtils; +import buttondevteam.discordplugin.mcchat.MinecraftChatModule; +import buttondevteam.discordplugin.util.DPState; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.ICommand2MC; @@ -58,7 +60,7 @@ public class DiscordMCCommand extends ICommand2MC { @Command2.Subcommand(permGroup = Command2.Subcommand.MOD_GROUP, helpText = { "Reload Discord plugin", - "Reloads the config. To apply some changes, you may need to also run /discord reset." + "Reloads the config. To apply some changes, you may need to also run /discord restart." }) public void reload(CommandSender sender) { if (DiscordPlugin.plugin.tryReloadConfig()) @@ -67,26 +69,24 @@ public class DiscordMCCommand extends ICommand2MC { sender.sendMessage("§cFailed to reload config."); } - public static boolean resetting = false; - @Command2.Subcommand(permGroup = Command2.Subcommand.MOD_GROUP, helpText = { - "Reset ChromaBot", // + "Restart the plugin", // "This command disables and then enables the plugin." // }) - public void reset(CommandSender sender) { + public void restart(CommandSender sender) { Runnable task = () -> { if (!DiscordPlugin.plugin.tryReloadConfig()) { - sender.sendMessage("§cFailed to reload config so not resetting. Check the console."); + sender.sendMessage("§cFailed to reload config so not restarting. Check the console."); return; } - resetting = true; //Turned off after sending enable message (ReadyEvent) + MinecraftChatModule.state = DPState.RESTARTING_PLUGIN; //Reset in MinecraftChatModule sender.sendMessage("§bDisabling DiscordPlugin..."); Bukkit.getPluginManager().disablePlugin(DiscordPlugin.plugin); if (!(sender instanceof DiscordSenderBase)) //Sending to Discord errors sender.sendMessage("§bEnabling DiscordPlugin..."); Bukkit.getPluginManager().enablePlugin(DiscordPlugin.plugin); if (!(sender instanceof DiscordSenderBase)) //Sending to Discord errors - sender.sendMessage("§bReset finished!"); + sender.sendMessage("§bRestart finished!"); }; if (!Bukkit.getName().equals("Paper")) { getPlugin().getLogger().warning("Async plugin events are not supported by the server, running on main thread"); @@ -116,9 +116,8 @@ public class DiscordMCCommand extends ICommand2MC { } DiscordPlugin.mainServer.getInvites().limitRequest(1) .switchIfEmpty(Mono.fromRunnable(() -> sender.sendMessage("§cNo invites found for the server."))) - .subscribe(inv -> { - sender.sendMessage("§bInvite link: https://discord.gg/" + inv.getCode()); - }, e -> sender.sendMessage("§cThe invite link is not set and the bot has no permission to get it.")); + .subscribe(inv -> sender.sendMessage("§bInvite link: https://discord.gg/" + inv.getCode()), + e -> sender.sendMessage("§cThe invite link is not set and the bot has no permission to get it.")); } @Override diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/ServerWatcher.java b/src/main/java/buttondevteam/discordplugin/playerfaker/ServerWatcher.java index 4bb9a45..903cea3 100644 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/ServerWatcher.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/ServerWatcher.java @@ -15,7 +15,7 @@ import java.util.*; public class ServerWatcher { private List playerList; - private final List fakePlayers = new ArrayList<>(); + public final List fakePlayers = new ArrayList<>(); private Server origServer; @IgnoreForBinding @@ -43,12 +43,12 @@ public class ServerWatcher { .filter(dcp -> dcp.getName().equalsIgnoreCase(argument)).findAny().orElse(null); } break; - case "getOnlinePlayers": + /*case "getOnlinePlayers": if (playerList == null) { @SuppressWarnings("unchecked") var list = (List) method.invoke(origServer, invocation.getArguments()); playerList = new AppendListView<>(list, fakePlayers); - } - return playerList; + } - Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should. + return playerList;*/ case "createProfile": //Paper's method, casts the player to a CraftPlayer if (pc == 2) { UUID uuid = invocation.getArgument(0); diff --git a/src/main/java/buttondevteam/discordplugin/playerfaker/perm/LPInjector.java b/src/main/java/buttondevteam/discordplugin/playerfaker/perm/LPInjector.java index aa42c11..3bf0b7b 100644 --- a/src/main/java/buttondevteam/discordplugin/playerfaker/perm/LPInjector.java +++ b/src/main/java/buttondevteam/discordplugin/playerfaker/perm/LPInjector.java @@ -1,7 +1,7 @@ package buttondevteam.discordplugin.playerfaker.perm; -import buttondevteam.core.MainPlugin; import buttondevteam.discordplugin.DiscordConnectedPlayer; +import buttondevteam.discordplugin.DiscordPlugin; import buttondevteam.discordplugin.mcchat.MCChatUtils; import buttondevteam.lib.TBMCCoreAPI; import me.lucko.luckperms.bukkit.LPBukkitBootstrap; @@ -42,7 +42,7 @@ public final class LPInjector implements Listener { //Disable login event for Lu private final Method setOldPermissible; private final Method getOldPermissible; - public LPInjector(MainPlugin mp) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException { + public LPInjector(DiscordPlugin dp) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException { LPBukkitBootstrap bs = (LPBukkitBootstrap) Bukkit.getPluginManager().getPlugin("LuckPerms"); Field field = LPBukkitBootstrap.class.getDeclaredField("plugin"); field.setAccessible(true); @@ -77,7 +77,7 @@ public final class LPInjector implements Listener { //Disable login event for Lu getOldPermissible = LuckPermsPermissible.class.getDeclaredMethod("getOldPermissible"); getOldPermissible.setAccessible(true); - TBMCCoreAPI.RegisterEventsForExceptions(this, mp); + TBMCCoreAPI.RegisterEventsForExceptions(this, dp); } @@ -146,7 +146,7 @@ public final class LPInjector implements Listener { //Disable login event for Lu t.printStackTrace(); e.disallow(PlayerLoginEvent.Result.KICK_OTHER, Message.LOADING_SETUP_ERROR.asString(plugin.getLocaleManager())); - return; + //return; } //this.plugin.getContextManager().signalContextUpdate(player); @@ -167,7 +167,7 @@ public final class LPInjector implements Listener { //Disable login event for Lu this.plugin.getBootstrap().getServer().getScheduler().runTaskLaterAsynchronously(this.plugin.getBootstrap(), () -> { // Remove the custom permissible try { - uninject(player, true); + uninject(player); } catch (Exception ex) { ex.printStackTrace(); } @@ -207,7 +207,7 @@ public final class LPInjector implements Listener { //Disable login event for Lu player.setPerm(newPermissible); } - private void uninject(DiscordConnectedPlayer player, boolean dummy) throws Exception { + private void uninject(DiscordConnectedPlayer player) throws Exception { // gets the players current permissible. PermissibleBase permissible = player.getPerm(); @@ -223,18 +223,9 @@ public final class LPInjector implements Listener { //Disable login event for Lu ((AtomicBoolean) getActive.invoke(lpPermissible)).set(false); // handle the replacement permissible. - if (dummy) { - // just inject a dummy class. this is used when we know the player is about to quit the server. - player.setPerm(DummyPermissibleBase.INSTANCE); + // just inject a dummy class. this is used when we know the player is about to quit the server. + player.setPerm(DummyPermissibleBase.INSTANCE); - } else { - PermissibleBase newPb = (PermissibleBase) getOldPermissible.invoke(lpPermissible); - if (newPb == null) { - newPb = new PermissibleBase(player); - } - - player.setPerm(newPb); - } } } } diff --git a/src/main/java/buttondevteam/discordplugin/util/DPState.java b/src/main/java/buttondevteam/discordplugin/util/DPState.java new file mode 100644 index 0000000..b83d4ac --- /dev/null +++ b/src/main/java/buttondevteam/discordplugin/util/DPState.java @@ -0,0 +1,24 @@ +package buttondevteam.discordplugin.util; + +public enum DPState { + /** + * Used from server start until anything else happens + */ + RUNNING, + /** + * Used when /restart is detected + */ + RESTARTING_SERVER, + /** + * Used when the plugin is disabled by outside forces + */ + STOPPING_SERVER, + /** + * Used when /discord restart is run + */ + RESTARTING_PLUGIN, + /** + * Used when the plugin is in the RUNNING state when the chat is disabled + */ + DISABLED_MCCHAT +}