diff --git a/gitadora@asphyxia/README.md b/gitadora@asphyxia/README.md index 0fb7102..3dfee5b 100644 --- a/gitadora@asphyxia/README.md +++ b/gitadora@asphyxia/README.md @@ -29,15 +29,17 @@ Known Issues Release Notes ============= +v1.3.0 +---------------- + * Added experimental 'Shared Favorite Songs' option. If disabled, players will be able to keep separate lists of favorite songs for each version of Gitadora, as well as between Guitar Freaks and Drummania. Enable this option to have a single unified list of favorite songs for both games, and across all versions. Default is false, to match original arcade behaviour. + * Added a leaderboards page to the WebUI. This page displays the rank of all players per game and version, ordered by Skill rating. + * More code cleanups to Profiles.ts + v1.2.4 ---------------- * Fixed note scroll speed defaulting to 0.5x for newly registered profiles. * Misc code cleanup. No changes expected to plugin behaviour. -v1.3.0 ----------------- - * Added experimental 'Shared Favorite Songs' option. If disabled, players will be able to keep separate lists of favorite songs for each version of Gitadora, as well as between Guitar Freaks and Drummania. Enable this option to have a single unified list of favorite songs for both games, and across all versions. Default is false, to match original arcade behaviour. - v1.2.3 ---------------- * Fixed bug preventing MDB files in XML format from loading (Thanks to DualEdge for reporting this ). diff --git a/gitadora@asphyxia/handlers/profiles.ts b/gitadora@asphyxia/handlers/profiles.ts index ca1a99c..0b5c3ec 100644 --- a/gitadora@asphyxia/handlers/profiles.ts +++ b/gitadora@asphyxia/handlers/profiles.ts @@ -16,6 +16,8 @@ import { getSecretMusicResponse, SecretMusicResponse } from "../models/Responses import { getSaveProfileResponse } from "../models/Responses/saveprofileresponse"; import { getDefaultBattleDataResponse } from "../models/Responses/battledataresponse"; import { applySharedFavoriteMusicToExtra, saveSharedFavoriteMusicFromExtra } from "./FavoriteMusic"; +import { getPlayerRecordResponse } from "../models/Responses/playerrecordresponse"; +import { getPlayerPlayInfoResponse, PlayerPlayInfoResponse } from "../models/Responses/playerplayinforesponse"; const logger = new Logger("profiles") @@ -89,65 +91,9 @@ export const getPlayer: EPR = async (info, data, send) => { await applySharedFavoriteMusicToExtra(refid, extra) const record: any = { - gf: {}, - dm: {}, + gf: getPlayerRecordResponse(gfProfile, gfRecord), + dm: getPlayerRecordResponse(dmProfile, dmRecord), }; - for (const mode of ['dm', 'gf']) { - let game = mode == 'gf' ? gfProfile : dmProfile; - let rec = mode == 'gf' ? gfRecord : dmRecord; - record[mode] = { - max_record: { - skill: K.ITEM('s32', game.max_skill), - all_skill: K.ITEM('s32', game.max_all_skill), - clear_diff: K.ITEM('s32', game.clear_diff), - full_diff: K.ITEM('s32', game.full_diff), - exce_diff: K.ITEM('s32', game.exce_diff), - clear_music_num: K.ITEM('s32', game.clear_music_num), - full_music_num: K.ITEM('s32', game.full_music_num), - exce_music_num: K.ITEM('s32', game.exce_music_num), - clear_seq_num: K.ITEM('s32', game.clear_seq_num), - classic_all_skill: K.ITEM('s32', game.classic_all_skill), - }, - diff_record: { - diff_100_nr: K.ITEM('s32', rec.diff_100_nr), - diff_150_nr: K.ITEM('s32', rec.diff_150_nr), - diff_200_nr: K.ITEM('s32', rec.diff_200_nr), - diff_250_nr: K.ITEM('s32', rec.diff_250_nr), - diff_300_nr: K.ITEM('s32', rec.diff_300_nr), - diff_350_nr: K.ITEM('s32', rec.diff_350_nr), - diff_400_nr: K.ITEM('s32', rec.diff_400_nr), - diff_450_nr: K.ITEM('s32', rec.diff_450_nr), - diff_500_nr: K.ITEM('s32', rec.diff_500_nr), - diff_550_nr: K.ITEM('s32', rec.diff_550_nr), - diff_600_nr: K.ITEM('s32', rec.diff_600_nr), - diff_650_nr: K.ITEM('s32', rec.diff_650_nr), - diff_700_nr: K.ITEM('s32', rec.diff_700_nr), - diff_750_nr: K.ITEM('s32', rec.diff_750_nr), - diff_800_nr: K.ITEM('s32', rec.diff_800_nr), - diff_850_nr: K.ITEM('s32', rec.diff_850_nr), - diff_900_nr: K.ITEM('s32', rec.diff_900_nr), - diff_950_nr: K.ITEM('s32', rec.diff_950_nr), - diff_100_clear: K.ARRAY('s32', rec.diff_100_clear), - diff_150_clear: K.ARRAY('s32', rec.diff_150_clear), - diff_200_clear: K.ARRAY('s32', rec.diff_200_clear), - diff_250_clear: K.ARRAY('s32', rec.diff_250_clear), - diff_300_clear: K.ARRAY('s32', rec.diff_300_clear), - diff_350_clear: K.ARRAY('s32', rec.diff_350_clear), - diff_400_clear: K.ARRAY('s32', rec.diff_400_clear), - diff_450_clear: K.ARRAY('s32', rec.diff_450_clear), - diff_500_clear: K.ARRAY('s32', rec.diff_500_clear), - diff_550_clear: K.ARRAY('s32', rec.diff_550_clear), - diff_600_clear: K.ARRAY('s32', rec.diff_600_clear), - diff_650_clear: K.ARRAY('s32', rec.diff_650_clear), - diff_700_clear: K.ARRAY('s32', rec.diff_700_clear), - diff_750_clear: K.ARRAY('s32', rec.diff_750_clear), - diff_800_clear: K.ARRAY('s32', rec.diff_800_clear), - diff_850_clear: K.ARRAY('s32', rec.diff_850_clear), - diff_900_clear: K.ARRAY('s32', rec.diff_900_clear), - diff_950_clear: K.ARRAY('s32', rec.diff_950_clear), - }, - }; - } // Format scores const musicdata = []; @@ -229,6 +175,7 @@ export const getPlayer: EPR = async (info, data, send) => { } const sticker: PlayerStickerResponse[] = getPlayerStickerResponse(name.card); + const playinfo: PlayerPlayInfoResponse = getPlayerPlayInfoResponse(profile); const playerData: any = { playerboard: { @@ -247,39 +194,7 @@ export const getPlayer: EPR = async (info, data, send) => { playstyle: K.ARRAY('s32', extra.playstyle), custom: K.ARRAY('s32', extra.custom), }, - playinfo: { - cabid: K.ITEM('s32', 0), - play: K.ITEM('s32', profile.play), - playtime: K.ITEM('s32', profile.playtime), - playterm: K.ITEM('s32', profile.playterm), - session_cnt: K.ITEM('s32', profile.session_cnt), - matching_num: K.ITEM('s32', 0), - extra_stage: K.ITEM('s32', profile.extra_stage), - extra_play: K.ITEM('s32', profile.extra_play), - extra_clear: K.ITEM('s32', profile.extra_clear), - encore_play: K.ITEM('s32', profile.encore_play), - encore_clear: K.ITEM('s32', profile.encore_clear), - pencore_play: K.ITEM('s32', profile.pencore_play), - pencore_clear: K.ITEM('s32', profile.pencore_clear), - max_clear_diff: K.ITEM('s32', profile.max_clear_diff), - max_full_diff: K.ITEM('s32', profile.max_full_diff), - max_exce_diff: K.ITEM('s32', profile.max_exce_diff), - clear_num: K.ITEM('s32', profile.clear_num), - full_num: K.ITEM('s32', profile.full_num), - exce_num: K.ITEM('s32', profile.exce_num), - no_num: K.ITEM('s32', profile.no_num), - e_num: K.ITEM('s32', profile.e_num), - d_num: K.ITEM('s32', profile.d_num), - c_num: K.ITEM('s32', profile.c_num), - b_num: K.ITEM('s32', profile.b_num), - a_num: K.ITEM('s32', profile.a_num), - s_num: K.ITEM('s32', profile.s_num), - ss_num: K.ITEM('s32', profile.ss_num), - last_category: K.ITEM('s32', profile.last_category), - last_musicid: K.ITEM('s32', profile.last_musicid), - last_seq: K.ITEM('s32', profile.last_seq), - disp_level: K.ITEM('s32', profile.disp_level), - }, + playinfo: playinfo, tutorial: { progress: K.ITEM('s32', profile.progress), disp_state: K.ITEM('u32', profile.disp_state), diff --git a/gitadora@asphyxia/models/Responses/playerplayinforesponse.ts b/gitadora@asphyxia/models/Responses/playerplayinforesponse.ts new file mode 100644 index 0000000..6d95d64 --- /dev/null +++ b/gitadora@asphyxia/models/Responses/playerplayinforesponse.ts @@ -0,0 +1,71 @@ +import { Profile } from "../profile"; + +export interface PlayerPlayInfoResponse { + cabid: KITEM<'s32'>, + play: KITEM<'s32'>, + playtime: KITEM<'s32'>, + playterm: KITEM<'s32'>, + session_cnt: KITEM<'s32'>, + matching_num: KITEM<'s32'>, + extra_stage: KITEM<'s32'>, + extra_play: KITEM<'s32'>, + extra_clear: KITEM<'s32'>, + encore_play: KITEM<'s32'>, + encore_clear: KITEM<'s32'>, + pencore_play: KITEM<'s32'>, + pencore_clear: KITEM<'s32'>, + max_clear_diff: KITEM<'s32'>, + max_full_diff: KITEM<'s32'>, + max_exce_diff: KITEM<'s32'>, + clear_num: KITEM<'s32'>, + full_num: KITEM<'s32'>, + exce_num: KITEM<'s32'>, + no_num: KITEM<'s32'>, + e_num: KITEM<'s32'>, + d_num: KITEM<'s32'>, + c_num: KITEM<'s32'>, + b_num: KITEM<'s32'>, + a_num: KITEM<'s32'>, + s_num: KITEM<'s32'>, + ss_num: KITEM<'s32'>, + last_category: KITEM<'s32'>, + last_musicid: KITEM<'s32'>, + last_seq: KITEM<'s32'>, + disp_level: KITEM<'s32'>, +} +export function getPlayerPlayInfoResponse(profile : Profile) : PlayerPlayInfoResponse { + return { + cabid: K.ITEM('s32', 0), + play: K.ITEM('s32', profile.play), + playtime: K.ITEM('s32', profile.playtime), + playterm: K.ITEM('s32', profile.playterm), + session_cnt: K.ITEM('s32', profile.session_cnt), + matching_num: K.ITEM('s32', 0), + extra_stage: K.ITEM('s32', profile.extra_stage), + extra_play: K.ITEM('s32', profile.extra_play), + extra_clear: K.ITEM('s32', profile.extra_clear), + encore_play: K.ITEM('s32', profile.encore_play), + encore_clear: K.ITEM('s32', profile.encore_clear), + pencore_play: K.ITEM('s32', profile.pencore_play), + pencore_clear: K.ITEM('s32', profile.pencore_clear), + max_clear_diff: K.ITEM('s32', profile.max_clear_diff), + max_full_diff: K.ITEM('s32', profile.max_full_diff), + max_exce_diff: K.ITEM('s32', profile.max_exce_diff), + clear_num: K.ITEM('s32', profile.clear_num), + full_num: K.ITEM('s32', profile.full_num), + exce_num: K.ITEM('s32', profile.exce_num), + no_num: K.ITEM('s32', profile.no_num), + e_num: K.ITEM('s32', profile.e_num), + d_num: K.ITEM('s32', profile.d_num), + c_num: K.ITEM('s32', profile.c_num), + b_num: K.ITEM('s32', profile.b_num), + a_num: K.ITEM('s32', profile.a_num), + s_num: K.ITEM('s32', profile.s_num), + ss_num: K.ITEM('s32', profile.ss_num), + last_category: K.ITEM('s32', profile.last_category), + last_musicid: K.ITEM('s32', profile.last_musicid), + last_seq: K.ITEM('s32', profile.last_seq), + disp_level: K.ITEM('s32', profile.disp_level), + } +} + diff --git a/gitadora@asphyxia/models/Responses/playerrecordresponse.ts b/gitadora@asphyxia/models/Responses/playerrecordresponse.ts new file mode 100644 index 0000000..f12699c --- /dev/null +++ b/gitadora@asphyxia/models/Responses/playerrecordresponse.ts @@ -0,0 +1,110 @@ +import { Profile } from "../profile" +import { Record } from "../record" + +export interface PlayerRecordResponse { + max_record: { + skill: KITEM<'s32'>, + all_skill: KITEM<'s32'>, + clear_diff: KITEM<'s32'>, + full_diff: KITEM<'s32'>, + exce_diff: KITEM<'s32'>, + clear_music_num: KITEM<'s32'>, + full_music_num: KITEM<'s32'>, + exce_music_num: KITEM<'s32'>, + clear_seq_num: KITEM<'s32'>, + classic_all_skill: KITEM<'s32'> + }, + diff_record: { + diff_100_nr: KITEM<'s32'>, + diff_150_nr: KITEM<'s32'>, + diff_200_nr: KITEM<'s32'>, + diff_250_nr: KITEM<'s32'>, + diff_300_nr: KITEM<'s32'>, + diff_350_nr: KITEM<'s32'>, + diff_400_nr: KITEM<'s32'>, + diff_450_nr: KITEM<'s32'>, + diff_500_nr: KITEM<'s32'>, + diff_550_nr: KITEM<'s32'>, + diff_600_nr: KITEM<'s32'>, + diff_650_nr: KITEM<'s32'>, + diff_700_nr: KITEM<'s32'>, + diff_750_nr: KITEM<'s32'>, + diff_800_nr: KITEM<'s32'>, + diff_850_nr: KITEM<'s32'>, + diff_900_nr: KITEM<'s32'>, + diff_950_nr: KITEM<'s32'>, + diff_100_clear: KARRAY<'s32'> + diff_150_clear: KARRAY<'s32'> + diff_200_clear: KARRAY<'s32'> + diff_250_clear: KARRAY<'s32'> + diff_300_clear: KARRAY<'s32'> + diff_350_clear: KARRAY<'s32'> + diff_400_clear: KARRAY<'s32'> + diff_450_clear: KARRAY<'s32'> + diff_500_clear: KARRAY<'s32'> + diff_550_clear: KARRAY<'s32'> + diff_600_clear: KARRAY<'s32'> + diff_650_clear: KARRAY<'s32'> + diff_700_clear: KARRAY<'s32'> + diff_750_clear: KARRAY<'s32'> + diff_800_clear: KARRAY<'s32'> + diff_850_clear: KARRAY<'s32'> + diff_900_clear: KARRAY<'s32'> + diff_950_clear: KARRAY<'s32'> + } +} + +export function getPlayerRecordResponse(profile: Profile, rec: Record) : PlayerRecordResponse { + return { + max_record: { + skill: K.ITEM('s32', profile.max_skill), + all_skill: K.ITEM('s32', profile.max_all_skill), + clear_diff: K.ITEM('s32', profile.clear_diff), + full_diff: K.ITEM('s32', profile.full_diff), + exce_diff: K.ITEM('s32', profile.exce_diff), + clear_music_num: K.ITEM('s32', profile.clear_music_num), + full_music_num: K.ITEM('s32', profile.full_music_num), + exce_music_num: K.ITEM('s32', profile.exce_music_num), + clear_seq_num: K.ITEM('s32', profile.clear_seq_num), + classic_all_skill: K.ITEM('s32', profile.classic_all_skill), + }, + diff_record: { + diff_100_nr: K.ITEM('s32', rec.diff_100_nr), + diff_150_nr: K.ITEM('s32', rec.diff_150_nr), + diff_200_nr: K.ITEM('s32', rec.diff_200_nr), + diff_250_nr: K.ITEM('s32', rec.diff_250_nr), + diff_300_nr: K.ITEM('s32', rec.diff_300_nr), + diff_350_nr: K.ITEM('s32', rec.diff_350_nr), + diff_400_nr: K.ITEM('s32', rec.diff_400_nr), + diff_450_nr: K.ITEM('s32', rec.diff_450_nr), + diff_500_nr: K.ITEM('s32', rec.diff_500_nr), + diff_550_nr: K.ITEM('s32', rec.diff_550_nr), + diff_600_nr: K.ITEM('s32', rec.diff_600_nr), + diff_650_nr: K.ITEM('s32', rec.diff_650_nr), + diff_700_nr: K.ITEM('s32', rec.diff_700_nr), + diff_750_nr: K.ITEM('s32', rec.diff_750_nr), + diff_800_nr: K.ITEM('s32', rec.diff_800_nr), + diff_850_nr: K.ITEM('s32', rec.diff_850_nr), + diff_900_nr: K.ITEM('s32', rec.diff_900_nr), + diff_950_nr: K.ITEM('s32', rec.diff_950_nr), + diff_100_clear: K.ARRAY('s32', rec.diff_100_clear), + diff_150_clear: K.ARRAY('s32', rec.diff_150_clear), + diff_200_clear: K.ARRAY('s32', rec.diff_200_clear), + diff_250_clear: K.ARRAY('s32', rec.diff_250_clear), + diff_300_clear: K.ARRAY('s32', rec.diff_300_clear), + diff_350_clear: K.ARRAY('s32', rec.diff_350_clear), + diff_400_clear: K.ARRAY('s32', rec.diff_400_clear), + diff_450_clear: K.ARRAY('s32', rec.diff_450_clear), + diff_500_clear: K.ARRAY('s32', rec.diff_500_clear), + diff_550_clear: K.ARRAY('s32', rec.diff_550_clear), + diff_600_clear: K.ARRAY('s32', rec.diff_600_clear), + diff_650_clear: K.ARRAY('s32', rec.diff_650_clear), + diff_700_clear: K.ARRAY('s32', rec.diff_700_clear), + diff_750_clear: K.ARRAY('s32', rec.diff_750_clear), + diff_800_clear: K.ARRAY('s32', rec.diff_800_clear), + diff_850_clear: K.ARRAY('s32', rec.diff_850_clear), + diff_900_clear: K.ARRAY('s32', rec.diff_900_clear), + diff_950_clear: K.ARRAY('s32', rec.diff_950_clear), + }, + }; +} diff --git a/gitadora@asphyxia/webui/leaderboards.pug b/gitadora@asphyxia/webui/leaderboards.pug new file mode 100644 index 0000000..aebd616 --- /dev/null +++ b/gitadora@asphyxia/webui/leaderboards.pug @@ -0,0 +1,85 @@ +//DATA// + infos: DB.Find(null, { collection: 'playerinfo' }) + profiles: DB.Find(null, { collection: 'profile' }) +- + +- + function getFullGameName(shortName) { + switch (shortName) { + case "dm" : + return "Drummania" + case "gf": + return "Guitar Freaks" + default: + return "Unknown" + } + } + + const versions = ["exchain", "nextage"] + const games = ["gf", "dm"] + + function generateLeaderboards(infos, profiles) { + let result = [] + + for (const version of versions) { + for (const game of games) { + result.push(generateLeaderboard(infos, profiles, version, game)) + } + } + + // Hide versions and games with no entries + result = result.filter((e) => e.entries.length > 0) + return result + } + + function generateLeaderboard(infos, profiles, version, game) { + let entries = [] + let idx = 1 + let currentProfiles = profiles.filter((e) => e.game === game && e.version === version) + currentProfiles = currentProfiles.sort((a, b) => b.skill - a.skill) + + for (const profile of currentProfiles) { + const info = infos.find(i => i.__refid === profile.__refid) + const name = info ? info.name : "Unknown" + const scoreData = { + rank: idx, + name: name, + skill: profile.skill / 100, + all_skill: profile.all_skill / 100, + clear_music_num : profile.clear_music_num, + clear_diff: profile.clear_diff / 100 + } + entries.push(scoreData) + idx++ + } + + let result = { + version: version, + game: game, + entries: entries + } + return result + } + +- + +each board in generateLeaderboards(infos, profiles) + h3 #{getFullGameName(board.game)} #{board.version} + table + tr + th Rank + th Name + th Skill + th All Skill + th Songs Cleared + th Hardest Clear + each e in board.entries + tr + td #{e.rank} + td #{e.name} + td #{e.skill} + td #{e.all_skill} + td #{e.clear_music_num} + td #{e.clear_diff} + +script(src="js/leaderboards.js") \ No newline at end of file diff --git a/gitadora@asphyxia/webui/profile_player_info.pug b/gitadora@asphyxia/webui/profile_player_info.pug index 76e5c1c..a3ac76b 100644 --- a/gitadora@asphyxia/webui/profile_player_info.pug +++ b/gitadora@asphyxia/webui/profile_player_info.pug @@ -67,7 +67,7 @@ div .control input.input(type="text" name="all_skill", value=(pr.all_skill/100) readonly) .field - label.label Stages Cleared + label.label Songs Cleared .control input.input(type="text" name="clear_num", value=pr.clear_num readonly) .field