[O] Redesign wacca score model

This commit is contained in:
Azalea 2024-03-28 11:08:09 -04:00
parent d6fc60e02b
commit 2fa5d09fc9
12 changed files with 215 additions and 91 deletions

View File

@ -117,6 +117,9 @@ catch (e: Exception) { null } }
val Calendar.year get() = get(Calendar.YEAR) val Calendar.year get() = get(Calendar.YEAR)
val Calendar.month get() = get(Calendar.MONTH) + 1 val Calendar.month get() = get(Calendar.MONTH) + 1
val Calendar.day get() = get(Calendar.DAY_OF_MONTH) val Calendar.day get() = get(Calendar.DAY_OF_MONTH)
fun cal() = Calendar.getInstance()
fun Date.cal() = Calendar.getInstance().apply { time = this@cal }
operator fun Calendar.invoke(field: Int) = get(field)
val Date.sec get() = time / 1000 val Date.sec get() = time / 1000
// Encodings // Encodings
@ -128,6 +131,8 @@ fun Any.long() = when (this) {
is String -> toLong() is String -> toLong()
else -> 400 - "Invalid number: $this" else -> 400 - "Invalid number: $this"
} }
fun Any.int() = long().toInt()
operator fun Bool.unaryPlus() = if (this) 1 else 0
// Collections // Collections
fun <T> ls(vararg args: T) = args.toList() fun <T> ls(vararg args: T) = args.toList()
@ -164,3 +169,13 @@ operator fun Path.div(part: Str) = resolve(part)
fun Str.ensureEndingSlash() = if (endsWith('/')) this else "$this/" fun Str.ensureEndingSlash() = if (endsWith('/')) this else "$this/"
fun <T: Any> T.logger() = LoggerFactory.getLogger(this::class.java) fun <T: Any> T.logger() = LoggerFactory.getLogger(this::class.java)
// I hate this ;-;
operator fun <E> List<E>.component6(): E = get(5)
operator fun <E> List<E>.component7(): E = get(6)
operator fun <E> List<E>.component8(): E = get(7)
operator fun <E> List<E>.component9(): E = get(8)
operator fun <E> List<E>.component10(): E = get(9)
operator fun <E> List<E>.component11(): E = get(10)
operator fun <E> List<E>.component12(): E = get(11)
operator fun <E> List<E>.component13(): E = get(12)

View File

