diff --git a/jubeat@asphyxia/README.md b/jubeat@asphyxia/README.md index c40587a..72a87a4 100644 --- a/jubeat@asphyxia/README.md +++ b/jubeat@asphyxia/README.md @@ -1,6 +1,6 @@ # Jubeat -Plugin Version: **v1.0.0** +Plugin Version: **v1.4.1** ### Supported Versions @@ -8,11 +8,31 @@ Plugin Version: **v1.0.0** - knit - knit APPEND +- copious +- copious APPEND +- saucer ### Changelogs *** +#### 1.4.1 + +- saucer support +- Change profile structure + +#### 1.3.0 + +- Matching Support (Experimental) + +#### 1.2.0 + +- copious (APPEND) support + +#### 1.1.0 + +- Fix profile structure + #### 1.0.0 - Initial Release diff --git a/jubeat@asphyxia/handlers/common.ts b/jubeat@asphyxia/handlers/common.ts index e5484a6..bd791cb 100644 --- a/jubeat@asphyxia/handlers/common.ts +++ b/jubeat@asphyxia/handlers/common.ts @@ -1,23 +1,27 @@ -import {getVersion} from "../utils"; +import {getVersion, VersionRange} from '../utils'; -export const shopinfo: EPR = (info, data, send) => { - const locId = $(data.shop).content("locationid"); +export const gameInfo: EPR = (info, data, send) => { + const locId = $(data).content('shop.locationid'); const version = getVersion(info); if (version === 0) return send.deny(); - if (version === 3) return send.object({ + return send.object({ data: { - cabid: K.ITEM('u32', 1), - locationid: K.ITEM('str', locId), - is_send: K.ITEM("u8", 1) - } - }) + ...info.module === 'shopinfo' && { + cabid: K.ITEM('u32', _.random(1, 10)), + locationid: K.ITEM('str', locId), + ...VersionRange(version, 3, 6) && { is_send: K.ITEM('u8', 1) }, + }, - return send.deny(); -} + ...VersionRange(version, 5, 6) && { + white_music_list: K.ARRAY('s32', Array(32).fill(-1)) + } + } + }); +}; export const demodata = { - getNews: (_, __, send) => send.object({ data: { officialnews: K.ATTR({ count: "0" }) } }), + getNews: (_, __, send) => send.object({ data: { officialnews: K.ATTR({ count: '0' }) } }), getData: (_, data, send) => { const newsId = $(data).number('officialnews.newsid'); return send.object({ @@ -36,15 +40,9 @@ export const demodata = { hitchart: { update: K.ITEM('str', ''), - hitchart_lic: K.ATTR({ count: "0" }), - hitchart_org: K.ATTR({ count: "0" }), + hitchart_lic: K.ATTR({ count: '0' }), + hitchart_org: K.ATTR({ count: '0' }), } } }), }; - -export const netlog: EPR = (info, data, send) => { - const errMsg = $(data).str('msg'); - console.error(errMsg); - return send.success(); -} diff --git a/jubeat@asphyxia/handlers/matching.ts b/jubeat@asphyxia/handlers/matching.ts index eabe516..e200f43 100644 --- a/jubeat@asphyxia/handlers/matching.ts +++ b/jubeat@asphyxia/handlers/matching.ts @@ -1,49 +1,147 @@ -export const check: EPR = (info, data, send) => { +import {Room} from '../models/matching'; + +export const check: EPR = async (info, data, send) => { const enter = $(data).bool('data.enter'); const time = $(data).number('data.time'); + + // enter + // 0 - game is loading + // 1 - music select screen + return send.object({ data: { entrant_nr: K.ITEM('u32', 1, { time: String(time) }), - interval: K.ITEM('s16', 1), - entry_timeout: K.ITEM('s16', U.GetConfig("matching_entry_timeout")), - waitlist: K.ATTR({ count: "0" }) + interval: K.ITEM('s16', 5), + entry_timeout: K.ITEM('s16', 30), + waitlist: K.ATTR({ count: '0' }) } }); }; -export const entry: EPR = (info, data, send) => { - const localMatchingNode = $(data).element("data.local_matching"); - const connectNode = $(data).element("data.connect"); +export const entry: EPR = async (info, data, send) => { + const localMatchingNode = $(data).element('data.local_matching'); + const connectNode = $(data).element('data.connect'); const musicNode = $(data).element('data.music'); - const roomId = _.random(1, 999999999999999); + const localKey = localMatchingNode.numbers('key'); + const connectKey = connectNode.numbers('key'); - // TODO Local matching support + let matchRoom = await DB.FindOne({ + collection: 'matching_rooms', + musicId: musicNode.number('id'), + seqId: musicNode.number('seq'), + isMatchEnd: false, + isFull: false + }); + + if (!matchRoom) { + matchRoom = { + collection: 'matching_rooms', + + version: $(data).number('data.version'), + roomId: _.random(1, 999999999), + masterKey: connectKey, + masterGlobal: connectNode.str('global'), + masterPrivate: connectNode.str('private'), + localKey, + musicId: musicNode.number('id'), + seqId: musicNode.number('seq'), + members: [ + { + cabid: $(data).number('data.cabid'), + addr: connectNode.str('private') + } + ], + isFull: false, + isMatchEnd: false + }; + + await DB.Upsert({ + collection: 'matching_rooms', localKey, + musicId: musicNode.number('id'), + seqId: musicNode.number('seq'), + isMatchEnd: false, + isFull: false + }, matchRoom); + } return send.object({ data: { - roomid: K.ITEM('s64', BigInt(roomId), { master: "1" }), - refresh_intr: K.ITEM('s16', 3), + roomid: K.ITEM('s64', BigInt(matchRoom.roomId), { master: matchRoom.masterKey === connectKey ? '1' : '0' }), + ...matchRoom.masterKey === connectKey && { + refresh_intr: K.ITEM('s16', 10), + }, + ...matchRoom.masterKey !== connectKey && { + connect: { + key: K.ARRAY('u8', matchRoom.masterKey), + global: K.ITEM('str', matchRoom.masterGlobal), + private: K.ITEM('str', matchRoom.masterPrivate), + } + }, music: { - id: K.ITEM("u32", musicNode.number("id")), - seq: K.ITEM("u8", musicNode.number("seq")), + id: K.ITEM('u32', matchRoom.musicId), + seq: K.ITEM('u8', matchRoom.seqId), } } }); }; -export const refresh: EPR = (info, data, send) => { +export const refresh: EPR = async (info, data, send) => { + const roomId = Number($(data).bigint('data.roomid')); + const pcbinfos = $(data).elements('data.joined.pcbinfo'); + + const room = await DB.FindOne({ collection: 'matching_rooms', roomId }); + + if (room) { + for (const i of pcbinfos) { + const cabid = i.number('cabid'); + const addr = i.str('addr'); + + for (const i of room.members) { + if (i.addr === addr) continue; + + room.members.push({ + cabid, + addr + }); + } + } + + await DB.Update({ collection: 'matching_rooms', roomId: Number(roomId) }, { + $set: { + members: room.members + } + }); + + if (room.members.length >= 4) { + await DB.Update({ collection: 'matching_rooms', roomId: Number(roomId) }, { + $set: { + isFull: true + } + }); + } + } + return send.object({ data: { - refresh_intr: K.ITEM('s16', 2), + refresh_intr: K.ITEM('s16', 5), + start: K.ITEM('bool', room.isFull) } }); }; -export const report: EPR = (info, data, send) => { +export const report: EPR = async (info, data, send) => { + const roomId = $(data).bigint('data.roomid'); + + await DB.Update({ collection: 'matching_rooms', roomId: Number(roomId) }, { + $set: { + isMatchEnd: true + } + }); + return send.object({ data: { - refresh_intr: K.ITEM('s16', 1), + refresh_intr: K.ITEM('s16', 3), } }); }; diff --git a/jubeat@asphyxia/handlers/profile.ts b/jubeat@asphyxia/handlers/profile.ts index 14508f5..bcdac0e 100644 --- a/jubeat@asphyxia/handlers/profile.ts +++ b/jubeat@asphyxia/handlers/profile.ts @@ -1,6 +1,6 @@ -import {getVersion} from "../utils"; -import Profile from '../models/profile'; -import {Score} from '../models/score'; +import {getVersion, getVersionName, VersionRange} from "../utils"; +import Profile from "../models/profile"; +import {Score} from "../models/score"; export const profile: EPR = async (info, data, send) => { let refId = $(data).str("data.player.pass.refid"); @@ -16,155 +16,239 @@ export const profile: EPR = async (info, data, send) => { if (!profile) { if (!name) return send.deny(); - const newProfile = new Profile(); - newProfile.jubeatId = _.random(1, 99999999); - newProfile.name = name; - newProfile.previous_version = version; + const newProfile: Profile = { + collection: "profile", + jubeatId: _.random(1, 99999999), + name: name, + + lastShopname: "NONE", + lastAreaname: "NONE" + }; await DB.Upsert(refId, { collection: "profile" }, newProfile); profile = newProfile; } - let migration = false; - if (profile.previous_version < version) { - migration = true; - profile.name = ""; - await DB.Update(refId, { collection: "profile" }, { $set: { name: "", previous_version: version } }); - } + return send.object({ + data: { + ...VersionRange(version, 5, 5) && require("../templates/gameInfos/saucer.ts")(profile), - if (name) { - profile.name = name; - await DB.Update(refId, { collection: "profile" }, { $set: { name } }); - } + player: { + name: K.ITEM("str", profile.name), + jid: K.ITEM("s32", profile.jubeatId), + refid: K.ITEM("str", profile.__refid), + session_id: K.ITEM("s32", 1), - if (version === 3) { - if (U.GetConfig("unlock_all_songs")) { - profile.knit.item = { - secretList: [-1, -1], - themeList: -1, - markerList: [-1, -1], - titleList: [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1] - }; - profile.knit.item_new = { - secretList: [0, 0], - themeList: 0, - markerList: [0, 0], - titleList: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - }; + ...version === 3 && require("../templates/profiles/knit.ts")(profile), + ...version === 4 && require("../templates/profiles/copious.ts")(profile), + ...version === 5 && require("../templates/profiles/saucer.ts")(profile), + } } - return send.pugFile('templates/knit/profile.pug', { refId, migration, ...profile }, { compress: false }); - } - - return send.deny(); + }); }; export const saveProfile: EPR = async (info, { data }, send) => { - console.log(U.toXML(data)); - const player = $(data).element("player"); + console.log(U.toXML({ + call: K.ATTR({ model: info.model }, { + [info.module]: K.ATTR({ method: info.method }, { data }) + }) + })); - const refId = player.str("refid"); + const refId = $(data).str("player.refid"); if (!refId) return send.deny(); const version = getVersion(info); if (version === 0) return send.deny(); const profile = await DB.FindOne(refId, { collection: "profile" }); + if (!profile) return send.deny(); - if (version === 3) { - profile.name = player.str("name"); + let lastMarker = 0; + let lastTheme = 0; + let lastTitle = 0; + let lastParts = 0; + let lastSort = 0; + let lastFilter = 0; + let lastCategory = 0; + let lastMselStat = 0; - profile.last.shopname = player.str("shopname", profile.last.shopname); - profile.last.areaname = player.str("areaname", profile.last.areaname); + const result = $(data).element("result"); - profile.jubility = player.number("info.jubility", profile.jubility); - profile.jubilityYday = player.number("info.jubility_yday", profile.jubilityYday); + if (result) { + const tunes = result.elements("tune"); + const historys = {}; + const historyNode = $(data).elements("player.history.tune"); - profile.knit.acvProg = player.number("info.acv_prog", profile.knit.acvProg); - profile.knit.acvWool = player.number("info.acv_wool", profile.knit.acvWool); - profile.knit.acvRouteProg = player.numbers("info.acv_route_prog", profile.knit.acvRouteProg); - profile.knit.acvPoint = player.number("info.acv_point", profile.knit.acvPoint); - - profile.tuneCount = player.number("info.tune_cnt", profile.tuneCount); - profile.saveCount = player.number("info.save_cnt", profile.saveCount); - profile.savedCount = player.number("info.saved_cnt", profile.savedCount); - profile.fullcomboCount = player.number("info.fc_cnt", profile.fullcomboCount); - profile.fullcomboSeqCount = player.number("info.fc_seq_cnt", profile.fullcomboSeqCount); - profile.excellentCount = player.number("info.exc_cnt", profile.excellentCount); - profile.excellentSeqCount = player.number("info.exc_seq_cnt", profile.excellentSeqCount); - profile.matchCount = player.number("info.match_cnt", profile.matchCount); - profile.beatCount = player.number('info.beat_cnt', profile.beatCount); - profile.conciergeSelectedCount = player.number('info.con_sel_cnt', profile.conciergeSelectedCount); - profile.tagCount = player.number('info.tag_cnt', profile.tagCount); - profile.mynewsCount = player.number('info.mynews_cnt', profile.mynewsCount); - - if (!U.GetConfig("unlock_all_songs")) { - profile.knit.item.secretList = player.numbers('item.secret_list', profile.knit.item.secretList); - profile.knit.item.themeList = player.number('item.theme_list', profile.knit.item.themeList); - profile.knit.item.markerList = player.numbers('item.marker_list', profile.knit.item.markerList); - profile.knit.item.titleList = player.numbers('item.title_list', profile.knit.item.titleList); - - profile.knit.item_new.secretList = player.numbers('item.secret_new', profile.knit.item_new.secretList); - profile.knit.item_new.themeList = player.number('item.theme_new', profile.knit.item_new.themeList); - profile.knit.item_new.markerList = player.numbers('item.marker_new', profile.knit.item_new.markerList); - profile.knit.item_new.titleList = player.numbers('item.title_new', profile.knit.item_new.titleList); - } - - profile.last.conciergeSuggestId = player.number('info.con_suggest_id', profile.last.conciergeSuggestId); - profile.last.playTime = BigInt(new Date().getMilliseconds()); - - // Append - const collabo = player.element("collabo"); - if (collabo) { - profile.knit.collabo.success = collabo.bool("success"); - profile.knit.collabo.completed = collabo.bool("completed"); - } - - const result = $(data).element("result"); - - if (result) { - const tunes = result.elements("tune"); - - for (const tune of tunes) { - const musicId = tune.number("music", 0); - profile.last.musicId = musicId; - profile.last.seqId = parseInt(tune.attr("player.score").seq) || 0; - profile.last.title = tune.number("title", profile.last.title); - profile.last.theme = tune.number("theme", profile.last.theme); - profile.last.marker = tune.number("marker", profile.last.marker); - profile.last.sort = tune.number("sort", profile.last.sort); - profile.last.filter = tune.number("filter", profile.last.filter); - profile.last.showRank = tune.number("combo_disp", profile.last.showRank); - profile.last.showCombo = tune.number("rank_sort", profile.last.showCombo); - profile.last.mselStat = tune.number("msel_stat", profile.last.mselStat); - - const score = tune.number('player.score'); - const seq = parseInt(tune.attr('player.score').seq); - const clear = parseInt(tune.attr('player.score').clear); - const combo = parseInt(tune.attr('player.score').combo); - const bestScore = tune.number('player.best_score'); - const bestClear = tune.number('player.best_clear'); - const playCount = tune.number('player.play_cnt'); - const clearCount = tune.number('player.clear_cnt'); - const fullcomboCount = tune.number('player.fc_cnt'); - const excellentCount = tune.number('player.exc_cnt'); - const mbar = tune.numbers('player.mbar'); - - await updateScore(refId, musicId, seq, score, clear, mbar, { - playCount, - clearCount, - fullcomboCount, - excellentCount - }); + if (historyNode) { + for (const history of historyNode) { + historys[history.attr().log_id] = { + timestamp: history.bigint("timestamp"), + isHard: history.bool("player.result.is_hard_mode") + }; } } - await DB.Update(refId, { collection: "profile" }, profile); + for (const tune of tunes) { + const tuneId = tune.attr().id; - return send.object({ data: { player: { session_id: K.ITEM('s32', 1) } } }); + profile.musicId = tune.number("music"); + profile.seqId = parseInt(tune.attr("player.score").seq); + lastMarker = tune.number("marker"); + lastTheme = tune.number("theme"); + lastTitle = tune.number("title"); + lastParts = tune.number("parts"); + lastSort = tune.number("sort"); + lastFilter = tune.number("filter"); + lastCategory = tune.number("category"); + lastMselStat = tune.number("msel_stat"); + profile.rankSort = tune.number("rank_sort"); + profile.comboDisp = tune.number("combo_disp"); + + await updateScore(refId, { + musicId: tune.number("music"), + seq: parseInt(tune.attr("player.score").seq), + score: tune.number("player.score"), + clear: parseInt(tune.attr("player.score").clear), + isHard: historys[tuneId]?.isHard || false, + bestScore: tune.number("player.best_score"), + bestClear: tune.number("player.best_clear"), + playCount: tune.number("player.play_cnt"), + clearCount: tune.number("player.clear_cnt"), + fullcomboCount: tune.number("player.fc_cnt"), + excellentCount: tune.number("player.exc_cnt"), + ...tune.element("player.mbar") && { mbar: tune.numbers("player.mbar") } + }); + } } - return send.deny(); + profile.lastPlayTime = Number($(data).bigint("player.time_gameend")); + profile.lastShopname = $(data).str("player.shopname"); + profile.lastAreaname = $(data).str("player.areaname"); + + if (version === 3) { + if (!profile.knit) profile.knit = {}; + profile.knit.jubility = $(data).number("player.info.jubility"); + profile.knit.jubilityYday = $(data).number("player.info.jubility_yday"); + profile.knit.acvProg = $(data).number("player.info.acv_prog"); + profile.knit.acvPoint = $(data).number("player.info.acv_point"); + profile.knit.acvWool = $(data).number("player.info.acv_wool"); + profile.knit.acvRouteProg = $(data).numbers("player.info.acv_route_prog"); + profile.knit.tuneCount = $(data).number("player.info.tune_cnt"); + profile.knit.saveCount = $(data).number("player.info.save_cnt"); + profile.knit.savedCount = $(data).number("player.info.saved_cnt"); + profile.knit.fcCount = $(data).number("player.info.fc_cnt"); + profile.knit.fcSeqCount = $(data).number("player.info.fc_seq_cnt"); + profile.knit.exCount = $(data).number("player.info.exc_cnt"); + profile.knit.exSeqCount = $(data).number("player.info.exc_seq_cnt"); + profile.knit.matchCount = $(data).number("player.info.match_cnt"); + profile.knit.conSelCount = $(data).number("player.info.con_sel_cnt"); + + profile.knit.marker = lastMarker; + profile.knit.theme = lastTheme; + profile.knit.title = lastTitle; + profile.knit.sort = lastSort; + profile.knit.filter = lastFilter; + profile.knit.mselStat = lastMselStat; + profile.knit.conSuggestId = $(data).number("player.info.con_suggest_id"); + + profile.knit.secretList = $(data).numbers("player.item.secret_list"); + profile.knit.themeList = $(data).number("player.item.theme_list"); + profile.knit.markerList = $(data).numbers("player.item.marker_list"); + profile.knit.titleList = $(data).numbers("player.item.title_list"); + + profile.knit.secretListNew = $(data).numbers("player.item.secret_new"); + profile.knit.themeListNew = $(data).number("player.item.theme_new"); + profile.knit.markerListNew = $(data).numbers("player.item.marker_new"); + profile.knit.titleListNew = $(data).numbers("player.item.title_new"); + } + + if (version === 4) { + if (!profile.copious) profile.copious = {}; + profile.copious.jubility = $(data).number("player.info.jubility"); + profile.copious.jubilityYday = $(data).number("player.info.jubility_yday"); + profile.copious.acvState = $(data).number("player.info.acv_state"); + profile.copious.acvPoint = $(data).number("player.info.acv_point"); + profile.copious.acvOwn = $(data).number("player.info.acv_own"); + profile.copious.acvThrow = $(data).numbers("player.info.acv_throw"); + profile.copious.tuneCount = $(data).number("player.info.tune_cnt"); + profile.copious.saveCount = $(data).number("player.info.save_cnt"); + profile.copious.savedCount = $(data).number("player.info.saved_cnt"); + profile.copious.fcCount = $(data).number("player.info.fc_cnt"); + profile.copious.fcSeqCount = $(data).number("player.info.fc_seq_cnt"); + profile.copious.exCount = $(data).number("player.info.exc_cnt"); + profile.copious.exSeqCount = $(data).number("player.info.exc_seq_cnt"); + profile.copious.matchCount = $(data).number("player.info.match_cnt"); + profile.copious.totalBestScore = $(data).number("player.info.total_best_score"); + + profile.copious.marker = lastMarker; + profile.copious.theme = lastTheme; + profile.copious.title = lastTitle; + profile.copious.parts = lastParts; + profile.copious.sort = lastSort; + profile.copious.category = lastCategory; + profile.copious.mselStat = lastMselStat; + + profile.copious.secretList = $(data).numbers("player.item.secret_list"); + profile.copious.themeList = $(data).number("player.item.theme_list"); + profile.copious.markerList = $(data).numbers("player.item.marker_list"); + profile.copious.titleList = $(data).numbers("player.item.title_list"); + profile.copious.partsList = $(data).numbers("player.item.parts_list"); + + profile.copious.secretListNew = $(data).numbers("player.item.secret_new"); + profile.copious.themeListNew = $(data).number("player.item.theme_new"); + profile.copious.markerListNew = $(data).numbers("player.item.marker_new"); + profile.copious.titleListNew = $(data).numbers("player.item.title_new"); + } + + if (version === 5) { + if (!profile.saucer) profile.saucer = {}; + profile.saucer.jubility = $(data).number("player.info.jubility"); + profile.saucer.jubilityYday = $(data).number("player.info.jubility_yday"); + profile.saucer.tuneCount = $(data).number("player.info.tune_cnt"); + profile.saucer.clearCount = $(data).number("player.info.clear_cnt"); + profile.saucer.saveCount = $(data).number("player.info.save_cnt"); + profile.saucer.savedCount = $(data).number("player.info.saved_cnt"); + profile.saucer.fcCount = $(data).number("player.info.fc_cnt"); + profile.saucer.exCount = $(data).number("player.info.exc_cnt"); + profile.saucer.matchCount = $(data).number("player.info.match_cnt"); + profile.saucer.totalBestScore = $(data).number("player.info.total_best_score"); + + profile.saucer.marker = lastMarker; + profile.saucer.theme = lastTheme; + profile.saucer.title = lastTitle; + profile.saucer.parts = lastParts; + profile.saucer.sort = lastSort; + profile.saucer.category = lastCategory; + + profile.saucer.secretList = $(data).numbers("player.item.secret_list"); + profile.saucer.themeList = $(data).number("player.item.theme_list"); + profile.saucer.markerList = $(data).numbers("player.item.marker_list"); + profile.saucer.titleList = $(data).numbers("player.item.title_list"); + profile.saucer.partsList = $(data).numbers("player.item.parts_list"); + + profile.saucer.secretListNew = $(data).numbers("player.item.secret_new"); + profile.saucer.themeListNew = $(data).number("player.item.theme_new"); + profile.saucer.markerListNew = $(data).numbers("player.item.marker_new"); + profile.saucer.titleListNew = $(data).numbers("player.item.title_new"); + + if (!profile.saucer.bistro) profile.saucer.bistro = {}; + profile.saucer.bistro.carry_over = $(data).number("player.bistro.carry_over"); + } + + try { + await DB.Update(refId, { collection: "profile" }, profile); + + return send.object({ + data: { + player: { session_id: K.ITEM("s32", 1) }, + ...version === 4 && { collabo: { deller: K.ITEM("s32", 0) } } + } + }); + } catch (e) { + console.error(`Profile save failed: ${e.message}`); + return send.deny(); + } }; export const loadScore: EPR = async (info, data, send) => { @@ -178,7 +262,7 @@ export const loadScore: EPR = async (info, data, send) => { if (version === 0) return send.deny(); const scores = await DB.Find(profile.__refid, { collection: "score" }); - const scoreData: { [musicId: number]: any } = {}; + const scoreData: { [musicId: number]: { score: number[], clear: number[], playCnt: number[], clearCnt: number[], fcCnt: number[], exCnt: number[], bar: number[][] } } = {}; for (const score of scores) { if (!scoreData[score.musicId]) { @@ -198,95 +282,112 @@ export const loadScore: EPR = async (info, data, send) => { data.clearCnt[score.seq] = score.clearCount; data.fcCnt[score.seq] = score.fullcomboCount; data.exCnt[score.seq] = score.excellentCount; - data.clear[score.seq] = score.clearType; + data.clear[score.seq] = score.clear; data.score[score.seq] = score.score; data.bar[score.seq] = score.bar; } - if (version === 3) return send.object({ + return send.object({ data: { player: { - playdata: K.ATTR({ count: String(Object.keys(scoreData).length) }, { - musicdata: (() => { - const musicdata = []; - Object.entries(scoreData).forEach(([k, v]) => { - musicdata.push(K.ATTR({ music_id: String(k) }, { - play_cnt: K.ARRAY('s32', v.playCnt), - clear_cnt: K.ARRAY('s32', v.clearCnt), - fc_cnt: K.ARRAY('s32', v.fcCnt), - ex_cnt: K.ARRAY('s32', v.exCnt), - clear: K.ARRAY('s8', v.clear), - score: K.ARRAY('s32', v.score), - bar: v.bar.map((v, i) => K.ARRAY('u8', v, { seq: String(i) })) - })); - }); - return musicdata; - })() - }) + jid: K.ITEM("s32", jubeatId), + + ...version >= 3 && { + playdata: K.ATTR({ count: String(Object.keys(scoreData).length) }, { + musicdata: Object.keys(scoreData).map(musicId => K.ATTR({ music_id: String(musicId) }, { + score: K.ARRAY("s32", scoreData[musicId].score), + clear: K.ARRAY("s8", scoreData[musicId].clear), + play_cnt: K.ARRAY("s32", scoreData[musicId].playCnt), + clear_cnt: K.ARRAY("s32", scoreData[musicId].clearCnt), + fc_cnt: K.ARRAY("s32", scoreData[musicId].fcCnt), + ex_cnt: K.ARRAY("s32", scoreData[musicId].exCnt), + bar: scoreData[musicId].bar.map((bar, seq) => K.ARRAY("u8", bar, { seq: String(seq) })) + })) + }) + } } } }); - - return send.deny(); }; -const updateScore = async (refId: string, musicId: number, seq: number, score: number, clear: number, mbar: number[], data: any) => { - let raised; +const updateScore = async (refId: string, data: any): Promise => { + try { + await DB.Upsert(refId, { + collection: "score", + musicId: data.musicId, + seq: data.seq, + isHardMode: data.isHard + }, { + $set: { + musicId: data.musicId, + seq: data.seq, + score: data.bestScore, + clear: data.bestClear, + musicRate: 0, + ...data.mbar && { bar: data.mbar, }, + playCount: data.playCount, + clearCount: data.clearCount, + fullcomboCount: data.fullcomboCount, + excellentCount: data.excellentCount, + isHardMode: data.isHard + } + }); - const oldScore = await DB.FindOne(refId, { collection: "score", musicId, seq }); - - let scoreData = oldScore; - - if (!oldScore) { - scoreData = new Score(); - scoreData.musicId = musicId; - scoreData.seq = seq; - raised = true; - } else { - raised = score > oldScore.score; - score = Math.max(oldScore.score, score); + return true; + } catch (e) { + console.error("Score saving failed: ", e.stack); + return false; } - - scoreData.clearType = Math.max(scoreData.clearType, clear); - scoreData.playCount = data.playCount; - scoreData.clearCount = data.clearCount; - scoreData.fullcomboCount = data.fullcomboCount; - scoreData.excellentCount = data.excellentCount; - scoreData.isHardmodeClear = false; - - if (mbar && raised) { - scoreData.score = score; - scoreData.bar = mbar; - } - - await DB.Upsert(refId, { collection: "score", musicId, seq }, scoreData); }; export const meeting: EPR = (info, data, send) => { return send.object({ data: { meeting: { - single: K.ATTR({ count: '0' }), - tag: K.ATTR({ count: '0' }), + single: K.ATTR({ count: "0" }), + tag: K.ATTR({ count: "0" }), }, reward: { - total: K.ITEM('s32', 0), - point: K.ITEM('s32', 0) + total: K.ITEM("s32", 0), + point: K.ITEM("s32", 0) } } }); }; -export const getCollabo: EPR = (info, data, send) => send.object({ - data: { - collabo: { - played: { - iidx: K.ITEM("s8", 1), - popn: K.ITEM("s8", 1), - ddr: K.ITEM("s8", 1), - reflec: K.ITEM("s8", 1), - gfdm: K.ITEM("s8", 1), +export const getCollabo: EPR = (info, data, send) => { + const version = getVersion(info); + if (version === 0) return send.deny(); + + if (version === 3) { + return send.object({ + data: { + collabo: { + played: { + iidx: K.ITEM("s8", 1), + popn: K.ITEM("s8", 1), + ddr: K.ITEM("s8", 1), + reflec: K.ITEM("s8", 1), + gfdm: K.ITEM("s8", 1), + } + } } - } + }); } -}); + + if (version === 4) { + return send.object({ + data: { + player: { + collabo: { + reward: K.ITEM("s32", 0), + dellar: K.ITEM("s32", 0), + music_id: K.ITEM("s32", 0), + wonder_state: K.ITEM("u32", 2), + yellow_state: K.ITEM("u32", 2), + } + } + } + }); + } +}; diff --git a/jubeat@asphyxia/index.ts b/jubeat@asphyxia/index.ts index 194f673..1a1fb95 100644 --- a/jubeat@asphyxia/index.ts +++ b/jubeat@asphyxia/index.ts @@ -1,60 +1,36 @@ -import {demodata, netlog, shopinfo} from "./handlers/common"; -import {check, entry, refresh, report} from "./handlers/matching"; -import {getCollabo, loadScore, meeting, profile, saveProfile} from "./handlers/profile"; +import {demodata, gameInfo} from './handlers/common'; +import {check, entry, refresh, report} from './handlers/matching'; +import {getCollabo, loadScore, meeting, profile, saveProfile} from './handlers/profile'; export function register() { if (CORE_VERSION_MAJOR <= 1 && CORE_VERSION_MINOR < 31) { - console.error("The current version of Asphyxia Core is not supported. Requires version '1.31' or later."); + console.error('The current version of Asphyxia Core is not supported. Requires version \'1.31\' or later.'); return; } - R.GameCode("J44"); + R.GameCode('J44'); + R.GameCode('K44'); + R.GameCode('L44'); - R.Config("unlock_all_songs", { - name: "Unlock All Songs", - desc: "Tired of unlocking songs? Have this!", - type: "boolean", - default: false - }); - - R.Config("quick_matching_end", { - name: "Quick Matching End", - desc: "Supported from clan to festo.", - type: "boolean", - default: false - }); - - R.Config("matching_entry_timeout", { - name: "Online Matching Timeout", - desc: "If online matching songs are too boring, save time! (second)", - type: "integer", - default: 30, - range: [15, 99], - }); - - R.Route("gametop.regist", profile); - R.Route("gametop.get_pdata", profile); - R.Route("gametop.get_mdata", loadScore); - R.Route("gametop.get_meeting", meeting); - R.Route("gametop.get_collabo", getCollabo); + R.Route('gametop.regist', profile); + R.Route('gametop.get_info', gameInfo); + R.Route('gametop.get_pdata', profile); + R.Route('gametop.get_mdata', loadScore); + R.Route('gametop.get_meeting', meeting); + R.Route('gametop.get_collabo', getCollabo); R.Route('gameend.regist', saveProfile); R.Route('gameend.log', true); R.Route('gameend.set_collabo', true); - R.Route("shopinfo.regist", shopinfo); - R.Route("netlog.send", netlog); - R.Route("demodata.get_news", demodata.getNews); - R.Route("demodata.get_data", demodata.getData); - R.Route("demodata.get_hitchart", demodata.getHitchart); - R.Route("lobby.check", check); - R.Route("lobby.entry", entry); - R.Route("lobby.refresh", refresh); - R.Route("lobby.report", report); + R.Route('shopinfo.regist', gameInfo); + R.Route('demodata.get_news', demodata.getNews); + R.Route('demodata.get_data', demodata.getData); + R.Route('demodata.get_hitchart', demodata.getHitchart); + R.Route('lobby.check', check); + R.Route('lobby.entry', entry); + R.Route('lobby.refresh', refresh); + R.Route('lobby.report', report); - R.Unhandled((info, data, send) => { - console.log(info.module, info.method); - console.log(U.toXML(data)); - - return send.deny(); - }); + R.Route('netlog.send', true); + R.Route('logger.report', true); } diff --git a/jubeat@asphyxia/models/matching.ts b/jubeat@asphyxia/models/matching.ts new file mode 100644 index 0000000..79597a4 --- /dev/null +++ b/jubeat@asphyxia/models/matching.ts @@ -0,0 +1,18 @@ +export interface Room { + collection: 'matching_rooms'; + + version: number; + roomId: number; + masterKey: number[]; + masterGlobal: string; + masterPrivate: string; + localKey: number[]; + musicId: number; + seqId: number; + members: { + cabid: number; + addr: string; + }[]; + isFull: boolean; + isMatchEnd: boolean; +} diff --git a/jubeat@asphyxia/models/profile.ts b/jubeat@asphyxia/models/profile.ts index f0e3925..7fec747 100644 --- a/jubeat@asphyxia/models/profile.ts +++ b/jubeat@asphyxia/models/profile.ts @@ -1,101 +1,123 @@ -export default class Profile { - collection: "profile" = "profile"; +export default interface Profile { + collection: "profile"; - jubeatId: number = _.random(1, 99999999); - name: string = "JUBEAT"; + jubeatId: number; + name: string; - previous_version = 0; + lastPlayTime?: number; + lastShopname: string; + lastAreaname: string; - jubility: number = 0; - jubilityYday: number = 0; - tuneCount: number = 0; - saveCount: number = 0; - savedCount: number = 0; - fullcomboCount: number = 0; - fullcomboSeqCount: number = 0; - excellentCount: number = 0; - excellentSeqCount: number = 0; - matchCount: number = 0; - beatCount: number = 0; - tagCount: number = 0; - mynewsCount: number = 0; - conciergeSelectedCount: number = 0; + musicId?: number; + seqId?: number; + rankSort?: number; + comboDisp?: number; - last: { - shopname: string; - areaname: string; - playTime: bigint; - title: number; - theme: number; - marker: number; - showRank: number; - showCombo: number; - musicId: number; - seqId: number; - seqEditId: string; - sort: number; - filter: number; - mselStat: number; - conciergeSuggestId: number; - } = { - shopname: "NONE", - areaname: "NONE", - playTime: BigInt(0), - title: 0, - theme: 0, - marker: 0, - showRank: 1, - showCombo: 1, - musicId: 0, - seqId: 0, - seqEditId: "", - sort: 0, - filter: 0, - mselStat: 0, - conciergeSuggestId: 0 + knit?: { + jubility?: number; + jubilityYday?: number; + acvProg?: number; + acvWool?: number; + acvRouteProg?: number[]; + acvPoint?: number; + tuneCount?: number; + saveCount?: number; + savedCount?: number; + fcCount?: number; + fcSeqCount?: number; + exCount?: number; + exSeqCount?: number; + matchCount?: number; + conSelCount?: number; + + marker?: number; + theme?: number; + title?: number; + sort?: number; + filter?: number; + mselStat?: number; + conSuggestId?: number; + + secretList?: number[]; + themeList?: number; + markerList?: number[]; + titleList?: number[]; + + secretListNew?: number[]; + themeListNew?: number; + markerListNew?: number[]; + titleListNew?: number[]; }; - knit: { - acvProg: number; - acvWool: number; - acvRouteProg: number[]; - acvPoint: number; - item: { - secretList: number[], - themeList: number, - markerList: number[], - titleList: number[] - }, - item_new: { - secretList: number[], - themeList: number, - markerList: number[], - titleList: number[] - }, - collabo: { - success: boolean; - completed: boolean; - } - } = { - acvProg: 0, - acvWool: 0, - acvRouteProg: [0, 0, 0, 0], - acvPoint: 0, - item: { - secretList: [0, 0], - themeList: 0, - markerList: [0, 0], - titleList: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - }, - item_new: { - secretList: [0, 0], - themeList: 0, - markerList: [0, 0], - titleList: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - }, - collabo: { - success: false, - completed: false + copious?: { + jubility?: number; + jubilityYday?: number; + acvPoint?: number; + acvState?: number; + acvThrow?: number[]; + acvOwn?: number; + tuneCount?: number; + saveCount?: number; + savedCount?: number; + fcCount?: number; + fcSeqCount?: number; + exCount?: number; + exSeqCount?: number; + matchCount?: number; + totalBestScore?: number; + + marker?: number; + theme?: number; + title?: number; + parts?: number; + sort?: number; + category?: number; + mselStat?: number; + + secretList?: number[]; + themeList?: number; + markerList?: number[]; + titleList?: number[]; + partsList?: number[]; + + secretListNew?: number[]; + themeListNew?: number; + markerListNew?: number[]; + titleListNew?: number[]; + }; + + saucer?: { + jubility?: number; + jubilityYday?: number; + tuneCount?: number; + clearCount?: number; + saveCount?: number; + savedCount?: number; + fcCount?: number; + exCount?: number; + matchCount?: number; + totalBestScore?: number; + + marker?: number; + theme?: number; + title?: number; + parts?: number; + sort?: number; + category?: number; + + secretList?: number[]; + themeList?: number; + markerList?: number[]; + titleList?: number[]; + partsList?: number[]; + + secretListNew?: number[]; + themeListNew?: number; + markerListNew?: number[]; + titleListNew?: number[]; + + bistro?: { + carry_over?: number; } }; } diff --git a/jubeat@asphyxia/models/score.ts b/jubeat@asphyxia/models/score.ts index 440c813..f520cd3 100644 --- a/jubeat@asphyxia/models/score.ts +++ b/jubeat@asphyxia/models/score.ts @@ -1,14 +1,15 @@ -export class Score { - collection: "score" = "score"; +export interface Score { + collection: "score"; musicId: number; seq: number; - score: number = 0; - clearType: number = 0; - playCount: number = 0; - clearCount: number = 0; - fullcomboCount: number = 0; - excellentCount: number = 0; - isHardmodeClear: boolean; + score: number; + clear: number; + musicRate: number; bar: number[]; + playCount: number; + clearCount: number; + fullcomboCount: number; + excellentCount: number; + isHardMode: boolean; } diff --git a/jubeat@asphyxia/templates/gameInfos/saucer.ts b/jubeat@asphyxia/templates/gameInfos/saucer.ts new file mode 100644 index 0000000..28a8a59 --- /dev/null +++ b/jubeat@asphyxia/templates/gameInfos/saucer.ts @@ -0,0 +1,27 @@ +module.exports = () => ({ + termver: K.ITEM("u8", 0), + season_etime: K.ITEM("u32", 0), + bistro_last_music_id: K.ITEM("s32", 0), + white_music_list: K.ARRAY("s32", Array(32).fill(-1)), + old_music_list: K.ARRAY("s32", Array(32).fill(0)), + open_music_list: K.ARRAY("s32", Array(32).fill(0)), + + collabo_info: { + collabo: [ + K.ATTR({ type: "1" }, { state: K.ITEM("u8", 0) }), + K.ATTR({ type: "2" }, { state: K.ITEM("u8", 0) }), + K.ATTR({ type: "3" }, { state: K.ITEM("u8", 0) }), + K.ATTR({ type: "4" }, { state: K.ITEM("u8", 0) }), + K.ATTR({ type: "5" }, { state: K.ITEM("u8", 0) }), + K.ATTR({ type: "8" }, { state: K.ITEM("u8", 0) }) + ], + + run_run_marathon: { + is_report_end: K.ITEM("bool", true) + }, + + policy_break: { + is_report_end: K.ITEM("bool", true) + } + } +}); diff --git a/jubeat@asphyxia/templates/knit/profile.pug b/jubeat@asphyxia/templates/knit/profile.pug deleted file mode 100644 index d56ad73..0000000 --- a/jubeat@asphyxia/templates/knit/profile.pug +++ /dev/null @@ -1,89 +0,0 @@ -gametop - data - player - name(__type="str") #{name} - jid(__type="s32") #{jubeatId} - refid(__type="str") #{refId} - session_id(__type="s32") 1 - - info - inherit(__type="bool") #{migration ? 1 : 0} - jubility(__type="s16") #{jubility} - jubility_yday(__type="s16") #{jubilityYday} - acv_prog(__type="s8") #{knit.acvProg} - acv_wool(__type="s8") #{knit.acvWool} - acv_route_prog(__type="s8" __count="4") #{knit.acvRouteProg.join(" ")} - acv_point(__type="s32") #{knit.acvPoint} - tune_cnt(__type="s32") #{tuneCount} - save_cnt(__type="s32") #{saveCount} - saved_cnt(__type="s32") #{savedCount} - fc_cnt(__type="s32") #{fullcomboCount} - ex_cnt(__type="s32") #{excellentCount} - match_cnt(__type="s32") #{matchCount} - beat_cnt(__type="s32") #{beatCount} - mynews_cnt(__type="s32") #{mynewsCount} - con_sel_cnt(__type="s32") #{conciergeSelectedCount} - tag_cnt(__type="s32") #{tagCount} - mtg_entry_cnt(__type="s32") 0 - tag_entry_cnt(__type="s32") 0 - mtg_hold_cnt(__type="s32") 0 - tag_hold_cnt(__type="s32") 0 - mtg_result(__type="u8") 0 - - last - play_time(__type="s64") #{last.playTime || 0} - shopname(__type="str") #{last.shopname} - areaname(__type="str") #{last.areaname} - title(__type="s16") #{last.title} - theme(__type="s8") #{last.theme} - marker(__type="s8") #{last.marker} - rank_sort(__type="s8") #{last.showRank} - combo_disp(__type="s8") #{last.showCombo} - music_id(__type="s32") #{last.musicId} - seq_id(__type="s8") #{last.seqId} - sort(__type="s8") #{last.sort} - filter(__type="s32") #{last.filter} - msel_stat(__type="s8") #{last.mselStat} - con_suggest_id(__type="s8") #{last.conciergeSuggestId} - - item - secret_list(__type="s32" __count="2") #{knit.item.secretList.join(" ")} - theme_list(__type="s16") #{knit.item.themeList} - marker_list(__type="s32" __count="2") #{knit.item.markerList.join(" ")} - title_list(__type="s32" __count="24") #{knit.item.titleList.join(" ")} - - new - secret_list(__type="s32" __count="2") #{knit.item_new.secretList.join(" ")} - theme_list(__type="s16") #{knit.item_new.themeList} - marker_list(__type="s32" __count="2") #{knit.item_new.markerList.join(" ")} - title_list(__type="s32" __count="24") #{knit.item_new.titleList.join(" ")} - - today_music - music_id(__type="s32") 0 - - news - checked(__type="s16") 0 - - friendlist(count="0") - - lucky_music - music_id(__type="s32") 0 - - mylist(count="0") - - group - group_id(__type="s32") 0 - - bingo - reward - total(__type="s32") 0 - point(__type="s32") 0 - - collabo - success(__type="bool") #{knit.collabo.success ? 1 : 0} - completed(__type="bool") #{knit.collabo.completed ? 1 : 0} - - history - play_hist(count="0") - - match_hist(count="0") diff --git a/jubeat@asphyxia/templates/profiles/copious.ts b/jubeat@asphyxia/templates/profiles/copious.ts new file mode 100644 index 0000000..e9a00a6 --- /dev/null +++ b/jubeat@asphyxia/templates/profiles/copious.ts @@ -0,0 +1,71 @@ +import Profile from "../../models/profile"; + +module.exports = (data: Profile) => ({ + info: { + jubility: K.ITEM("s16", data.copious?.jubility || 0), + jubility_yday: K.ITEM("s16", data.copious?.jubilityYday || 0), + acv_point: K.ITEM("s32", data.copious?.acvPoint || 0), + acv_state: K.ITEM("s8", data.copious?.acvState || 0), + acv_throw: K.ARRAY("s32", data.copious?.acvThrow || [0, 0, 0]), + acv_own: K.ITEM("s32", data.copious?.acvOwn || 0), + tune_cnt: K.ITEM("s32", data.copious?.tuneCount || 0), + save_cnt: K.ITEM("s32", data.copious?.saveCount || 0), + saved_cnt: K.ITEM("s32", data.copious?.savedCount || 0), + fc_cnt: K.ITEM("s32", data.copious?.fcCount || 0), + ex_cnt: K.ITEM("s32", data.copious?.exCount || 0), + match_cnt: K.ITEM("s32", data.copious?.matchCount || 0), + beat_cnt: K.ITEM("s32", 0), + mynews_cnt: K.ITEM("s32", 0), + mtg_entry_cnt: K.ITEM("s32", 0), + mtg_hold_cnt: K.ITEM("s32", 0), + mtg_result: K.ITEM("u8", 0) + }, + + last: { + play_time: K.ITEM("s64", BigInt(0)), + shopname: K.ITEM("str", data.lastShopname), + areaname: K.ITEM("str", data.lastAreaname), + title: K.ITEM("s16", data.copious?.title || 0), + parts: K.ITEM("s16", data.copious?.parts || 0), + theme: K.ITEM("s8", data.copious?.theme || 0), + marker: K.ITEM("s8", data.copious?.marker || 0), + rank_sort: K.ITEM("s8", data.rankSort || 1), + combo_disp: K.ITEM("s8", data.comboDisp || 1), + music_id: K.ITEM("s32", data.musicId || 0), + seq_id: K.ITEM("s8", data.seqId || 0), + sort: K.ITEM("s8", data.copious?.sort || 0), + category: K.ITEM("s8", data.copious?.category || 0), + msel_stat: K.ITEM("s8", data.copious?.mselStat || 0) + }, + + item: { + secret_list: K.ARRAY("s32", data.copious?.secretList || Array(12).fill(0)), + theme_list: K.ITEM("s16", data.copious?.themeList || 0), + marker_list: K.ARRAY("s32", data.copious?.markerList || [0, 0]), + title_list: K.ARRAY("s32", data.copious?.titleList || Array(32).fill(0)), + parts_list: K.ARRAY("s32", data.copious?.partsList || Array(96).fill(0)), + + new: { + secret_list: K.ARRAY("s32", data.copious?.secretListNew || Array(12).fill(0)), + theme_list: K.ITEM("s16", data.copious?.themeListNew || 0), + marker_list: K.ARRAY("s32", data.copious?.markerListNew || [0, 0]), + title_list: K.ARRAY("s32", data.copious?.titleListNew || Array(32).fill(0)) + } + }, + + challenge: { + today: { + music_id: K.ITEM("s32", 0) + }, + onlynow: { + magic_no: K.ITEM("s32", 0), + cycle: K.ITEM("s16", 0) + } + }, + + news: { + checked: K.ITEM("s16", 0) + }, + + rivallist: K.ATTR({ count: "0" }) +}); diff --git a/jubeat@asphyxia/templates/profiles/knit.ts b/jubeat@asphyxia/templates/profiles/knit.ts new file mode 100644 index 0000000..8ebb2aa --- /dev/null +++ b/jubeat@asphyxia/templates/profiles/knit.ts @@ -0,0 +1,75 @@ +import Profile from "../../models/profile"; + +module.exports = (data: Profile) => ({ + info: { + jubility: K.ITEM("s16", data.knit?.jubility || 0), + jubility_yday: K.ITEM("s16", data.knit?.jubilityYday || 0), + acv_prog: K.ITEM("s8", data.knit?.acvProg || 0), + acv_wool: K.ITEM("s8", data.knit?.acvWool || 0), + acv_route_prog: K.ARRAY("s8", data.knit?.acvRouteProg || [0, 0, 0, 0]), + acv_point: K.ITEM("s32", data.knit?.acvPoint || 0), + tune_cnt: K.ITEM("s32", data.knit?.tuneCount || 0), + save_cnt: K.ITEM("s32", data.knit?.saveCount || 0), + saved_cnt: K.ITEM("s32", data.knit?.savedCount || 0), + fc_cnt: K.ITEM("s32", data.knit?.fcCount || 0), + ex_cnt: K.ITEM("s32", data.knit?.exCount || 0), + match_cnt: K.ITEM("s32", data.knit?.matchCount || 0), + beat_cnt: K.ITEM("s32", 0), + mynews_cnt: K.ITEM("s32", 0), + con_sel_cnt: K.ITEM("s32", data.knit?.conSelCount || 0), + tag_cnt: K.ITEM("s32", 0), + mtg_entry_cnt: K.ITEM("s32", 0), + tag_entry_cnt: K.ITEM("s32", 0), + mtg_hold_cnt: K.ITEM("s32", 0), + tag_hold_cnt: K.ITEM("s32", 0), + mtg_result: K.ITEM("u8", 0) + }, + + last: { + play_time: K.ITEM("s64", BigInt(0)), + shopname: K.ITEM("str", data.lastShopname), + areaname: K.ITEM("str", data.lastAreaname), + title: K.ITEM("s16", data.knit?.title || 0), + theme: K.ITEM("s8", data.knit?.theme || 0), + marker: K.ITEM("s8", data.knit?.marker || 0), + rank_sort: K.ITEM("s8", data.rankSort || 1), + combo_disp: K.ITEM("s8", data.comboDisp || 1), + music_id: K.ITEM("s32", data.musicId || 0), + seq_id: K.ITEM("s8", data.seqId || 0), + sort: K.ITEM("s8", data.knit?.sort || 0), + filter: K.ITEM("s32", data.knit?.filter || 0), + msel_stat: K.ITEM("s8", data.knit?.mselStat || 0), + con_suggest_id: K.ITEM("s8", data.knit?.conSuggestId || 0) + }, + + item: { + secret_list: K.ARRAY("s32", data.knit?.secretList || [0, 0]), + theme_list: K.ITEM("s16", data.knit?.themeList || 0), + marker_list: K.ARRAY("s32", data.knit?.markerList || [0, 0]), + title_list: K.ARRAY("s32", data.knit?.titleList || Array(24).fill(0)), + + new: { + secret_list: K.ARRAY("s32", data.knit?.secretListNew || [0, 0]), + theme_list: K.ITEM("s16", data.knit?.themeListNew || 0), + marker_list: K.ARRAY("s32", data.knit?.markerListNew || [0, 0]), + title_list: K.ARRAY("s32", data.knit?.titleListNew || Array(24).fill(0)) + } + }, + + today_music: { + music_id: K.ITEM("s32", 0) + }, + + news: { + checked: K.ITEM("s16", 0) + }, + + friendlist: K.ATTR({ count: "0" }), + + mylist: K.ATTR({ count: "0" }), + + collabo: { + success: K.ITEM("bool", true), + completed: K.ITEM("bool", true) + } +}); diff --git a/jubeat@asphyxia/templates/profiles/saucer.ts b/jubeat@asphyxia/templates/profiles/saucer.ts new file mode 100644 index 0000000..025e844 --- /dev/null +++ b/jubeat@asphyxia/templates/profiles/saucer.ts @@ -0,0 +1,101 @@ +import Profile from "../../models/profile"; + +module.exports = (data: Profile) => ({ + info: { + jubility: K.ITEM("s16", data.saucer?.jubility || 0), + jubility_yday: K.ITEM("s16", data.saucer?.jubilityYday || 0), + tune_cnt: K.ITEM("s32", data.saucer?.tuneCount || 0), + save_cnt: K.ITEM("s32", data.saucer?.saveCount || 0), + saved_cnt: K.ITEM("s32", data.saucer?.savedCount || 0), + fc_cnt: K.ITEM("s32", data.saucer?.fcCount || 0), + ex_cnt: K.ITEM("s32", data.saucer?.exCount || 0), + clear_cnt: K.ITEM("s32", data.saucer?.clearCount || 0), + pf_cnt: K.ITEM("s32", 0), + match_cnt: K.ITEM("s32", data.saucer?.matchCount || 0), + beat_cnt: K.ITEM("s32", 0), + mynews_cnt: K.ITEM("s32", 0), + mtg_entry_cnt: K.ITEM("s32", 0), + mtg_hold_cnt: K.ITEM("s32", 0), + mtg_result: K.ITEM("u8", 0) + }, + + last: { + play_time: K.ITEM("s64", BigInt(0)), + shopname: K.ITEM("str", data.lastShopname), + areaname: K.ITEM("str", data.lastAreaname), + title: K.ITEM("s16", data.saucer?.title || 0), + parts: K.ITEM("s16", data.saucer?.parts || 0), + theme: K.ITEM("s8", data.saucer?.theme || 0), + marker: K.ITEM("s8", data.saucer?.marker || 0), + rank_sort: K.ITEM("s8", data.rankSort || 1), + combo_disp: K.ITEM("s8", data.comboDisp || 1), + music_id: K.ITEM("s32", data.musicId || 0), + seq_id: K.ITEM("s8", data.seqId || 0), + sort: K.ITEM("s8", data.saucer?.sort || 0), + category: K.ITEM("s8", data.saucer?.category || 0) + }, + + item: { + secret_list: K.ARRAY("s32", Array(32).fill(-1)), + theme_list: K.ITEM("s16", -1), + marker_list: K.ARRAY("s32", Array(2).fill(-1)), + title_list: K.ARRAY("s32", Array(96).fill(-1)), + parts_list: K.ARRAY("s32", Array(96).fill(-1)), + + new: { + secret_list: K.ARRAY("s32", Array(32).fill(0)), + theme_list: K.ITEM("s16", 0), + marker_list: K.ARRAY("s32", Array(2).fill(0)), + title_list: K.ARRAY("s32", Array(96).fill(0)) + } + }, + + history: K.ATTR({ count: "0" }), + + challenge: { + today: { + music_id: K.ITEM("s32", 0), + state: K.ITEM("u8", 0) + } + }, + + news: { + checked: K.ITEM("s16", 0) + }, + + bistro: { + info: { + delicious_rate: K.ITEM("float", 1.0), + favorite_rate: K.ITEM("float", 1.0) + }, + + chef: { + id: K.ITEM("s32", 0), + ability: K.ITEM("u8", 0), + remain: K.ITEM("u8", 0), + rate: K.ARRAY("u8", [0, 0, 0, 0]) + }, + + carry_over: K.ITEM("s32", data.saucer?.bistro?.carry_over || 0), + + route: Array(9).fill(0).map((v, i) => (K.ATTR({ no: String(i) }, { + music: { + id: K.ITEM("s32", 0), + price_s32: K.ITEM("s32", 0) + }, + + gourmates: { + id: K.ITEM("s32", 0), + favorite: K.ARRAY("u8", Array(30).fill(0)), + satisfaction_s32: K.ITEM("s32", 0) + } + }))) + }, + + rivallist: K.ATTR({ count: "0" }), + + only_now_music: K.ATTR({ count: "0" }), + requested_music: K.ATTR({ count: "0" }), + lab_edit_seq: K.ATTR({ count: "0" }), + kac_music: K.ATTR({ count: "0" }), +}); diff --git a/jubeat@asphyxia/utils.ts b/jubeat@asphyxia/utils.ts index 3647c04..222560c 100644 --- a/jubeat@asphyxia/utils.ts +++ b/jubeat@asphyxia/utils.ts @@ -1,6 +1,30 @@ export function getVersion({ model }: EamuseInfo) { - const dateCode = model.split(':')[4]; + const dateCode = parseInt(model.split(":")[4]); if (model.startsWith("J44")) return 3; + if (model.startsWith("K44")) return 4; + if (model.startsWith("L44")) { + if (dateCode >= 2012082400 && dateCode <= 2014022400) return 5; + if (dateCode >= 2014030303 && dateCode <= 2014121802) return 6; + return 0; + } return 0; } + +export function getVersionName({ model }: EamuseInfo) { + const dateCode = parseInt(model.split(":")[4]); + + if (model.startsWith("J44")) return "knit"; + if (model.startsWith("K44")) return "copious"; + if (model.startsWith("L44")) { + if (dateCode >= 2012082400 && dateCode <= 2014022400) return "saucer"; + if (dateCode >= 2014030303 && dateCode <= 2014121802) return "fulfill"; + return null; + } + return null; +} + +export function VersionRange(version: number, start: number, end: number = -1) { + if (end === -1) return version >= start; + return version >= start && version <= end; +}