add discord after hours of work?

This commit is contained in:
ChomeNS 2023-03-26 17:34:35 +07:00
parent ed34bcd63f
commit 0d38dbec49
14 changed files with 380 additions and 25 deletions

View file

@ -6,6 +6,11 @@
<option name="name" value="Minecraft Libraries" /> <option name="name" value="Minecraft Libraries" />
<option name="url" value="https://libraries.minecraft.net" /> <option name="url" value="https://libraries.minecraft.net" />
</remote-repository> </remote-repository>
<remote-repository>
<option name="id" value="dv8tion" />
<option name="name" value="m2-dv8tion" />
<option name="url" value="https://m2.dv8tion.net/releases" />
</remote-repository>
<remote-repository> <remote-repository>
<option name="id" value="central" /> <option name="id" value="central" />
<option name="name" value="Central Repository" /> <option name="name" value="Central Repository" />

View file

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="EntryPointsManager">
<writeAnnotations>
<writeAnnotation name="lombok.Getter" />
</writeAnnotations>
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager"> <component name="MavenProjectsManager">
<option name="originalFiles"> <option name="originalFiles">

View file

@ -46,6 +46,11 @@
<name>Minecraft Libraries</name> <name>Minecraft Libraries</name>
<url>https://libraries.minecraft.net</url> <url>https://libraries.minecraft.net</url>
</repository> </repository>
<repository>
<id>dv8tion</id>
<name>m2-dv8tion</name>
<url>https://m2.dv8tion.net/releases</url>
</repository>
</repositories> </repositories>
<properties> <properties>
<maven.compiler.target>17</maven.compiler.target> <maven.compiler.target>17</maven.compiler.target>

12
pom.xml
View file

