Compare commits
No commits in common. "bf7aafad0cf07a21f4f1e6c16b0759c1322fa6dc" and "269c44c065124c37d95e6bcf12516d74b2d1e4f0" have entirely different histories.
bf7aafad0c
...
269c44c065
10 changed files with 433 additions and 75 deletions
|
@ -13,6 +13,7 @@ public class Config {
|
||||||
@SuppressWarnings("unused") private String token;
|
@SuppressWarnings("unused") private String token;
|
||||||
@SuppressWarnings("unused") private String prefix;
|
@SuppressWarnings("unused") private String prefix;
|
||||||
@SuppressWarnings("unused") private DBConfig mariadb;
|
@SuppressWarnings("unused") private DBConfig mariadb;
|
||||||
|
@SuppressWarnings("unused") private boolean levelling = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the configuration object for this bot
|
* Returns the configuration object for this bot
|
||||||
|
@ -36,6 +37,7 @@ public class Config {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
public String getPrefix() { return prefix; }
|
public String getPrefix() { return prefix; }
|
||||||
|
public boolean getLevelling() { return levelling; }
|
||||||
|
|
||||||
public DBConfig getDbConfig() {
|
public DBConfig getDbConfig() {
|
||||||
return mariadb;
|
return mariadb;
|
||||||
|
|
|
@ -6,6 +6,8 @@ import net.dv8tion.jda.api.JDA;
|
||||||
import net.dv8tion.jda.api.JDABuilder;
|
import net.dv8tion.jda.api.JDABuilder;
|
||||||
import net.dv8tion.jda.api.entities.*;
|
import net.dv8tion.jda.api.entities.*;
|
||||||
import net.dv8tion.jda.api.requests.GatewayIntent;
|
import net.dv8tion.jda.api.requests.GatewayIntent;
|
||||||
|
import net.hypr.doki.listeners.LevellingListener;
|
||||||
|
import org.apache.commons.dbcp2.BasicDataSource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -14,6 +16,7 @@ public class Doki {
|
||||||
private static final Logger log = Logging.getLogger();
|
private static final Logger log = Logging.getLogger();
|
||||||
private static JDA jda;
|
private static JDA jda;
|
||||||
private static Config config;
|
private static Config config;
|
||||||
|
private static final BasicDataSource dataSource = new BasicDataSource();
|
||||||
|
|
||||||
private Doki(JDA jda, Config config) {
|
private Doki(JDA jda, Config config) {
|
||||||
Doki.jda = jda;
|
Doki.jda = jda;
|
||||||
|
@ -24,6 +27,7 @@ public class Doki {
|
||||||
return jda;
|
return jda;
|
||||||
}
|
}
|
||||||
public static String getPrefix() { return config.getPrefix(); }
|
public static String getPrefix() { return config.getPrefix(); }
|
||||||
|
public static BasicDataSource getDataSource() { return dataSource; }
|
||||||
|
|
||||||
public static void start() throws IOException, InterruptedException {
|
public static void start() throws IOException, InterruptedException {
|
||||||
config = Config.readConfig();
|
config = Config.readConfig();
|
||||||
|
@ -34,6 +38,19 @@ public class Doki {
|
||||||
.build()
|
.build()
|
||||||
.awaitReady();
|
.awaitReady();
|
||||||
|
|
||||||
|
// Connect to the DB
|
||||||
|
if (config.getLevelling()) {
|
||||||
|
Config.DBConfig dbConfig = config.getDbConfig();
|
||||||
|
dataSource.setDriverClassName("org.mariadb.jdbc.Driver");
|
||||||
|
dataSource.setUrl("jdbc:mariadb://" + dbConfig.getHost() + ":" + dbConfig.getPortNumber() + "/" + dbConfig.getDatabase());
|
||||||
|
dataSource.setUsername(dbConfig.getUser());
|
||||||
|
dataSource.setPassword(dbConfig.getPassword());
|
||||||
|
dataSource.setMaxTotal(10);
|
||||||
|
dataSource.setMaxIdle(5);
|
||||||
|
dataSource.setMinIdle(2);
|
||||||
|
dataSource.setInitialSize(10);
|
||||||
|
}
|
||||||
|
|
||||||
// Print some information about the bot
|
// Print some information about the bot
|
||||||
log.info("Bot connected as {}", jda.getSelfUser().getAsTag());
|
log.info("Bot connected as {}", jda.getSelfUser().getAsTag());
|
||||||
log.info("The bot is present in the following guilds:");
|
log.info("The bot is present in the following guilds:");
|
||||||
|
@ -51,6 +68,11 @@ public class Doki {
|
||||||
CommandsBuilder.newBuilder(437970062922612737L)
|
CommandsBuilder.newBuilder(437970062922612737L)
|
||||||
.textCommandBuilder(textCommandsBuilder -> textCommandsBuilder.addPrefix(getPrefix()))
|
.textCommandBuilder(textCommandsBuilder -> textCommandsBuilder.addPrefix(getPrefix()))
|
||||||
.build(jda, "net.hypr.doki.commands"); //Registering listeners is taken care of by the lib
|
.build(jda, "net.hypr.doki.commands"); //Registering listeners is taken care of by the lib
|
||||||
|
if (config.getLevelling()) {
|
||||||
|
jda.addEventListener(new LevellingListener());
|
||||||
|
} else {
|
||||||
|
log.info("Levelling is disabled");
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to start the bot", e);
|
log.error("Failed to start the bot", e);
|
||||||
System.exit(-1);
|
System.exit(-1);
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package net.hypr.doki.commands.levelling;
|
||||||
|
|
||||||
|
import com.freya02.botcommands.api.annotations.CommandMarker;
|
||||||
|
import com.freya02.botcommands.api.prefixed.CommandEvent;
|
||||||
|
import com.freya02.botcommands.api.prefixed.TextCommand;
|
||||||
|
import com.freya02.botcommands.api.prefixed.annotations.Category;
|
||||||
|
import com.freya02.botcommands.api.prefixed.annotations.Description;
|
||||||
|
import com.freya02.botcommands.api.prefixed.annotations.JDATextCommand;
|
||||||
|
import net.dv8tion.jda.api.EmbedBuilder;
|
||||||
|
import net.dv8tion.jda.api.JDA;
|
||||||
|
import net.dv8tion.jda.api.entities.User;
|
||||||
|
import net.hypr.doki.utils.DBUtils;
|
||||||
|
import net.hypr.doki.utils.UserRecord;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@CommandMarker
|
||||||
|
@Category("Levelling")
|
||||||
|
@Description("Get the global leaderboard")
|
||||||
|
public class Leaderboard extends TextCommand {
|
||||||
|
@JDATextCommand(name = "leaderboard", order = 1, aliases = { "lb" })
|
||||||
|
public void execute(CommandEvent event) throws SQLException {
|
||||||
|
List<UserRecord> userRecords = DBUtils.getAllUserRecords(event.getGuild().getIdLong());
|
||||||
|
// Sort the leaderboard highest level first
|
||||||
|
userRecords.sort((o1, o2) -> o2.totalXp - o1.totalXp);
|
||||||
|
EmbedBuilder whoIsEmbed = buildLeaderboardEmbed(userRecords, event);
|
||||||
|
event.reply(whoIsEmbed.build()).queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmbedBuilder buildLeaderboardEmbed(List<UserRecord> userRecords , CommandEvent event) {
|
||||||
|
StringBuilder leaderboard = new StringBuilder();
|
||||||
|
JDA jda = event.getJDA();
|
||||||
|
int idx = 1;
|
||||||
|
for (UserRecord record : userRecords) {
|
||||||
|
User user = jda.retrieveUserById(record.user_id).complete();
|
||||||
|
leaderboard
|
||||||
|
.append("**")
|
||||||
|
.append(idx)
|
||||||
|
.append(".** ")
|
||||||
|
.append(user.getName())
|
||||||
|
.append(" - ")
|
||||||
|
.append(record.level)
|
||||||
|
.append(" (")
|
||||||
|
.append(record.totalXp)
|
||||||
|
.append(" Total XP)\n");
|
||||||
|
idx += 1;
|
||||||
|
if (idx > 10) break; // Break out after 10 records is reached
|
||||||
|
}
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setTitle(event.getGuild().getName() + " Leaderboard")
|
||||||
|
.setDescription(leaderboard)
|
||||||
|
.setColor(new Color(210,138,39));
|
||||||
|
}
|
||||||
|
}
|
46
src/main/java/net/hypr/doki/commands/levelling/Rank.java
Normal file
46
src/main/java/net/hypr/doki/commands/levelling/Rank.java
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package net.hypr.doki.commands.levelling;
|
||||||
|
|
||||||
|
import com.freya02.botcommands.api.annotations.CommandMarker;
|
||||||
|
import com.freya02.botcommands.api.prefixed.BaseCommandEvent;
|
||||||
|
import com.freya02.botcommands.api.prefixed.CommandEvent;
|
||||||
|
import com.freya02.botcommands.api.prefixed.TextCommand;
|
||||||
|
import com.freya02.botcommands.api.prefixed.annotations.Category;
|
||||||
|
import com.freya02.botcommands.api.prefixed.annotations.Description;
|
||||||
|
import com.freya02.botcommands.api.prefixed.annotations.JDATextCommand;
|
||||||
|
import com.freya02.botcommands.api.prefixed.annotations.TextOption;
|
||||||
|
import net.dv8tion.jda.api.EmbedBuilder;
|
||||||
|
import net.dv8tion.jda.api.entities.Member;
|
||||||
|
import net.hypr.doki.utils.DBUtils;
|
||||||
|
import net.hypr.doki.utils.UserRecord;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
@CommandMarker
|
||||||
|
@Category("Levelling")
|
||||||
|
@Description("Get a user's rank")
|
||||||
|
public class Rank extends TextCommand {
|
||||||
|
@JDATextCommand(name = "rank", order = 1)
|
||||||
|
public void execute(BaseCommandEvent event, @TextOption Member member) throws SQLException {
|
||||||
|
UserRecord userRecord = DBUtils.getUserRecord(member.getIdLong(), event.getGuild().getIdLong());
|
||||||
|
EmbedBuilder rankEmbed = buildRankEmbed(member, userRecord);
|
||||||
|
event.reply(rankEmbed.build()).queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JDATextCommand(name = "rank", order = 2)
|
||||||
|
public void execute(CommandEvent event) throws SQLException {
|
||||||
|
UserRecord userRecord = DBUtils.getUserRecord(event.getMember().getIdLong(), event.getGuild().getIdLong());
|
||||||
|
EmbedBuilder whoIsEmbed = buildRankEmbed(event.getMember(), userRecord);
|
||||||
|
event.reply(whoIsEmbed.build()).queue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private EmbedBuilder buildRankEmbed(Member user, UserRecord userRecord) {
|
||||||
|
int xpToNextLevel = (((userRecord.level + 1) * 5) * 40) - userRecord.xp;
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setAuthor(user.getUser().getName(), null, user.getEffectiveAvatarUrl())
|
||||||
|
.setThumbnail(user.getEffectiveAvatarUrl())
|
||||||
|
.addField("Level", String.valueOf(userRecord.level), true)
|
||||||
|
.addField("XP", String.valueOf(userRecord.xp), true)
|
||||||
|
.addField("XP Until level " + (userRecord.level + 1), String.valueOf(xpToNextLevel), true)
|
||||||
|
.setColor(user.getColor());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,48 +0,0 @@
|
||||||
package net.hypr.doki.commands.moderation;
|
|
||||||
|
|
||||||
import com.freya02.botcommands.api.annotations.CommandMarker;
|
|
||||||
import com.freya02.botcommands.api.prefixed.BaseCommandEvent;
|
|
||||||
import com.freya02.botcommands.api.prefixed.CommandEvent;
|
|
||||||
import com.freya02.botcommands.api.prefixed.TextCommand;
|
|
||||||
import com.freya02.botcommands.api.prefixed.annotations.Category;
|
|
||||||
import com.freya02.botcommands.api.prefixed.annotations.Description;
|
|
||||||
import com.freya02.botcommands.api.prefixed.annotations.JDATextCommand;
|
|
||||||
import com.freya02.botcommands.api.prefixed.annotations.TextOption;
|
|
||||||
import net.dv8tion.jda.api.Permission;
|
|
||||||
import net.dv8tion.jda.api.entities.Member;
|
|
||||||
import net.dv8tion.jda.api.entities.Message;
|
|
||||||
import net.dv8tion.jda.api.interactions.commands.Command;
|
|
||||||
import net.hypr.doki.utils.DurationUtils;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
|
|
||||||
@CommandMarker
|
|
||||||
@Category("Moderation")
|
|
||||||
@Description("Mutes a user for a specified amount of time")
|
|
||||||
public class Mute extends TextCommand {
|
|
||||||
@JDATextCommand(name = "mute", order = 1)
|
|
||||||
public void execute(BaseCommandEvent event, @TextOption(example = "<@437970062922612737>") Member member, @TextOption(example = "30m") String duration) {
|
|
||||||
Member commandExecutor = event.getMember();
|
|
||||||
if (!commandExecutor.hasPermission(Permission.KICK_MEMBERS)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Duration timeoutDuration;
|
|
||||||
try {
|
|
||||||
timeoutDuration = DurationUtils.parseDuration(duration);
|
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
event.reply("Invalid duration format!").queue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Math.abs(timeoutDuration.toDays()) > 28) {
|
|
||||||
event.reply("Duration must be less than 28 days!").queue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
member.timeoutFor(timeoutDuration).queue();
|
|
||||||
event.reply("Muted " + member.getAsMention() + " (" + member.getEffectiveName() + ") for " + duration).queue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@JDATextCommand(name = "mute", order = 2)
|
|
||||||
public void execute(CommandEvent event) {
|
|
||||||
event.reply("You must specify a user and duration!").queue();
|
|
||||||
}
|
|
||||||
}
|
|
74
src/main/java/net/hypr/doki/listeners/LevellingListener.java
Normal file
74
src/main/java/net/hypr/doki/listeners/LevellingListener.java
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package net.hypr.doki.listeners;
|
||||||
|
|
||||||
|
import com.freya02.botcommands.api.Logging;
|
||||||
|
import net.dv8tion.jda.api.entities.Guild;
|
||||||
|
import net.dv8tion.jda.api.entities.User;
|
||||||
|
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||||
|
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||||
|
import net.hypr.doki.Doki;
|
||||||
|
import net.hypr.doki.utils.DBUtils;
|
||||||
|
import net.hypr.doki.utils.LevellingUtils;
|
||||||
|
import net.hypr.doki.utils.UserRecord;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class LevellingListener extends ListenerAdapter {
|
||||||
|
@Override
|
||||||
|
public void onMessageReceived(MessageReceivedEvent event) {
|
||||||
|
Logger log = Logging.getLogger();
|
||||||
|
|
||||||
|
/* Ignore the message if one of the following conditions is met:
|
||||||
|
- Message is from self user
|
||||||
|
- Message is from a bot
|
||||||
|
- Message is command (starts with bot prefix)
|
||||||
|
- Message is a Direct Message to the bot
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
event.getGuild();
|
||||||
|
} catch (IllegalStateException ex) {
|
||||||
|
log.debug("Ignoring direct message with ID {}", event.getMessageId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
Doki.getJDA().getSelfUser().getId().equals(event.getAuthor().getId()) ||
|
||||||
|
event.getAuthor().isBot() ||
|
||||||
|
event.getMessage().getContentStripped().startsWith(Doki.getPrefix())
|
||||||
|
) {
|
||||||
|
log.debug("Ignoring self/bot message with ID {}", event.getMessageId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = event.getAuthor();
|
||||||
|
Guild guild = event.getGuild();
|
||||||
|
boolean userIsInDb = DBUtils.doesUserRecordExist(user.getIdLong(), guild.getIdLong());
|
||||||
|
if (userIsInDb) {
|
||||||
|
try {
|
||||||
|
UserRecord rec = DBUtils.getUserRecord(user.getIdLong(), guild.getIdLong());
|
||||||
|
Duration timeSinceLastMessage = Duration.between(
|
||||||
|
rec.lastMessage.toLocalDateTime(),
|
||||||
|
LocalDateTime.now()
|
||||||
|
);
|
||||||
|
if (timeSinceLastMessage.compareTo(Duration.ofHours(1)) > 0) {
|
||||||
|
// it has been over an hour since the user last sent a message that affected XP
|
||||||
|
LevellingUtils.incrementXp(log, rec);
|
||||||
|
} else {
|
||||||
|
log.debug("Ignoring message ID {} as not enough time has passed", event.getMessageId());
|
||||||
|
}
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.info("No record of user ID {} in server {}, creating blank record", user.getId(), guild.getId());
|
||||||
|
try {
|
||||||
|
UserRecord rec = DBUtils.createUserRecord(user.getIdLong(), guild.getIdLong());
|
||||||
|
LevellingUtils.incrementXp(log, rec);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
154
src/main/java/net/hypr/doki/utils/DBUtils.java
Normal file
154
src/main/java/net/hypr/doki/utils/DBUtils.java
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
package net.hypr.doki.utils;
|
||||||
|
|
||||||
|
import com.freya02.botcommands.api.Logging;
|
||||||
|
import net.hypr.doki.Doki;
|
||||||
|
import org.apache.commons.dbcp2.BasicDataSource;
|
||||||
|
import org.apache.commons.dbutils.QueryRunner;
|
||||||
|
import org.apache.commons.dbutils.ResultSetHandler;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.sql.*;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class DBUtils {
|
||||||
|
/**
|
||||||
|
* Checks if the user record exists
|
||||||
|
* @param user_id User ID to search for
|
||||||
|
* @param server_id Server ID to search for
|
||||||
|
* @return Whether the record exists or not
|
||||||
|
*/
|
||||||
|
public static boolean doesUserRecordExist(long user_id, long server_id) {
|
||||||
|
Logger log = Logging.getLogger();
|
||||||
|
BasicDataSource dataSource = Doki.getDataSource();
|
||||||
|
QueryRunner qr = new QueryRunner(dataSource);
|
||||||
|
ResultSetHandler<Set<BigInteger>> resultSetHandler = rs -> {
|
||||||
|
Set<BigInteger> rows = new HashSet<>();
|
||||||
|
while (rs.next()) {
|
||||||
|
rows.add(BigInteger.valueOf(rs.getLong(1)));
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Find out if the user is already in the DB
|
||||||
|
try {
|
||||||
|
log.debug("Searching DB for (usr{},srv:{})", user_id, server_id);
|
||||||
|
Set<BigInteger> foundIds = qr.query("SELECT user_id FROM users WHERE user_id = " + user_id + " AND server_id = " + server_id, resultSetHandler);
|
||||||
|
log.debug("Matching records: {}", foundIds.size());
|
||||||
|
return !foundIds.isEmpty();
|
||||||
|
} catch (SQLException ignored) {
|
||||||
|
log.debug("An SQL error occurred");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new user record
|
||||||
|
* @param user_id The users ID
|
||||||
|
* @param server_id The server ID
|
||||||
|
* @throws SQLException A SQL exception
|
||||||
|
*/
|
||||||
|
public static UserRecord createUserRecord(long user_id, long server_id) throws SQLException {
|
||||||
|
Logger log = Logging.getLogger();
|
||||||
|
log.info("Creating record (usr:{},srv:{})", user_id, server_id);
|
||||||
|
BasicDataSource dataSource = Doki.getDataSource();
|
||||||
|
Connection conn = dataSource.getConnection();
|
||||||
|
PreparedStatement stmt = conn.prepareStatement(
|
||||||
|
"INSERT INTO users (user_id, server_id, last_message) VALUES (?, ?, ?)"
|
||||||
|
);
|
||||||
|
stmt.setLong(1, user_id);
|
||||||
|
stmt.setLong(2, server_id);
|
||||||
|
stmt.setTimestamp(3, Timestamp.valueOf(LocalDateTime.now()));
|
||||||
|
stmt.execute();
|
||||||
|
log.info("Record (usr:{},srv:{}) created!", user_id, server_id);
|
||||||
|
return new UserRecord(user_id, server_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a user record
|
||||||
|
* @param user_id User ID of the record to update
|
||||||
|
* @param server_id Server ID of the record to update
|
||||||
|
* @param now The current time
|
||||||
|
* @param xp The new XP count
|
||||||
|
* @param totalXp The new total XP count
|
||||||
|
* @param level The new level
|
||||||
|
* @throws SQLException A SQL exception
|
||||||
|
*/
|
||||||
|
public static void updateUserRecord(long user_id, long server_id, Timestamp now, int xp, int totalXp, int level) throws SQLException {
|
||||||
|
Logger log = Logging.getLogger();
|
||||||
|
log.info("Updating record (usr:{},srv:{})", user_id, server_id);
|
||||||
|
BasicDataSource dataSource = Doki.getDataSource();
|
||||||
|
Connection conn = dataSource.getConnection();
|
||||||
|
PreparedStatement stmt = conn.prepareStatement(
|
||||||
|
"UPDATE users SET last_message = ?, xp = ?, total_xp = ?, level = ? WHERE user_id = ? AND server_id = ?"
|
||||||
|
);
|
||||||
|
stmt.setTimestamp(1, now);
|
||||||
|
stmt.setInt(2, xp);
|
||||||
|
stmt.setInt(3, totalXp);
|
||||||
|
stmt.setInt(4, level);
|
||||||
|
stmt.setLong(5, user_id);
|
||||||
|
stmt.setLong(6, server_id);
|
||||||
|
stmt.executeQuery();
|
||||||
|
log.info("Updated record (usr:{},srv:{})!", user_id, server_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a user record
|
||||||
|
* @param user_id The User ID of the record to get
|
||||||
|
* @param server_id The Server ID of the record to get
|
||||||
|
* @return The found UserRecord
|
||||||
|
* @throws SQLException A SQL exception
|
||||||
|
*/
|
||||||
|
public static UserRecord getUserRecord(long user_id, long server_id) throws SQLException {
|
||||||
|
BasicDataSource dataSource = Doki.getDataSource();
|
||||||
|
Connection conn = dataSource.getConnection();
|
||||||
|
PreparedStatement stmt = conn.prepareStatement(
|
||||||
|
"SELECT user_id, server_id, last_message, xp, total_xp, level FROM users WHERE user_id = ? AND server_id = ?"
|
||||||
|
);
|
||||||
|
stmt.setLong(1, user_id);
|
||||||
|
stmt.setLong(2, server_id);
|
||||||
|
ResultSet rs = stmt.executeQuery();
|
||||||
|
rs.next();
|
||||||
|
return new UserRecord(
|
||||||
|
rs.getLong("user_id"),
|
||||||
|
rs.getLong("server_id"),
|
||||||
|
rs.getTimestamp("last_message"),
|
||||||
|
rs.getInt("xp"),
|
||||||
|
rs.getInt("total_xp"),
|
||||||
|
rs.getInt("level")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all user records for a server
|
||||||
|
* @param server_id The Server ID
|
||||||
|
* @return A List of UserRecords
|
||||||
|
* @throws SQLException A SQL exception
|
||||||
|
*/
|
||||||
|
public static List<UserRecord> getAllUserRecords(long server_id) throws SQLException {
|
||||||
|
BasicDataSource dataSource = Doki.getDataSource();
|
||||||
|
Connection conn = dataSource.getConnection();
|
||||||
|
PreparedStatement stmt = conn.prepareStatement(
|
||||||
|
"SELECT user_id, last_message, xp, total_xp, level FROM users WHERE server_id = ?"
|
||||||
|
);
|
||||||
|
stmt.setLong(1, server_id);
|
||||||
|
ResultSet rs = stmt.executeQuery();
|
||||||
|
List<UserRecord> userRecordList = new ArrayList<>();
|
||||||
|
while (rs.next()) {
|
||||||
|
userRecordList.add(new UserRecord(
|
||||||
|
rs.getLong("user_id"),
|
||||||
|
server_id,
|
||||||
|
rs.getTimestamp("last_message"),
|
||||||
|
rs.getInt("xp"),
|
||||||
|
rs.getInt("total_xp"),
|
||||||
|
rs.getInt("level")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return userRecordList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
package net.hypr.doki.utils;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class DurationUtils {
|
|
||||||
private static final Pattern timePattern = Pattern.compile("(\\d+)(?:([dhms]))?");
|
|
||||||
public static Duration parseDuration(String input) throws IllegalArgumentException {
|
|
||||||
Matcher matcher = timePattern.matcher(input);
|
|
||||||
|
|
||||||
if (!matcher.matches()) {
|
|
||||||
throw new IllegalArgumentException("Invalid duration format");
|
|
||||||
}
|
|
||||||
|
|
||||||
int value = Integer.parseInt(matcher.group(1));
|
|
||||||
String unit = matcher.group(2);
|
|
||||||
|
|
||||||
return switch (unit == null || unit.isEmpty() ? "m" : unit.toLowerCase()) {
|
|
||||||
case "d" -> Duration.ofDays(value);
|
|
||||||
case "h" -> Duration.ofHours(value);
|
|
||||||
case "m" -> Duration.ofMinutes(value);
|
|
||||||
case "s" -> Duration.ofSeconds(value);
|
|
||||||
default -> throw new IllegalArgumentException("Invalid unit");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
35
src/main/java/net/hypr/doki/utils/LevellingUtils.java
Normal file
35
src/main/java/net/hypr/doki/utils/LevellingUtils.java
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package net.hypr.doki.utils;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class LevellingUtils {
|
||||||
|
public static void incrementXp(Logger logger, UserRecord userRecord) throws SQLException {
|
||||||
|
Random random = new Random();
|
||||||
|
// Random increment between 15 and 25
|
||||||
|
int xpInc = (random.nextInt(10) + 16) * 3;
|
||||||
|
int xpNew = userRecord.xp + xpInc;
|
||||||
|
int totalXp = userRecord.xp + xpInc;
|
||||||
|
int levelNew = userRecord.level;
|
||||||
|
if (xpNew >= ((userRecord.level + 1) * 5) * 40) {
|
||||||
|
levelNew ++;
|
||||||
|
xpNew = 0;
|
||||||
|
}
|
||||||
|
DBUtils.updateUserRecord(
|
||||||
|
userRecord.user_id,
|
||||||
|
userRecord.server_id,
|
||||||
|
Timestamp.valueOf(LocalDateTime.now()),
|
||||||
|
xpNew,
|
||||||
|
totalXp,
|
||||||
|
levelNew
|
||||||
|
);
|
||||||
|
logger.info("Incremented {}'s XP in {} ({} -> {})", userRecord.user_id, userRecord.server_id, userRecord.xp, xpNew);
|
||||||
|
if (levelNew > userRecord.level) {
|
||||||
|
logger.info("Incremented {}'s level in {} ({} -> {})", userRecord.user_id, userRecord.server_id, userRecord.level, levelNew);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
src/main/java/net/hypr/doki/utils/UserRecord.java
Normal file
44
src/main/java/net/hypr/doki/utils/UserRecord.java
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package net.hypr.doki.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
public class UserRecord {
|
||||||
|
public final long user_id;
|
||||||
|
public final long server_id;
|
||||||
|
public final Timestamp lastMessage;
|
||||||
|
public final int xp;
|
||||||
|
public int totalXp;
|
||||||
|
public final int level;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new UserRecord
|
||||||
|
* @param user_id The User ID
|
||||||
|
* @param server_id The Server/Guild ID
|
||||||
|
*/
|
||||||
|
public UserRecord (long user_id, long server_id) {
|
||||||
|
this.user_id = user_id;
|
||||||
|
this.server_id = server_id;
|
||||||
|
this.lastMessage = new Timestamp(0);
|
||||||
|
this.xp = 0;
|
||||||
|
this.level = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new UserRecord
|
||||||
|
* @param user_id The User ID
|
||||||
|
* @param server_id The Server/Guild ID
|
||||||
|
* @param lastMessage The timestamp of the user's last message
|
||||||
|
* @param xp The user's XP
|
||||||
|
* @param totalXp The user's total XP
|
||||||
|
* @param level The user's level
|
||||||
|
*/
|
||||||
|
public UserRecord (long user_id, long server_id, Timestamp lastMessage, int xp, int totalXp, int level) {
|
||||||
|
this.user_id = user_id;
|
||||||
|
this.server_id = server_id;
|
||||||
|
this.lastMessage = lastMessage;
|
||||||
|
this.xp = xp;
|
||||||
|
this.totalXp = totalXp;
|
||||||
|
this.level = level;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue