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
This commit is contained in:
parent
ccc15aa048
commit
a27a262858
17 changed files with 311 additions and 175 deletions
|
@ -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.
|
||||
|
|
|
@ -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<MessageChannel>, Mono<Message>> 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<MessageChannel>, Mono<Message>> message, @Nullable ChannelconBroadcast toggle) {
|
||||
MCChatUtils.forCustomAndAllMCChat(ch -> message.apply(ch).subscribe(), toggle, false);
|
||||
MCChatUtils.forCustomAndAllMCChat(message::apply, toggle, false).subscribe();
|
||||
}
|
||||
|
||||
public void updatePlayerList() {
|
||||
|
|
|
@ -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<Player> 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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -82,6 +82,7 @@ public class AnnouncerModule extends Component<DiscordPlugin> {
|
|||
while (!stop) {
|
||||
try {
|
||||
if (!isEnabled()) {
|
||||
//noinspection BusyWait
|
||||
Thread.sleep(10000);
|
||||
continue;
|
||||
}
|
||||
|
@ -135,6 +136,7 @@ public class AnnouncerModule extends Component<DiscordPlugin> {
|
|||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
//noinspection BusyWait
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,8 +45,9 @@ public class MCChatListener implements Listener {
|
|||
private BukkitTask sendtask;
|
||||
private final LinkedBlockingQueue<AbstractMap.SimpleEntry<TBMCChatEvent, Instant>> 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<MessageCreateEvent> recevents = new LinkedBlockingQueue<>();
|
||||
private Runnable recrun;
|
||||
private static Thread recthread;
|
||||
private Thread recthread;
|
||||
|
||||
// Discord
|
||||
public Mono<Boolean> 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
|
||||
|
|
|
@ -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
|
||||
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, true);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Mono<MessageChannel>> action) {
|
||||
if (notEnabled()) return;
|
||||
action.accept(module.chatChannelMono());
|
||||
public static Mono<?> forPublicPrivateChat(Function<Mono<MessageChannel>, Mono<?>> action) {
|
||||
if (notEnabled()) return Mono.empty();
|
||||
var list = new ArrayList<Mono<?>>();
|
||||
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<Mono<MessageChannel>> action, @Nullable ChannelconBroadcast toggle, boolean hookmsg) {
|
||||
if (notEnabled()) return;
|
||||
public static Mono<?> forCustomAndAllMCChat(Function<Mono<MessageChannel>, Mono<?>> action, @Nullable ChannelconBroadcast toggle, boolean hookmsg) {
|
||||
if (notEnabled()) return Mono.empty();
|
||||
var list = new ArrayList<Publisher<?>>();
|
||||
if (!GeneralEventBroadcasterModule.isHooked() || !hookmsg)
|
||||
forAllMCChat(action);
|
||||
final Consumer<MCChatCustom.CustomLMD> customLMDConsumer = cc -> action.accept(Mono.just(cc.channel));
|
||||
list.add(forPublicPrivateChat(action));
|
||||
final Function<MCChatCustom.CustomLMD, Publisher<?>> 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<Mono<MessageChannel>> action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle) {
|
||||
if (notEnabled()) return;
|
||||
MCChatCustom.lastmsgCustom.stream().filter(clmd -> {
|
||||
public static Mono<?> forAllowedCustomMCChat(Function<Mono<MessageChannel>, Mono<?>> action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle) {
|
||||
if (notEnabled()) return Mono.empty();
|
||||
Stream<Publisher<?>> 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<Mono<MessageChannel>> action, @Nullable CommandSender sender, @Nullable ChannelconBroadcast toggle, boolean hookmsg) {
|
||||
if (notEnabled()) return;
|
||||
public static Mono<?> forAllowedCustomAndAllMCChat(Function<Mono<MessageChannel>, 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<Mono<MessageChannel>> send(String message) {
|
||||
public static Function<Mono<MessageChannel>, Mono<?>> send(String message) {
|
||||
return ch -> ch.flatMap(mc -> {
|
||||
resetLastMessage(mc);
|
||||
return mc.createMessage(DPUtils.sanitizeString(message));
|
||||
}).subscribe();
|
||||
});
|
||||
}
|
||||
|
||||
public static void forAllowedMCChat(Consumer<Mono<MessageChannel>> action, TBMCSystemChatEvent event) {
|
||||
if (notEnabled()) return;
|
||||
public static Mono<?> forAllowedMCChat(Function<Mono<MessageChannel>, Mono<?>> action, TBMCSystemChatEvent event) {
|
||||
if (notEnabled()) return Mono.empty();
|
||||
var list = new ArrayList<Mono<?>>();
|
||||
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) {
|
||||
|
|
|
@ -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<Mono<Role>> 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
|
||||
|
|
|
@ -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<DiscordPlugin> {
|
||||
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<DiscordPlugin> {
|
|||
*/
|
||||
private final ConfigData<Boolean> addFakePlayersToBukkit = getConfig().getData("addFakePlayersToBukkit", true);
|
||||
|
||||
/**
|
||||
* Set by the component to report crashes.
|
||||
*/
|
||||
private final ConfigData<Boolean> serverUp = getConfig().getData("serverUp", false);
|
||||
|
||||
@Override
|
||||
protected void enable() {
|
||||
if (DPUtils.disableIfConfigErrorRes(this, chatChannel(), chatChannelMono()))
|
||||
|
@ -158,7 +167,7 @@ public class MinecraftChatModule extends Component<DiscordPlugin> {
|
|||
|
||||
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<DiscordPlugin> {
|
|||
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<DiscordPlugin> {
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -15,7 +15,7 @@ import java.util.*;
|
|||
|
||||
public class ServerWatcher {
|
||||
private List<Player> playerList;
|
||||
private final List<Player> fakePlayers = new ArrayList<>();
|
||||
public final List<Player> 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<Player>) 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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
} else {
|
||||
PermissibleBase newPb = (PermissibleBase) getOldPermissible.invoke(lpPermissible);
|
||||
if (newPb == null) {
|
||||
newPb = new PermissibleBase(player);
|
||||
}
|
||||
|
||||
player.setPerm(newPb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
24
src/main/java/buttondevteam/discordplugin/util/DPState.java
Normal file
24
src/main/java/buttondevteam/discordplugin/util/DPState.java
Normal file
|
@ -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
|
||||
}
|
Loading…
Reference in a new issue