diff --git a/pom.xml b/pom.xml index dbf2760..8bb101a 100644 --- a/pom.xml +++ b/pom.xml @@ -35,10 +35,31 @@ 8 + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + + bungeecore + + + dv8tion + m2-dv8tion + https://m2.dv8tion.net/releases + + + steamwar @@ -61,5 +82,23 @@ system ${main.basedir}/lib/BungeeTabListPlus.jar + + net.dv8tion + JDA + 4.3.0_299 + compile + + + club.minnced + opus-java + + + + + org.projectlombok + lombok + 1.18.20 + provided + \ No newline at end of file diff --git a/src/de/steamwar/bungeecore/BungeeCore.java b/src/de/steamwar/bungeecore/BungeeCore.java index e3a11b0..7dee2ca 100644 --- a/src/de/steamwar/bungeecore/BungeeCore.java +++ b/src/de/steamwar/bungeecore/BungeeCore.java @@ -19,16 +19,19 @@ package de.steamwar.bungeecore; +import de.steamwar.bungeecore.bot.SteamwarDiscordBot; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; import de.steamwar.bungeecore.commands.*; import de.steamwar.bungeecore.comms.SpigotReceiver; import de.steamwar.bungeecore.listeners.*; -import de.steamwar.bungeecore.listeners.mods.ModLoaderBlocker; import de.steamwar.bungeecore.listeners.mods.Forge; import de.steamwar.bungeecore.listeners.mods.LabyMod; +import de.steamwar.bungeecore.listeners.mods.ModLoaderBlocker; import de.steamwar.bungeecore.listeners.mods.WorldDownloader; -import de.steamwar.bungeecore.sql.SQL; +import de.steamwar.bungeecore.sql.Statement; import de.steamwar.bungeecore.sql.SteamwarUser; import de.steamwar.bungeecore.sql.Team; +import net.dv8tion.jda.api.JDA; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.ProxyServer; @@ -108,6 +111,7 @@ public class BungeeCore extends Plugin { new DenyCommand("watchcat", "wc"); new TeamCommand(); new ServerTeamchatCommand(); + new DevCommand(); new EventCommand(); new EventreloadCommand(); new EventRescheduleCommand(); @@ -121,6 +125,9 @@ public class BungeeCore extends Plugin { new UnIgnoreCommand(); new PollresultCommand(); new ResourcereloadCommand(); + new ListCommand(); + new StatCommand(); + new VerifyCommand(); if(!EVENT_MODE){ new BauCommand(); @@ -145,12 +152,20 @@ public class BungeeCore extends Plugin { SteamwarUser.clearCache(); Team.clearCache(); }, 1, 1, TimeUnit.HOURS); + + new SteamwarDiscordBot(); } @Override public void onDisable(){ ErrorLogger.stop(); - SQL.close(); + Statement.close(); + try { + SteamwarDiscordBot.instance().getJda().shutdownNow(); + SteamwarDiscordBot.instance().getJda().awaitStatus(JDA.Status.SHUTDOWN); + } catch (Exception e) { + // Ignored + } } public static BungeeCore get() { @@ -245,13 +260,14 @@ public class BungeeCore extends Plugin { Persistent.setChatPrefix(CHAT_PREFIX); Persistent.setLobbyServer(LOBBY_SERVER); - SQL.connect( + Statement.connect( config.getString("db.url"), config.getString("db.username"), config.getString("db.password") ); ArenaMode.init(config.getSection("games")); + SteamwarDiscordBotConfig.loadConfig(config.getSection("discord")); final Configuration servers = config.getSection("servers"); for(final String serverName : servers.getKeys()){ diff --git a/src/de/steamwar/bungeecore/LoadEvaluation.java b/src/de/steamwar/bungeecore/LoadEvaluation.java new file mode 100644 index 0000000..59fda6c --- /dev/null +++ b/src/de/steamwar/bungeecore/LoadEvaluation.java @@ -0,0 +1,96 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2021 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore; + +import java.io.*; + +public class LoadEvaluation { + private LoadEvaluation(){} + + private static final File meminfo = new File("/proc/meminfo"); + + public static double getRamPercentage() { + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(meminfo)))) { + String memTotal = bufferedReader.readLine().replaceAll(" +", " "); + bufferedReader.readLine(); + String memAvailable = bufferedReader.readLine().replaceAll(" +", " "); + + long memTotalLong = getNumber(memTotal); + long memAvailableLong = getNumber(memAvailable); + return (memTotalLong - memAvailableLong) / (double) memTotalLong; + } catch (IOException e) { + return 1D; + } + } + + public static double getRemoteRamPercentage(String remote) { + try { + // Attention: + // memInfo.sh needs to contain: cat /proc/meminfo + Process process = new ProcessBuilder("ssh", remote, "\"./memInfo.sh\"").start(); + process.waitFor(); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String memTotal = bufferedReader.readLine().replaceAll(" +", " "); + bufferedReader.readLine(); + String memAvailable = bufferedReader.readLine().replaceAll(" +", " "); + + long memTotalLong = getNumber(memTotal); + long memAvailableLong = getNumber(memAvailable); + return (memTotalLong - memAvailableLong) / (double) memTotalLong; + } catch (IOException e) { + return 1D; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return 1D; + } + } + + public static double getCPULoad() { + try { + Process process = new ProcessBuilder("bash", "-c", "cat <(grep 'cpu ' /proc/stat) <(sleep 1 && grep 'cpu ' /proc/stat) | awk -v RS=\"\" '{printf \"%.2f\\n\", ($13-$2+$15-$4)*100/($13-$2+$15-$4+$16-$5)}'").start(); + process.waitFor(); + return Double.parseDouble(new BufferedReader(new InputStreamReader(process.getInputStream())).readLine()) / 100.0; + } catch (IOException e) { + return 1D; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return 1D; + } + } + + public static double getRemoteCPULoad(String remote) { + try { + // Attention: + // cpuLoad.sh needs to contain: cat <(grep 'cpu ' /proc/stat) <(sleep 1 && grep 'cpu ' /proc/stat) | awk -v RS="" '{printf "%.2f\n", ($13-$2+$15-$4)*100/($13-$2+$15-$4+$16-$5)}' + Process process = new ProcessBuilder("ssh", remote, "\"./cpuLoad.sh\"").start(); + process.waitFor(); + return Double.parseDouble(new BufferedReader(new InputStreamReader(process.getInputStream())).readLine()) / 100.0; + } catch (IOException e) { + return 1D; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return 1D; + } + } + + private static long getNumber(String s) { + return Long.parseLong(s.split(" ")[1]); + } +} diff --git a/src/de/steamwar/bungeecore/SubserverSystem.java b/src/de/steamwar/bungeecore/SubserverSystem.java index 2812eb3..d5e85b0 100644 --- a/src/de/steamwar/bungeecore/SubserverSystem.java +++ b/src/de/steamwar/bungeecore/SubserverSystem.java @@ -89,7 +89,7 @@ public class SubserverSystem { * @return * The new started subserver. */ - public static Subserver startArena(ArenaMode modus, String map, int eventFightID, int checkSchemID, int prepareSchemID, String serverName, String mapName, UUID player1, UUID player2, boolean ranked){ + public static synchronized Subserver startArena(ArenaMode modus, String map, int eventFightID, int checkSchemID, int prepareSchemID, String serverName, String mapName, UUID player1, UUID player2, boolean ranked){ //Generate missing parameters int port = freePort(FIRST_ARENA_PORT); @@ -118,8 +118,10 @@ public class SubserverSystem { Thread.currentThread().interrupt(); } + File directory = new File(SERVER_PATH, modus.getFolder()); List cmd = serverStartCommand( modus.serverJar(), + directory, worldDir, mapName, port, @@ -135,7 +137,7 @@ public class SubserverSystem { //Start server ProcessBuilder process = new ProcessBuilder(cmd); - process.directory(new File(SERVER_PATH, modus.getFolder())); + process.directory(directory); String finalMapName = mapName; if(eventFightID == -1) @@ -177,7 +179,7 @@ public class SubserverSystem { startArena(m, map, -1, checkSchemId, prepareSchemId, p.getName() + "s Bau", p.getName(), p.getUniqueId(), null, false).sendPlayer(p); } - private static void sendToBau(ProxiedPlayer p, UUID owner, String prototype, String worldFolder, String serverJar, String worldDir, String worldName, String xmx, String serverName){ + private static synchronized void sendToBau(ProxiedPlayer p, UUID owner, String prototype, String worldFolder, String serverJar, String worldDir, String worldName, String xmx, String serverName){ if(bauRunning(p, owner)) return; @@ -185,8 +187,10 @@ public class SubserverSystem { copyBauweltIfRequired(p, prototype, worldFolder + worldName); int port = freePort(4000); + File directory = new File(SERVER_PATH, serverName); List cmd = serverStartCommand( serverJar, + directory, worldDir, worldName, port, @@ -195,7 +199,7 @@ public class SubserverSystem { //Start server ProcessBuilder process = new ProcessBuilder(cmd); - process.directory(new File(SERVER_PATH, serverName)); + process.directory(directory); new Bauserver(user.getUserName() + "s Bau", owner, port, process, () -> {}).sendPlayer(p); } @@ -231,9 +235,30 @@ public class SubserverSystem { new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/bau addmember " + p.getName())); } - private static List serverStartCommand(String serverJar, String worldDir, String levelName, int port, String xmx, String... dParams){ + private static List serverStartCommand(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams){ List cmd = new ArrayList<>(); boolean jdk11 = serverJar.contains("1.15.2"); + + boolean fallback = false; + if (!steamwarStartAvailable()) { + cmd.add("ssh"); + cmd.add("-L"); + cmd.add(port + ":localhost:" + port); + if (remoteStartAvailable("lx")) { + cmd.add("lx"); + } else if (remoteStartAvailable("az")) { + cmd.add("az"); + } else { + fallback = true; + } + cmd.add("cd"); + cmd.add(directory.getPath()); + cmd.add(";"); + } + if (fallback) { + cmd.clear(); + } + if(jdk11) cmd.add("/usr/lib/jvm/java-11-openjdk-amd64/bin/java"); else @@ -259,6 +284,14 @@ public class SubserverSystem { return cmd; } + private static boolean steamwarStartAvailable(){ + return LoadEvaluation.getCPULoad() < 0.7 && LoadEvaluation.getRamPercentage() < 0.8; + } + + private static boolean remoteStartAvailable(String remote) { + return LoadEvaluation.getRemoteCPULoad(remote) < 0.7 && LoadEvaluation.getRemoteRamPercentage(remote) < 0.8; + } + private static boolean bauRunning(ProxiedPlayer p, UUID owner){ for(Subserver subserver : Subserver.getServerList()){ if(subserver.getType() == Servertype.BAUSERVER && ((Bauserver)subserver).getOwner().equals(owner)){ diff --git a/src/de/steamwar/bungeecore/bot/AuthManager.java b/src/de/steamwar/bungeecore/bot/AuthManager.java new file mode 100644 index 0000000..1502b68 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/AuthManager.java @@ -0,0 +1,86 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot; + +import de.steamwar.bungeecore.BungeeCore; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import de.steamwar.bungeecore.sql.SteamwarUser; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.Emoji; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.interactions.components.ActionRow; +import net.dv8tion.jda.api.interactions.components.Button; +import net.md_5.bungee.api.scheduler.ScheduledTask; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +public class AuthManager { + + private static final Map TOKENS = new HashMap<>(); + private static final Random rand = new Random(); + + public static String createDiscordAuthToken(Member member) { + if(TOKENS.containsValue(member.getIdLong())) return null; + + byte[] randBytes = new byte[16]; + rand.nextBytes(randBytes); + randBytes[0] = 'D'; + randBytes[1] = 'C'; + String code = Base64.getEncoder().encodeToString(randBytes); + + TOKENS.put(code, member.getIdLong()); + BungeeCore.log("Created Discord Auth-Token: " + code + " for: " + member.getUser().getAsTag()); + ScheduledTask[] task = new ScheduledTask[1]; + task[0] = BungeeCore.get().getProxy().getScheduler().schedule(BungeeCore.get(), () -> { + TOKENS.remove(code); + task[0].cancel(); + }, 10, 10, TimeUnit.MINUTES); + return code; + } + + public static Member connectAuth(SteamwarUser user, String code) { + if (TOKENS.containsKey(code)) { + Member member = SteamwarDiscordBot.instance().getJda().getGuildById(SteamwarDiscordBotConfig.GUILD).retrieveMemberById(TOKENS.get(code).longValue()).complete(); + if(member == null) return null; + user.setDiscordId(member.getId()); + MessageBuilder builder = new MessageBuilder(); + builder.setContent(":white_check_mark: Dein Discord Konto wurde mit **" + user.getUserName() + "** verknüpft"); + builder.setActionRows(ActionRow.of(Button.success("tada", Emoji.fromUnicode("U+1F389")), Button.danger("invalid", "Ich war das nicht"))); + + try { + member.getUser().openPrivateChannel().complete().sendMessage(builder.build()).complete(); + if (member.getNickname() == null) { + try { + member.getGuild().modifyNickname(member, user.getUserName()).complete(); + } catch (Exception e) { + // Ignored + } + } + TOKENS.remove(code); + return member; + } catch (Exception e) { + return null; + } + } else { + return null; + } + } +} diff --git a/src/de/steamwar/bungeecore/bot/SteamwarDiscordBot.java b/src/de/steamwar/bungeecore/bot/SteamwarDiscordBot.java new file mode 100644 index 0000000..7c5f1db --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/SteamwarDiscordBot.java @@ -0,0 +1,153 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot; + +import de.steamwar.bungeecore.BungeeCore; +import de.steamwar.bungeecore.bot.commands.*; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import de.steamwar.bungeecore.bot.events.EventManager; +import de.steamwar.bungeecore.bot.events.SchematicsManager; +import de.steamwar.bungeecore.bot.listeners.*; +import de.steamwar.bungeecore.bot.util.DiscordRolesMessage; +import de.steamwar.bungeecore.bot.util.DiscordRulesMessage; +import de.steamwar.bungeecore.bot.util.DiscordTicketMessage; +import de.steamwar.bungeecore.sql.Event; +import lombok.Getter; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.OnlineStatus; +import net.dv8tion.jda.api.entities.Activity; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction; +import net.dv8tion.jda.api.utils.MemberCachePolicy; +import net.md_5.bungee.api.ProxyServer; + +import javax.security.auth.login.LoginException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class SteamwarDiscordBot { + + private static SteamwarDiscordBot INSTANCE; + + public static SteamwarDiscordBot instance() { + return INSTANCE; + } + + @Getter + private AnnouncementListener announcementListener; + + @Getter + private IngameChatListener ingameChatListener; + + @Getter + private ServerTeamChatListener serverTeamChatListener; + + @Getter + private final JDA jda; + + @Getter + private static Map discordCommandMap = new HashMap<>(); + + public SteamwarDiscordBot() { + INSTANCE = this; + JDABuilder builder = JDABuilder.createDefault(SteamwarDiscordBotConfig.TOKEN); + builder.setStatus(OnlineStatus.ONLINE); + builder.setMemberCachePolicy(MemberCachePolicy.ONLINE); + try { + jda = builder.build(); + } catch (LoginException e) { + throw new SecurityException("Could not Login: " + SteamwarDiscordBotConfig.TOKEN, e); + } + try { + jda.awaitReady(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + activity(); + EventManager.update(); + SchematicsManager.update(); + ProxyServer.getInstance().getScheduler().schedule(BungeeCore.get(), () -> { + activity(); + EventManager.update(); + SchematicsManager.update(); + }, 30, 30, TimeUnit.SECONDS); + DiscordRolesMessage.sendMessage(); + DiscordRulesMessage.sendMessage(); + DiscordTicketMessage.sendMessage(); + + new RolesInteractionButtonListener(); + new DiscordTicketListener(); + new DiscordAuthListener(); + announcementListener = new AnnouncementListener(); + ingameChatListener = new IngameChatListener(); + serverTeamChatListener = new ServerTeamChatListener(); + new SlashCommandListener(); + + jda.retrieveCommands().complete().forEach(command -> jda.deleteCommandById(command.getId()).complete()); + + Guild guild = jda.getGuildById(SteamwarDiscordBotConfig.GUILD); + guild.retrieveCommands().complete().forEach(command -> guild.deleteCommandById(command.getId()).complete()); + CommandListUpdateAction commands = jda.getGuildById(SteamwarDiscordBotConfig.GUILD).updateCommands(); + addCommand(commands, new MuteCommand()); + addCommand(commands, new BanCommand()); + addCommand(commands, new WhoisCommand()); + addCommand(commands, new TeamCommand()); + addCommand(commands, new ListCommand()); + addCommand(commands, new UnbanCommand()); + commands.complete(); + } + + private void addCommand(CommandListUpdateAction commands, BasicDiscordCommand basicDiscordCommand) { + commands.addCommands(basicDiscordCommand); + discordCommandMap.put(basicDiscordCommand.getName(), basicDiscordCommand); + } + + private int index = 0; + + private void activity() { + switch (index) { + case 0: + Event event = Event.get(); + if (event != null) { + jda.getPresence().setActivity(Activity.competing("dem Event " + event.getEventName())); + } else { + jda.getPresence().setActivity(Activity.playing("auf SteamWar.de")); + } + break; + case 1: + int count = BungeeCore.get().getProxy().getOnlineCount(); + if (count == 1) { + jda.getPresence().setActivity(Activity.playing("mit 1 Spieler")); + } else { + jda.getPresence().setActivity(Activity.playing("mit " + count + " Spielern")); + } + index = 0; + return; + } + index++; + } + + public void addListener(ListenerAdapter listenerAdapter) { + jda.addEventListener(listenerAdapter); + } +} diff --git a/src/de/steamwar/bungeecore/bot/commands/BanCommand.java b/src/de/steamwar/bungeecore/bot/commands/BanCommand.java new file mode 100644 index 0000000..7d3772f --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/commands/BanCommand.java @@ -0,0 +1,65 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.commands; + +import de.steamwar.bungeecore.Message; +import de.steamwar.bungeecore.sql.SteamwarUser; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import net.dv8tion.jda.api.interactions.commands.OptionType; + +import java.sql.Timestamp; + +public class BanCommand extends BasicDiscordCommand { + + public BanCommand() { + super("ban", "Banne einen Nutzer, wenn du die Rechte hast."); + + addOption(OptionType.STRING, "user", "Der Benutzer", true); + addOption(OptionType.STRING, "time", "Bis Wann", true); + addOption(OptionType.STRING, "reason", "Warum", true); + } + + @Override + public void run(SlashCommandEvent event) { + if (!testPermission(event)) { + return; + } + + SteamwarUser sender = SteamwarUser.get(event.getMember().getIdLong()); + SteamwarUser target = SteamwarUser.getOrCreateOfflinePlayer(event.getOption("user").getAsString()); + if (target == null) { + event.reply("Angegebener User invalide").setEphemeral(true).complete(); + return; + } + + Timestamp time = de.steamwar.bungeecore.commands.BanCommand.parseTime(null, event.getOption("time").getAsString()); + if (time == null) { + event.reply("Angegebene Zeit invalide").setEphemeral(true).complete(); + return; + } + + String msg = event.getOption("reason").getAsString(); + boolean isPerma = event.getOption("time").getAsString().equals("perma"); + + target.ban(time, msg, sender.getId(), isPerma); + Message.team("BAN_TEAM_BANNED", new Message("PREFIX"), target.getUserName(), sender.getUserName(), new Message((isPerma ? "BAN_PERMA" : "BAN_UNTIL"), time), msg); + event.reply("Erfolgreich " + target.getUserName() + (isPerma ? " permanent" : " bis " + time) + " gebannt").setEphemeral(true).complete(); + } +} diff --git a/src/de/steamwar/bungeecore/bot/commands/BasicDiscordCommand.java b/src/de/steamwar/bungeecore/bot/commands/BasicDiscordCommand.java new file mode 100644 index 0000000..a767eba --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/commands/BasicDiscordCommand.java @@ -0,0 +1,54 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.commands; + +import de.steamwar.bungeecore.sql.SteamwarUser; +import de.steamwar.bungeecore.sql.UserGroup; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import net.dv8tion.jda.api.interactions.commands.build.CommandData; + +public abstract class BasicDiscordCommand extends CommandData { + + protected BasicDiscordCommand(String name, String description) { + super(name, description); + } + + public abstract void run(SlashCommandEvent event); + + protected SteamwarUser getSteamwarUser(SlashCommandEvent event) { + Member member = event.getMember(); + SteamwarUser steamwarUser = SteamwarUser.get(member.getIdLong()); + if (steamwarUser == null) { + return null; + } + return steamwarUser; + } + + protected boolean testPermission(SlashCommandEvent event) { + Member member = event.getMember(); + SteamwarUser steamwarUser = SteamwarUser.get(member.getIdLong()); + if (steamwarUser == null || (!steamwarUser.getUserGroup().isTeamGroup() && steamwarUser.getUserGroup() != UserGroup.Builder)) { + event.reply("Du hast für " + event.getName() + " keine Rechte oder es existiert keine Verknüpfung für dich.").setEphemeral(true).complete(); + return false; + } + return true; + } +} diff --git a/src/de/steamwar/bungeecore/bot/commands/ListCommand.java b/src/de/steamwar/bungeecore/bot/commands/ListCommand.java new file mode 100644 index 0000000..2050180 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/commands/ListCommand.java @@ -0,0 +1,43 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.commands; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; + +import java.util.stream.Collectors; + +public class ListCommand extends BasicDiscordCommand { + + public ListCommand() { + super("list", "Gebe eine Liste aller online Spieler"); + } + + @Override + public void run(SlashCommandEvent event) { + de.steamwar.bungeecore.commands.ListCommand.updateCustomTablist(); + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setTitle("List"); + de.steamwar.bungeecore.commands.ListCommand.getPlayerMap().forEach((s, proxiedPlayers) -> { + embedBuilder.addField(s, proxiedPlayers.stream().map(player -> "`" + player.getName() + "`").collect(Collectors.joining(", ")), true); + }); + event.replyEmbeds(embedBuilder.build()).setEphemeral(true).complete(); + } +} diff --git a/src/de/steamwar/bungeecore/bot/commands/MuteCommand.java b/src/de/steamwar/bungeecore/bot/commands/MuteCommand.java new file mode 100644 index 0000000..700baac --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/commands/MuteCommand.java @@ -0,0 +1,66 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.commands; + +import de.steamwar.bungeecore.Message; +import de.steamwar.bungeecore.commands.BanCommand; +import de.steamwar.bungeecore.sql.SteamwarUser; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import net.dv8tion.jda.api.interactions.commands.OptionType; + +import java.sql.Timestamp; + +public class MuteCommand extends BasicDiscordCommand { + + public MuteCommand() { + super("mute", "Mute einen Nutzer, wenn du die Rechte hast."); + + addOption(OptionType.STRING, "user", "Der Benutzer", true); + addOption(OptionType.STRING, "time", "Bis Wann", true); + addOption(OptionType.STRING, "reason", "Warum", true); + } + + @Override + public void run(SlashCommandEvent event) { + if (!testPermission(event)) { + return; + } + + SteamwarUser sender = SteamwarUser.get(event.getMember().getIdLong()); + SteamwarUser target = SteamwarUser.getOrCreateOfflinePlayer(event.getOption("user").getAsString()); + if (target == null) { + event.reply("Angegebener User invalide").setEphemeral(true).complete(); + return; + } + + Timestamp time = BanCommand.parseTime(null, event.getOption("time").getAsString()); + if (time == null) { + event.reply("Angegebene Zeit invalide").setEphemeral(true).complete(); + return; + } + + String msg = event.getOption("reason").getAsString(); + boolean isPerma = event.getOption("time").getAsString().equals("perma"); + + target.mute(time, msg, sender.getId(), isPerma); + Message.team("MUTE_TEAM_MUTED", new Message("PREFIX"), target.getUserName(), sender.getUserName(), new Message((isPerma ? "BAN_PERMA" : "BAN_UNTIL"), time), msg); + event.reply("Erfolgreich " + target.getUserName() + (isPerma ? " permanent" : " bis " + time) + " gemutet").setEphemeral(true).complete(); + } +} diff --git a/src/de/steamwar/bungeecore/bot/commands/TeamCommand.java b/src/de/steamwar/bungeecore/bot/commands/TeamCommand.java new file mode 100644 index 0000000..53d7039 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/commands/TeamCommand.java @@ -0,0 +1,96 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.commands; + +import de.steamwar.bungeecore.sql.Event; +import de.steamwar.bungeecore.sql.SteamwarUser; +import de.steamwar.bungeecore.sql.Team; +import de.steamwar.bungeecore.sql.TeamTeilnahme; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Emoji; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; +import net.md_5.bungee.api.ProxyServer; + +import java.awt.*; +import java.util.List; +import java.util.stream.Collectors; + +public class TeamCommand extends BasicDiscordCommand { + + public TeamCommand() { + super("team", "Alle Team bezogenen Befehle"); + + addSubcommands(new SubcommandData("info", "Infos über das Team oder deins") + .addOption(OptionType.STRING, "team", "Name oder Kuerzel", false) + ); + } + + private Emoji emoji = Emoji.fromUnicode("U+1F7E2"); + + @Override + public void run(SlashCommandEvent event) { + SteamwarUser steamwarUser = getSteamwarUser(event); + + if (event.getSubcommandName() != null) { + switch (event.getSubcommandName()) { + case "info": + OptionMapping optionMapping = event.getOption("team"); + Team team; + if (optionMapping == null) { + if (steamwarUser == null) { + event.reply("Dein Discord ist nicht verknüpft").setEphemeral(true).complete(); + return; + } + if (steamwarUser.getTeam() == 0) { + event.reply("Du bist in keinem Team").setEphemeral(true).complete(); + return; + } + team = Team.get(steamwarUser.getTeam()); + } else { + team = Team.get(optionMapping.getAsString()); + } + if (team == null) { + event.reply("Unbekanntes Team").setEphemeral(true).complete(); + return; + } + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setTitle("Team: " + team.getTeamName() + " [" + team.getTeamKuerzel() + "]"); + embedBuilder.setColor(Color.GRAY); + List members = team.getMembers().stream().map(SteamwarUser::get).collect(Collectors.toList()); + + embedBuilder.addField("Leader", members.stream().filter(SteamwarUser::isLeader).map(user -> "`" + (isOnline(user) ? emoji.getAsMention() : "") + user.getUserName() + "`").collect(Collectors.joining(" ")), false); + embedBuilder.addField("Member", members.stream().filter(user -> !user.isLeader()).map(user -> "`" + (isOnline(user) ? emoji.getAsMention() : "") + user.getUserName() + "`").collect(Collectors.joining(" ")), false); + embedBuilder.addField("Events", "`" + TeamTeilnahme.getEvents(team.getTeamId()).stream().map(Event::getEventName).collect(Collectors.joining("` `")) + "`", false); + event.replyEmbeds(embedBuilder.build()).setEphemeral(true).complete(); + return; + default: + event.reply("Unbekannter Befehl").setEphemeral(true).complete(); + return; + } + } + } + + private boolean isOnline(SteamwarUser user) { + return ProxyServer.getInstance().getPlayer(user.getUuid()) != null; + } +} diff --git a/src/de/steamwar/bungeecore/bot/commands/UnbanCommand.java b/src/de/steamwar/bungeecore/bot/commands/UnbanCommand.java new file mode 100644 index 0000000..7147108 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/commands/UnbanCommand.java @@ -0,0 +1,59 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.commands; + +import de.steamwar.bungeecore.Message; +import de.steamwar.bungeecore.sql.SteamwarUser; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import net.dv8tion.jda.api.interactions.commands.OptionType; + +import java.sql.Timestamp; +import java.util.Date; + +public class UnbanCommand extends BasicDiscordCommand { + + public UnbanCommand() { + super("unban", "Entbannt einen Nutzer, wenn du die Rechte hast."); + + addOption(OptionType.STRING, "user", "Der Benutzer", true); + } + + @Override + public void run(SlashCommandEvent event) { + if (!testPermission(event)) { + return; + } + + SteamwarUser sender = SteamwarUser.get(event.getMember().getIdLong()); + SteamwarUser target = SteamwarUser.getOrCreateOfflinePlayer(event.getOption("user").getAsString()); + if (target == null) { + event.reply("Angegebener User invalide").setEphemeral(true).complete(); + return; + } + + if (!target.isBanned()) { + event.reply("Angegebener User ist nicht gebannt").setEphemeral(true).complete(); + return; + } + + target.ban(Timestamp.from(new Date().toInstant()), "Unban", sender.getId(), false); + event.reply("Erfolgreich " + target.getUserName() + " entbannt").setEphemeral(true).complete(); + } +} diff --git a/src/de/steamwar/bungeecore/bot/commands/WhoisCommand.java b/src/de/steamwar/bungeecore/bot/commands/WhoisCommand.java new file mode 100644 index 0000000..b40c049 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/commands/WhoisCommand.java @@ -0,0 +1,94 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.commands; + +import de.steamwar.bungeecore.sql.Punishment; +import de.steamwar.bungeecore.sql.SteamwarUser; +import de.steamwar.bungeecore.sql.Team; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import net.dv8tion.jda.api.interactions.commands.OptionType; + +import java.sql.Timestamp; +import java.text.DecimalFormat; +import java.util.List; + +public class WhoisCommand extends BasicDiscordCommand { + + public WhoisCommand() { + super("whois", "Der whois Befehl"); + + addOption(OptionType.STRING, "user", "Der Benutzer", true); + } + + @Override + public void run(SlashCommandEvent event) { + if (!testPermission(event)) { + return; + } + + String s = event.getOption("user").getAsString(); + + SteamwarUser user = SteamwarUser.get(s); + if (user == null) { + try { + int id = Integer.parseInt(s); + user = SteamwarUser.get(id); + } catch (NumberFormatException ignored) { + // Ignored + } + } + if (user == null) { + try { + long id = Long.parseLong(s); + user = SteamwarUser.get(id); + } catch (NumberFormatException ignored) { + // Ignored + } + } + + if (user == null) { + event.reply("Der angegebene Spieler ist unbekannt").setEphemeral(true).complete(); + return; + } + + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setTitle("Whois: " + user.getUserName()); + StringBuilder st = new StringBuilder(); + st.append("UUID: ").append(user.getUuid()).append("\n"); + st.append("ID: ").append(user.getId()).append("\n"); + if (user.getDiscordId() != null) { + st.append("DiscordID: ").append(user.getDiscordId()).append("\n"); + } + Timestamp timestamp = user.getFirstjoin(); + st.append("Beigetreten am: ").append(timestamp == null ? "0000-00-00 00:00:00" : timestamp.toString()).append("\n"); + st.append("Online Time: ").append(new DecimalFormat("###.##").format(user.getOnlinetime() / (double) 3600)).append("h\n"); + Team team = Team.get(user.getTeam()); + st.append("Team: [").append(team.getTeamKuerzel()).append("] ").append(team.getTeamName()); + embedBuilder.addField("Daten:", st.toString(), false); + + List punishmentList = Punishment.getAllPunishmentsOfPlayer(user.getId()); + for (Punishment punishment : punishmentList) { + embedBuilder.addField(punishment.getType().name() + " von " + SteamwarUser.get(punishment.getPunisher()).getUserName(), "Von: " + punishment.getBantime(punishment.getStartTime(), false) + "\nBis: " + punishment.getBantime(punishment.getEndTime(), punishment.isPerma()) + "\nGrund: " + punishment.getReason(), true); + } + + event.replyEmbeds(embedBuilder.build()).setEphemeral(true).complete(); + } +} diff --git a/src/de/steamwar/bungeecore/bot/config/DiscordRole.java b/src/de/steamwar/bungeecore/bot/config/DiscordRole.java new file mode 100644 index 0000000..68b57be --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/config/DiscordRole.java @@ -0,0 +1,39 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.config; + +import lombok.AllArgsConstructor; +import lombok.Data; +import net.dv8tion.jda.api.entities.Emoji; +import net.dv8tion.jda.api.interactions.components.Button; +import net.dv8tion.jda.api.interactions.components.ButtonStyle; + +@Data +@AllArgsConstructor +public class DiscordRole { + + private String emoji; + private String label; + private String roleId; + + public Button toButton() { + return Button.of(ButtonStyle.SECONDARY, roleId, label, Emoji.fromUnicode(emoji)); + } +} diff --git a/src/de/steamwar/bungeecore/bot/config/DiscordRulesLink.java b/src/de/steamwar/bungeecore/bot/config/DiscordRulesLink.java new file mode 100644 index 0000000..4f2ebe0 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/config/DiscordRulesLink.java @@ -0,0 +1,36 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.config; + +import lombok.AllArgsConstructor; +import lombok.Data; +import net.dv8tion.jda.api.interactions.components.Button; + +@Data +@AllArgsConstructor +public class DiscordRulesLink { + + private String label; + private String link; + + public Button toButton() { + return Button.link(link, label); + } +} diff --git a/src/de/steamwar/bungeecore/bot/config/DiscordTicketType.java b/src/de/steamwar/bungeecore/bot/config/DiscordTicketType.java new file mode 100644 index 0000000..5ba4c65 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/config/DiscordTicketType.java @@ -0,0 +1,41 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.config; + +import lombok.AllArgsConstructor; +import lombok.Data; +import net.dv8tion.jda.api.entities.Emoji; +import net.dv8tion.jda.api.interactions.components.Button; +import net.dv8tion.jda.api.interactions.components.ButtonStyle; + +@Data +@AllArgsConstructor +public class DiscordTicketType { + + private String key; + private String emoji; + private String label; + private String color; + private String preMessage; + + public Button toButton() { + return Button.of(ButtonStyle.valueOf(color), key, Emoji.fromUnicode(emoji)).withLabel(label); + } +} diff --git a/src/de/steamwar/bungeecore/bot/config/SteamwarDiscordBotConfig.java b/src/de/steamwar/bungeecore/bot/config/SteamwarDiscordBotConfig.java new file mode 100644 index 0000000..f69a3ac --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/config/SteamwarDiscordBotConfig.java @@ -0,0 +1,114 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.config; + +import de.steamwar.bungeecore.sql.UserGroup; +import net.md_5.bungee.config.Configuration; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class SteamwarDiscordBotConfig { + + public static String TOKEN; + public static String GUILD; + public static String ANNOUNCEMENTS_CHANNEL; + public static String EVENTS_CHANNEL; + public static String INGAME_CHANNEL; + public static String SERVER_TEAM_CHANNEL; + public static String SCHEMATICS_CHANNEL; + public static String ROLES_CHANNEL; + public static String ROLES_BASE_MESSAGE; + public static String ROLES_ADDED; + public static String ROLES_REMOVED; + public static List ROLES; + public static String RULES_CHANNEL; + public static String RULES_TITLE; + public static List RULES_RULES; + public static List RULES_LINKS; + public static String TICKET_CATEGORY; + public static String TICKET_CHANNEL; + public static String TICKET_MESSAGE; + public static String TICKET_CREATED; + public static String TICKET_LOG; + public static Map TICKET_TYPES; + public static Map RANKS; + + public static void loadConfig(Configuration config) { + TOKEN = config.getString("token"); + GUILD = config.getString("guild"); + ANNOUNCEMENTS_CHANNEL = config.getString("announcements-channel"); + EVENTS_CHANNEL = config.getString("events-channel"); + INGAME_CHANNEL = config.getString("ingame-channel"); + SERVER_TEAM_CHANNEL = config.getString("server-team-channel"); + SCHEMATICS_CHANNEL = config.getString("schematics-channel"); + Configuration rolesSection = config.getSection("roles-claim"); + ROLES_CHANNEL = rolesSection.getString("channel"); + ROLES_BASE_MESSAGE = rolesSection.getString("base"); + ROLES_ADDED = rolesSection.getString("added"); + ROLES_REMOVED = rolesSection.getString("removed"); + ROLES = new ArrayList<>(); + + for (String roles : rolesSection.getSection("roles").getKeys()) { + Configuration role = rolesSection.getSection("roles").getSection(roles); + ROLES.add(new DiscordRole(role.getString("emoji"), + role.getString("label"), + role.getString("roleId"))); + } + + Configuration rulesSection = config.getSection("rules"); + RULES_CHANNEL = rulesSection.getString("channel"); + RULES_TITLE = rulesSection.getString("title"); + RULES_RULES = rulesSection.getStringList("rules"); + + RULES_LINKS = new ArrayList<>(); + + for (String links : rulesSection.getSection("links").getKeys()) { + Configuration link = rulesSection.getSection("links").getSection(links); + RULES_LINKS.add(new DiscordRulesLink(link.getString("label"), + link.getString("url"))); + } + + Configuration ticketSection = config.getSection("tickets"); + TICKET_CATEGORY = ticketSection.getString("category"); + TICKET_CHANNEL = ticketSection.getString("channel"); + TICKET_MESSAGE = ticketSection.getString("message"); + TICKET_CREATED = ticketSection.getString("created"); + TICKET_LOG = ticketSection.getString("log"); + TICKET_TYPES = new HashMap<>(); + + for (String types : ticketSection.getSection("types").getKeys()) { + Configuration type = ticketSection.getSection("types").getSection(types); + TICKET_TYPES.put(types, new DiscordTicketType(types, + type.getString("emoji"), + type.getString("label"), + type.getString("color"), + type.getString("pre"))); + } + + RANKS = new HashMap<>(); + Configuration ranksSections = config.getSection("ranks"); + for (String type : ranksSections.getKeys()) { + RANKS.put(UserGroup.getUsergroup(type), ranksSections.getString(type)); + } + } +} diff --git a/src/de/steamwar/bungeecore/bot/events/EventManager.java b/src/de/steamwar/bungeecore/bot/events/EventManager.java new file mode 100644 index 0000000..56f982c --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/events/EventManager.java @@ -0,0 +1,128 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.events; + +import de.steamwar.bungeecore.bot.SteamwarDiscordBot; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import de.steamwar.bungeecore.sql.Event; +import de.steamwar.bungeecore.sql.EventFight; +import de.steamwar.bungeecore.sql.Team; +import de.steamwar.bungeecore.sql.TeamTeilnahme; +import lombok.experimental.UtilityClass; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; + +import java.awt.*; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.stream.Collectors; + +@UtilityClass +public class EventManager { + + private Message message; + private TextChannel textChannel; + + static { + textChannel = SteamwarDiscordBot.instance().getJda().getGuildById(SteamwarDiscordBotConfig.GUILD).getTextChannelById(SteamwarDiscordBotConfig.EVENTS_CHANNEL); + assert textChannel != null; + if(textChannel.hasLatestMessage()) { + message = textChannel.getIterableHistory().complete().stream().filter(m -> m.getAuthor().isBot()).findFirst().orElse(null); + } + } + + public void update() { + if (Event.get() == null) { + updateComing(); + } else { + updateCurrent(); + } + } + + private void updateComing() { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.GRAY); + embedBuilder.setTitle("Zukünftige Events"); + embedBuilder.setAuthor("SteamWar", "https://www.steamwar.de"); + + Timestamp now = Timestamp.from(Instant.now()); + Event.getComing().forEach(event -> { + StringBuilder st = new StringBuilder(); + if (event.getDeadline().after(now)) { + st.append("Deadline: \n"); + } + st.append("Start: "); + String teilname = TeamTeilnahme.getTeams(event.getEventID()).stream().map(Team::getTeamKuerzel).collect(Collectors.joining(", ")); + if (!teilname.isEmpty()) { + st.append("\nAngemeldete Teams: ").append(teilname); + } + embedBuilder.addField(event.getEventName(), st.toString(), false); + }); + + MessageBuilder messageBuilder = new MessageBuilder(); + messageBuilder.setEmbeds(embedBuilder.build()); + if (message == null) { + message = textChannel.sendMessage(messageBuilder.build()).complete(); + } else { + message.editMessage(messageBuilder.build()).complete(); + } + } + + private void updateCurrent() { + Event event = Event.get(); + if (event == null) return; + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.GRAY); + embedBuilder.setTitle("Event: " + event.getEventName()); + embedBuilder.setAuthor("SteamWar", "https://www.steamwar.de"); + + Instant now = Instant.now(); + EventFight.getEvent(event.getEventID()).forEach(eventFight -> { + Team teamBlue = Team.get(eventFight.getTeamBlue()); + Team teamRed = Team.get(eventFight.getTeamRed()); + + StringBuilder st = new StringBuilder(); + st.append("Fightbeginn: "); + if(now.isAfter(eventFight.getStartTime().toInstant().plus(35, ChronoUnit.MINUTES))) { + st.append("\n"); + if (eventFight.getErgebnis() == 1) { + st.append("Sieg ").append(teamBlue.getTeamKuerzel()); + } else if (eventFight.getErgebnis() == 2) { + st.append("Sieg ").append(teamRed.getTeamKuerzel()); + } else { + st.append("Unentschieden"); + } + } + embedBuilder.addField(teamBlue.getTeamKuerzel() + " vs. " + teamRed.getTeamKuerzel(), st.toString(), true); + }); + + MessageBuilder messageBuilder = new MessageBuilder(); + messageBuilder.setEmbeds(embedBuilder.build()); + if (message == null) { + message = textChannel.sendMessage(messageBuilder.build()).complete(); + } else { + message.editMessage(messageBuilder.build()).complete(); + } + } + +} diff --git a/src/de/steamwar/bungeecore/bot/events/SchematicsManager.java b/src/de/steamwar/bungeecore/bot/events/SchematicsManager.java new file mode 100644 index 0000000..64809e1 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/events/SchematicsManager.java @@ -0,0 +1,73 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.events; + +import de.steamwar.bungeecore.bot.SteamwarDiscordBot; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import de.steamwar.bungeecore.commands.CheckCommand; +import de.steamwar.bungeecore.sql.SteamwarUser; +import lombok.experimental.UtilityClass; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; + +import java.awt.*; + +@UtilityClass +public class SchematicsManager { + + private Message message; + private TextChannel textChannel; + + static { + textChannel = SteamwarDiscordBot.instance().getJda().getGuildById(SteamwarDiscordBotConfig.GUILD).getTextChannelById(SteamwarDiscordBotConfig.SCHEMATICS_CHANNEL); + assert textChannel != null; + if(textChannel.hasLatestMessage()) { + message = textChannel.getIterableHistory().complete().stream().filter(m -> m.getAuthor().isBot()).findFirst().orElse(null); + } + } + + public void update() { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.GRAY); + embedBuilder.setTitle("Check List"); + embedBuilder.setAuthor("SteamWar", "https://www.steamwar.de"); + + CheckCommand.getSchemsToCheck().forEach(schematic -> { + StringBuilder st = new StringBuilder(); + st.append("Typ: ").append(schematic.getSchemType().getKuerzel()); + st.append("\nVon: ").append(SteamwarUser.get(schematic.getSchemOwner()).getUserName()); + String checker = CheckCommand.getChecker(schematic); + if (checker != null) { + st.append("\nWird Geprüft von: ").append(checker); + } + embedBuilder.addField(schematic.getSchemName(), st.toString(), true); + }); + + MessageBuilder messageBuilder = new MessageBuilder(); + messageBuilder.setEmbeds(embedBuilder.build()); + if (message == null) { + message = textChannel.sendMessage(messageBuilder.build()).complete(); + } else { + message.editMessage(messageBuilder.build()).queue(); + } + } +} diff --git a/src/de/steamwar/bungeecore/bot/listeners/AnnouncementListener.java b/src/de/steamwar/bungeecore/bot/listeners/AnnouncementListener.java new file mode 100644 index 0000000..2877fbd --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/listeners/AnnouncementListener.java @@ -0,0 +1,50 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.listeners; + +import de.steamwar.bungeecore.Message; +import de.steamwar.bungeecore.bot.SteamwarDiscordBot; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import org.jetbrains.annotations.NotNull; + +public class AnnouncementListener extends BasicDiscordListener { + + @Override + public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) { + if (!event.getChannel().getId().equals(SteamwarDiscordBotConfig.ANNOUNCEMENTS_CHANNEL)) { + return; + } + if (event.getAuthor().isBot()) { + return; + } + Message.broadcast("ALERT", event.getMessage().getContentDisplay()); + } + + public void announce(String message) { + TextChannel textChannel = SteamwarDiscordBot.instance().getJda().getGuildById(SteamwarDiscordBotConfig.GUILD).getTextChannelById(SteamwarDiscordBotConfig.ANNOUNCEMENTS_CHANNEL); + assert textChannel != null; + MessageBuilder messageBuilder = new MessageBuilder(); + messageBuilder.append(message.replace("&", "")); + textChannel.sendMessage(messageBuilder.build()).complete(); + } +} diff --git a/src/de/steamwar/bungeecore/bot/listeners/BasicDiscordListener.java b/src/de/steamwar/bungeecore/bot/listeners/BasicDiscordListener.java new file mode 100644 index 0000000..1c8a5ff --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/listeners/BasicDiscordListener.java @@ -0,0 +1,30 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.listeners; + +import de.steamwar.bungeecore.bot.SteamwarDiscordBot; +import net.dv8tion.jda.api.hooks.ListenerAdapter; + +public abstract class BasicDiscordListener extends ListenerAdapter { + + BasicDiscordListener() { + SteamwarDiscordBot.instance().addListener(this); + } +} diff --git a/src/de/steamwar/bungeecore/bot/listeners/DiscordAuthListener.java b/src/de/steamwar/bungeecore/bot/listeners/DiscordAuthListener.java new file mode 100644 index 0000000..514b193 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/listeners/DiscordAuthListener.java @@ -0,0 +1,59 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.listeners; + +import de.steamwar.bungeecore.bot.AuthManager; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import de.steamwar.bungeecore.sql.SteamwarUser; +import net.dv8tion.jda.api.entities.ChannelType; +import net.dv8tion.jda.api.events.interaction.GenericComponentInteractionCreateEvent; +import net.dv8tion.jda.api.interactions.InteractionType; +import org.jetbrains.annotations.NotNull; + +public class DiscordAuthListener extends BasicDiscordListener { + + @Override + public void onGenericComponentInteractionCreate(@NotNull GenericComponentInteractionCreateEvent event) { + if(event.getType() == InteractionType.COMPONENT) { + if(event.getChannel().getId().equals(SteamwarDiscordBotConfig.RULES_CHANNEL) && event.getComponentId().equals("auth")) { + String authMessage = AuthManager.createDiscordAuthToken(event.getMember()); + if(authMessage != null) { + event.reply("Gebe innerhalb der nächsten 10 Minuten ``/verify " + authMessage + "`` auf dem Minecraft Server ein").setEphemeral(true).complete(); + } else { + event.reply("Du hast bereits einen Code am laufen").setEphemeral(true).complete(); + } + } + + if(event.getComponentId().equals("tada") && event.getChannelType() == ChannelType.PRIVATE) { + event.reply(":tada:").setEphemeral(false).complete(); + } + + if(event.getComponentId().equals("invalid") && event.getChannelType() == ChannelType.PRIVATE) { + SteamwarUser user = SteamwarUser.get(event.getUser().getIdLong()); + if(user == null) { + event.reply(":question: Da ist keine verknüpfung?").setEphemeral(false).complete(); + } else { + user.setDiscordId(null); + event.reply(":x: Die Verknüpfung wurde beendet").setEphemeral(false).complete(); + } + } + } + } +} diff --git a/src/de/steamwar/bungeecore/bot/listeners/DiscordTicketListener.java b/src/de/steamwar/bungeecore/bot/listeners/DiscordTicketListener.java new file mode 100644 index 0000000..1ac4920 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/listeners/DiscordTicketListener.java @@ -0,0 +1,144 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.listeners; + +import de.steamwar.bungeecore.BungeeCore; +import de.steamwar.bungeecore.Message; +import de.steamwar.bungeecore.bot.config.DiscordTicketType; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import de.steamwar.bungeecore.sql.SteamwarUser; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.events.interaction.GenericComponentInteractionCreateEvent; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.api.interactions.InteractionType; +import net.dv8tion.jda.api.interactions.components.ActionRow; +import net.dv8tion.jda.api.interactions.components.Button; +import net.md_5.bungee.api.chat.ClickEvent; +import org.jetbrains.annotations.NotNull; + +import java.awt.*; +import java.time.Instant; +import java.util.LinkedList; + +public class DiscordTicketListener extends BasicDiscordListener { + + @Override + public void onGenericComponentInteractionCreate(@NotNull GenericComponentInteractionCreateEvent event) { + if(event.getType() == InteractionType.COMPONENT && event.getChannelType() == ChannelType.TEXT && event.getTextChannel().getParent() != null && event.getTextChannel().getParent().getId().equals(SteamwarDiscordBotConfig.TICKET_CATEGORY)) { + if(event.getTextChannel().getId().equals(SteamwarDiscordBotConfig.TICKET_CHANNEL) && SteamwarDiscordBotConfig.TICKET_TYPES.containsKey(event.getComponentId())) { + DiscordTicketType ticketType = SteamwarDiscordBotConfig.TICKET_TYPES.get(event.getComponentId()); + Category ct = event.getGuild().getCategoryById(SteamwarDiscordBotConfig.TICKET_CATEGORY); + SteamwarUser swUser = SteamwarUser.get(event.getUser().getIdLong()); + TextChannel ticketChannel = ct.createTextChannel((swUser == null?event.getUser().getName():swUser.getUserName()) + "-" + event.getComponentId() + "-" + System.currentTimeMillis() % 1000).complete(); + ticketChannel.createPermissionOverride(event.getMember()).setAllow(Permission.VIEW_CHANNEL, + Permission.MESSAGE_WRITE, + Permission.MESSAGE_ATTACH_FILES, + Permission.MESSAGE_ADD_REACTION, + Permission.MESSAGE_READ, + Permission.MESSAGE_EMBED_LINKS, + Permission.MESSAGE_HISTORY).complete(); + ticketChannel.getManager().setTopic(event.getUser().getId()).complete(); + + MessageBuilder messageBuilder = new MessageBuilder(); + EmbedBuilder builder = new EmbedBuilder(); + builder.setDescription(ticketType.getPreMessage()); + builder.setTitle("Steamwar Ticket"); + builder.setColor(Color.GREEN); + + Button closeButton = Button.danger("close-" + ticketChannel.getName(), "Schließen").withEmoji(Emoji.fromUnicode("U+26A0")); + messageBuilder.setEmbeds(builder.build()); + messageBuilder.setActionRows(ActionRow.of(closeButton)); + + ticketChannel.sendMessage(messageBuilder.build()).complete(); + event.reply(SteamwarDiscordBotConfig.TICKET_CREATED.replace("%channel%", ticketChannel.getAsMention())).setEphemeral(true).complete(); + Message.team("DISCORD_TICKET_NEW", ticketChannel.getName()); + } else if(event.getComponentId().startsWith("close-")) { + TextChannel logChannel = event.getGuild().getTextChannelById(SteamwarDiscordBotConfig.TICKET_LOG); + + MessageBuilder builder = new MessageBuilder(); + StringBuilder stringBuilder = new StringBuilder(); + + new LinkedList<>(event.getTextChannel().getIterableHistory().complete()).descendingIterator().forEachRemaining(message -> { + if(message.getAuthor().isSystem() || message.getAuthor().isBot()) return; + stringBuilder.append(" ") + .append("**") + .append(message.getAuthor().getName()) + .append("**: ") + .append(message.getContentRaw()); + if(!message.getAttachments().isEmpty()) { + stringBuilder.append("\n") + .append("Files: ").append("\n"); + message.getAttachments().forEach(attachment -> stringBuilder.append(attachment.getUrl()).append("\n")); + } + + stringBuilder.append("\n"); + }); + + stringBuilder.append("\n"); + stringBuilder.append(" ") + .append("**").append(event.getUser().getName()).append("**: ") + .append("Ticket geschlossen"); + + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder.setColor(Color.GREEN); + User user = event.getJDA().retrieveUserById(event.getTextChannel().getTopic()).complete(); + SteamwarUser swuser = SteamwarUser.get(user.getIdLong()); + + embedBuilder.setAuthor(user.getName(), swuser==null?"https://steamwar.de/":("https://steamwar.de/users/" + swuser.getUserName().toLowerCase() + "/"), user.getAvatarUrl()); + embedBuilder.setTimestamp(Instant.now()); + embedBuilder.setTitle(event.getTextChannel().getName()); + embedBuilder.setDescription(stringBuilder); + + builder.setEmbeds(embedBuilder.build()); + + logChannel.sendMessage(builder.build()).complete(); + + Message.team("DISCORD_TICKET_CLOSED", event.getTextChannel().getName()); + event.getTextChannel().delete().reason("Closed").complete(); + } + } + } + + @Override + public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) { + if(event.getChannel().getParent() != null && event.getChannel().getParent().getId().equals(SteamwarDiscordBotConfig.TICKET_CATEGORY)) { + if(!event.getChannel().getId().equals(SteamwarDiscordBotConfig.TICKET_CHANNEL) && !event.getChannel().getId().equals(SteamwarDiscordBotConfig.TICKET_LOG)) { + BungeeCore.get().getProxy().getPlayers().forEach(player -> { + if(event.getAuthor().isBot() || event.getAuthor().isSystem()) return; + SteamwarUser user = SteamwarUser.get(player); + if(user.getDiscordId() == null) { + if(user.getUserGroup().isTeamGroup()) { + Message.sendPrefixless("DISCORD_TICKET_MESSAGE", player, "Zur nachricht", new ClickEvent(ClickEvent.Action.OPEN_URL, event.getMessage().getJumpUrl()), event.getChannel().getName(), event.getAuthor().getName(), event.getMessage().getContentRaw()); + } + } else { + if(event.getAuthor().getId().equals(user.getDiscordId())) return; + Member member = event.getGuild().retrieveMemberById(user.getDiscordId()).complete(); + if(member.hasPermission(event.getChannel().getManager().getChannel(), Permission.MESSAGE_WRITE)) { + Message.sendPrefixless("DISCORD_TICKET_MESSAGE", player, "Zur nachricht", new ClickEvent(ClickEvent.Action.OPEN_URL, event.getMessage().getJumpUrl()), event.getChannel().getName(), event.getAuthor().getName(), event.getMessage().getContentRaw()); + } + } + }); + } + } + } +} diff --git a/src/de/steamwar/bungeecore/bot/listeners/IngameChatListener.java b/src/de/steamwar/bungeecore/bot/listeners/IngameChatListener.java new file mode 100644 index 0000000..ce635f3 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/listeners/IngameChatListener.java @@ -0,0 +1,68 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.listeners; + +import de.steamwar.bungeecore.bot.SteamwarDiscordBot; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import de.steamwar.bungeecore.listeners.ChatListener; +import de.steamwar.bungeecore.sql.SteamwarUser; +import de.steamwar.bungeecore.sql.UserGroup; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import org.jetbrains.annotations.NotNull; + +public class IngameChatListener extends BasicDiscordListener { + + @Override + public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) { + if (!event.getChannel().getId().equals(SteamwarDiscordBotConfig.INGAME_CHANNEL)) { + return; + } + if (event.getAuthor().isBot()) { + return; + } + Member member = event.getMember(); + SteamwarUser steamwarUser = SteamwarUser.get(member.getIdLong()); + if (steamwarUser == null || event.getMessage().getContentRaw().length() > 250) { + event.getMessage().delete().complete(); + } else { + String s = event.getMessage().getContentDisplay(); + if (steamwarUser.getUserGroup() == UserGroup.Member && (s.contains("http") || s.contains("www"))) { + event.getMessage().delete().complete(); + return; + } + if (steamwarUser.isMuted() || steamwarUser.isBanned()) { + event.getMessage().delete().complete(); + return; + } + ChatListener.discordChat(steamwarUser, event.getMessage().getContentDisplay().replaceAll("§[a-f0-9]", "").replace('\n', ' ')); + } + } + + public void send(String message) { + TextChannel textChannel = SteamwarDiscordBot.instance().getJda().getGuildById(SteamwarDiscordBotConfig.GUILD).getTextChannelById(SteamwarDiscordBotConfig.INGAME_CHANNEL); + assert textChannel != null; + MessageBuilder messageBuilder = new MessageBuilder(); + messageBuilder.append(message.replace("&", "").replace("@everyone", "`@everyone`").replace("@here", "`@here`").replaceAll("<[@#]!?\\d+>", "`$0`")); + textChannel.sendMessage(messageBuilder.build()).queue(); + } +} diff --git a/src/de/steamwar/bungeecore/bot/listeners/RolesInteractionButtonListener.java b/src/de/steamwar/bungeecore/bot/listeners/RolesInteractionButtonListener.java new file mode 100644 index 0000000..035cd77 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/listeners/RolesInteractionButtonListener.java @@ -0,0 +1,42 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.listeners; + +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import net.dv8tion.jda.api.entities.ChannelType; +import net.dv8tion.jda.api.events.interaction.GenericComponentInteractionCreateEvent; +import net.dv8tion.jda.api.interactions.InteractionType; +import org.jetbrains.annotations.NotNull; + +public class RolesInteractionButtonListener extends BasicDiscordListener { + + @Override + public void onGenericComponentInteractionCreate(@NotNull GenericComponentInteractionCreateEvent event) { + if(event.getType() == InteractionType.COMPONENT && event.getChannelType() == ChannelType.TEXT && event.getTextChannel().getId().equals(SteamwarDiscordBotConfig.ROLES_CHANNEL) && SteamwarDiscordBotConfig.ROLES.stream().anyMatch(discordRole -> discordRole.getRoleId().equals(event.getComponentId()))) { + if (event.getMember().getRoles().stream().anyMatch(role -> role.getId().equals(event.getComponentId()))) { + event.getGuild().removeRoleFromMember(event.getMember(), event.getGuild().getRoleById(event.getComponentId())).complete(); + event.reply(SteamwarDiscordBotConfig.ROLES_REMOVED.replace("%role%", event.getGuild().getRoleById(event.getComponentId()).getAsMention())).setEphemeral(true).complete(); + } else { + event.getGuild().addRoleToMember(event.getMember(), event.getGuild().getRoleById(event.getComponentId())).complete(); + event.reply(SteamwarDiscordBotConfig.ROLES_ADDED.replace("%role%", event.getGuild().getRoleById(event.getComponentId()).getAsMention())).setEphemeral(true).complete(); + } + } + } +} diff --git a/src/de/steamwar/bungeecore/bot/listeners/ServerTeamChatListener.java b/src/de/steamwar/bungeecore/bot/listeners/ServerTeamChatListener.java new file mode 100644 index 0000000..0f82673 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/listeners/ServerTeamChatListener.java @@ -0,0 +1,59 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.listeners; + +import de.steamwar.bungeecore.bot.SteamwarDiscordBot; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import de.steamwar.bungeecore.commands.ServerTeamchatCommand; +import de.steamwar.bungeecore.listeners.ChatListener; +import de.steamwar.bungeecore.sql.SteamwarUser; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import org.jetbrains.annotations.NotNull; + +public class ServerTeamChatListener extends BasicDiscordListener { + + @Override + public void onGuildMessageReceived(@NotNull GuildMessageReceivedEvent event) { + if (!event.getChannel().getId().equals(SteamwarDiscordBotConfig.SERVER_TEAM_CHANNEL)) { + return; + } + if (event.getAuthor().isBot()) { + return; + } + Member member = event.getMember(); + SteamwarUser steamwarUser = SteamwarUser.get(member.getIdLong()); + if (steamwarUser == null) { + event.getMessage().delete().complete(); + } else { + ServerTeamchatCommand.sendToTeam(event.getMessage().getContentRaw(), steamwarUser); + } + } + + public void send(String message) { + TextChannel textChannel = SteamwarDiscordBot.instance().getJda().getGuildById(SteamwarDiscordBotConfig.GUILD).getTextChannelById(SteamwarDiscordBotConfig.SERVER_TEAM_CHANNEL); + assert textChannel != null; + MessageBuilder messageBuilder = new MessageBuilder(); + messageBuilder.append(message.replace("&", "")); + textChannel.sendMessage(messageBuilder.build()).queue(); + } +} diff --git a/src/de/steamwar/bungeecore/bot/listeners/SlashCommandListener.java b/src/de/steamwar/bungeecore/bot/listeners/SlashCommandListener.java new file mode 100644 index 0000000..565ca44 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/listeners/SlashCommandListener.java @@ -0,0 +1,32 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.listeners; + +import de.steamwar.bungeecore.bot.SteamwarDiscordBot; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import org.jetbrains.annotations.NotNull; + +public class SlashCommandListener extends BasicDiscordListener { + + @Override + public void onSlashCommand(@NotNull SlashCommandEvent event) { + SteamwarDiscordBot.getDiscordCommandMap().get(event.getName()).run(event); + } +} diff --git a/src/de/steamwar/bungeecore/bot/util/DiscordRanks.java b/src/de/steamwar/bungeecore/bot/util/DiscordRanks.java new file mode 100644 index 0000000..dedf0a5 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/util/DiscordRanks.java @@ -0,0 +1,67 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2020 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.util; + +import de.steamwar.bungeecore.bot.SteamwarDiscordBot; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import de.steamwar.bungeecore.sql.SteamwarUser; +import de.steamwar.bungeecore.sql.UserGroup; +import lombok.experimental.UtilityClass; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Role; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@UtilityClass +public class DiscordRanks { + + public void update(SteamwarUser steamwarUser) { + if (steamwarUser.getDiscordId() == null) { + return; + } + Guild guild = SteamwarDiscordBot.instance().getJda().getGuildById(SteamwarDiscordBotConfig.GUILD); + Member member = guild.retrieveMemberById(steamwarUser.getDiscordId()).complete(); + if (member == null) { + return; + } + + List roleList = member.getRoles(); + Set strings = new HashSet<>(SteamwarDiscordBotConfig.RANKS.values()); + String needed = SteamwarDiscordBotConfig.RANKS.get(steamwarUser.getUserGroup()); + for (Role role : roleList) { + if (!strings.contains(role.getId())) { + continue; + } + if (role.getId().equals(needed)) { + needed = ""; + continue; + } + guild.removeRoleFromMember(member, role).complete(); + } + + if (needed != null && !needed.isEmpty()) { + guild.addRoleToMember(member, guild.getRoleById(needed)).complete(); + } + } +} diff --git a/src/de/steamwar/bungeecore/bot/util/DiscordRolesMessage.java b/src/de/steamwar/bungeecore/bot/util/DiscordRolesMessage.java new file mode 100644 index 0000000..baa8801 --- /dev/null +++ b/src/de/steamwar/bungeecore/bot/util/DiscordRolesMessage.java @@ -0,0 +1,58 @@ +/* + This file is a part of the SteamWar software. + + Copyright (C) 2020 SteamWar.de-Serverteam + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + */ + +package de.steamwar.bungeecore.bot.util; + +import de.steamwar.bungeecore.bot.SteamwarDiscordBot; +import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; +import lombok.experimental.UtilityClass; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.interactions.components.ActionRow; +import net.dv8tion.jda.api.interactions.components.Button; + +import java.util.ArrayList; +import java.util.List; + +@UtilityClass +public class DiscordRolesMessage { + + + public void sendMessage() { + TextChannel channel = SteamwarDiscordBot.instance().getJda().getGuildById(SteamwarDiscordBotConfig.GUILD).getTextChannelById(SteamwarDiscordBotConfig.ROLES_CHANNEL); + assert channel != null; + Message message = null; + if(channel.hasLatestMessage()) { + message = channel.getIterableHistory().complete().stream().filter(m -> m.getAuthor().isBot()).findFirst().orElse(null); + } + + MessageBuilder builder = new MessageBuilder(); + builder.setContent(SteamwarDiscordBotConfig.ROLES_BASE_MESSAGE); + List