@ -26,6 +26,12 @@
<name>Minecraft Libraries</name> <name>Minecraft Libraries</name>
<url>https://libraries.minecraft.net</url> <url>https://libraries.minecraft.net</url>
</repository> </repository>
<repository>
<id>dv8tion</id>
<name>m2-dv8tion</name>
<url>https://m2.dv8tion.net/releases</url>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
@ -96,6 +102,12 @@
<artifactId>luaj-jse</artifactId> <artifactId>luaj-jse</artifactId>
<version>3.0.1</version> <version>3.0.1</version>
</dependency> </dependency>
<dependency>
<groupId>net.dv8tion</groupId>
<artifactId>JDA</artifactId>
<version>4.4.0_350</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -53,6 +53,10 @@ public class Bot {
this.allBots = allBots; this.allBots = allBots;
this.config = config; this.config = config;
try {
DiscordPlugin.readyLatch().await();
} catch (InterruptedException ignored) { System.exit(1); }
this.chat = new ChatPlugin(this); this.chat = new ChatPlugin(this);
this.selfCare = new SelfCarePlugin(this); this.selfCare = new SelfCarePlugin(this);
this.position = new PositionPlugin(this); this.position = new PositionPlugin(this);

View file

@ -2,6 +2,7 @@ package me.chayapak1.chomens_bot;
import lombok.Getter; import lombok.Getter;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -16,6 +17,7 @@ public class Configuration {
@Getter public Map<String, String> keys; @Getter public Map<String, String> keys;
@Getter public Core core = new Core(); @Getter public Core core = new Core();
@Getter public Discord discord = new Discord();
@Getter public SelfCare selfCare = new SelfCare(); @Getter public SelfCare selfCare = new SelfCare();
@Getter public Bots[] bots = new Bots[]{}; @Getter public Bots[] bots = new Bots[]{};
@ -25,6 +27,18 @@ public class Configuration {
@Getter public String customName = "[{\"text\":\"ChomeNS \",\"color\":\"yellow\"},{\"text\":\"Core\",\"color\":\"green\"},{\"text\":\"\",\"color\":\"gold\"}]"; @Getter public String customName = "[{\"text\":\"ChomeNS \",\"color\":\"yellow\"},{\"text\":\"Core\",\"color\":\"green\"},{\"text\":\"\",\"color\":\"gold\"}]";
} }
public static class Discord {
@Getter public String prefix = "default!";
@Getter public String token;
@Getter public Map<String, String> servers = new HashMap<>();
@Getter public EmbedColors embedColors = new EmbedColors();
}
public static class EmbedColors {
@Getter public String normal = "#FFFF00";
@Getter public String error = "#FF0000";
}
public static class SelfCare { public static class SelfCare {
@Getter public int checkInterval; @Getter public int checkInterval;

View file

@ -1,7 +1,7 @@
package me.chayapak1.chomens_bot; package me.chayapak1.chomens_bot;
import me.chayapak1.chomens_bot.plugins.ConsolePlugin; import me.chayapak1.chomens_bot.plugins.ConsolePlugin;
import org.yaml.snakeyaml.LoaderOptions; import me.chayapak1.chomens_bot.plugins.DiscordPlugin;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.constructor.Constructor;
@ -11,6 +11,10 @@ import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
public class Main { public class Main {
public static final List<Bot> allBots = new ArrayList<>();
public static CountDownLatch latch = null;
public static void main(String[] args) throws IOException, InterruptedException { public static void main(String[] args) throws IOException, InterruptedException {
final File file = new File("config.yml"); final File file = new File("config.yml");
final Constructor constructor = new Constructor(Configuration.class); final Constructor constructor = new Constructor(Configuration.class);
@ -47,9 +51,7 @@ public class Main {
Configuration.Bots[] botsOptions = config.bots(); Configuration.Bots[] botsOptions = config.bots();
final List<Bot> allBots = new ArrayList<>(); latch = new CountDownLatch(botsOptions.length);
final CountDownLatch latch = new CountDownLatch(botsOptions.length);
for (Configuration.Bots botOption : botsOptions) { for (Configuration.Bots botOption : botsOptions) {
final String host = botOption.host(); final String host = botOption.host();
@ -65,6 +67,8 @@ public class Main {
}).start(); }).start();
} }
new DiscordPlugin(config);
latch.await(); latch.await();
new ConsolePlugin(allBots); new ConsolePlugin(allBots);
} }

View file

@ -0,0 +1,74 @@
package me.chayapak1.chomens_bot.command;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import me.chayapak1.chomens_bot.Bot;
import me.chayapak1.chomens_bot.chatParsers.data.MutablePlayerListEntry;
import me.chayapak1.chomens_bot.util.ComponentUtilities;
import me.chayapak1.chomens_bot.util.EscapeCodeBlock;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.kyori.adventure.text.Component;
import java.awt.*;
import java.util.UUID;
public class DiscordCommandContext extends CommandContext {
private final MessageReceivedEvent event;
private final Bot bot;
public DiscordCommandContext(Bot bot, String prefix, MessageReceivedEvent event, String hash, String ownerHash) {
super(
bot,
prefix,
new MutablePlayerListEntry(
new GameProfile(
new UUID(0L, 0L),
null
),
GameMode.SURVIVAL,
0,
Component.text(event.getAuthor().getName()),
0L,
null,
new byte[0]
),
hash,
ownerHash
);
this.bot = bot;
this.event = event;
}
@Override
public void sendOutput (Component component) {
final String output = ComponentUtilities.stringifyAnsi(component);
final EmbedBuilder builder = new EmbedBuilder();
builder.setTitle("Output");
builder.setColor(Color.decode(bot.config().discord().embedColors().normal()));
builder.setDescription("```ansi\n" + EscapeCodeBlock.escape(output.replace("\u001b[9", "\u001b[3")) + "\n```");
final MessageEmbed embed = builder.build();
event.getMessage().replyEmbeds(embed).queue();
}
public void sendError (Component component) {
final String output = ComponentUtilities.stringifyAnsi(component);
final EmbedBuilder builder = new EmbedBuilder();
builder.setTitle("Error");
builder.setColor(Color.decode(bot.config().discord().embedColors().error()));
builder.setDescription("```ansi\n" + output + "\n```");
final MessageEmbed embed = builder.build();
event.getMessage().replyEmbeds(embed).queue();
}
@Override
public Component displayName () {
return Component.text(event.getAuthor().getName());
}
}

View file

@ -55,7 +55,7 @@ public class ChatCommandHandlerPlugin extends ChatPlugin.ChatListener {
final PlayerCommandContext context = new PlayerCommandContext(bot, displayName, prefix, selector, message.sender(), bot.hashing().hash(), bot.hashing().ownerHash()); final PlayerCommandContext context = new PlayerCommandContext(bot, displayName, prefix, selector, message.sender(), bot.hashing().hash(), bot.hashing().ownerHash());
final Component output = bot.commandHandler().executeCommand(commandString, context, bot.hashing().hash(), bot.hashing().ownerHash()); final Component output = bot.commandHandler().executeCommand(commandString, context, false, bot.hashing().hash(), bot.hashing().ownerHash(), null);
final String textOutput = ((TextComponent) output).content(); final String textOutput = ((TextComponent) output).content();
if (!textOutput.equals("success")) { if (!textOutput.equals("success")) {

View file

@ -5,6 +5,8 @@ import me.chayapak1.chomens_bot.command.Command;
import me.chayapak1.chomens_bot.command.CommandContext; import me.chayapak1.chomens_bot.command.CommandContext;
import me.chayapak1.chomens_bot.commands.*; import me.chayapak1.chomens_bot.commands.*;
import me.chayapak1.chomens_bot.util.ElementUtilities; import me.chayapak1.chomens_bot.util.ElementUtilities;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
@ -44,7 +46,7 @@ public class CommandHandlerPlugin {
commands.add(command); commands.add(command);
} }
public Component executeCommand (String input, CommandContext context, String hash, String ownerHash) { public Component executeCommand (String input, CommandContext context, boolean discord, String hash, String ownerHash, MessageReceivedEvent event) {
final String[] splitInput = input.split("\\s+"); final String[] splitInput = input.split("\\s+");
final String commandName = splitInput[0]; final String commandName = splitInput[0];
@ -68,17 +70,33 @@ public class CommandHandlerPlugin {
final String[] args = Arrays.copyOfRange(splitInput, (trustLevel > 0) ? 2 : 1, splitInput.length); final String[] args = Arrays.copyOfRange(splitInput, (trustLevel > 0) ? 2 : 1, splitInput.length);
// fix shit random messy code
if (command.trustLevel() > 0) { if (command.trustLevel() > 0) {
if ( if (!discord) {
command.trustLevel() == 1 && final List<Role> roles = event.getMember().getRoles();
!userHash.equals(hash) &&
!userHash.equals(ownerHash)
) return Component.text("Invalid hash").color(NamedTextColor.RED);
if ( if (
command.trustLevel() == 2 && command.trustLevel() == 1 &&
!userHash.equals(ownerHash) roles.stream().noneMatch(role -> role.getName().equalsIgnoreCase("Trusted")) &&
) return Component.text("Invalid OwnerHash").color(NamedTextColor.RED); roles.stream().noneMatch(role -> role.getName().equalsIgnoreCase("Host"))
) return Component.text("You're not in the trusted role!").color(NamedTextColor.RED);
if (
command.trustLevel() == 2 &&
roles.stream().noneMatch(role -> role.getName().equalsIgnoreCase("Host"))
) return Component.text("You're not in the host role!").color(NamedTextColor.RED);
} else {
if (
command.trustLevel() == 1 &&
!userHash.equals(hash) &&
!userHash.equals(ownerHash)
) return Component.text("Invalid hash").color(NamedTextColor.RED);
if (
command.trustLevel() == 2 &&
!userHash.equals(ownerHash)
) return Component.text("Invalid OwnerHash").color(NamedTextColor.RED);
}
} }
try { try {
@ -87,15 +105,19 @@ public class CommandHandlerPlugin {
exception.printStackTrace(); exception.printStackTrace();
final String stackTrace = ExceptionUtils.getStackTrace(exception); final String stackTrace = ExceptionUtils.getStackTrace(exception);
return Component if (!discord) {
.text("An error occurred while trying to execute the command, hover here for more details", NamedTextColor.RED) return Component
.hoverEvent( .text("An error occurred while trying to execute the command, hover here for more details", NamedTextColor.RED)
HoverEvent.showText( .hoverEvent(
Component HoverEvent.showText(
.text(stackTrace) Component
.color(NamedTextColor.RED) .text(stackTrace)
) .color(NamedTextColor.RED)
); )
);
} else {
return Component.text(stackTrace).color(NamedTextColor.RED);
}
} }
} }

View file

@ -84,7 +84,7 @@ public class ConsolePlugin {
if (line.startsWith(prefix)) { if (line.startsWith(prefix)) {
final ConsoleCommandContext context = new ConsoleCommandContext(bot, prefix, "h", "o"); // ? should the hashes be hardcoded? final ConsoleCommandContext context = new ConsoleCommandContext(bot, prefix, "h", "o"); // ? should the hashes be hardcoded?
final Component output = bot.commandHandler().executeCommand(line.substring(prefix.length()), context, "h", "o"); final Component output = bot.commandHandler().executeCommand(line.substring(prefix.length()), context, false, "h", "o", null);
final String textOutput = ((TextComponent) output).content(); final String textOutput = ((TextComponent) output).content();
if (!textOutput.equals("success")) { if (!textOutput.equals("success")) {

View file

@ -0,0 +1,197 @@
package me.chayapak1.chomens_bot.plugins;
import com.github.steveice10.packetlib.event.session.ConnectedEvent;
import com.github.steveice10.packetlib.event.session.DisconnectedEvent;
import com.github.steveice10.packetlib.event.session.SessionAdapter;
import lombok.Getter;
import me.chayapak1.chomens_bot.Bot;
import me.chayapak1.chomens_bot.Configuration;
import me.chayapak1.chomens_bot.Main;
import me.chayapak1.chomens_bot.command.DiscordCommandContext;
import me.chayapak1.chomens_bot.util.ComponentUtilities;
import me.chayapak1.chomens_bot.util.EscapeCodeBlock;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import org.jetbrains.annotations.NotNull;
import javax.security.auth.login.LoginException;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;
public class DiscordPlugin {
@Getter private JDA jda;
public final Map<String, String> servers;
public final String prefix;
@Getter private static CountDownLatch readyLatch = new CountDownLatch(1);
private final Map<String, Boolean> alreadyAddedListeners = new HashMap<>();
public DiscordPlugin (Configuration config) {
final Configuration.Discord options = config.discord();
this.prefix = options.prefix();
this.servers = options.servers();
JDABuilder builder = JDABuilder.createDefault(options.token());
new Thread(() -> {
try {
jda = builder.build();
jda.awaitReady();
} catch (LoginException e) {
System.err.println("Failed to login to Discord, stacktrace:");
e.printStackTrace();
System.exit(1);
} catch (InterruptedException ignored) {
System.exit(1);
}
readyLatch.countDown();
}).start();
try {
Main.latch.await();
} catch (InterruptedException ignored) { System.exit(1); }
for (Bot bot : Main.allBots) {
String channelId = servers.get(bot.host() + ":" + bot.port());
boolean channelAlreadyAddedListeners = alreadyAddedListeners.getOrDefault(channelId, false);
bot.addListener(new SessionAdapter() {
@Override
public void connected(ConnectedEvent event) {
boolean channelAlreadyAddedListeners = alreadyAddedListeners.getOrDefault(channelId, false);
if (channelAlreadyAddedListeners) return;
sendMessageInstantly("Successfully connected to: " + "`" + bot.host() + ":" + bot.port() + "`", channelId);
jda.addEventListener(new ListenerAdapter() {
@Override
public void onMessageReceived(@NotNull MessageReceivedEvent event) {
if (
!event.getChannel().getId().equals(channelId) ||
event.getAuthor().getId().equals(jda.getSelfUser().getId())
) return;
final String tag = event.getAuthor().getAsTag();
final String message = event.getMessage().getContentRaw();
if (message.startsWith(prefix)) {
final DiscordCommandContext context = new DiscordCommandContext(bot, prefix, event, null, null);
final Component output = bot.commandHandler().executeCommand(message.substring(prefix.length()), context, true, null, null, event);
final String textOutput = ((TextComponent) output).content();
if (!textOutput.equals("success")) {
context.sendError(output);
}
return;
}
final Component component = Component.translatable(
"[%s %s] %s %s",
Component.text("ChomeNS").color(NamedTextColor.YELLOW),
Component.text("Discord").color(NamedTextColor.BLUE),
Component.text(tag).color(NamedTextColor.RED),
Component.text(message).color(NamedTextColor.GRAY)
).color(NamedTextColor.DARK_GRAY);
bot.chat().tellraw(component);
}
});
alreadyAddedListeners.put(channelId, true);
bot.chat().addListener(new ChatPlugin.ChatListener() {
@Override
public void systemMessageReceived (String ignoredMessage, Component component) {
final String content = ComponentUtilities.stringifyAnsi(component);
sendMessage(EscapeCodeBlock.escape(content.replace("\u001b[9", "\u001b[3")), channelId);
}
});
final TimerTask task = new TimerTask() {
@Override
public void run() {
onDiscordTick(channelId);
}
};
final Timer timer = new Timer();
timer.schedule(task, 50, 50);
}
@Override
public void disconnected(DisconnectedEvent event) {
sendMessageInstantly("Disconnected: " + "`" + event.getReason().replace("`", "\\`") + "`", channelId);
}
});
}
}
// totallynotskidded from HBot (and changed a bit)
final Map<String, StringBuilder> logMessages = new HashMap<>();
final Map<String, Long> nextLogTimes = new HashMap<>();
final Map<String, Boolean> doneSendingInLogs = new HashMap<>();
public void sendMessage(String message, String channelId) {
synchronized (logMessages) {
if (!logMessages.containsKey(channelId)) {
logMessages.put(channelId, new StringBuilder());
}
StringBuilder logMessage = logMessages.get(channelId);
if (logMessage.length() < 2000) {
if (logMessage.length() > 0) {
logMessage.append('\n');
}
logMessage.append(message);
}
}
}
public void sendMessageInstantly (String message, String channelId) {
final TextChannel logChannel = jda.getTextChannelById(channelId);
logChannel.sendMessage(message).queue(
(msg) -> doneSendingInLogs.put(channelId, true),
(err) -> doneSendingInLogs.put(channelId, false)
);
}
public void onDiscordTick(String channelId) {
synchronized (logMessages) {
if (!logMessages.containsKey(channelId) || logMessages.get(channelId).length() == 0) {
return;
}
}
long currentTime = System.currentTimeMillis();
if (!nextLogTimes.containsKey(channelId) || (currentTime >= nextLogTimes.get(channelId) && doneSendingInLogs.get(channelId))
|| currentTime - nextLogTimes.get(channelId) > 5000) {
long logDelay = 2000; // mabe don't hardcode this
nextLogTimes.put(channelId, currentTime + logDelay);
String message;
synchronized (logMessages) {
StringBuilder logMessage = logMessages.get(channelId);
message = logMessage.toString();
if (message.length() >= 2000) {
message = message.substring(0, 2000);
}
logMessage.setLength(0);
}
sendMessageInstantly("```ansi\n" + message + "\n```", channelId);
}
}
}

View file

@ -0,0 +1,7 @@
package me.chayapak1.chomens_bot.util;
public class EscapeCodeBlock {
public static String escape (String message) {
return message.replace("`", "\\`");
}
}

View file

@ -11,6 +11,12 @@ consolePrefixes:
reconnectDelay: 7000 reconnectDelay: 7000
discord:
prefix: 'default!'
token: 'token here'
servers:
localhost:25565: 'channel id'
keys: keys:
normalKey: 'normal hash key here' normalKey: 'normal hash key here'
ownerKey: 'OwnerHash™ key here' ownerKey: 'OwnerHash™ key here'