Reputation: 11
I am trying to get my discord bot to send a message at specific times. I am utilizing the onGuildAvailable(GuildAvailableEvent event) method in Discord JDA's ListenerAdapter. I have also tried onGuildReady(GuildReadyEvent event), but that doesn't seem to work either. Any help is appreciated. Here is my code thus far:
private static GuildAvailableEvent e;
private static final Timer timer = new Timer(1000, new Listener());
public void onGuildAvailable(GuildAvailableEvent event) {
e = event;
timer.setRepeats(true);
timer.start();
timer.restart();
}
private static class Listener implements ActionListener {
public void actionPerformed(ActionEvent event) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("e HH:mm");
String time = dtf.format(LocalDateTime.now());
if(time.charAt(0) == '0' || time.charAt(0) == '2' || time.charAt(0) == '3' || time.charAt(0) == '4' || time.charAt(0) == '5') {
String message = "Class is starting! Get to class!";
if(time.substring(2, time.length() - 1).equalsIgnoreCase("08:05")) {
Objects.requireNonNull(e.getGuild().getDefaultChannel()).sendMessage(message).queue();
} else if(time.substring(2, time.length() - 1).equalsIgnoreCase("09:25")) {
Objects.requireNonNull(e.getGuild().getDefaultChannel()).sendMessage(message).queue();
} else if(time.substring(2, time.length() - 1).equalsIgnoreCase("11:55")) {
Objects.requireNonNull(e.getGuild().getDefaultChannel()).sendMessage(message).queue();
} else if(time.substring(2, time.length() - 1).equalsIgnoreCase("13:30")) {
Objects.requireNonNull(e.getGuild().getDefaultChannel()).sendMessage(message).queue();
} else if(time.substring(2, time.length() - 1).equalsIgnoreCase("15:39")) { // test time
Objects.requireNonNull(e.getGuild().getDefaultChannel()).sendMessage(message).queue();
}
}
}
}
Upvotes: 1
Views: 2881
Reputation: 54
Here is a working, readable & aesthetic solution for your problem:
public class TestListener extends ListenerAdapter {
private final ScheduledExecutorService scheduler;
private final Set<LocalTime> targetTimes;
private final ZoneId zoneId = ZoneId.of("Your_Region_ID"); // Replace "Your_Region_ID" with the ID of your desired region
public TestListener() {
this.scheduler = Executors.newScheduledThreadPool(1);
// Add your target times to the set
this.targetTimes = Set.of(
LocalTime.of(8, 5),
LocalTime.of(9, 25),
LocalTime.of(11, 55),
LocalTime.of(13, 30)
);
}
@Override
public void onGuildReady(GuildReadyEvent event) {
TextChannel channel = event.getGuild().getTextChannelById("Your-channel-id"); // The channel that you want to send the message
if (channel == null) return;
Runnable runnable = () -> {
LocalTime now = LocalTime.now(zoneId); // Obtain current time for the specified region
for (LocalTime time : targetTimes) {
if (time.equals(now)) {
String message = "Class is starting! Get to class!";
channel.sendMessage(message).queue();
}
}
};
scheduler.scheduleAtFixedRate(runnable, 0, 1, TimeUnit.MINUTES); // Check every minute
}
}
Here is a little more detailed explanation for this code:
The Instance Variables: ScheduledExecutorService scheduler: This is a service provided by Java's java.util.concurrent package that allows scheduling tasks to be executed periodically or after a delay.
Set targetTimes: This set contains the target times when the bot should send a message. It's initialized with the specified class start times.
ZoneId zoneId: This variable holds the time zone ID for the desired region. It's initialized with the ID of the desired time zone (e.g., "America/New_York"). Here is a list of time zones you can use
The Constructor:
The onGuildReady
Method:
This method is called when the bot is ready to operate in a guild (server).
Obtains the text channel (TextChannel
) where the bot should send messages. The channel is identified by its unique ID.
Creates a Runnable object that checks the current time every minute (scheduleAtFixedRate
).
If the current time matches any of the target times, a message is sent to the text channel indicating that the class is starting.
Upvotes: 0
Reputation: 842
You can use the ReadyEvent
but I would suggest sending those messages using a ScheduledExecutorService
.
At first you have to compare the current time to the time you want to schedule your message at.
public void onReady(@NotNull ReadyEvent event) {
// get the current ZonedDateTime of your TimeZone
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("Europe/Berlin"));
// set the ZonedDateTime of the first lesson at 8:05
ZonedDateTime nextFirstLesson = now.withHour(8).withMinute(05).withSecond(0);
// if it's already past the time (in this case 8:05) the first lesson will be scheduled for the next day
if (now.compareTo(nextFirstLesson) > 0) {
nextFirstLesson = nextFirstLesson.plusDays(1);
}
// duration between now and the beginning of the next first lesson
Duration durationUntilFirstLesson = Duration.between(now, nextFirstLesson);
// in seconds
long initialDelayFirstLesson = durationUntilFirstLesson.getSeconds();
// schedules the reminder at a fixed rate of one day
ScheduledExecutorService schedulerFirstLesson = Executors.newScheduledThreadPool(1);
schedulerFirstLesson.scheduleAtFixedRate(() -> {
// send a message
/*
String message = "Class is starting! Get to class!";
JDA jda = event.getJDA();
for (Guild guild : jda.getGuilds()) {
guild.getDefaultChannel().sendMessage(message).queue();
}
*/
},
initialDelayFirstLesson,
TimeUnit.DAYS.toSeconds(1),
TimeUnit.SECONDS);
}
This is just a basic idea for the first lesson. It is up to you on implementing the rest.
For example, you might want to check which day it is in order to not send messages on weekends, or use only one scheduler for all the lessons.
I don't know whether you want to send those messages only to one specific server (in which case you might just want to hardcode the guild id) or to multiple servers (here you could initialize a list of guilds or just get every guild the bot is in).
Upvotes: 2