-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ensure player inventory reflects cards + items that are removed from …
…their deck Prior to this commit; if a key is consumed in the dungeon but was somehow still in the player's inventory in the lobby, then the key will still remain in the player's lobby inventory when they reconnect. This was because Citadel did not remove items/cards from the player's inventory if they were removed from the deck. Relates to #45
- Loading branch information
Showing
4 changed files
with
267 additions
and
1 deletion.
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
200 changes: 200 additions & 0 deletions
200
src/main/kotlin/org/trackedout/citadel/commands/ConfigCommand.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,200 @@ | ||
package org.trackedout.citadel.commands | ||
|
||
import co.aikar.commands.BaseCommand | ||
import co.aikar.commands.annotation.CommandAlias | ||
import co.aikar.commands.annotation.CommandPermission | ||
import co.aikar.commands.annotation.Description | ||
import co.aikar.commands.annotation.Subcommand | ||
import com.mongodb.client.model.Filters | ||
import com.mongodb.client.model.Filters.eq | ||
import me.devnatan.inventoryframework.ViewFrame | ||
import net.kyori.adventure.text.Component | ||
import net.kyori.adventure.text.event.ClickEvent | ||
import net.kyori.adventure.text.event.HoverEvent | ||
import net.kyori.adventure.text.format.NamedTextColor | ||
import net.kyori.adventure.text.minimessage.MiniMessage | ||
import org.bukkit.command.CommandSender | ||
import org.bukkit.entity.Player | ||
import org.trackedout.citadel.Citadel | ||
import org.trackedout.citadel.async | ||
import org.trackedout.citadel.commands.ScoreManagementCommand.RunTypes | ||
import org.trackedout.citadel.config.scoreboardMap | ||
import org.trackedout.citadel.mongo.MongoDBManager | ||
import org.trackedout.citadel.mongo.MongoPlayerStats | ||
import org.trackedout.citadel.sendRedMessage | ||
import org.trackedout.client.apis.EventsApi | ||
import org.trackedout.client.apis.ScoreApi | ||
import org.trackedout.client.models.Score | ||
import org.trackedout.data.BrillianceScoreboardDescription | ||
import java.math.BigDecimal | ||
|
||
@CommandAlias("decked-out|do") | ||
class ConfigCommand( | ||
private val plugin: Citadel, | ||
private val eventsApi: EventsApi, | ||
private val scoreApi: ScoreApi, | ||
private val viewFrame: ViewFrame, | ||
) : BaseCommand() { | ||
|
||
@Subcommand("config list") | ||
@Description("List config values") | ||
fun showConfig(source: CommandSender, runType: RunTypes) { | ||
if (source is Player) { | ||
source.sendConfigList(runType, source.name) | ||
} else { | ||
source.sendRedMessage("Cannot list your configs as you are not a player. Use /do config list <playerName>") | ||
} | ||
} | ||
|
||
@Subcommand("config list") | ||
@CommandPermission("decked-out.config.view.all") | ||
@Description("List config values for target player") | ||
fun showConfigForPlayer(source: CommandSender, runType: RunTypes, targetPlayer: String) { | ||
source.sendConfigList(runType, targetPlayer) | ||
} | ||
|
||
private fun CommandSender.sendConfigList(runType: RunTypes, targetPlayer: String) { | ||
val mm = MiniMessage.miniMessage() | ||
|
||
plugin.async(this) { | ||
val scores = scoreApi.scoresGet(player = targetPlayer).results!! | ||
|
||
val applicableScores = scores.filter { isEditableScore(runType, it) } | ||
if (applicableScores.isEmpty()) { | ||
this.sendRedMessage("No applicable scores found for $targetPlayer") | ||
return@async | ||
} | ||
/* | ||
Decked Out 2 config: | ||
- Dungeon difficulty [easy] [medium] [hard] [deadly] [deepfrost] | ||
AKA: | ||
/tellraw @a ["",{"text":"Decked Out 2 config:","bold":true,"italic":true,"color":"gold"},{"text":"\n- "},{"text":"Dungeon difficulty","bold":true},{"text":" [easy]","color":"aqua"},{"text":" [","color":"light_purple"},{"text":"medium","color":"light_purple","clickEvent":{"action":"run_command","value":"do config set do2.config.dungeonDifficulty 1"}},{"text":"] [hard] [deadly] [deepfrost]","color":"light_purple"}] | ||
Next we convert this to MiniMessage: | ||
*/ | ||
|
||
this.sendMessage(mm.deserialize("<gold><bold>Decked Out 2 config for ${targetPlayer}:</bold></gold>")) | ||
applicableScores.mapNotNull { getPlayerScore(runType, it) }.sortedBy { it.key }.forEach { score -> | ||
|
||
val opts = score.config.values?.map { possibleValue -> | ||
if (possibleValue.key == score.value?.toInt()?.toString()) { | ||
return@map Component.text("[${possibleValue.value}]") | ||
.hoverEvent(HoverEvent.showText(Component.text("Current value is ${possibleValue.value}"))) | ||
.color(NamedTextColor.AQUA) | ||
} else { | ||
val command = ClickEvent.runCommand("/do config set ${score.key} ${possibleValue.key}") | ||
return@map Component.text("[${possibleValue.value}]") | ||
.clickEvent(command) | ||
.hoverEvent(HoverEvent.showText(Component.text("Click to set to ${possibleValue.value}"))) | ||
.color(NamedTextColor.LIGHT_PURPLE) | ||
} | ||
} | ||
|
||
val scoreTitleWithAnnotation = "<hover:show_text:'${score.config.description}'>${score.config.displayText ?: score.key}</hover>" | ||
var parsed = mm.deserialize("- <white>$scoreTitleWithAnnotation</white>:") | ||
opts?.forEach { | ||
parsed = parsed.append(mm.deserialize(" ")).append(it) | ||
} | ||
|
||
this.sendMessage(parsed) | ||
} | ||
} | ||
} | ||
|
||
data class PlayerScore( | ||
val key: String, | ||
val config: BrillianceScoreboardDescription, | ||
val value: BigDecimal?, | ||
) | ||
|
||
private fun isEditableScore(runType: RunTypes, score: Score): Boolean { | ||
val key = score.key | ||
if (key == null || !key.startsWith("${runType.runType}-")) { | ||
return false | ||
} | ||
|
||
return editableConfigs.contains(key) || scoreboardMap[score.scoreKeyWithoutRunPrefix(runType)]?.values?.isNotEmpty() == true | ||
} | ||
|
||
private fun getPlayerScore(runType: RunTypes, score: Score): PlayerScore? { | ||
plugin.logger.info("getPlayerScore: $score") | ||
return scoreboardMap[score.scoreKeyWithoutRunPrefix(runType)]?.let { | ||
return PlayerScore(score.key!!, it, score.value) | ||
} | ||
} | ||
|
||
private fun Score.scoreKeyWithoutRunPrefix(runType: RunTypes) = key?.removePrefix("${runType.runType}-") | ||
|
||
fun setConfig(source: CommandSender, key: String, value: Int) { | ||
val mm = MiniMessage.miniMessage() | ||
|
||
plugin.async(source) { | ||
val scores = scoreApi.scoresGet(player = source.name).results!! | ||
|
||
val score = scores.find { it.key == key } | ||
if (score == null) { | ||
source.sendRedMessage("No score found for $key") | ||
return@async | ||
} | ||
|
||
// val updatedScore = scoreApi.scoresPost( | ||
// score.id, | ||
// Score( | ||
// key = key, | ||
// value = value.toString(), | ||
// player = source.name, | ||
// ) | ||
// ) | ||
|
||
source.sendMessage(mm.deserialize("[not really] Updated score for $key to $value")) | ||
} | ||
} | ||
|
||
private val editableConfigs = listOf( | ||
"do2.inventory.shards.competitive" | ||
) | ||
|
||
fun getConfigsForPlayer(source: CommandSender, playerName: String) { | ||
val mm = MiniMessage.miniMessage() | ||
plugin.async(source) { | ||
val database = MongoDBManager.getDatabase() | ||
val playerStatsCollection = database.getCollection("playerStats", MongoPlayerStats::class.java) | ||
|
||
/* | ||
{ | ||
_id: ObjectId('674f5e20dc8b1753eb673c6b'), | ||
player: 'InaByt', | ||
key: 'do2.inventory.shards.competitive', | ||
value: 0, | ||
createdAt: ISODate('2024-12-03T19:38:08.433Z'), | ||
updatedAt: ISODate('2024-12-14T18:10:27.760Z'), | ||
__v: 0 | ||
}, | ||
*/ | ||
|
||
val scores = playerStatsCollection.find( | ||
Filters.and( | ||
eq("player", playerName), | ||
Filters.or( | ||
editableConfigs.map { | ||
eq("key", it) | ||
} | ||
) | ||
), | ||
).toList() | ||
|
||
if (scores.isEmpty()) { | ||
source.sendRedMessage("Unable to find any configs for player $playerName") | ||
return@async | ||
} | ||
|
||
val message = """ | ||
Scores for <orange>${playerName}</orange>: | ||
""".trimIndent() | ||
scores.map { "- ${it.player} = ${it.stats.total}" } | ||
|
||
source.sendMessage(mm.deserialize(message)) | ||
} | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/main/kotlin/org/trackedout/citadel/config/BrillianceData.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,19 @@ | ||
package org.trackedout.citadel.config | ||
|
||
import kotlinx.serialization.json.Json | ||
import org.trackedout.data.BrillianceScoreboardDescription | ||
|
||
val json = Json { ignoreUnknownKeys = true } | ||
typealias ScoreboardMap = Map<String, BrillianceScoreboardDescription> | ||
|
||
val scoreboardMap: ScoreboardMap by lazy { | ||
loadScoreboardMap() ?: throw IllegalStateException("Failed to load the scoreboard map") | ||
} | ||
|
||
private fun loadScoreboardMap(): ScoreboardMap? { | ||
// Load the JSON file content | ||
return object {}.javaClass.getResource("/items_json/scoreboards.json")?.readText()?.let { | ||
// Deserialize the JSON content into the ScoreboardMap type | ||
json.decodeFromString(it) | ||
} | ||
} |