@ -33,6 +33,7 @@ val JACKSON = jacksonObjectMapper().apply {
setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE); setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
} }
inline fun <reified T> ObjectMapper.parse(str: Str) = readValue(str, T::class.java) inline fun <reified T> ObjectMapper.parse(str: Str) = readValue(str, T::class.java)
inline fun <reified T> ObjectMapper.parse(map: Map<*, *>) = convertValue(map, T::class.java)
// TODO: https://stackoverflow.com/q/78197784/7346633 // TODO: https://stackoverflow.com/q/78197784/7346633
inline fun <reified T> Str.parseJackson() = if (contains("null")) { inline fun <reified T> Str.parseJackson() = if (contains("null")) {
val map = JACKSON.parse<MutableMap<String, Any>>(this) val map = JACKSON.parse<MutableMap<String, Any>>(this)

View File

@ -0,0 +1,10 @@
package icu.samnyan.aqua.sega.general
import jakarta.persistence.AttributeConverter
import jakarta.persistence.Converter
@Converter
class IntegerListConverter : AttributeConverter<List<Int>, String> {
override fun convertToDatabaseColumn(lst: List<Int>?) = lst?.joinToString(";") ?: ""
override fun convertToEntityAttribute(str: String?) = str?.split(';')?.map { it.toInt() }?.toMutableList() ?: mutableListOf()
}

View File

@ -7,7 +7,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize
import icu.samnyan.aqua.net.games.BaseEntity import icu.samnyan.aqua.net.games.BaseEntity
import icu.samnyan.aqua.net.games.IGenericUserData import icu.samnyan.aqua.net.games.IGenericUserData
import icu.samnyan.aqua.sega.general.model.Card import icu.samnyan.aqua.sega.general.model.Card
import icu.samnyan.aqua.sega.maimai2.util.IntegerListConverter import icu.samnyan.aqua.sega.general.IntegerListConverter
import icu.samnyan.aqua.sega.util.jackson.AccessCodeSerializer import icu.samnyan.aqua.sega.util.jackson.AccessCodeSerializer
import jakarta.persistence.* import jakarta.persistence.*

View File

@ -8,7 +8,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonPropertyOrder import com.fasterxml.jackson.annotation.JsonPropertyOrder
import icu.samnyan.aqua.net.games.BaseEntity import icu.samnyan.aqua.net.games.BaseEntity
import icu.samnyan.aqua.net.games.IGenericGamePlaylog import icu.samnyan.aqua.net.games.IGenericGamePlaylog
import icu.samnyan.aqua.sega.maimai2.util.IntegerListConverter import icu.samnyan.aqua.sega.general.IntegerListConverter
import jakarta.persistence.* import jakarta.persistence.*
import lombok.AllArgsConstructor import lombok.AllArgsConstructor
import lombok.Data import lombok.Data

View File

@ -1,47 +0,0 @@
package icu.samnyan.aqua.sega.maimai2.util;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import static java.util.Collections.*;
import java.util.ArrayList;
@Converter
public class IntegerListConverter implements AttributeConverter<List<Integer>, String> {
private static final String SPLIT_CHAR = ";";
@Override
public String convertToDatabaseColumn(List<Integer> integerList) {
if (integerList != null && !integerList.isEmpty()) {
StringBuilder str = new StringBuilder();
Iterator<Integer> iter = integerList.iterator();
while(iter.hasNext()) {
str.append(iter.next());
if(iter.hasNext()){
str.append(SPLIT_CHAR);
}
}
return str.toString();
} else {
return "";
}
}
@Override
public List<Integer> convertToEntityAttribute(String string) {
if (string != null && !string.isEmpty()) {
List<Integer> iList = new ArrayList<>();
for (String s : string.split(SPLIT_CHAR)) {
iList.add(Integer.parseInt(s));
}
return iList;
} else {
return emptyList();
}
}
}

View File

@ -93,3 +93,22 @@ enum class WaccaOptionType(val id: Int, val default: Int) {
SET_NAV_ID(1004, 210001), // ID SET_NAV_ID(1004, 210001), // ID
SET_PLATE_ID(1005, 211001), // ID SET_PLATE_ID(1005, 211001), // ID
} }
val waccaRatingMult = linkedMapOf(
990_000 to 4.0,
980_000 to 3.75,
970_000 to 3.5,
960_000 to 3.25,
950_000 to 3.0,
940_000 to 2.75,
930_000 to 2.5,
920_000 to 2.25,
910_000 to 2.0,
900_000 to 1.0,
0 to 0.0
)
fun waccaRating(score: Int, level: Double): Int {
val mult = waccaRatingMult.entries.firstOrNull { score >= it.key }?.value ?: 0.0
return (level * mult * 10).toInt()
}

View File

@ -18,12 +18,18 @@ interface IWaccaUserLinked<T> : JpaRepository<T, Long> {
} }
interface WcUserOptionRepo : IWaccaUserLinked<WcUserOption> interface WcUserOptionRepo : IWaccaUserLinked<WcUserOption>
interface WcUserBingoRepo : IWaccaUserLinked<WcUserBingo> interface WcUserBingoRepo : IWaccaUserLinked<WcUserBingo> {
fun findByUserAndPageNumber(user: WaccaUser, pageNumber: Int): WcUserBingo?
}
interface WcUserFriendRepo : IWaccaUserLinked<WcUserFriend> interface WcUserFriendRepo : IWaccaUserLinked<WcUserFriend>
interface WcUserFavoriteSongRepo : IWaccaUserLinked<WcUserFavoriteSong> interface WcUserFavoriteSongRepo : IWaccaUserLinked<WcUserFavoriteSong>
interface WcUserGateRepo : IWaccaUserLinked<WcUserGate> interface WcUserGateRepo : IWaccaUserLinked<WcUserGate> {
fun findByUserAndGateId(user: WaccaUser, gateId: Int): WcUserGate?
}
interface WcUserItemRepo : IWaccaUserLinked<WcUserItem> interface WcUserItemRepo : IWaccaUserLinked<WcUserItem>
interface WcUserBestScoreRepo : IWaccaUserLinked<WcUserScore> interface WcUserBestScoreRepo : IWaccaUserLinked<WcUserScore> {
fun findByUserAndSongIdAndDifficulty(user: WaccaUser, songId: Int, difficulty: Int): WcUserScore?
}
interface WcUserPlayLogRepo : IWaccaUserLinked<WcUserPlayLog> interface WcUserPlayLogRepo : IWaccaUserLinked<WcUserPlayLog>
interface WcUserStageUpRepo : IWaccaUserLinked<WcUserStageUp> interface WcUserStageUpRepo : IWaccaUserLinked<WcUserStageUp>

View File

