From f69ad4da72927509b9a9573af954cc72abc109e1 Mon Sep 17 00:00:00 2001 From: sk1982 Date: Tue, 12 Mar 2024 06:52:52 -0400 Subject: [PATCH] chuni playlog actions --- src/actions/chuni/playlog.ts | 64 ++++++++++++++++++++++++++++++++++++ src/helpers/chuni/music.ts | 12 +++++++ src/helpers/chuni/rating.ts | 16 +++++++++ 3 files changed, 92 insertions(+) create mode 100644 src/actions/chuni/playlog.ts create mode 100644 src/helpers/chuni/music.ts create mode 100644 src/helpers/chuni/rating.ts diff --git a/src/actions/chuni/playlog.ts b/src/actions/chuni/playlog.ts new file mode 100644 index 0000000..fa371bf --- /dev/null +++ b/src/actions/chuni/playlog.ts @@ -0,0 +1,64 @@ +'use server'; + +import { requireUser } from '@/actions/auth'; +import { db } from '@/db'; +import { CHUNI_MUSIC_PROPERTIES } from '@/helpers/chuni/music'; +import { chuniRating } from '@/helpers/chuni/rating'; +import { sql } from 'kysely'; + +export type GetPlaylogOptions = { + limit: number +} & ({} | + { musicId: number } | + { musicId: number, chartId: number }); + +export async function getPlaylog(opts: GetPlaylogOptions) { + const user = await requireUser(); + + const playlog = await db.with('p', db => db + .selectFrom('chuni_score_playlog as playlog') + .innerJoin('chuni_static_music as music', join => join + .onRef('music.songId', '=', 'playlog.musicId') + .onRef('music.chartId', '=', 'playlog.level')) + .where(({ and, eb, selectFrom }) => and([ + eb('playlog.user', '=', user.id), + eb('music.version', '=', selectFrom('chuni_static_music') + .select(({ fn }) => fn.max('version').as('latest'))), + ])) + .select( + ({ ref }) => ['playlog.id', 'playlog.sortNumber', 'playlog.playDate', 'playlog.userPlayDate', 'playlog.track', + 'playlog.score', 'playlog.rank', 'playlog.maxCombo', 'playlog.maxChain', 'playlog.rateTap', + 'playlog.rateHold', 'playlog.rateSlide', 'playlog.rateAir', 'playlog.rateFlick', 'playlog.judgeGuilty', + 'playlog.judgeAttack', 'playlog.judgeCritical', 'playlog.judgeHeaven', 'playlog.playerRating', + 'playlog.isNewRecord', 'playlog.isFullCombo', 'playlog.fullChainKind', 'playlog.isAllJustice', + 'playlog.playKind', 'playlog.isClear', 'playlog.placeName', + ...CHUNI_MUSIC_PROPERTIES, + chuniRating(ref('playlog.score')), + sql`(playlog.playerRating - (LEAD(playlog.playerRating) OVER (ORDER BY id DESC)))` + .as('playerRatingChange') + ]) + .orderBy('playlog.id desc') + ) + .selectFrom('p') + .where(({ and, eb }) => and([ + ...('musicId' in opts ? [eb('p.songId', '=', opts.musicId)] : []), + ...('chartId' in opts ? [eb('p.chartId', '=', opts.chartId)] : []), + ])) + .selectAll() + .limit(+opts.limit) + .execute(); + + let remaining = 0; + if (playlog.length) + remaining = Number((await db.selectFrom('chuni_score_playlog as playlog') + .where(({ and, eb }) => and([ + eb('playlog.user', '=', user.id), + eb('playlog.id', '<', playlog.at(-1)!.id), + ...('musicId' in opts ? [eb('playlog.musicId', '=', opts.musicId)] : []), + ...('chartId' in opts ? [eb('playlog.level', '=', opts.chartId)] : []), + ])) + .select(({ fn }) => fn.countAll().as('remaining')) + .executeTakeFirstOrThrow()).remaining); + + return { data: playlog, remaining }; +} diff --git a/src/helpers/chuni/music.ts b/src/helpers/chuni/music.ts new file mode 100644 index 0000000..ce2ab0c --- /dev/null +++ b/src/helpers/chuni/music.ts @@ -0,0 +1,12 @@ +import { sql } from 'kysely'; + +export const CHUNI_MUSIC_PROPERTIES = ['music.songId', + 'music.chartId', + 'music.title', + 'music.artist', + 'music.jacketPath', + 'music.worldsEndTag', + 'music.genre', + 'music.level' + // sql`CAST(music.level AS DECIMAL(3, 1))`.as('level') +] as const; diff --git a/src/helpers/chuni/rating.ts b/src/helpers/chuni/rating.ts new file mode 100644 index 0000000..0b7712a --- /dev/null +++ b/src/helpers/chuni/rating.ts @@ -0,0 +1,16 @@ +import { sql } from 'kysely'; + +export const chuniRating = (score: any = sql.raw(`CAST(score.scoreMax AS INT)`), + level: any = sql.raw(`(CAST(music.level AS DECIMAL(3, 1)) * 100)`)) => sql` +CAST(GREATEST((CASE + WHEN ${score} IS NULL THEN NULL + WHEN ${score} >= 1009000 THEN ${level} + 215 + WHEN ${score} >= 1007500 THEN ${level} + 200 + (${score} - 1007500) / 100 + WHEN ${score} >= 1005000 THEN ${level} + 150 + (${score} - 1005000) / 50 + WHEN ${score} >= 1000000 THEN ${level} + 100 + (${score} - 1000000) / 100 + WHEN ${score} >= 975000 THEN ${level} + (${score} - 975000) / 250 + WHEN ${score} >= 900000 THEN ${level} - 500 + (${score} - 900000) / 150 + WHEN ${score} >= 800000 THEN (${level} - 500) / 2 + (${score} - 800000) * ((${level} - 500) / 2) / 100000 + WHEN ${score} >= 500000 THEN ((${level} - 500) / 2 * (${score} - 500000)) / 300000 + ELSE 0 END) / 100, 0) AS DECIMAL(10, 8)) +`.as('rating');