mirror of
https://github.com/AtlasMediaGroup/TotalFreedomMod.git
synced 2025-06-28 19:26:42 +00:00
Part 1 / 2
Only thing left is to fix all the code issues from moving out the discord and shop implementations.
This commit is contained in:
41
discord/pom.xml
Normal file
41
discord/pom.xml
Normal file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>me.totalfreedom</groupId>
|
||||
<artifactId>TotalFreedomMod</artifactId>
|
||||
<version>2023.02</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>discord</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.discord4j</groupId>
|
||||
<artifactId>discord4j-core</artifactId>
|
||||
<version>3.2.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.totalfreedom</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
<version>2023.02</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
138
discord/src/main/java/me/totalfreedom/discord/Bot.java
Normal file
138
discord/src/main/java/me/totalfreedom/discord/Bot.java
Normal file
@ -0,0 +1,138 @@
|
||||
package me.totalfreedom.discord;
|
||||
|
||||
import discord4j.common.util.Snowflake;
|
||||
import discord4j.core.DiscordClientBuilder;
|
||||
import discord4j.core.GatewayDiscordClient;
|
||||
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
|
||||
import discord4j.core.object.entity.Guild;
|
||||
import discord4j.core.object.entity.Message;
|
||||
import discord4j.core.object.entity.channel.TextChannel;
|
||||
import me.totalfreedom.discord.command.HelpCommand;
|
||||
import me.totalfreedom.discord.command.ListCommand;
|
||||
import me.totalfreedom.discord.command.TPSCommand;
|
||||
import me.totalfreedom.discord.handling.CommandHandler;
|
||||
import me.totalfreedom.discord.util.SnowflakeEntry;
|
||||
import me.totalfreedom.discord.util.TFM_Bridge;
|
||||
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
|
||||
import me.totalfreedom.totalfreedommod.player.PlayerData;
|
||||
import me.totalfreedom.totalfreedommod.util.FLog;
|
||||
import net.dv8tion.jda.internal.utils.concurrent.CountingThreadFactory;
|
||||
import org.bukkit.Bukkit;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
|
||||
public class Bot
|
||||
{
|
||||
private final GatewayDiscordClient client;
|
||||
private final TFM_Bridge tfm;
|
||||
private final HashMap<String, PlayerData> LINK_CODES = new HashMap<>();
|
||||
private ScheduledThreadPoolExecutor RATELIMIT_EXECUTOR;
|
||||
private Boolean enabled = false;
|
||||
|
||||
|
||||
public Bot()
|
||||
{
|
||||
//Creates the gateway client and connects to the gateway
|
||||
this.client = DiscordClientBuilder.create(ConfigEntry.DISCORD_TOKEN.getString())
|
||||
.build()
|
||||
.login()
|
||||
.block();
|
||||
|
||||
if (client == null) throw new IllegalStateException();
|
||||
|
||||
final CommandHandler handler = new CommandHandler(client.getRestClient());
|
||||
|
||||
/* Call our code to handle creating/deleting/editing our global slash commands.
|
||||
We have to hard code our list of command files since iterating over a list of files in a resource directory
|
||||
is overly complicated for such a simple demo and requires handling for both IDE and .jar packaging.
|
||||
Using SpringBoot we can avoid all of this and use their resource pattern matcher to do this for us.
|
||||
*/
|
||||
List<String> commands = List.of("greet.json", "ping.json");
|
||||
|
||||
try
|
||||
{
|
||||
handler.registerCommands(commands);
|
||||
handler.registerCommand(new HelpCommand());
|
||||
handler.registerCommand(new ListCommand());
|
||||
handler.registerCommand(new TPSCommand());
|
||||
} catch (Exception e)
|
||||
{
|
||||
Bukkit.getLogger().severe("Error trying to register global slash commands.\n" + e.getMessage());
|
||||
}
|
||||
//Register our slash command listener
|
||||
client.on(ChatInputInteractionEvent.class, handler::handle)
|
||||
.then(client.onDisconnect())
|
||||
.block(); // We use .block() as there is not another non-daemon thread and the jvm would close otherwise.
|
||||
|
||||
this.tfm = new TFM_Bridge(this);
|
||||
|
||||
RATELIMIT_EXECUTOR = new ScheduledThreadPoolExecutor(5, new CountingThreadFactory(this::poolIdentifier, "RateLimit"));
|
||||
RATELIMIT_EXECUTOR.setRemoveOnCancelPolicy(true);
|
||||
}
|
||||
|
||||
private String poolIdentifier()
|
||||
{
|
||||
return "TFD4J";
|
||||
}
|
||||
|
||||
public TFM_Bridge getTFM()
|
||||
{
|
||||
return tfm;
|
||||
}
|
||||
|
||||
public Mono<Guild> getGuildById()
|
||||
{
|
||||
return client.getGuildById(SnowflakeEntry.serverID);
|
||||
}
|
||||
|
||||
public GatewayDiscordClient getClient()
|
||||
{
|
||||
return client;
|
||||
}
|
||||
|
||||
public Map<String, PlayerData> getLinkCodes()
|
||||
{
|
||||
return LINK_CODES;
|
||||
}
|
||||
|
||||
public boolean shouldISendReport()
|
||||
{
|
||||
if (ConfigEntry.DISCORD_REPORT_CHANNEL_ID.getString().isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ConfigEntry.DISCORD_SERVER_ID.getString().isEmpty())
|
||||
{
|
||||
FLog.severe("No Discord server ID was specified in the config, but there is a report channel ID.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Guild server = client.getGuildById(SnowflakeEntry.serverID).block();
|
||||
if (server == null)
|
||||
|
||||
{
|
||||
FLog.severe("The Discord server ID specified is invalid, or the bot is not on the server.");
|
||||
return false;
|
||||
}
|
||||
|
||||
TextChannel channel = server.getChannelById(SnowflakeEntry.reportChannelID)
|
||||
.ofType(TextChannel.class)
|
||||
.block();
|
||||
|
||||
if (channel == null)
|
||||
{
|
||||
FLog.severe("The report channel ID specified in the config is invalid.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
54
discord/src/main/java/me/totalfreedom/discord/TFD4J.java
Normal file
54
discord/src/main/java/me/totalfreedom/discord/TFD4J.java
Normal file
@ -0,0 +1,54 @@
|
||||
package me.totalfreedom.discord;
|
||||
|
||||
import me.totalfreedom.discord.listener.AdminChatListener;
|
||||
import me.totalfreedom.discord.listener.BukkitNative;
|
||||
import me.totalfreedom.discord.listener.MinecraftListener;
|
||||
import me.totalfreedom.discord.util.Utilities;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class TFD4J extends JavaPlugin
|
||||
{
|
||||
private Bot bot;
|
||||
private Utilities utils;
|
||||
private MinecraftListener mc;
|
||||
private AdminChatListener ac;
|
||||
|
||||
@Override
|
||||
public void onEnable()
|
||||
{
|
||||
this.bot = new Bot();
|
||||
this.utils = new Utilities(this);
|
||||
new BukkitNative(this);
|
||||
this.mc = new MinecraftListener(this);
|
||||
this.ac = new AdminChatListener(this);
|
||||
|
||||
mc.minecraftChatBound();
|
||||
ac.adminChatBound();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable()
|
||||
{
|
||||
bot.getClient().onDisconnect().subscribe();
|
||||
}
|
||||
|
||||
public Bot getBot()
|
||||
{
|
||||
return bot;
|
||||
}
|
||||
|
||||
public Utilities getUtils()
|
||||
{
|
||||
return utils;
|
||||
}
|
||||
|
||||
public MinecraftListener getMinecraftListener()
|
||||
{
|
||||
return mc;
|
||||
}
|
||||
|
||||
public AdminChatListener getAdminChatListener()
|
||||
{
|
||||
return ac;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package me.totalfreedom.discord;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class TFM_Accessor
|
||||
{
|
||||
private final TFD4J accessor;
|
||||
|
||||
public TFM_Accessor()
|
||||
{
|
||||
this.accessor = (TFD4J) Bukkit.getPluginManager().getPlugin("TFD4J");
|
||||
}
|
||||
|
||||
public TFD4J botAccessor()
|
||||
{
|
||||
return accessor;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package me.totalfreedom.discord.command;
|
||||
|
||||
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
|
||||
import discord4j.core.spec.EmbedCreateSpec;
|
||||
import discord4j.rest.util.Color;
|
||||
import me.totalfreedom.discord.handling.SlashCommand;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
public class HelpCommand implements SlashCommand
|
||||
{
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return "help";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(ChatInputInteractionEvent event)
|
||||
{
|
||||
EmbedCreateSpec spec = EmbedCreateSpec.builder()
|
||||
.color(Color.GREEN)
|
||||
.title("Help Command")
|
||||
.addField("Commands", "This is a list of all commands", false)
|
||||
.addField("\u200B", "\u200B", false)
|
||||
.addField("help", "Displays the help command. (This command.)", true)
|
||||
.addField("list", "Displays a list of all online players.", true)
|
||||
.addField("tps", "Displays the server's TPS.", true)
|
||||
.timestamp(Instant.now())
|
||||
.build();
|
||||
|
||||
return event.reply()
|
||||
.withEmbeds(spec);
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package me.totalfreedom.discord.command;
|
||||
|
||||
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
|
||||
import discord4j.core.spec.EmbedCreateSpec;
|
||||
import discord4j.rest.util.Color;
|
||||
import me.totalfreedom.discord.handling.SlashCommand;
|
||||
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class ListCommand implements SlashCommand
|
||||
{
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return "list";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(ChatInputInteractionEvent event)
|
||||
{
|
||||
List<String> playerNames = Bukkit.getOnlinePlayers()
|
||||
.stream()
|
||||
.map(HumanEntity::getName)
|
||||
.toList();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Iterator<String> iterator = playerNames.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
sb.append(iterator.next());
|
||||
if (iterator.hasNext()) {
|
||||
sb.append(", \n");
|
||||
}
|
||||
}
|
||||
|
||||
String empty = "\u200B";
|
||||
|
||||
EmbedCreateSpec spec = EmbedCreateSpec.builder()
|
||||
.title("Player List - " + ConfigEntry.SERVER_NAME.getString())
|
||||
.color(Color.BISMARK)
|
||||
.addField("Online Players", String.join(", ", playerNames), false)
|
||||
.addField(empty, "Currently Online: " + playerNames.size(), false)
|
||||
.addField(empty, empty, false)
|
||||
.addField("Players: ", sb.toString(), true)
|
||||
.build();
|
||||
|
||||
return event.reply()
|
||||
.withEmbeds(spec)
|
||||
.withEphemeral(true)
|
||||
.withContent(sb.toString());
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package me.totalfreedom.discord.command;
|
||||
|
||||
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
|
||||
import discord4j.core.spec.EmbedCreateSpec;
|
||||
import discord4j.rest.util.Color;
|
||||
import me.totalfreedom.discord.handling.SlashCommand;
|
||||
import me.totalfreedom.totalfreedommod.util.FUtil;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class TPSCommand implements SlashCommand
|
||||
{
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return "tps";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(@NotNull ChatInputInteractionEvent event)
|
||||
{
|
||||
String tps = String.valueOf(FUtil.getMeanAverageDouble(Bukkit.getServer().getTPS()));
|
||||
|
||||
EmbedCreateSpec spec = EmbedCreateSpec.builder()
|
||||
.title("Current Server Tick Information")
|
||||
.addField("TPS", tps, false)
|
||||
.addField("Uptime", FUtil.getUptime(), false)
|
||||
.addField("Maximum Memory", Math.ceil(FUtil.getMaxMem()) + " MB", false)
|
||||
.addField("Allocated Memory", Math.ceil(FUtil.getTotalMem()) + " MB", false)
|
||||
.addField("Free Memory", Math.ceil(FUtil.getFreeMem()) + " MB", false)
|
||||
.color(Color.BISMARK)
|
||||
.build();
|
||||
|
||||
return event.reply()
|
||||
.withEmbeds(spec)
|
||||
.withEphemeral(true);
|
||||
}
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
package me.totalfreedom.discord.handling;
|
||||
|
||||
import discord4j.common.JacksonResources;
|
||||
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
|
||||
import discord4j.discordjson.json.ApplicationCommandRequest;
|
||||
import discord4j.rest.RestClient;
|
||||
import discord4j.rest.service.ApplicationService;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CommandHandler
|
||||
{
|
||||
private final List<SlashCommand> commands = new ArrayList<>();
|
||||
private final RestClient restClient;
|
||||
|
||||
public CommandHandler(RestClient restClient)
|
||||
{
|
||||
this.restClient = restClient;
|
||||
}
|
||||
|
||||
public void registerCommands(List<String> fileNames) throws IOException
|
||||
{
|
||||
//Create an ObjectMapper that supports Discord4J classes
|
||||
final JacksonResources d4jMapper = JacksonResources.create();
|
||||
|
||||
// Convenience variables for the sake of easier to read code below
|
||||
final ApplicationService applicationService = restClient.getApplicationService();
|
||||
final long applicationId = Objects.requireNonNull(restClient.getApplicationId().block());
|
||||
|
||||
//Get our commands json from resources as command data
|
||||
List<ApplicationCommandRequest> commands = new ArrayList<>();
|
||||
for (String json : getCommandsJson(fileNames))
|
||||
{
|
||||
ApplicationCommandRequest request = d4jMapper.getObjectMapper()
|
||||
.readValue(json, ApplicationCommandRequest.class);
|
||||
|
||||
commands.add(request); //Add to our array list
|
||||
}
|
||||
|
||||
/* Bulk overwrite commands. This is now idempotent, so it is safe to use this even when only 1 command
|
||||
is changed/added/removed
|
||||
*/
|
||||
applicationService.bulkOverwriteGlobalApplicationCommand(applicationId, commands)
|
||||
.doOnNext(cmd -> Bukkit.getLogger().info("Successfully registered Global Command "
|
||||
+ cmd.name()))
|
||||
.doOnError(e -> Bukkit.getLogger().severe("Failed to register global commands.\n"
|
||||
+ e.getMessage()))
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
private @NotNull List<String> getCommandsJson(List<String> fileNames) throws IOException
|
||||
{
|
||||
// Confirm that the commands folder exists
|
||||
String commandsFolderName = "commands/";
|
||||
URL url = this.getClass().getClassLoader().getResource(commandsFolderName);
|
||||
Objects.requireNonNull(url, commandsFolderName + " could not be found");
|
||||
|
||||
//Get all the files inside this folder and return the contents of the files as a list of strings
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String file : fileNames)
|
||||
{
|
||||
String resourceFileAsString = getResourceFileAsString(commandsFolderName + file);
|
||||
list.add(Objects.requireNonNull(resourceFileAsString, "Command file not found: " + file));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private @Nullable String getResourceFileAsString(String fileName) throws IOException
|
||||
{
|
||||
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
|
||||
try (InputStream resourceAsStream = classLoader.getResourceAsStream(fileName))
|
||||
{
|
||||
if (resourceAsStream == null) return null;
|
||||
try (InputStreamReader inputStreamReader = new InputStreamReader(resourceAsStream);
|
||||
BufferedReader reader = new BufferedReader(inputStreamReader))
|
||||
{
|
||||
return reader.lines().collect(Collectors.joining(System.lineSeparator()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void registerCommand(SlashCommand command)
|
||||
{
|
||||
commands.add(command);
|
||||
}
|
||||
|
||||
public Mono<Void> handle(ChatInputInteractionEvent event)
|
||||
{
|
||||
// Convert our array list to a flux that we can iterate through
|
||||
return Flux.fromIterable(commands)
|
||||
//Filter out all commands that don't match the name of the command this event is for
|
||||
.filter(command -> command.getName().equals(event.getCommandName()))
|
||||
// Get the first (and only) item in the flux that matches our filter
|
||||
.next()
|
||||
//have our command class handle all the logic related to its specific command.
|
||||
.flatMap(command -> command.handle(event));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package me.totalfreedom.discord.handling;
|
||||
|
||||
import discord4j.core.event.domain.interaction.ChatInputInteractionEvent;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public interface SlashCommand {
|
||||
String getName();
|
||||
|
||||
Mono<Void> handle(ChatInputInteractionEvent event);
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
package me.totalfreedom.discord.listener;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import discord4j.core.event.domain.message.MessageCreateEvent;
|
||||
import discord4j.core.object.entity.Attachment;
|
||||
import discord4j.core.object.entity.Guild;
|
||||
import discord4j.core.object.entity.Member;
|
||||
import discord4j.core.object.entity.Message;
|
||||
import me.totalfreedom.discord.Bot;
|
||||
import me.totalfreedom.discord.TFD4J;
|
||||
import me.totalfreedom.discord.util.SnowflakeEntry;
|
||||
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
|
||||
import me.totalfreedom.totalfreedommod.admin.Admin;
|
||||
import me.totalfreedom.totalfreedommod.rank.Displayable;
|
||||
import me.totalfreedom.totalfreedommod.rank.Rank;
|
||||
import me.totalfreedom.totalfreedommod.rank.Title;
|
||||
import me.totalfreedom.totalfreedommod.util.FLog;
|
||||
import me.totalfreedom.totalfreedommod.util.FUtil;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
public class AdminChatListener
|
||||
{
|
||||
private final Bot bot;
|
||||
private final TFD4J tfd4j;
|
||||
|
||||
public AdminChatListener(TFD4J tfd4j)
|
||||
{
|
||||
this.tfd4j = tfd4j;
|
||||
this.bot = tfd4j.getBot();
|
||||
}
|
||||
|
||||
public static net.md_5.bungee.api.ChatColor getColor(Displayable display)
|
||||
{
|
||||
return display.getColor();
|
||||
}
|
||||
|
||||
public void adminChatBound()
|
||||
{
|
||||
tfd4j.getBot()
|
||||
.getClient()
|
||||
.getEventDispatcher()
|
||||
.on(MessageCreateEvent.class)
|
||||
.filter(m -> m.getMessage()
|
||||
.getChannel()
|
||||
.blockOptional()
|
||||
.orElseThrow()
|
||||
.getId()
|
||||
.equals(SnowflakeEntry.adminChatChannelID))
|
||||
.filter(m -> !m.getMessage()
|
||||
.getAuthor()
|
||||
.orElseThrow()
|
||||
.getId()
|
||||
.equals(tfd4j.getBot().getClient().getSelfId()))
|
||||
.subscribe(this::createMessageSpec);
|
||||
}
|
||||
|
||||
public void createMessageSpec(MessageCreateEvent m)
|
||||
{
|
||||
Member member = m.getMember().orElseThrow(IllegalAccessError::new);
|
||||
String tag = tfd4j.getMinecraftListener().getDisplay(member);
|
||||
Message msg = m.getMessage();
|
||||
String mediamessage = ChatColor.YELLOW + "[Media]";
|
||||
|
||||
StringBuilder logmessage = new StringBuilder(ChatColor.DARK_GRAY + "[" + ChatColor.DARK_AQUA + "Discord" + ChatColor.DARK_GRAY + "] " + ChatColor.RESET);
|
||||
String lm = ChatColor.DARK_RED + member.getDisplayName() + " "
|
||||
+ ChatColor.DARK_GRAY + tag + ChatColor.DARK_GRAY
|
||||
+ ChatColor.WHITE + ": " + ChatColor.GOLD + FUtil.colorize(msg.getContent());
|
||||
logmessage.append(lm);
|
||||
|
||||
if (!msg.getAttachments().isEmpty())
|
||||
{
|
||||
|
||||
logmessage.append(mediamessage); // Actually for logging...
|
||||
|
||||
}
|
||||
FLog.info(logmessage.toString());
|
||||
|
||||
Bukkit.getOnlinePlayers().stream().filter(player -> TotalFreedomMod.getPlugin().al.isAdmin(player)).forEach(player ->
|
||||
{
|
||||
StringBuilder message = new StringBuilder(ChatColor.DARK_GRAY + "[" + ChatColor.DARK_AQUA + "Discord" + ChatColor.DARK_GRAY + "] " + ChatColor.RESET);
|
||||
|
||||
ComponentBuilder builder = new ComponentBuilder(message.toString());
|
||||
|
||||
Admin admin = TotalFreedomMod.getPlugin().al.getAdmin(player);
|
||||
String format = admin.getAcFormat();
|
||||
if (!Strings.isNullOrEmpty(format))
|
||||
{
|
||||
Displayable display = getDisplay(member);
|
||||
net.md_5.bungee.api.ChatColor color = getColor(display);
|
||||
String m1 = format.replace("%name%", member.getDisplayName())
|
||||
.replace("%rank%", display.getAbbr())
|
||||
.replace("%rankcolor%", color.toString())
|
||||
.replace("%msg%", FUtil.colorize(msg.getContent()));
|
||||
builder.append(FUtil.colorize(m1));
|
||||
|
||||
} else
|
||||
{
|
||||
String m1 = ChatColor.DARK_RED + member.getDisplayName() + " "
|
||||
+ ChatColor.DARK_GRAY + tag + ChatColor.DARK_GRAY
|
||||
+ ChatColor.WHITE + ": " + ChatColor.GOLD + FUtil.colorize(msg.getContent());
|
||||
builder.append(m1);
|
||||
}
|
||||
|
||||
if (!msg.getAttachments().isEmpty())
|
||||
{
|
||||
for (Attachment attachment : msg.getAttachments())
|
||||
{
|
||||
TextComponent text = new TextComponent(mediamessage);
|
||||
text.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, attachment.getUrl()));
|
||||
if (!msg.getContent().isEmpty())
|
||||
{
|
||||
builder.append(" ");
|
||||
}
|
||||
builder.append(text);
|
||||
}
|
||||
}
|
||||
player.spigot().sendMessage(builder.create());
|
||||
});
|
||||
}
|
||||
|
||||
public Displayable getDisplay(Member member)
|
||||
{
|
||||
Guild server = tfd4j.getBot().getGuildById().block();
|
||||
// Server Owner
|
||||
assert server != null;
|
||||
return member.getRoles().map(role ->
|
||||
{
|
||||
if (role.getId().equals(SnowflakeEntry.ownerRoleID))
|
||||
{
|
||||
return Title.OWNER;
|
||||
} else if (role.getId().equals(SnowflakeEntry.developerRoleID))
|
||||
{
|
||||
return Title.DEVELOPER;
|
||||
} else if (role.getId().equals(SnowflakeEntry.executiveRoleID))
|
||||
{
|
||||
return Title.EXECUTIVE;
|
||||
} else if (role.getId().equals(SnowflakeEntry.assistantRoleID))
|
||||
{
|
||||
return Title.ASSTEXEC;
|
||||
} else if (role.getId().equals(SnowflakeEntry.seniorRoleID))
|
||||
{
|
||||
return Rank.SENIOR_ADMIN;
|
||||
} else if (role.getId().equals(SnowflakeEntry.adminRoleID))
|
||||
{
|
||||
return Rank.ADMIN;
|
||||
} else if (role.getId().equals(SnowflakeEntry.builderRoleID))
|
||||
{
|
||||
return Title.MASTER_BUILDER;
|
||||
} else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}).blockFirst();
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package me.totalfreedom.discord.listener;
|
||||
|
||||
import me.totalfreedom.discord.Bot;
|
||||
import me.totalfreedom.discord.TFD4J;
|
||||
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
|
||||
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
public class BukkitNative implements Listener
|
||||
{
|
||||
private final TotalFreedomMod commons;
|
||||
private final Bot bot;
|
||||
private final TFD4J tfd4j;
|
||||
|
||||
public BukkitNative(TFD4J tfd4j)
|
||||
{
|
||||
this.tfd4j = tfd4j;
|
||||
this.bot = tfd4j.getBot();
|
||||
this.commons = bot.getTFM().getCommons();
|
||||
|
||||
tfd4j.getServer().getPluginManager().registerEvents(this, tfd4j);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerJoin(PlayerJoinEvent event)
|
||||
{
|
||||
if (!commons.al.isVanished(event.getPlayer().getUniqueId()))
|
||||
{
|
||||
tfd4j.getUtils().messageChatChannel("**"
|
||||
+ tfd4j.getUtils().deformat(event.getPlayer().getName())
|
||||
+ " joined the server" + "**", true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerLeave(PlayerQuitEvent event)
|
||||
{
|
||||
if (!commons.al.isVanished(event.getPlayer().getUniqueId()))
|
||||
{
|
||||
tfd4j.getUtils().messageChatChannel("**"
|
||||
+ tfd4j.getUtils().deformat(event.getPlayer().getName())
|
||||
+ " left the server" + "**", true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerDeath(PlayerDeathEvent event)
|
||||
{
|
||||
//Avoiding NPE Unboxing Warnings
|
||||
Boolean b = event.getEntity().getWorld().getGameRuleValue(GameRule.SHOW_DEATH_MESSAGES);
|
||||
if (b == null || !b)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Component deathMessage = event.deathMessage();
|
||||
|
||||
if (deathMessage != null)
|
||||
{
|
||||
tfd4j.getUtils().messageChatChannel("**"
|
||||
+ tfd4j.getUtils().deformat(PlainTextComponentSerializer.plainText().serialize(deathMessage))
|
||||
+ "**", true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onAsyncPlayerChat(AsyncPlayerChatEvent event)
|
||||
{
|
||||
Player player = event.getPlayer();
|
||||
String message = event.getMessage();
|
||||
|
||||
if (!ConfigEntry.ADMIN_ONLY_MODE.getBoolean() && !tfd4j.getServer().hasWhitelist()
|
||||
&& !commons.pl.getPlayer(player).isMuted() && bot != null)
|
||||
{
|
||||
tfd4j.getUtils().messageChatChannel(player.getName()
|
||||
+ " \u00BB "
|
||||
+ ChatColor.stripColor(message), true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
package me.totalfreedom.discord.listener;
|
||||
|
||||
import discord4j.core.event.domain.message.MessageCreateEvent;
|
||||
import discord4j.core.object.entity.Attachment;
|
||||
import discord4j.core.object.entity.Guild;
|
||||
import discord4j.core.object.entity.Member;
|
||||
import discord4j.core.object.entity.Message;
|
||||
import discord4j.core.object.entity.channel.TextChannel;
|
||||
import me.totalfreedom.discord.Bot;
|
||||
import me.totalfreedom.discord.TFD4J;
|
||||
import me.totalfreedom.discord.util.SnowflakeEntry;
|
||||
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
|
||||
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
|
||||
import me.totalfreedom.totalfreedommod.rank.Rank;
|
||||
import me.totalfreedom.totalfreedommod.rank.Title;
|
||||
import me.totalfreedom.totalfreedommod.util.FLog;
|
||||
import me.totalfreedom.totalfreedommod.util.FUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class MinecraftListener
|
||||
{
|
||||
private final TotalFreedomMod commons;
|
||||
private final Bot bot;
|
||||
private final TFD4J tfd4j;
|
||||
|
||||
public MinecraftListener(TFD4J tfd4j)
|
||||
{
|
||||
this.tfd4j = tfd4j;
|
||||
this.bot = tfd4j.getBot();
|
||||
this.commons = bot.getTFM().getCommons();
|
||||
}
|
||||
|
||||
public void minecraftChatBound()
|
||||
{
|
||||
tfd4j.getBot().getClient()
|
||||
.getEventDispatcher()
|
||||
.on(MessageCreateEvent.class)
|
||||
.filter(m -> m.getMember().orElse(null) != null)
|
||||
.filter(m -> !m.getMessage()
|
||||
.getAuthor()
|
||||
.orElseThrow(IllegalAccessError::new)
|
||||
.getId()
|
||||
.equals(tfd4j.getBot().getClient().getSelfId()))
|
||||
.filter(m -> m.getMessage()
|
||||
.getChannel()
|
||||
.blockOptional()
|
||||
.orElseThrow(IllegalAccessError::new)
|
||||
.getId()
|
||||
.equals(SnowflakeEntry.chatChannelID))
|
||||
.filter(m ->
|
||||
{
|
||||
Boolean b = m.getMessage()
|
||||
.getChannel()
|
||||
.map(c -> c instanceof TextChannel)
|
||||
.block();
|
||||
return b != null && b;
|
||||
}).subscribe(this::doMessageBodyDetails);
|
||||
}
|
||||
|
||||
private void doMessageBodyDetails(MessageCreateEvent m)
|
||||
{
|
||||
Member member = m.getMember().orElseThrow();
|
||||
Message msg = m.getMessage();
|
||||
String tag = getDisplay(member);
|
||||
TextComponent[] emsg = {Component.empty()}; // We are using a single value arrays here to silence SonarLint's "return value never used" bullshit.
|
||||
|
||||
emsg[0] = emsg[0].append(Component.text("[", NamedTextColor.DARK_GRAY));
|
||||
TextComponent[] inviteLink = {Component.text("Discord")};
|
||||
inviteLink[0] = inviteLink[0].color(NamedTextColor.DARK_AQUA);
|
||||
HoverEvent<Component> hoverEvent = HoverEvent.showText(Component.text("Click to join our Discord server!"));
|
||||
ClickEvent clickEvent = ClickEvent.openUrl(ConfigEntry.DISCORD_INVITE_LINK.getString());
|
||||
inviteLink[0] = inviteLink[0].hoverEvent(hoverEvent);
|
||||
inviteLink[0] = inviteLink[0].clickEvent(clickEvent);
|
||||
emsg[0] = emsg[0].append(inviteLink[0]);
|
||||
emsg[0] = emsg[0].append(Component.text("] ", NamedTextColor.DARK_GRAY));
|
||||
|
||||
// Tag (if they have one)
|
||||
if (tag != null)
|
||||
{
|
||||
emsg[0] = emsg[0].append(Component.text(tag));
|
||||
}
|
||||
|
||||
emsg[0] = emsg[0].append(Component.space());
|
||||
|
||||
// User
|
||||
TextComponent[] user = {Component.text(FUtil.stripColors(member.getDisplayName()))};
|
||||
user[0] = user[0].color(NamedTextColor.RED);
|
||||
emsg[0] = emsg[0].append(user[0]);
|
||||
|
||||
// Message
|
||||
emsg[0] = emsg[0].append(Component.text(": ", NamedTextColor.DARK_GRAY));
|
||||
emsg[0] = emsg[0].append(Component.text(FUtil.stripColors(msg.getContent()), NamedTextColor.WHITE));
|
||||
// Attachments
|
||||
if (!msg.getAttachments().isEmpty())
|
||||
{
|
||||
if (!msg.getContent().isEmpty())
|
||||
emsg[0] = emsg[0].append(Component.space());
|
||||
|
||||
for (Attachment attachment : msg.getAttachments())
|
||||
{
|
||||
TextComponent[] media = {Component.text("[Media] ")};
|
||||
media[0] = media[0].color(NamedTextColor.YELLOW);
|
||||
HoverEvent<Component> hover = HoverEvent.showText(Component.text(attachment.getUrl()));
|
||||
ClickEvent click = ClickEvent.openUrl(attachment.getUrl());
|
||||
media[0] = media[0].clickEvent(click);
|
||||
media[0] = media[0].hoverEvent(hover);
|
||||
emsg[0] = emsg[0].append(media[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers())
|
||||
{
|
||||
if (TotalFreedomMod.getPlugin().pl.getData(player).doesDisplayDiscord())
|
||||
{
|
||||
player.sendMessage(emsg[0]);
|
||||
}
|
||||
}
|
||||
|
||||
FLog.info(emsg[0].content(), true);
|
||||
}
|
||||
|
||||
public String getDisplay(Member member)
|
||||
{
|
||||
Guild server = tfd4j.getBot().getGuildById().block();
|
||||
// Server Owner
|
||||
assert server != null;
|
||||
return member.getRoles().map(role ->
|
||||
{
|
||||
if (role.getId().equals(SnowflakeEntry.ownerRoleID))
|
||||
{
|
||||
return Title.OWNER.getColoredTag();
|
||||
} else if (role.getId().equals(SnowflakeEntry.developerRoleID))
|
||||
{
|
||||
return Title.DEVELOPER.getColoredTag();
|
||||
} else if (role.getId().equals(SnowflakeEntry.executiveRoleID))
|
||||
{
|
||||
return Title.EXECUTIVE.getColoredTag();
|
||||
} else if (role.getId().equals(SnowflakeEntry.assistantRoleID))
|
||||
{
|
||||
return Title.ASSTEXEC.getColoredTag();
|
||||
} else if (role.getId().equals(SnowflakeEntry.seniorRoleID))
|
||||
{
|
||||
return Rank.SENIOR_ADMIN.getColoredTag();
|
||||
} else if (role.getId().equals(SnowflakeEntry.adminRoleID))
|
||||
{
|
||||
return Rank.ADMIN.getColoredTag();
|
||||
} else if (role.getId().equals(SnowflakeEntry.builderRoleID))
|
||||
{
|
||||
return Title.MASTER_BUILDER.getColoredTag();
|
||||
} else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}).blockFirst();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
package me.totalfreedom.discord.listener;
|
||||
|
||||
import discord4j.core.event.domain.message.MessageCreateEvent;
|
||||
import me.totalfreedom.discord.TFD4J;
|
||||
import me.totalfreedom.discord.discord.Discord;
|
||||
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
|
||||
import me.totalfreedom.totalfreedommod.admin.Admin;
|
||||
import me.totalfreedom.totalfreedommod.player.PlayerData;
|
||||
|
||||
public class PrivateMessageListener
|
||||
{
|
||||
private final TFD4J tfd4j;
|
||||
|
||||
public PrivateMessageListener(TFD4J tfd4j)
|
||||
{
|
||||
this.tfd4j = tfd4j;
|
||||
}
|
||||
|
||||
public void privateMessageReceived()
|
||||
{
|
||||
tfd4j.getBot()
|
||||
.getClient()
|
||||
.getEventDispatcher()
|
||||
.on(MessageCreateEvent.class)
|
||||
.filter(event -> event.getMessage().getAuthor().orElse(null) != null)
|
||||
.filter(event -> !event.getMessage().getAuthor().orElseThrow().getId().equals(tfd4j.getBot().getClient().getSelfId()))
|
||||
.filter(event -> event.getMessage().getContent().strip().matches("[0-9][0-9][0-9][0-9][0-9]"))
|
||||
.subscribe(event ->
|
||||
{
|
||||
String code = event.getMessage().getContent().strip();
|
||||
String name;
|
||||
if (Discord.LINK_CODES.get(code) != null)
|
||||
{
|
||||
PlayerData player = Discord.LINK_CODES.get(code);
|
||||
name = player.getName();
|
||||
player.setDiscordID(event.getMessage().getAuthor().orElseThrow().getId().asString());
|
||||
|
||||
Admin admin = TotalFreedomMod.getPlugin().al.getEntryByUuid(player.getUuid());
|
||||
if (admin != null)
|
||||
{
|
||||
Discord.syncRoles(admin, player.getDiscordID());
|
||||
}
|
||||
|
||||
TotalFreedomMod.getPlugin().pl.save(player);
|
||||
Discord.LINK_CODES.remove(code);
|
||||
} else
|
||||
{
|
||||
return;
|
||||
}
|
||||
event.getMessage()
|
||||
.getChannel()
|
||||
.blockOptional()
|
||||
.orElseThrow(UnsupportedOperationException::new)
|
||||
.createMessage("Link successful. Now this Discord account is linked with your Minecraft account **" + name + "**.").block();
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package me.totalfreedom.discord.listener;
|
||||
|
||||
import discord4j.core.event.domain.message.ReactionAddEvent;
|
||||
import discord4j.core.object.Embed;
|
||||
import discord4j.core.object.entity.Member;
|
||||
import discord4j.core.object.entity.Message;
|
||||
import discord4j.core.object.entity.channel.Channel;
|
||||
import discord4j.discordjson.json.MessageCreateRequest;
|
||||
import me.totalfreedom.discord.TFD4J;
|
||||
import me.totalfreedom.discord.util.SnowflakeEntry;
|
||||
import me.totalfreedom.totalfreedommod.util.FLog;
|
||||
|
||||
public class ReactionListener
|
||||
{
|
||||
private final TFD4J tfd4j;
|
||||
|
||||
public ReactionListener(TFD4J tfd4J)
|
||||
{
|
||||
this.tfd4j = tfd4J;
|
||||
}
|
||||
|
||||
public void onReactionAdd()
|
||||
{
|
||||
tfd4j.getBot()
|
||||
.getClient()
|
||||
.getEventDispatcher()
|
||||
.on(ReactionAddEvent.class)
|
||||
.filter(r -> r.getGuild().block() != null)
|
||||
.filter(r -> r.getMember().orElse(null) != null)
|
||||
.filter(r -> !r.getMember()
|
||||
.orElseThrow()
|
||||
.getId()
|
||||
.equals(tfd4j.getBot().getClient().getSelfId()))
|
||||
.filter(r -> !r.getChannel()
|
||||
.blockOptional()
|
||||
.orElseThrow().getId().equals(SnowflakeEntry.reportChannelID))
|
||||
.filter(r -> r.getEmoji()
|
||||
.asUnicodeEmoji()
|
||||
.orElseThrow(UnsupportedOperationException::new)
|
||||
.getRaw()
|
||||
.equals("\uD83D\uDCCB"))
|
||||
.subscribe(this::reactionWork);
|
||||
}
|
||||
|
||||
public void reactionWork(ReactionAddEvent event)
|
||||
{
|
||||
final Channel archiveChannel = tfd4j.getBot().getClient().getChannelById(SnowflakeEntry.archiveChannelID).block();
|
||||
|
||||
if (archiveChannel == null)
|
||||
{
|
||||
FLog.warning("Report archive channel is defined in the config, yet doesn't actually exist!");
|
||||
return;
|
||||
}
|
||||
|
||||
final Message message = event.getMessage().blockOptional().orElseThrow();
|
||||
final Member completer = event.getMember().orElseThrow();
|
||||
|
||||
if (!message.getAuthor().orElseThrow().getId().equals(tfd4j.getBot().getClient().getSelfId()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't need other embeds... yet?
|
||||
final Embed embed = message.getEmbeds().get(0);
|
||||
|
||||
final MessageCreateRequest request = MessageCreateRequest.builder()
|
||||
.content("Report completed by " + completer.getUsername()
|
||||
+ " (" + completer.getDiscriminator()
|
||||
+ ")")
|
||||
.addEmbed(embed.getData())
|
||||
.build();
|
||||
|
||||
archiveChannel.getRestChannel().createMessage(request);
|
||||
|
||||
message.delete().block();
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package me.totalfreedom.discord.util;
|
||||
|
||||
import discord4j.common.util.Snowflake;
|
||||
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
|
||||
|
||||
public class SnowflakeEntry
|
||||
{
|
||||
public static final Snowflake adminChatChannelID = Snowflake.of(ConfigEntry.DISCORD_ADMINCHAT_CHANNEL_ID.getString());
|
||||
public static final Snowflake chatChannelID = Snowflake.of(ConfigEntry.DISCORD_CHAT_CHANNEL_ID.getString());
|
||||
public static final Snowflake serverID = Snowflake.of(ConfigEntry.DISCORD_SERVER_ID.getString());
|
||||
public static final Snowflake ownerRoleID = Snowflake.of(ConfigEntry.DISCORD_SERVER_OWNER_ROLE_ID.getString());
|
||||
public static final Snowflake developerRoleID = Snowflake.of(ConfigEntry.DISCORD_DEVELOPER_ROLE_ID.getString());
|
||||
public static final Snowflake executiveRoleID = Snowflake.of(ConfigEntry.DISCORD_EXECUTIVE_ROLE_ID.getString());
|
||||
public static final Snowflake assistantRoleID = Snowflake.of(ConfigEntry.DISCORD_ASSISTANT_EXECUTIVE_ROLE_ID.getString());
|
||||
public static final Snowflake seniorRoleID = Snowflake.of(ConfigEntry.DISCORD_SENIOR_ADMIN_ROLE_ID.getString());
|
||||
public static final Snowflake adminRoleID = Snowflake.of(ConfigEntry.DISCORD_NEW_ADMIN_ROLE_ID.getString());
|
||||
public static final Snowflake builderRoleID = Snowflake.of(ConfigEntry.DISCORD_MASTER_BUILDER_ROLE_ID.getString());
|
||||
public static final Snowflake reportChannelID = Snowflake.of(ConfigEntry.DISCORD_REPORT_CHANNEL_ID.getString());
|
||||
public static final Snowflake archiveChannelID = Snowflake.of(ConfigEntry.DISCORD_REPORT_ARCHIVE_CHANNEL_ID.getString());
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
package me.totalfreedom.discord.util;
|
||||
|
||||
import discord4j.common.util.Snowflake;
|
||||
import discord4j.core.object.entity.Guild;
|
||||
import discord4j.core.object.entity.Member;
|
||||
import discord4j.core.object.entity.Role;
|
||||
import me.totalfreedom.discord.Bot;
|
||||
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
|
||||
import me.totalfreedom.totalfreedommod.admin.Admin;
|
||||
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
|
||||
import me.totalfreedom.totalfreedommod.player.PlayerData;
|
||||
import me.totalfreedom.totalfreedommod.rank.Rank;
|
||||
import me.totalfreedom.totalfreedommod.rank.Title;
|
||||
import me.totalfreedom.totalfreedommod.util.FLog;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class TFM_Bridge
|
||||
{
|
||||
private final Bot bot;
|
||||
private final TotalFreedomMod commons;
|
||||
|
||||
public TFM_Bridge(Bot bot)
|
||||
{
|
||||
this.bot = bot;
|
||||
this.commons = (TotalFreedomMod) Bukkit.getPluginManager().getPlugin("TotalFreedomMod");
|
||||
|
||||
if (commons == null) throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public String getDisplay(Member member)
|
||||
{
|
||||
Guild server = bot.getGuildById().block();
|
||||
// Server Owner
|
||||
if (server == null)
|
||||
{
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
Snowflake ownerID = Snowflake.of(ConfigEntry.DISCORD_SERVER_OWNER_ROLE_ID.getString());
|
||||
Snowflake developerID = Snowflake.of(ConfigEntry.DISCORD_DEVELOPER_ROLE_ID.getString());
|
||||
Snowflake executiveID = Snowflake.of(ConfigEntry.DISCORD_EXECUTIVE_ROLE_ID.getString());
|
||||
Snowflake assistantExecutiveID = Snowflake.of(ConfigEntry.DISCORD_ASSISTANT_EXECUTIVE_ROLE_ID.getString());
|
||||
Snowflake seniorAdminID = Snowflake.of(ConfigEntry.DISCORD_SENIOR_ADMIN_ROLE_ID.getString());
|
||||
Snowflake adminID = Snowflake.of(ConfigEntry.DISCORD_NEW_ADMIN_ROLE_ID.getString());
|
||||
Snowflake masterBuilderID = Snowflake.of(ConfigEntry.DISCORD_MASTER_BUILDER_ROLE_ID.getString());
|
||||
|
||||
Snowflake[] ids = {ownerID, developerID, executiveID, assistantExecutiveID, seniorAdminID, adminID, masterBuilderID};
|
||||
String[] titles = {Title.OWNER.getColoredTag(), Title.DEVELOPER.getColoredTag(), Title.EXECUTIVE.getColoredTag(), Title.ASSTEXEC.getColoredTag(), Rank.SENIOR_ADMIN.getColoredTag(), Rank.ADMIN.getColoredTag(), Title.MASTER_BUILDER.getColoredTag()};
|
||||
|
||||
return member.getRoles().map(role ->
|
||||
{
|
||||
for (int i = 0; i < ids.length; i++)
|
||||
{
|
||||
if (role.getId().equals(ids[i]))
|
||||
{
|
||||
return titles[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}).blockFirst();
|
||||
}
|
||||
|
||||
public String getCode(PlayerData playerData)
|
||||
{
|
||||
for (String code : bot.getLinkCodes().keySet())
|
||||
{
|
||||
if (bot.getLinkCodes().get(code).equals(playerData))
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean syncRoles(Admin admin, String discordID)
|
||||
{
|
||||
if (discordID == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Guild server = bot.getGuildById().block();
|
||||
|
||||
if (server == null)
|
||||
{
|
||||
FLog.severe("The Discord server ID specified is invalid, or the bot is not on the server.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Member member = server.getMemberById(Snowflake.of(discordID)).block();
|
||||
if (member == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Role adminRole = server.getRoleById(SnowflakeEntry.adminRoleID).block();
|
||||
if (adminRole == null)
|
||||
{
|
||||
FLog.severe("The specified Admin role does not exist!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Role senioradminRole = server.getRoleById(SnowflakeEntry.seniorRoleID).block();
|
||||
if (senioradminRole == null)
|
||||
{
|
||||
FLog.severe("The specified Senior Admin role does not exist!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!admin.isActive())
|
||||
{
|
||||
member.getRoles()
|
||||
.filter(role -> role.equals(adminRole) || role.equals(senioradminRole))
|
||||
.subscribe(r -> member.removeRole(r.getId()).block());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (admin.getRank().equals(Rank.ADMIN))
|
||||
{
|
||||
member.getRoles()
|
||||
.filter(role -> !role.equals(adminRole))
|
||||
.subscribe(r -> member.addRole(r.getId()).block());
|
||||
member.getRoles()
|
||||
.filter(role -> role.equals(senioradminRole))
|
||||
.subscribe(r -> member.removeRole(r.getId()).block());
|
||||
return true;
|
||||
}
|
||||
else if (admin.getRank().equals(Rank.SENIOR_ADMIN))
|
||||
{
|
||||
member.getRoles()
|
||||
.filter(role -> !role.equals(senioradminRole))
|
||||
.subscribe(r -> member.addRole(r.getId()).block());
|
||||
|
||||
member.getRoles()
|
||||
.filter(role -> role.equals(adminRole))
|
||||
.subscribe(r -> member.removeRole(r.getId()).block());
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public TotalFreedomMod getCommons() {
|
||||
return commons;
|
||||
}
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
package me.totalfreedom.discord.util;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import discord4j.core.object.entity.Guild;
|
||||
import discord4j.core.object.entity.Message;
|
||||
import discord4j.core.object.entity.channel.TextChannel;
|
||||
import discord4j.core.object.reaction.ReactionEmoji;
|
||||
import discord4j.core.spec.EmbedCreateSpec;
|
||||
import discord4j.core.spec.MessageCreateSpec;
|
||||
import me.totalfreedom.discord.TFD4J;
|
||||
import me.totalfreedom.totalfreedommod.config.ConfigEntry;
|
||||
import me.totalfreedom.totalfreedommod.util.FLog;
|
||||
import org.apache.commons.lang.WordUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Utilities
|
||||
{
|
||||
private final Flux<Message> sentMessages = Flux.fromIterable(new ArrayList<>());
|
||||
private final TFD4J tfd4J;
|
||||
private final ImmutableList<String> DISCORD_SUBDOMAINS = (ImmutableList<String>)
|
||||
List.of("discordapp.com",
|
||||
"discord.com",
|
||||
"discord.gg");
|
||||
|
||||
public Utilities(TFD4J tfd4J)
|
||||
{
|
||||
this.tfd4J = tfd4J;
|
||||
}
|
||||
|
||||
public String sanitizeChatMessage(String message)
|
||||
{
|
||||
String newMessage = message;
|
||||
|
||||
if (message.contains("@"))
|
||||
{
|
||||
// \u200B is Zero Width Space, invisible on Discord
|
||||
newMessage = message.replace("@", "@\u200B");
|
||||
}
|
||||
|
||||
if (message.toLowerCase().contains("discord.gg")) // discord.gg/invite works as an invite
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
for (String subdomain : DISCORD_SUBDOMAINS)
|
||||
{
|
||||
if (message.toLowerCase().contains(subdomain + "/invite"))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
if (message.contains("§"))
|
||||
{
|
||||
newMessage = message.replace("§", "");
|
||||
}
|
||||
|
||||
return deformat(newMessage);
|
||||
}
|
||||
|
||||
public void messageChatChannel(String message, boolean system)
|
||||
{
|
||||
String chat_channel_id = ConfigEntry.DISCORD_CHAT_CHANNEL_ID.getString();
|
||||
|
||||
String sanitizedMessage = (system) ? message : sanitizeChatMessage(message);
|
||||
|
||||
if (sanitizedMessage.isBlank()) return;
|
||||
|
||||
if (!chat_channel_id.isEmpty())
|
||||
{
|
||||
MessageCreateSpec spec = MessageCreateSpec.builder()
|
||||
.content(sanitizedMessage)
|
||||
.build();
|
||||
|
||||
Mono<Message> sentMessage = tfd4J
|
||||
.getBot()
|
||||
.getClient()
|
||||
.getChannelById(SnowflakeEntry.chatChannelID)
|
||||
.ofType(TextChannel.class)
|
||||
.flatMap(c -> c.createMessage(spec));
|
||||
|
||||
insert(sentMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public void messageAdminChatChannel(String message)
|
||||
{
|
||||
String chat_channel_id = ConfigEntry.DISCORD_ADMINCHAT_CHANNEL_ID.getString();
|
||||
|
||||
String sanitizedMessage = sanitizeChatMessage(message);
|
||||
|
||||
if (sanitizedMessage.isBlank()) return;
|
||||
|
||||
if (!chat_channel_id.isEmpty())
|
||||
{
|
||||
MessageCreateSpec spec = MessageCreateSpec.builder()
|
||||
.content(sanitizedMessage)
|
||||
.build();
|
||||
|
||||
Mono<Message> sentMessage = tfd4J
|
||||
.getBot()
|
||||
.getClient()
|
||||
.getChannelById(SnowflakeEntry.adminChatChannelID)
|
||||
.ofType(TextChannel.class)
|
||||
.flatMap(c -> c.createMessage(spec));
|
||||
|
||||
insert(sentMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean sendReport(Player reporter, Player reported, String reason)
|
||||
{
|
||||
if (!tfd4J.getBot().shouldISendReport())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
final Guild server = tfd4J.getBot()
|
||||
.getClient()
|
||||
.getGuildById(SnowflakeEntry.serverID)
|
||||
.block();
|
||||
|
||||
if (server == null)
|
||||
{
|
||||
FLog.severe("The guild ID specified in the config is invalid.");
|
||||
return false;
|
||||
}
|
||||
|
||||
final TextChannel channel = server.getChannelById(SnowflakeEntry.reportChannelID)
|
||||
.ofType(TextChannel.class)
|
||||
.block();
|
||||
|
||||
if (channel == null)
|
||||
{
|
||||
FLog.severe("The report channel ID specified in the config is invalid.");
|
||||
return false;
|
||||
}
|
||||
String location = "World: " + Objects.requireNonNull(reported.getLocation().getWorld()).getName() + ", X: " + reported.getLocation().getBlockX() + ", Y: " + reported.getLocation().getBlockY() + ", Z: " + reported.getLocation().getBlockZ();
|
||||
|
||||
final EmbedCreateSpec spec = EmbedCreateSpec.builder()
|
||||
.title("Report for " + reported.getName())
|
||||
.description(reason)
|
||||
.footer("Reported by " + reporter.getName(), "https://minotar.net/helm/" + reporter.getName() + ".png")
|
||||
.timestamp(Instant.from(ZonedDateTime.now()))
|
||||
.addField("Location", location, true)
|
||||
.addField("Game Mode", WordUtils.capitalizeFully(reported.getGameMode().name()), true)
|
||||
.build();
|
||||
|
||||
Message message = channel.createMessage(spec).block();
|
||||
|
||||
if (!ConfigEntry.DISCORD_REPORT_ARCHIVE_CHANNEL_ID.getString().isEmpty() && message != null)
|
||||
{
|
||||
ReactionEmoji emoji = ReactionEmoji.unicode("\uD83D\uDCCB");
|
||||
message.addReaction(emoji);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public String deformat(String input)
|
||||
{
|
||||
return input.replaceAll("([_\\\\`*>|])", "\\\\$1");
|
||||
}
|
||||
|
||||
public Flux<Message> getMessagesSent()
|
||||
{
|
||||
return sentMessages;
|
||||
}
|
||||
|
||||
public void insert(Mono<Message> messageMono)
|
||||
{
|
||||
sentMessages.concatWith(messageMono);
|
||||
}
|
||||
}
|
4
discord/src/main/resources/commands/help.json
Normal file
4
discord/src/main/resources/commands/help.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "help",
|
||||
"description": "Bot help command."
|
||||
}
|
4
discord/src/main/resources/commands/list.json
Normal file
4
discord/src/main/resources/commands/list.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "list",
|
||||
"description": "List all currently online players"
|
||||
}
|
4
discord/src/main/resources/commands/tps.json
Normal file
4
discord/src/main/resources/commands/tps.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "tps",
|
||||
"description": "Gets the current TPS for the server."
|
||||
}
|
8
discord/src/main/resources/plugin.yml
Normal file
8
discord/src/main/resources/plugin.yml
Normal file
@ -0,0 +1,8 @@
|
||||
name: TFD4J
|
||||
main: me.totalfreedom.discord.TFD4J
|
||||
version: 1.0
|
||||
api-version: 1.19
|
||||
depend: [TotalFreedomMod]
|
||||
libraries:
|
||||
- com.discord4j:discord4j-core:3.2.0
|
||||
- io.projectreactor:reactor-core:3.4.9
|
Reference in New Issue
Block a user