@ -55,6 +55,8 @@ class WaccaUser : BaseEntity() {
var lastFolderId = 0 var lastFolderId = 0
var lastSongOrder = 0 var lastSongOrder = 0
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
var lastConsecDate: Date = Date(0)
@Temporal(TemporalType.TIMESTAMP)
var lastLoginDate: Date = Date() var lastLoginDate: Date = Date()
var gateTutorialFlags: String = "[[1, 0], [2, 0], [3, 0], [4, 0], [5, 0]]" var gateTutorialFlags: String = "[[1, 0], [2, 0], [3, 0], [4, 0], [5, 0]]"

View File

@ -1,9 +1,9 @@
package icu.samnyan.aqua.sega.wacca.model.db package icu.samnyan.aqua.sega.wacca.model.db
import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.annotation.JsonIgnore
import ext.ls import ext.*
import ext.sec
import icu.samnyan.aqua.net.games.BaseEntity import icu.samnyan.aqua.net.games.BaseEntity
import icu.samnyan.aqua.sega.general.IntegerListConverter
import icu.samnyan.aqua.sega.wacca.WaccaItemType import icu.samnyan.aqua.sega.wacca.WaccaItemType
import icu.samnyan.aqua.sega.wacca.WaccaItemType.* import icu.samnyan.aqua.sega.wacca.WaccaItemType.*
import jakarta.persistence.* import jakarta.persistence.*
@ -60,7 +60,7 @@ class WcUserGate : WaccaUserEntity() {
var progress = 0 var progress = 0
var loops = 0 var loops = 0
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
var lastUsed = 0 var lastUsed = Date(0)
var missionFlag = 0 var missionFlag = 0
var totalPoints = 0 var totalPoints = 0
@ -98,53 +98,50 @@ class WcUserItem(
@Entity @Table(name = "wacca_user_score", uniqueConstraints = [UC("", ["user_id", "song_id", "chart_id"])]) @Entity @Table(name = "wacca_user_score", uniqueConstraints = [UC("", ["user_id", "song_id", "chart_id"])])
class WcUserScore : WaccaUserEntity() { class WcUserScore : WaccaUserEntity() {
var songId = 0 var songId = 0
var chartId = 0 var difficulty = 0 // aka difficulty
var score = 0 var score = 0
var playCt = 0
var clearCt = 0 @Convert(converter = IntegerListConverter::class)
var misslessCt = 0 var clears: MutableList<Int> = mutableListOf(0, 0, 0, 0, 0) // Played, Clear, Full Combo, Missless, All Marv
var fullcomboCt = 0
var allmarvCt = 0 @Convert(converter = IntegerListConverter::class)
var gradeDCt = 0 var grades: MutableList<Int> = (1..13).map { 0 }.toMutableList() // From D to SSS+
var gradeCCt = 0
var gradeBCt = 0
var gradeACt = 0
var gradeAACt = 0
var gradeAAACt = 0
var gradeSCt = 0
var gradeSSCt = 0
var gradeSSSCt = 0
var gradeMasterCt = 0
var gradeSpCt = 0
var gradeSspCt = 0
var gradeSsspCt = 0
var bestCombo = 0 var bestCombo = 0
var lowestMissCt = 0 var lowestMissCt = Int.MAX_VALUE
var rating = 0 var rating = 0
fun ls() = ls(songId, chartId, fun ls() = ls(songId, difficulty, clears, clears, grades, score, lowestMissCt, 0, 1, rating)
ls(playCt, clearCt, misslessCt, fullcomboCt, allmarvCt),
ls(playCt, clearCt, misslessCt, fullcomboCt, allmarvCt),
ls(gradeDCt, gradeCCt, gradeBCt, gradeACt, gradeAACt, gradeAAACt, gradeSCt, gradeSSCt, gradeSSSCt, gradeMasterCt),
score, bestCombo, lowestMissCt, 1, rating)
} }
@Entity @Table(name = "wacca_user_playlog", uniqueConstraints = [UC("", ["user_id", "song_id", "chart_id", "date_scored"])]) @Entity @Table(name = "wacca_user_playlog", uniqueConstraints = [UC("", ["user_id", "song_id", "chart_id", "date_scored"])])
class WcUserPlayLog : WaccaUserEntity() { class WcUserPlayLog : WaccaUserEntity() {
var songId = 0 var songId = 0
var chartId = 0 var difficulty = 0
var level = 0.0
var score = 0 var score = 0
var clear = 0 @Convert(converter = IntegerListConverter::class)
var grade = 0 var judgements: MutableList<Int> = mutableListOf(0, 0, 0, 0) // Marv, Great, Good, Miss
var maxCombo = 0 var maxCombo = 0
var marvCt = 0 var grade = 0
var greatCt = 0 var clear = false
var goodCt = 0 var missless = false
var missCt = 0 var fullCombo = false
var allMarv = false
var giveUp = false
var skillPt = 0
var fastCt = 0 var fastCt = 0
var lateCt = 0 var lateCt = 0
var season = 0 var newRecord = false
var dateScored = ""
@Temporal(TemporalType.TIMESTAMP)
var dateScored = Date()
fun clears() = ls(1, +clear, +fullCombo, +missless, +allMarv)
companion object {
val keys = ls("songId", "difficulty", "level", "score", "judgements", "maxCombo", "grade", "clear", "missless", "fullCombo", "allMarv", "giveUp", "skillPt", "fastCt", "lateCt", "newRecord")
fun parse(l: List<*>) = JACKSON.parse<WcUserPlayLog>(keys.zip(l).toMap())
}
} }
@Entity @Table(name = "wacca_user_stageup", uniqueConstraints = [UC("", ["user_id", "stage_id"])]) @Entity @Table(name = "wacca_user_stageup", uniqueConstraints = [UC("", ["user_id", "stage_id"])])

View File

@ -32,4 +32,5 @@ ALTER TABLE wacca_user
DROP COLUMN last_login_date, DROP COLUMN last_login_date,
DROP COLUMN vip_expire_time, DROP COLUMN vip_expire_time,
ADD last_login_date datetime NOT NULL, ADD last_login_date datetime NOT NULL,
ADD vip_expire_time datetime NOT NULL; ADD vip_expire_time datetime NOT NULL,
ADD last_consec_date datetime NOT NULL;

View File

@ -0,0 +1,120 @@
ALTER TABLE wacca_user_playlog
ADD all_marv BIT(1) NOT NULL;
ALTER TABLE wacca_user_playlog
ADD full_combo BIT(1) NOT NULL;
ALTER TABLE wacca_user_playlog
ADD give_up BIT(1) NOT NULL;
ALTER TABLE wacca_user_playlog
ADD judgements VARCHAR(255) NOT NULL;
ALTER TABLE wacca_user_playlog
ADD level DOUBLE NOT NULL;
ALTER TABLE wacca_user_playlog
ADD missless BIT(1) NOT NULL;
ALTER TABLE wacca_user_playlog
ADD new_record BIT(1) NOT NULL;
ALTER TABLE wacca_user_playlog
ADD skill_pt INT NOT NULL;
ALTER TABLE wacca_user_playlog
MODIFY all_marv BIT(1) NOT NULL;
ALTER TABLE wacca_user_score
ADD clears VARCHAR(255) NOT NULL;
ALTER TABLE wacca_user_score
ADD grades VARCHAR(255) NOT NULL;
ALTER TABLE wacca_user_score
DROP COLUMN allmarv_ct;
ALTER TABLE wacca_user_score RENAME COLUMN chart_id TO difficulty;
ALTER TABLE wacca_user_score
DROP COLUMN clear_ct;
ALTER TABLE wacca_user_score
DROP COLUMN fullcombo_ct;
ALTER TABLE wacca_user_score
DROP COLUMN grade_master_ct;
ALTER TABLE wacca_user_score
DROP COLUMN grade_sp_ct;
ALTER TABLE wacca_user_score
DROP COLUMN grade_ssp_ct;
ALTER TABLE wacca_user_score
DROP COLUMN grade_sssp_ct;
ALTER TABLE wacca_user_score
DROP COLUMN gradeaaact;
ALTER TABLE wacca_user_score
DROP COLUMN gradeaact;
ALTER TABLE wacca_user_score
DROP COLUMN gradeact;
ALTER TABLE wacca_user_score
DROP COLUMN gradebct;
ALTER TABLE wacca_user_score
DROP COLUMN gradecct;
ALTER TABLE wacca_user_score
DROP COLUMN gradedct;
ALTER TABLE wacca_user_score
DROP COLUMN gradesct;
ALTER TABLE wacca_user_score
DROP COLUMN gradessct;
ALTER TABLE wacca_user_score
DROP COLUMN gradesssct;
ALTER TABLE wacca_user_score
DROP COLUMN missless_ct;
ALTER TABLE wacca_user_score
DROP COLUMN play_ct;
ALTER TABLE wacca_user_playlog RENAME COLUMN chart_id TO difficulty;
ALTER TABLE wacca_user_playlog
DROP COLUMN good_ct;
ALTER TABLE wacca_user_playlog
DROP COLUMN great_ct;
ALTER TABLE wacca_user_playlog
DROP COLUMN marv_ct;
ALTER TABLE wacca_user_playlog
DROP COLUMN miss_ct;
ALTER TABLE wacca_user_playlog
DROP COLUMN season;
ALTER TABLE wacca_user_playlog
DROP COLUMN clear;
ALTER TABLE wacca_user_playlog
DROP COLUMN date_scored;
ALTER TABLE wacca_user_item
MODIFY acquired_date datetime NOT NULL;
ALTER TABLE wacca_user_playlog
ADD clear BIT(1) NOT NULL;
ALTER TABLE wacca_user_playlog
ADD date_scored datetime NOT NULL;