Skip to content

Commit

Permalink
implement xp loot drops
Browse files Browse the repository at this point in the history
  • Loading branch information
Kaktushose committed Jan 7, 2024
1 parent ee3a12f commit 1a859bf
Show file tree
Hide file tree
Showing 7 changed files with 346 additions and 32 deletions.
1 change: 0 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ POSTGRES_USER=user
POSTGRES_PASSWORD=password
POSTGRES_URL=jdbc:postgresql://postgres:5432/database
GF_SECURITY_ADMIN_PASSWORD=password
BOT_GUILD=0123456789
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,3 @@ buildNumber.properties
*.env
/data
/logs
wait-for-it.sh
11 changes: 8 additions & 3 deletions embeds.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@
"description": "Der EmbedCache wurde aktualisiert",
"color": "#67c94f"
},
"setXpResult" : {
"setXpResult": {
"title": "Erfolg",
"description": "Die XP von {user} wurden auf {xp} XP gesetzt",
"color": "#67c94f"
},
"addXpResult" : {
"addXpResult": {
"title": "Erfolg",
"description": "{user} wurden {xp} XP hinzugefügt",
"color": "#67c94f"
Expand All @@ -105,9 +105,14 @@
"description": "{leaderboard}",
"color": "#67c94f"
},
"switchDaily" : {
"switchDaily": {
"title": "Erfolg",
"description": "Die tägliche Kontoinformation wurde {switch}",
"color": "#67c94f"
},
"xpLootDropClaimed": {
"title": "Glückwunsch :tada:",
"description": "{user} hat {xp} XP :star2: gefunden!",
"color": "#67c94f"
}
}
89 changes: 79 additions & 10 deletions src/main/java/com/github/kaktushose/nplaybot/rank/RankListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,43 @@

import com.github.kaktushose.jda.commands.data.EmbedCache;
import com.github.kaktushose.nplaybot.Database;
import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
import com.github.kaktushose.nplaybot.settings.SettingsService;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class RankListener extends ListenerAdapter {

private static final Logger log = LoggerFactory.getLogger(RankListener.class);
private final RankService rankService;
private final SettingsService settingsService;
private final EmbedCache embedCache;
private final Map<Long, Integer> xpLootDrops;

public RankListener(Database database, EmbedCache embedCache) {
this.rankService = database.getRankService();
this.settingsService = database.getSettingsService();
this.embedCache = embedCache;
xpLootDrops = new HashMap<>();
}

@Override
public void onMessageReceived(@NotNull MessageReceivedEvent event) {
log.debug("Received message event");
var author = event.getAuthor();
var message = event.getMessage();

if (author.isBot()) {
log.trace("Author is bot");
Expand All @@ -40,16 +51,30 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) {

rankService.increaseTotalMessageCount();

if (!rankService.isValidMessage(message)) {
log.trace("Message doesn't meet rank criteria");
if (!rankService.isValidChannel(event.getChannel(), event.getGuild())) {
return;
}

rankService.updateValidMessage(author);
var result = rankService.addRandomXp(author);
onXpLootDrop(event);

if (!rankService.isValidMessage(event.getMessage())) {
log.debug("Message doesn't meet rank criteria");
return;
}

onAddRegularXp(event);
}

private void onAddRegularXp(MessageReceivedEvent event) {
rankService.updateValidMessage(event.getAuthor());
var result = rankService.addRandomXp(event.getAuthor());

log.debug("Checking for rank up: {}", author);
rankService.updateRankRoles(event.getMember(), event.getGuild(), result);
onXpChange(result, event.getMember(), event.getGuild());
}

private void onXpChange(XpChangeResult result, Member member, Guild guild) {
log.debug("Checking for rank up: {}", member);
rankService.updateRankRoles(member, guild, result);

if (!result.rankChanged()) {
log.debug("Rank hasn't changed");
Expand All @@ -58,9 +83,53 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
log.debug("Applying changes. New rank: {}", result.currentRank());

var embed = result.nextRank().isPresent() ? "rankIncrease" : "rankIncreaseMax";
var messageData = new MessageCreateBuilder().addContent(author.getAsMention())
.addEmbeds(embedCache.getEmbed(embed).injectValues(result.getEmbedValues(author)).toMessageEmbed())
var messageData = new MessageCreateBuilder().addContent(member.getAsMention())
.addEmbeds(embedCache.getEmbed(embed).injectValues(result.getEmbedValues(member)).toMessageEmbed())
.build();
settingsService.getBotChannel(event.getGuild()).sendMessage(messageData).queue();
settingsService.getBotChannel(guild).sendMessage(messageData).queue();
}

private void onXpLootDrop(MessageReceivedEvent event) {
var xp = rankService.getXpLootDrop(event.getMessage());

if (xp < 1) {
log.debug("No xp loot drop for this message");
return;
}

xpLootDrops.put(event.getMessageIdLong(), xp);
event.getMessage().addReaction(Emoji.fromUnicode("\uD83C\uDF1F")).queue();
}

@Override
public void onMessageReactionAdd(@NotNull MessageReactionAddEvent event) {
if (event.getUser().isBot()) {
return;
}

var messageId = event.getMessageIdLong();
if (!xpLootDrops.containsKey(messageId)) {
return;
}
if (!event.getEmoji().equals(Emoji.fromUnicode("\uD83C\uDF1F"))) {
return;
}

log.debug("Xp loot drop got claimed by {}", event.getMember());

var xp = xpLootDrops.get(messageId);
var result = rankService.addXp(event.getMember(), xp);
onXpChange(result, event.getMember(), event.getGuild());
xpLootDrops.remove(messageId);

event.retrieveMessage().queue(message -> {
message.reply(
embedCache.getEmbed("xpLootDropClaimed")
.injectValue("user", event.getMember().getAsMention())
.injectValue("xp", xp)
.toMessageCreateData()
).queue(it -> it.delete().queueAfter(10, TimeUnit.SECONDS));
message.clearReactions().queue();
});
}
}
73 changes: 57 additions & 16 deletions src/main/java/com/github/kaktushose/nplaybot/rank/RankService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import com.github.kaktushose.nplaybot.rank.model.UserInfo;
import com.github.kaktushose.nplaybot.rank.model.XpChangeResult;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.channel.Channel;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.channel.unions.MessageChannelUnion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -121,31 +125,19 @@ public boolean isValidMessage(Message message) {
var lastMessage = result.getLong("last_valid_message");
var messageCooldown = result.getInt("message_cooldown");
var minimumLength = result.getInt("min_message_length");
var validChannels = Arrays.asList((Long[]) result.getArray("valid_channels").getArray());

if (System.currentTimeMillis() - lastMessage < messageCooldown) {
log.trace("User still has cooldown ({} < {})", System.currentTimeMillis() - lastMessage, messageCooldown);
log.debug("User still has cooldown ({} < {})", System.currentTimeMillis() - lastMessage, messageCooldown);
return false;
}

if (message.getContentDisplay().length() < minimumLength) {
log.trace("Message is too short (Length: {}, Required: {}", message.getContentDisplay().length(), minimumLength);
log.debug("Message is too short (Length: {}, Required: {}", message.getContentDisplay().length(), minimumLength);
return false;
}

var channelId = message.getChannelIdLong();
if (message.getChannelType().isThread()) {
channelId = message.getChannel().asThreadChannel().getParentChannel().getIdLong();
}
var valid = validChannels.contains(channelId);

if (valid) {
log.debug("Message is valid");
} else {
log.trace("Invalid message channel");
}

return valid;
log.debug("Message is valid");
return true;
} catch (SQLException e) {
throw new RuntimeException(e);
}
Expand Down Expand Up @@ -347,4 +339,53 @@ public Map<Long, UserInfo> getDailyRankInfos() {
throw new RuntimeException(e);
}
}

public int getXpLootDrop(Message message) {
log.debug("Querying xp loot drop for message {}", message);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("SELECT * FROM get_xp_loot_drop(?)");
statement.setLong(1, message.getGuildIdLong());

var result = statement.executeQuery();
result.next();
var xp = result.getInt(1);
log.debug("Xp loot drop: {} xp", xp);
return xp;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}

public boolean isValidChannel(MessageChannelUnion channel, Guild guild) {
log.debug("Checking channel: {}", channel);
try (Connection connection = dataSource.getConnection()) {
var statement = connection.prepareStatement("""
SELECT rank_settings.valid_channels
FROM rank_settings
WHERE guild_id = ?
"""
);
statement.setLong(1, guild.getIdLong());

var result = statement.executeQuery();
result.next();
var validChannels = Arrays.asList((Long[]) result.getArray("valid_channels").getArray());

var channelId = channel.getIdLong();
if (channel.getType().isThread()) {
channelId = channel.asThreadChannel().getParentChannel().getIdLong();
}
var valid = validChannels.contains(channelId);

if (valid) {
log.debug("Channel is valid");
} else {
log.debug("Invalid message channel");
}

return valid;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
20 changes: 19 additions & 1 deletion src/main/resources/db/migration/V1.0.0__setup_rank_system.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ CREATE TABLE rank_settings (
guild_id BIGINT NOT NULL PRIMARY KEY,
message_cooldown INT NOT NULL,
min_message_length INT NOT NULL,
valid_channels BIGINT[] NOT NULL
valid_channels BIGINT[] NOT NULL,
xp_loot_chance REAL NOT NULL
);

CREATE TABLE ranks (
Expand Down Expand Up @@ -178,3 +179,20 @@ BEGIN
ON CONFLICT (DATE) DO UPDATE SET total_message_count = rank_statistics.total_message_count + 1;
END;
$$ LANGUAGE plpgsql;

CREATE FUNCTION get_xp_loot_drop(id BIGINT)
RETURNS TABLE (xp INT) AS
$$
DECLARE
chance INT;
drop_chance REAL;
BEGIN
SELECT rank_settings.xp_loot_chance INTO drop_chance FROM rank_settings WHERE guild_id = id;
chance := floor(random() * 100) + 1;
IF ROUND(drop_chance) >= chance THEN
RETURN QUERY SELECT get_random_xp FROM get_random_xp();
ELSE
RETURN QUERY SELECT 0;
END IF;
END;
$$ LANGUAGE plpgsql;
Loading

0 comments on commit 1a859bf

Please sign in to comment.