A class to represent a chat channel and control the messages sent etc.
- * + * * @author Oliver Martin (Revilo410) * */ @@ -132,12 +133,14 @@ public void setFormat(String format) { } public void sendMessage(ProxiedPlayer sender, String message, String format) { - DebugManager.log("CHANNEL #" + getName() + ": Got a message for the channel"); DebugManager.log("CHANNEL #" + getName() + ": SENDER = " + sender.getName()); DebugManager.log("CHANNEL #" + getName() + ": MESSAGE = " + message); DebugManager.log("CHANNEL #" + getName() + ": FORMAT = " + format); + Boolean serverGroupsEnabled = ServerGroups.getServerGroupsEnabled(); + ArrayListThe back-end code which manages the creation, deletion and scheduling of announcements
+ * + * @author Oliver Martin (Revilo410) + */ +public class Announcements { + + private static final MapThe back-end code which manages the creation, deletion and scheduling of bulletins
+ * + * @author Oliver Martin (Revilo410) + */ +public class Bulletins { + private static final Object lock = new Object(); + + private static ScheduledTask currentlyScheduled = null; + private static int nextBulletin = -1; + private static ArrayListManages all plug-in messaging channels on the BungeeCord side
+ * + * @author Oliver Martin (Revilo410) + */ +public class BungeeComm { + + public static void sendMessage(String message, ServerInfo server) { + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(stream); + + try { + // Players name + out.writeUTF(message); + + // Should display name be set? + ConfigurationNode configYML = ConfigManager.getInstance().getHandler("config.yml").getConfig(); + if (configYML.getChildrenMap().containsKey("set_display_name")) { + if (configYML.getNode("set_display_name").getBoolean()) { + out.writeUTF("T"); + } else { + out.writeUTF("F"); + } + } else { + out.writeUTF("T"); + } + + // Display name format + if (configYML.getChildrenMap().containsKey("display_name_format")) { + out.writeUTF(Objects.requireNonNull(configYML.getNode("display_name_format").getString())); + } else { + out.writeUTF("%PREFIX%%NICK%%SUFFIX%"); + } + + // Is this server a global chat server? + if (ConfigManager.getInstance().getHandler("config.yml").getConfig().getNode("global").getBoolean() + && !ConfigManager.getInstance().getHandler("config.yml").getConfig().getNode("no_global").getList(String::valueOf).contains(server.getName())) { + out.writeUTF("T"); + } else { + out.writeUTF("F"); + } + + // Send the global format + out.writeUTF(Channel.getGlobalChannel().getFormat()); + + } catch (IOException e) { + e.printStackTrace(); + } + MultiChat.getInstance().getServer().getServer(server.getName()).ifPresent( + registeredServer -> registeredServer.sendPluginMessage(MinecraftChannelIdentifier.from("multichat:comm"), stream.toByteArray())); + } + + public static void sendCommandMessage(String command, ServerInfo server) { + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(stream); + + try { + + // Command + out.writeUTF(command); + + } catch (IOException e) { + e.printStackTrace(); + } + + MultiChat.getInstance().getServer().getServer(server.getName()).ifPresent( + registeredServer -> registeredServer.sendPluginMessage(MinecraftChannelIdentifier.from("multichat:act"), stream.toByteArray())); + } + + public static void sendPlayerCommandMessage(String command, String playerRegex, ServerInfo server) { + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(stream); + + try { + + // Command + out.writeUTF(playerRegex); + out.writeUTF(command); + + } catch (IOException e) { + e.printStackTrace(); + } + + MultiChat.getInstance().getServer().getServer(server.getName()).ifPresent( + registeredServer -> registeredServer.sendPluginMessage(MinecraftChannelIdentifier.from("multichat:pact"), stream.toByteArray())); + } + + public static void sendChatMessage(String message, ServerInfo server) { + + // This has been repurposed to send casts to local chat streams! + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(stream); + + + try { + // message part + out.writeUTF(message); + + + } catch (IOException e) { + e.printStackTrace(); + } + + MultiChat.getInstance().getServer().getServer(server.getName()).ifPresent( + registeredServer -> registeredServer.sendPluginMessage(MinecraftChannelIdentifier.from("multichat:chat"), stream.toByteArray())); + } + + public static void sendIgnoreMap(ServerInfo server) { + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try { + ObjectOutputStream oout = new ObjectOutputStream(stream); + + oout.writeObject(ChatControl.getIgnoreMap()); + + } catch (IOException e) { + e.printStackTrace(); + } + + MultiChat.getInstance().getServer().getServer(server.getName()).ifPresent( + registeredServer -> registeredServer.sendPluginMessage(MinecraftChannelIdentifier.from("multichat:ignore"), stream.toByteArray())); + } + + public static void sendPlayerChannelMessage(String playerName, String channel, Channel channelObject, ServerInfo server, boolean colour, boolean rgb) { + + sendIgnoreMap(server); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + //DataOutputStream out = new DataOutputStream(stream); + try { + ObjectOutputStream oout = new ObjectOutputStream(stream); + + // Players name + oout.writeUTF(playerName); + // Channel part + oout.writeUTF(channel); + oout.writeBoolean(colour); + oout.writeBoolean(rgb); + oout.writeBoolean(channelObject.isWhitelistMembers()); + oout.writeObject(channelObject.getMembers()); + + } catch (IOException e) { + e.printStackTrace(); + } + + MultiChat.getInstance().getServer().getServer(server.getName()).ifPresent( + registeredServer -> registeredServer.sendPluginMessage(MinecraftChannelIdentifier.from("multichat:ch"), stream.toByteArray())); + + DebugManager.log("Sent message on multichat:ch channel!"); + + } + + @Subscribe + public void onPluginMessage(PluginMessageEvent ev) { + if (!ev.getIdentifier().getId().startsWith("multichat:")) + return; + + if (!(ev.getSource() instanceof ServerConnection)) { + ev.setResult(PluginMessageEvent.ForwardResult.handled()); + return; + } + + if (ev.getIdentifier().getId().equals("multichat:chat")) { + + ev.setResult(PluginMessageEvent.ForwardResult.handled()); + + DebugManager.log("{multichat:chat} Got a plugin message"); + + ByteArrayInputStream stream = new ByteArrayInputStream(ev.getData()); + DataInputStream in = new DataInputStream(stream); + + try { + + UUID uuid = UUID.fromString(in.readUTF()); + DebugManager.log("{multichat:chat} UUID = " + uuid); + String message = in.readUTF(); + DebugManager.log("{multichat:chat} Message = " + message); + String format = in.readUTF(); + + DebugManager.log("{multichat:chat} Format (before removal of double chars) = " + format); + + format = format.replace("%%", "%"); + + DebugManager.log("{multichat:chat} Format = " + format); + + Player player = MultiChat.getInstance().getServer().getPlayer(uuid).orElse(null); + + if (player == null) { + DebugManager.log("{multichat:chat} Could not get player! Abandoning chat message... (Is IP-Forwarding on?)"); + return; + } + + DebugManager.log("{multichat:chat} Got player successfully! Name = " + player.getUsername()); + + //synchronized (player) { + + DebugManager.log("{multichat:chat} Global Channel Available? = " + (Channel.getGlobalChannel() != null)); + Channel.getGlobalChannel().sendMessage(player, message, format); + + //} + + } catch (IOException e) { + DebugManager.log("{multichat:chat} ERROR READING PLUGIN MESSAGE"); + e.printStackTrace(); + } + + + return; + + } + + if (ev.getIdentifier().getId().equals("multichat:nick")) { + + ev.setResult(PluginMessageEvent.ForwardResult.handled()); + + ByteArrayInputStream stream = new ByteArrayInputStream(ev.getData()); + DataInputStream in = new DataInputStream(stream); + + try { + + UUID uuid = UUID.fromString(in.readUTF()); + String nick = in.readUTF(); + Player player = MultiChat.getInstance().getServer().getPlayer(uuid).orElse(null); + + if (player == null) return; + + synchronized (player) { + + /* + * Update the nickname stored somewhere and call for an update of the player + * display name in that location. (Pending the "true" value of fetch display names) + * and a new config option to decide if the display name should be set. + */ + + OptionalManages the creation, deletion and displaying of Custom broadcASTs (CASTs)
+ * + * @author Oliver Martin (Revilo410) + */ +public class CastControl { + + public static MapA class to represent a chat channel and control the messages sent etc.
+ * + * @author Oliver Martin (Revilo410) + */ +public class Channel { + + private static final GlobalChannel global; + private static final LocalChannel local; + + static { + global = new GlobalChannel("&f%DISPLAYNAME%&f: "); + local = new LocalChannel(); + } + + public static GlobalChannel getGlobalChannel() { + return global; + } + + public static LocalChannel getLocalChannel() { + return local; + } + + public static MapThis class now only serves the purpose of replacing the placeholders in message formats
+ * + *It used to manage "fixing format codes" and "getting URLBIT" before these were made redundant
+ * + * @author Oliver Martin (Revilo410) + * + */ +public class ChatManipulation { + + public String replaceMsgVars(String messageFormat, String message, Player sender, Player target) { + + messageFormat = messageFormat.replace("%MESSAGE%", message); + messageFormat = messageFormat.replace("%DISPLAYNAME%", sender.getUsername()); + messageFormat = messageFormat.replace("%NAME%", sender.getUsername()); + + OptionalManages loading / creation of an individual configuration file
+ * + * @author Oliver Martin (Revilo410) + */ +public class ConfigHandler { + + // The config file + private ConfigurationNode config; + // Path of config file + private final File configPath; + // Name of config file + private final String fileName; + + public ConfigHandler(File configPath, String fileName) { + + this.configPath = configPath; + this.config = null; + this.fileName = fileName; + this.startupConfig(); + + } + + public ConfigurationNode getConfig() { + if (config == null) startupConfig(); + return config; + } + + public void startupConfig() { + + try { + + File file = new File(configPath, fileName); + + if (!file.exists()) { + + MultiChat.getInstance().getLogger().info("Config file " + fileName + " not found... Creating new one."); + saveDefaultConfig(); + + loadConfig(); + + } else { + + MultiChat.getInstance().getLogger().info("Loading " + fileName + "..."); + loadConfig(); + + } + + } catch (Exception e) { + MultiChat.getInstance().getLogger().info("[ERROR] Could not load " + fileName); + e.printStackTrace(); + } + } + + private void saveDefaultConfig() { + + // Load default file into input stream + // Copy to desired location + try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(fileName)) { + Files.copy(Objects.requireNonNull(inputStream), new File(configPath, fileName).toPath()); + } catch (IOException | NullPointerException e) { + MultiChat.getInstance().getLogger().info("[ERROR] Could not create new " + fileName + " file..."); + e.printStackTrace(); + } + } + + private void loadConfig() { + try { + this.config = YAMLConfigurationLoader.builder().setFile(new File(configPath, fileName)).build().load(); + } catch (IOException e) { + MultiChat.getInstance().getLogger().info("[ERROR] Could not load " + fileName + " file..."); + e.printStackTrace(); + } + } +} diff --git a/multichat/src/main/java/xyz/olivermartin/multichat/velocity/ConfigManager.java b/multichat/src/main/java/xyz/olivermartin/multichat/velocity/ConfigManager.java new file mode 100644 index 00000000..d44d84f3 --- /dev/null +++ b/multichat/src/main/java/xyz/olivermartin/multichat/velocity/ConfigManager.java @@ -0,0 +1,71 @@ +package xyz.olivermartin.multichat.velocity; + + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * Configuration Manager Class + *Manages all access and creation of the config.yml file
+ * + * @author Oliver Martin (Revilo410) + */ +public class ConfigManager { + + private static final ConfigManager instance; + + static { + + instance = new ConfigManager(); + + } + + public static ConfigManager getInstance() { + return instance; + } + + // END OF STATIC + + private final MapManages the majority of the event listeners, chat message, login and logout
+ * + * @author Oliver Martin (Revilo410) + */ +public class Events { + + public static ListHandles Group Chat Operations
+ * + * @author Oliver Martin (Revilo410) + */ +public class GroupManager { + + /** + * Creates a new informal group chat based on the specified parameters + * Also adds the creator to the group as the owner + */ + public void createGroup(String groupname, UUID owneruuid, boolean secret, String password) { + + TGroupChatInfo newgroup = new TGroupChatInfo(); + + newgroup.addMember(owneruuid); + newgroup.addViewer(owneruuid); + newgroup.addAdmin(owneruuid); + newgroup.setName(groupname.toLowerCase()); + newgroup.setChatColor(ConfigManager.getInstance().getHandler("config.yml").getConfig().getNode("groupchat").getNode("ccdefault").getString().toCharArray()[0]); + newgroup.setNameColor(ConfigManager.getInstance().getHandler("config.yml").getConfig().getNode("groupchat").getNode("ncdefault").getString().toCharArray()[0]); + newgroup.setSecret(secret); + newgroup.setPassword(password); + newgroup.setFormal(false); + + MultiChat.groupchats.put(groupname.toLowerCase(), newgroup); + + } + + /** + * Adds a player to a group chat while removing them from the spy list if they were spying on it before + * This will also check if they are banned and stop them being added + * It will also check if they are already a member + * Passwords for the group are also checked + */ + public boolean joinGroup(String groupname, Player player, String password) { + + boolean success = false; + + TGroupChatInfo groupchat = MultiChat.groupchats.get(groupname.toLowerCase()); + + if (!groupchat.existsBanned(player.getUniqueId())) { + + if (!groupchat.existsMember(player.getUniqueId())) { + + if (!groupchat.getSecret()) { + + if (groupchat.existsViewer(player.getUniqueId())) { + + if (player.hasPermission("multichat.staff.spy")) { + + MessageManager.sendSpecialMessage(player, "command_group_spy_off", groupname.toUpperCase()); + groupchat.delViewer(player.getUniqueId()); + + } else { + + groupchat.delViewer(player.getUniqueId()); + + } + + } + + groupchat.addMember(player.getUniqueId()); + groupchat.addViewer(player.getUniqueId()); + + MultiChat.groupchats.remove(groupname.toLowerCase()); + MultiChat.groupchats.put(groupname.toLowerCase(), groupchat); + + success = true; + + } else { + + if (password.equals("")) { + + MessageManager.sendSpecialMessage(player, "groups_password_protected", groupname.toUpperCase()); + + } else { + + if (password.equals(groupchat.getPassword())) { + + if (groupchat.existsViewer(player.getUniqueId())) { + + if (player.hasPermission("multichat.staff.spy")) { + + MessageManager.sendSpecialMessage(player, "command_group_spy_off", groupname.toUpperCase()); + groupchat.delViewer(player.getUniqueId()); + + } else { + groupchat.delViewer(player.getUniqueId()); + } + + } + + groupchat.addMember(player.getUniqueId()); + groupchat.addViewer(player.getUniqueId()); + + MultiChat.groupchats.remove(groupname.toLowerCase()); + MultiChat.groupchats.put(groupname.toLowerCase(), groupchat); + + success = true; + + } else { + + MessageManager.sendSpecialMessage(player, "groups_password_incorrect", groupname.toUpperCase()); + + } + + } + } + + } else { + MessageManager.sendSpecialMessage(player, "groups_already_joined", groupname.toUpperCase()); + } + + } else { + MessageManager.sendSpecialMessage(player, "groups_banned", groupname.toUpperCase()); + } + return success; + } + + /** + * Sets the selected group of a player to the specified group + */ + public void setViewedChat(UUID playeruuid, String groupname) { + + String viewedchat = groupname.toLowerCase(); + MultiChat.viewedchats.remove(playeruuid); + MultiChat.viewedchats.put(playeruuid, viewedchat); + + } + + /** + * The INFO announce in a group that a player has joined + */ + public void announceJoinGroup(String playername, String groupname) { + + GCCommand.sendMessage(playername + MessageManager.getMessage("groups_info_joined"), "&lINFO", MultiChat.groupchats.get(groupname.toLowerCase())); + + } + + /** + * The INFO announce in a group that a player has left + */ + public void announceQuitGroup(String playername, String groupname) { + + GCCommand.sendMessage(playername + MessageManager.getMessage("groups_info_quit"), "&lINFO", MultiChat.groupchats.get(groupname.toLowerCase())); + + } + + /** + * Quits a group, announces in the group chat and notifies the player quitting + */ + public void quitGroup(String groupname, UUID player, Player pinstance) { + + TGroupChatInfo groupchatinfo = MultiChat.groupchats.get(groupname.toLowerCase()); + + if (groupchatinfo.existsMember(player)) { + + if ((!groupchatinfo.existsAdmin(player)) || (groupchatinfo.getAdmins().size() > 1)) { + + groupchatinfo.delMember(player); + groupchatinfo.delViewer(player); + + if (groupchatinfo.existsAdmin(player)) { + groupchatinfo.delAdmin(player); + } + + MultiChat.viewedchats.remove(player); + MultiChat.viewedchats.put(player, null); + MultiChat.groupchats.remove(groupname.toLowerCase()); + MultiChat.groupchats.put(groupname.toLowerCase(), groupchatinfo); + + MessageManager.sendSpecialMessage(pinstance, "groups_quit", groupname.toUpperCase()); + announceQuitGroup(pinstance.getUsername(), groupname); + + } else if (!groupchatinfo.getFormal()) { + + MessageManager.sendSpecialMessage(pinstance, "groups_cannot_quit_owner_1", groupname.toUpperCase()); + MessageManager.sendSpecialMessage(pinstance, "groups_cannot_quit_owner_2", groupname.toUpperCase()); + + } else { + + MessageManager.sendSpecialMessage(pinstance, "groups_cannot_quit_admin_1", groupname.toUpperCase()); + MessageManager.sendSpecialMessage(pinstance, "groups_cannot_quit_admin_2", groupname.toUpperCase()); + } + + } else { + + MessageManager.sendSpecialMessage(pinstance, "command_group_not_a_member", groupname.toUpperCase()); + + } + } + + public void displayHelp(int page, CommandSource sender) { + + if (page == 1) { + + MessageManager.sendMessage(sender, "groups_help_1"); + + } else { + + MessageManager.sendMessage(sender, "groups_help_2"); + + } + } +} diff --git a/multichat/src/main/java/xyz/olivermartin/multichat/velocity/LocalChannel.java b/multichat/src/main/java/xyz/olivermartin/multichat/velocity/LocalChannel.java new file mode 100644 index 00000000..07115f69 --- /dev/null +++ b/multichat/src/main/java/xyz/olivermartin/multichat/velocity/LocalChannel.java @@ -0,0 +1,32 @@ +package xyz.olivermartin.multichat.velocity; + +import com.velocitypowered.api.command.CommandSource; +import com.velocitypowered.api.proxy.Player; + +public class LocalChannel extends Channel { + + public LocalChannel() { + super("local", "", false, false); + } + + /** + * This has no purpose as local chat for players is handled by the local servers + */ + @Override + public void sendMessage(Player sender, String message, String format) { + /* EMPTY */ + } + + @Override + public void sendMessage(String message, CommandSource sender) { + + DebugManager.log("LocalChannel wants to send a cast message!"); + + // Use this to relay CASTS to local chat! + if (sender instanceof Player) { + BungeeComm.sendChatMessage(message, ((Player) sender).getCurrentServer().get().getServerInfo()); + } + + } + +} diff --git a/multichat/src/main/java/xyz/olivermartin/multichat/velocity/MessageManager.java b/multichat/src/main/java/xyz/olivermartin/multichat/velocity/MessageManager.java new file mode 100644 index 00000000..fc3fe787 --- /dev/null +++ b/multichat/src/main/java/xyz/olivermartin/multichat/velocity/MessageManager.java @@ -0,0 +1,455 @@ +package xyz.olivermartin.multichat.velocity; + +import com.velocitypowered.api.command.CommandSource; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import ninja.leaping.configurate.ConfigurationNode; +import com.velocitypowered.api.proxy.Player; + +import java.util.HashMap; +import java.util.Map; + +/** + * Message Manager + *Used to display all plugin messages to players
+ * + * @author Oliver Martin (Revilo410) + */ +public class MessageManager { + + private static final MapThis class is the main plugin. All plugin enable and disable control happens here.
+ * + * @author Oliver Martin (Revilo410) + */ +@Plugin(id = "multichat", name = "MultiChat", version = "1.9.9", authors = {"Revilo410", "Haha007", "Gadse", "Seraek"}) +public class MultiChat { + + public static final String LATEST_VERSION = "1.9.9"; + + public static final String[] ALLOWED_VERSIONS = new String[]{ + LATEST_VERSION, + "1.9.8", + "1.9.7", + "1.9.6", + "1.9.5", + "1.9.4", + "1.9.3", + "1.9.2", + "1.9.1", + "1.9", + "1.8.2", + "1.8.1", + "1.8", + "1.7.5", + "1.7.4", + "1.7.3", + "1.7.2", + "1.7.1", + "1.7", + "1.6.2", + "1.6.1", + "1.6", + "1.5.2", + "1.5.1", + "1.5", + "1.4.2", + "1.4.1", + "1.4", + "1.3.4", + "1.3.3", + "1.3.2", + "1.3.1", + "1.3" + + }; + + public static Map