More shit.

This commit is contained in:
yenon 2023-11-10 16:57:36 +01:00
parent 428226dcd4
commit 6915315192
3 changed files with 117 additions and 11 deletions

View File

@ -6,9 +6,19 @@ import io.ktor.server.cio.*
import io.ktor.server.engine.* import io.ktor.server.engine.*
import io.ktor.server.response.* import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
import java.nio.file.Files
import kotlin.io.path.Path
suspend fun main() { suspend fun main() {
val path = Path("data.json")
if (Files.isRegularFile(path)) {
RaceHolder.load(path)
}
Runtime.getRuntime().addShutdownHook(Thread {
RaceHolder.save(path)
})
val kord = Kord("MTE3MTIwODc1MDE5MTg5MDQ4Mw.GOUedL.i3zD6IG5B6fFRvaSOotWwJ5KBRK2whC9xr0vL8") val kord = Kord("MTE3MTIwODc1MDE5MTg5MDQ4Mw.GOUedL.i3zD6IG5B6fFRvaSOotWwJ5KBRK2whC9xr0vL8")
kord.on<MessageCreateEvent> { kord.on<MessageCreateEvent> {

View File

@ -1,9 +1,15 @@
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
@Serializable @Serializable
data class RaceData(var name: String, var description: String) { data class RaceData(var name: String, var description: String) {
val trackList = arrayListOf<Long>() private val trackList = arrayListOf<Long>()
val leaderboardMap = hashMapOf<Long, Velocidrone.Leaderboard>() private val leaderboardMap = hashMapOf<Long, Velocidrone.Leaderboard>()
private var totalScores = arrayListOf<Pair<String, Long>>()
fun addTrack(trackId: Long) { fun addTrack(trackId: Long) {
trackList.add(trackId) trackList.add(trackId)
@ -14,7 +20,7 @@ data class RaceData(var name: String, var description: String) {
leaderboardMap.remove(trackId) leaderboardMap.remove(trackId)
} }
suspend fun rescanLeaderboard(trackId: Long, newLeaderboardCallback: (Velocidrone.Leaderboard) -> Unit) { private suspend fun rescanLeaderboard(trackId: Long, newLeaderboardCallback: (Velocidrone.Leaderboard) -> Unit) {
if (trackList.contains(trackId)) { if (trackList.contains(trackId)) {
Velocidrone.getLeaderboardForId(trackId).getOrNull()?.let { newLeaderboard -> Velocidrone.getLeaderboardForId(trackId).getOrNull()?.let { newLeaderboard ->
if (leaderboardMap[trackId]?.equals(newLeaderboard) == false) { if (leaderboardMap[trackId]?.equals(newLeaderboard) == false) {
@ -25,17 +31,56 @@ data class RaceData(var name: String, var description: String) {
} }
} }
fun getTotalScores(): List<Pair<String, Long>> { suspend fun rescanAll() {
var changes = false
trackList.forEach {
rescanLeaderboard(it) {
changes = true
}
}
if (changes) {
calculateTotalScores()
}
}
fun calculateTotalScores() {
val scoreMap = hashMapOf<String, Long>() val scoreMap = hashMapOf<String, Long>()
leaderboardMap.forEach { leaderboardEntry -> leaderboardMap.forEach { leaderboardEntry ->
val sortedTimes = leaderboardEntry.value.tracktimes.sortedBy { it.lap_time }.forEach { leaderboardEntry.value.tracktimes.sortedBy { it.lap_time }.forEach {
scoreMap[it.playername] = scoreMap.getOrDefault(it.playername, 0L) + 1 scoreMap[it.playername] = scoreMap.getOrDefault(it.playername, 0L) + 1
} }
} }
return scoreMap.toList().sortedByDescending { it.second } synchronized(totalScores) {
totalScores.clear()
scoreMap.asIterable().sortedByDescending { it.value }.map { it.toPair() }.toCollection(totalScores)
}
} }
} }
object RaceHolder { object RaceHolder {
val races = arrayListOf<RaceData>() var races = arrayListOf<RaceData>()
fun save(path: Path) {
val tempSavePath = path.resolveSibling("save.json.tmp")
val stream = Files.newBufferedWriter(
tempSavePath,
StandardOpenOption.TRUNCATE_EXISTING,
StandardOpenOption.WRITE,
StandardOpenOption.CREATE
).buffered()
stream.write(Json.encodeToString(races))
stream.flush()
stream.close()
if (Files.isRegularFile(path)) {
Files.delete(path)
}
Files.move(tempSavePath, path)
}
fun load(path: Path) {
val stream = Files.newBufferedReader(path)
races = Json.decodeFromString(stream.readText())
stream.close()
}
} }

View File

@ -1,14 +1,32 @@
import io.ktor.server.application.* import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.* import io.ktor.server.routing.*
import io.ktor.util.pipeline.* import io.ktor.util.pipeline.*
import kotlinx.html.div import kotlinx.html.*
import kotlinx.html.h1
import kotlinx.html.p
fun Routing.racePage() { fun Routing.racePage() {
get("/races") { get("/race/list") {
raceOverviewPage(RaceHolder.races) raceOverviewPage(RaceHolder.races)
} }
get("/race/new") {
newRacePage()
}
post("/race/new") {
val parameters = call.receiveParameters()
val name = parameters["name"]
val description = parameters["description"]
if (name == null || description == null) {
newRacePage("Not all parameters given.", name ?: "", description ?: "")
return@post
}
if (RaceHolder.races.any { it.name == name }) {
newRacePage("Race with the same name already exists.", name, description)
return@post
}
RaceHolder.races.add(RaceData(name, description))
call.respondRedirect("/race/list")
}
} }
private suspend fun PipelineContext<Unit, ApplicationCall>.raceOverviewPage(races: ArrayList<RaceData>) { private suspend fun PipelineContext<Unit, ApplicationCall>.raceOverviewPage(races: ArrayList<RaceData>) {
@ -23,3 +41,36 @@ private suspend fun PipelineContext<Unit, ApplicationCall>.raceOverviewPage(race
} }
} }
} }
private suspend fun PipelineContext<Unit, ApplicationCall>.newRacePage(
error: String? = null,
name: String = "",
description: String = ""
) {
respondThemedHtml("Race Overview") {
form("/race/new", encType = FormEncType.applicationXWwwFormUrlEncoded, method = FormMethod.post) {
error?.let {
p(classes = "error") {
+it
}
}
p {
+"Name:"
textInput(name = "name") {
value = name
}
}
p {
+"Description:"
}
p {
TEXTAREA(mapOf("name" to "description", "rows" to "4", "cols" to "40"), consumer).visit {
+description
}
}
p {
submitInput()
}
}
}
}