-
-
Notifications
You must be signed in to change notification settings - Fork 171
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make Loritta's reaction collecting events in a generic way to make it…
… easier to create and add new Loritta events without always copying and pasting the old code
- Loading branch information
1 parent
48c1c76
commit a7a4cef
Showing
37 changed files
with
1,503 additions
and
600 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
563 changes: 0 additions & 563 deletions
563
...otlin/net/perfectdreams/loritta/morenitta/interactions/vanilla/easter2023/EventCommand.kt
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
...ions/vanilla/economy/transactiontransformers/ReactionEventSonhosTransactionTransformer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package net.perfectdreams.loritta.morenitta.interactions.vanilla.economy.transactiontransformers | ||
|
||
import net.perfectdreams.i18nhelper.core.I18nContext | ||
import net.perfectdreams.loritta.morenitta.LorittaBot | ||
import net.perfectdreams.loritta.morenitta.reactionevents.ReactionEventsAttributes | ||
import net.perfectdreams.loritta.morenitta.utils.CachedUserInfo | ||
import net.perfectdreams.loritta.serializable.ReactionEventSonhosTransaction | ||
import net.perfectdreams.loritta.serializable.UserId | ||
|
||
object ReactionEventSonhosTransactionTransformer : SonhosTransactionTransformer<ReactionEventSonhosTransaction> { | ||
override suspend fun transform( | ||
loritta: LorittaBot, | ||
i18nContext: I18nContext, | ||
cachedUserInfo: CachedUserInfo, | ||
cachedUserInfos: MutableMap<UserId, CachedUserInfo?>, | ||
transaction: ReactionEventSonhosTransaction | ||
): suspend StringBuilder.() -> (Unit) = { | ||
val event = ReactionEventsAttributes.attributes[transaction.eventInternalId]!! | ||
|
||
appendMoneyEarnedEmoji() | ||
append(event.createSonhosRewardTransactionMessage(i18nContext, transaction.sonhos, transaction.craftedCount)) | ||
} | ||
} |
662 changes: 662 additions & 0 deletions
662
...n/net/perfectdreams/loritta/morenitta/interactions/vanilla/reactionevents/EventCommand.kt
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
.../src/main/kotlin/net/perfectdreams/loritta/morenitta/profile/badges/Halloween2024Badge.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package net.perfectdreams.loritta.morenitta.profile.badges | ||
|
||
import net.perfectdreams.loritta.cinnamon.pudding.Pudding | ||
import net.perfectdreams.loritta.cinnamon.pudding.tables.CollectedCandies | ||
import net.perfectdreams.loritta.morenitta.dao.Profile | ||
import net.perfectdreams.loritta.morenitta.profile.Badge | ||
import net.perfectdreams.loritta.morenitta.profile.ProfileDesignManager | ||
import net.perfectdreams.loritta.morenitta.profile.ProfileUserInfoData | ||
import org.jetbrains.exposed.sql.select | ||
import java.util.* | ||
|
||
class Halloween2024Badge(val pudding: Pudding) : Badge.LorittaBadge( | ||
UUID.fromString("3b74665b-d30c-4cc6-8465-0873ec3dc3b6"), | ||
ProfileDesignManager.I18N_BADGES_PREFIX.Halloween2019.Title, | ||
ProfileDesignManager.I18N_BADGES_PREFIX.Halloween2019.Description, | ||
"halloween2019.png", | ||
100 | ||
) { | ||
override suspend fun checkIfUserDeservesBadge(user: ProfileUserInfoData, profile: Profile, mutualGuilds: Set<Long>): Boolean { | ||
return pudding.transaction { | ||
CollectedCandies.select { | ||
CollectedCandies.user eq profile.id.value | ||
}.count() >= 400L | ||
} | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
.../src/main/kotlin/net/perfectdreams/loritta/morenitta/profile/badges/ReactionEventBadge.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package net.perfectdreams.loritta.morenitta.profile.badges | ||
|
||
import net.perfectdreams.i18nhelper.core.keydata.StringI18nData | ||
import net.perfectdreams.loritta.cinnamon.pudding.Pudding | ||
import net.perfectdreams.loritta.cinnamon.pudding.tables.reactionevents.CraftedReactionEventItems | ||
import net.perfectdreams.loritta.cinnamon.pudding.tables.reactionevents.ReactionEventPlayers | ||
import net.perfectdreams.loritta.morenitta.dao.Profile | ||
import net.perfectdreams.loritta.morenitta.profile.Badge | ||
import net.perfectdreams.loritta.morenitta.profile.ProfileDesignManager | ||
import net.perfectdreams.loritta.morenitta.profile.ProfileUserInfoData | ||
import net.perfectdreams.loritta.morenitta.reactionevents.ReactionEvent | ||
import net.perfectdreams.loritta.morenitta.reactionevents.ReactionEventReward | ||
import net.perfectdreams.loritta.morenitta.reactionevents.events.Halloween2024ReactionEvent | ||
import org.jetbrains.exposed.sql.and | ||
import org.jetbrains.exposed.sql.selectAll | ||
import java.util.* | ||
|
||
sealed class ReactionEventBadge( | ||
val pudding: Pudding, | ||
id: UUID, | ||
title: StringI18nData, | ||
description: StringI18nData, | ||
badgeName: String, | ||
priority: Int, | ||
reactionEvent: ReactionEvent | ||
) : Badge.LorittaBadge( | ||
id, | ||
title, | ||
description, | ||
badgeName, | ||
priority | ||
) { | ||
class Halloween2024ReactionEventBadge(pudding: Pudding) : ReactionEventBadge( | ||
pudding, | ||
UUID.fromString("e9de17d4-8ee6-4f18-b8a0-ef9087b5ec43"), | ||
ProfileDesignManager.I18N_BADGES_PREFIX.Halloween2024.Title, | ||
ProfileDesignManager.I18N_BADGES_PREFIX.Halloween2024.Description, | ||
"halloween2019.png", | ||
100, | ||
Halloween2024ReactionEvent | ||
) | ||
|
||
private val eventInternalId = reactionEvent.internalId | ||
private val requiredPoints = reactionEvent.rewards.filterIsInstance<ReactionEventReward.BadgeReward>().first().requiredPoints | ||
|
||
override suspend fun checkIfUserDeservesBadge(user: ProfileUserInfoData, profile: Profile, mutualGuilds: Set<Long>): Boolean { | ||
return pudding.transaction { | ||
CraftedReactionEventItems.innerJoin(ReactionEventPlayers).selectAll() | ||
.where { | ||
CraftedReactionEventItems.event eq eventInternalId and (ReactionEventPlayers.userId eq user.id) | ||
} | ||
.count() >= requiredPoints | ||
} | ||
} | ||
} |
117 changes: 117 additions & 0 deletions
117
...c/main/kotlin/net/perfectdreams/loritta/morenitta/reactionevents/DropPointsStuffModule.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package net.perfectdreams.loritta.morenitta.reactionevents | ||
|
||
import com.github.benmanes.caffeine.cache.Caffeine | ||
import mu.KotlinLogging | ||
import net.dv8tion.jda.api.Permission | ||
import net.perfectdreams.i18nhelper.core.I18nContext | ||
import net.perfectdreams.loritta.cinnamon.pudding.tables.reactionevents.ReactionEventDrops | ||
import net.perfectdreams.loritta.cinnamon.pudding.tables.reactionevents.ReactionEventPlayers | ||
import net.perfectdreams.loritta.common.locale.BaseLocale | ||
import net.perfectdreams.loritta.morenitta.LorittaBot | ||
import net.perfectdreams.loritta.morenitta.dao.Profile | ||
import net.perfectdreams.loritta.morenitta.dao.ServerConfig | ||
import net.perfectdreams.loritta.morenitta.events.LorittaMessageEvent | ||
import net.perfectdreams.loritta.morenitta.modules.MessageReceivedModule | ||
import net.perfectdreams.loritta.morenitta.utils.LorittaUser | ||
import net.perfectdreams.loritta.morenitta.utils.extensions.toJDA | ||
import org.jetbrains.exposed.sql.and | ||
import org.jetbrains.exposed.sql.insert | ||
import org.jetbrains.exposed.sql.selectAll | ||
import java.time.Instant | ||
import java.util.concurrent.TimeUnit | ||
import kotlin.collections.set | ||
|
||
class DropPointsStuffModule(val m: LorittaBot) : MessageReceivedModule { | ||
companion object { | ||
private val logger = KotlinLogging.logger {} | ||
} | ||
private val dropInMessageAt = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build<Long, Long>() | ||
.asMap() | ||
private val lastDropsAt = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build<Long, Long>() | ||
.asMap() | ||
private val lastDropsByUserAt = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build<Long, Long>() | ||
.asMap() | ||
|
||
override suspend fun matches(event: LorittaMessageEvent, lorittaUser: LorittaUser, lorittaProfile: Profile?, serverConfig: ServerConfig, locale: BaseLocale, i18nContext: I18nContext): Boolean { | ||
if (lorittaProfile == null) | ||
return false | ||
|
||
val now = Instant.now() | ||
|
||
// Get the current active event | ||
val activeEvent = ReactionEventsAttributes.getActiveEvent(now) | ||
|
||
return event.guild?.selfMember?.hasPermission(Permission.MESSAGE_ADD_REACTION) == true && activeEvent != null | ||
} | ||
|
||
override suspend fun handle(event: LorittaMessageEvent, lorittaUser: LorittaUser, lorittaProfile: Profile?, serverConfig: ServerConfig, locale: BaseLocale, i18nContext: I18nContext): Boolean { | ||
if (lorittaProfile == null) | ||
return false | ||
|
||
if (event.guild == null) | ||
return false | ||
|
||
val now = Instant.now() | ||
|
||
// Get the current active event | ||
val activeEvent = ReactionEventsAttributes.getActiveEvent(now) ?: return false | ||
|
||
val date = System.currentTimeMillis() | ||
|
||
val id = event.channel.idLong | ||
|
||
val lastDrop = lastDropsAt.getOrDefault(id, 0L) | ||
val lastDropDiff = date - lastDrop | ||
|
||
if (1_000 >= lastDropDiff) | ||
return false | ||
|
||
val userDropTime = lastDropsByUserAt.getOrDefault(event.author.idLong, 0L) | ||
|
||
if (10_000 >= date - userDropTime) | ||
return false | ||
|
||
if (event.message.contentStripped.hashCode() != lorittaProfile.lastMessageSentHash && event.message.contentRaw.length >= 5) { | ||
for (reactionSet in activeEvent.reactionSets) { | ||
val randomNumber = LorittaBot.RANDOM.nextFloat() | ||
|
||
if (reactionSet.chance >= randomNumber) { | ||
val shouldAddReaction = m.newSuspendedTransaction { | ||
val spawnTheCandy = ReactionEventPlayers.selectAll() | ||
.where { | ||
ReactionEventPlayers.userId eq lorittaProfile.id.value and (ReactionEventPlayers.event eq activeEvent.internalId) | ||
}.count() != 0L | ||
|
||
if (spawnTheCandy) { | ||
lastDropsAt[id] = date | ||
lastDropsByUserAt[event.author.idLong] = date | ||
|
||
// TODO: Fix this | ||
// val type = LorittaEaster2023Event.easterEggColors.random() | ||
// val emoji = LorittaEaster2023Event.easterEggColorToEmoji(type) | ||
ReactionEventDrops.insert { | ||
it[ReactionEventDrops.event] = activeEvent.internalId | ||
it[ReactionEventDrops.reactionSetId] = reactionSet.reactionSetId | ||
it[ReactionEventDrops.guildId] = event.guild.idLong | ||
it[ReactionEventDrops.channelId] = event.channel.idLong | ||
it[ReactionEventDrops.messageId] = event.message.idLong | ||
it[ReactionEventDrops.createdAt] = Instant.now() | ||
} | ||
return@newSuspendedTransaction true | ||
} | ||
|
||
return@newSuspendedTransaction false | ||
} | ||
|
||
if (shouldAddReaction) { | ||
event.message.addReaction(m.emojiManager.get(reactionSet.reaction).toJDA()).queue { | ||
dropInMessageAt[event.message.idLong] = date | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return false | ||
} | ||
} |
91 changes: 91 additions & 0 deletions
91
...scord/src/main/kotlin/net/perfectdreams/loritta/morenitta/reactionevents/ReactionEvent.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package net.perfectdreams.loritta.morenitta.reactionevents | ||
|
||
import dev.minn.jda.ktx.messages.InlineMessage | ||
import net.dv8tion.jda.api.entities.User | ||
import net.perfectdreams.i18nhelper.core.I18nContext | ||
import net.perfectdreams.loritta.common.emojis.LorittaEmojiReference | ||
import net.perfectdreams.loritta.morenitta.LorittaBot | ||
import net.perfectdreams.loritta.morenitta.interactions.UnleashedContext | ||
import java.time.Instant | ||
import java.util.* | ||
import kotlin.math.round | ||
import kotlin.random.Random | ||
|
||
abstract class ReactionEvent { | ||
abstract val internalId: String | ||
abstract val startsAt: Instant | ||
abstract val endsAt: Instant | ||
abstract val reactionSets: List<ReactionSet> | ||
abstract val rewards: List<ReactionEventReward> | ||
|
||
abstract fun createJoinMessage(context: UnleashedContext): InlineMessage<*>.() -> (Unit) | ||
|
||
// Reaction Set ID -> Required Quantity | ||
fun getCurrentActiveCraft(user: User, alreadyCraftedQuantity: Long): Map<UUID, Int> = getCurrentActiveCraft(user.idLong, alreadyCraftedQuantity) | ||
abstract fun getCurrentActiveCraft(userId: Long, alreadyCraftedQuantity: Long): Map<UUID, Int> | ||
|
||
/** | ||
* Creates the message used in the transaction command | ||
*/ | ||
abstract fun createSonhosRewardTransactionMessage(i18nContext: I18nContext, sonhos: Long, craftedCount: Int): String | ||
|
||
/** | ||
* Creates the message used in the event inventory command to craft an item | ||
*/ | ||
abstract fun createCraftItemButtonMessage(i18nContext: I18nContext): TextAndEmoji | ||
|
||
/** | ||
* Creates the message used in the event inventory command to craft an item | ||
*/ | ||
abstract fun createHowManyCraftedItemsYouHaveMessage(i18nContext: I18nContext, craftedCount: Long, commandMention: String): String | ||
|
||
/** | ||
* Creates the message used in the event inventory command to craft an item | ||
*/ | ||
abstract fun createItemsInYourInventoryMessage(i18nContext: I18nContext): String | ||
|
||
/** | ||
* Creates the message used in the event inventory command to craft an item | ||
*/ | ||
abstract fun createYourNextCraftIngredientsAreMessage(i18nContext: I18nContext): String | ||
|
||
abstract fun createYouDontHaveEnoughItemsMessage(i18nContext: I18nContext): String | ||
abstract fun createYouCraftedAItemMessage(i18nContext: I18nContext): TextAndEmoji | ||
abstract fun createCraftedXItemsMessage(loritta: LorittaBot, i18nContext: I18nContext, quantity: Long, commandMention: String): String | ||
abstract fun createShortCraftedItemMessage(i18nContext: I18nContext, quantity: Int): String | ||
|
||
// https://www.reddit.com/r/cpp_questions/comments/101f70k/how_to_generate_x_random_integers_whose_sum_is_100/j2okst5/ | ||
fun generateNormalizedIntegers(random: Random, count: Int, expectedSum: Int): List<Int> { | ||
// Step 1: Generate random integers between 0 and 100 | ||
val randomIntegers = List(count) { random.nextInt(0, expectedSum + 1) } | ||
|
||
// Step 2: Calculate the total sum of these integers | ||
val totalSum = randomIntegers.sum() | ||
|
||
// Step 3: Normalize each integer by rounding (100 * x / S) | ||
val normalizedIntegers = randomIntegers.map { round(expectedSum.toDouble() * it / totalSum).toInt() }.toMutableList() | ||
|
||
// Step 4: Adjust to make sure the sum is exactly 100 | ||
val normalizedSum = normalizedIntegers.sum() | ||
val difference = expectedSum - normalizedSum | ||
|
||
if (difference != 0) { | ||
// Pick a random index to adjust | ||
while (true) { | ||
val randomIndex = random.nextInt(0, normalizedIntegers.size) | ||
val newValue = normalizedIntegers[randomIndex] + difference | ||
if (newValue >= 0) { | ||
normalizedIntegers[randomIndex] += difference | ||
break | ||
} | ||
} | ||
} | ||
|
||
return normalizedIntegers | ||
} | ||
|
||
data class TextAndEmoji( | ||
val text: String, | ||
val emoji: LorittaEmojiReference | ||
) | ||
} |
Oops, something went wrong.