diff --git a/sdvx@asphyxia/README.md b/sdvx@asphyxia/README.md index ca4cb63..1c0c309 100644 --- a/sdvx@asphyxia/README.md +++ b/sdvx@asphyxia/README.md @@ -4,5 +4,6 @@ Plugin Version: **v1.1** Supported Versions: +- BOOTH - HEAVENLY HAVEN - VIVID WAVE diff --git a/sdvx@asphyxia/handlers/common.ts b/sdvx@asphyxia/handlers/common.ts index da45335..a5b4d0b 100644 --- a/sdvx@asphyxia/handlers/common.ts +++ b/sdvx@asphyxia/handlers/common.ts @@ -6,6 +6,12 @@ export const common: EPR = async (info, data, send) => { let courses = []; let extend = []; + const version = parseInt(info.model.split(":")[4]); + + if (version <= 2013052900) { + return send.pugFile('templates/booth/common.pug'); + } + switch (info.method) { case 'sv4_common': { events = EVENT4; @@ -26,13 +32,13 @@ export const common: EPR = async (info, data, send) => { if (U.GetConfig('unlock_all_songs')) { for (let i = 1; i < 1700; ++i) { for (let j = 0; j < 5; ++j) { - + songs.push({ music_id: K.ITEM('s32', i), music_type: K.ITEM('u8', j), limited: K.ITEM('u8', 3), }); - + } } } diff --git a/sdvx@asphyxia/handlers/features.ts b/sdvx@asphyxia/handlers/features.ts index 371f8e2..fe5abec 100644 --- a/sdvx@asphyxia/handlers/features.ts +++ b/sdvx@asphyxia/handlers/features.ts @@ -1,17 +1,46 @@ -import { Profile } from '../models/profile'; -import { MusicRecord } from '../models/music_record'; -import { IDToCode, GetCounter } from '../utils'; -import { Mix } from '../models/mix'; +import {Profile} from '../models/profile'; +import {MusicRecord} from '../models/music_record'; +import {getVersion, IDToCode, GetCounter} from '../utils'; +import {Mix} from '../models/mix'; export const hiscore: EPR = async (info, data, send) => { const records = await DB.Find(null, { collection: 'music' }); + const version = getVersion(info); + const profiles = _.groupBy( await DB.Find(null, { collection: 'profile' }), '__refid' ); - send.object({ + if (version === 1) { + return send.object({ + hiscore: K.ATTR({ type: "1" }, { + music: _.map( + _.groupBy(records, r => { + return `${r.mid}:${r.type}`; + }), + r => _.maxBy(r, 'score') + ).map(r => (K.ATTR({ id: String(r.mid) }, { + note: (() => { + const notes = []; + + for (let i = 1; i <= 3; i++) { + if (r.type !== i) continue; + notes.push(K.ATTR({ type: String(r.type) }, { + name: K.ITEM('str', profiles[r.__refid][0].name), + score: K.ITEM('u32', r.score) + })) + } + + return notes; + })() + }))), + }) + }) + } + + return send.object({ sc: { d: _.map( _.groupBy(records, r => { @@ -40,7 +69,7 @@ export const rival: EPR = async (info, data, send) => { await DB.Find(null, { collection: 'profile' }) ).filter(p => p.__refid != refid); - send.object({ + return send.object({ rival: await Promise.all( rivals.map(async (p, index) => { return { @@ -84,7 +113,7 @@ export const saveMix: EPR = async (info, data, send) => { jacket: mix.number('jacket_id'), }); - send.object({ + return send.object({ automation: { mix_id: K.ITEM('s32', id), mix_code: K.ITEM('str', doc.code), @@ -105,11 +134,10 @@ export const loadMix: EPR = async (info, data, send) => { const mix = await DB.FindOne({ collection: 'mix', code }); if (!mix) { - send.object({ result: K.ITEM('s32', 1) }); - return; + return send.object({ result: K.ITEM('s32', 1) }); } - send.object({ + return send.object({ automation: { mix_id: K.ITEM('s32', mix.id), mix_code: K.ITEM('str', mix.code), diff --git a/sdvx@asphyxia/handlers/profiles.ts b/sdvx@asphyxia/handlers/profiles.ts index 217fbb2..3e55e7d 100644 --- a/sdvx@asphyxia/handlers/profiles.ts +++ b/sdvx@asphyxia/handlers/profiles.ts @@ -1,18 +1,12 @@ -import { Skill } from '../models/skill'; -import { SDVX_AUTOMATION_SONGS } from '../data/vvw'; -import { Item } from '../models/item'; -import { Param } from '../models/param'; -import { MusicRecord } from '../models/music_record'; -import { CourseRecord } from '../models/course_record'; -import { Profile } from '../models/profile'; -import { IDToCode } from '../utils'; -import { Mix } from '../models/mix'; - -function getVersion(info: EamuseInfo) { - if (info.method.startsWith('sv4')) return 4; - if (info.method.startsWith('sv5')) return 5; - return 0; -} +import {Skill} from '../models/skill'; +import {SDVX_AUTOMATION_SONGS} from '../data/vvw'; +import {Item} from '../models/item'; +import {Param} from '../models/param'; +import {MusicRecord} from '../models/music_record'; +import {CourseRecord} from '../models/course_record'; +import {Profile} from '../models/profile'; +import {getVersion, IDToCode} from '../utils'; +import {Mix} from '../models/mix'; async function getAutomationMixes(params: Param[]) { const mixids = params @@ -30,12 +24,37 @@ function unlockNavigators(items: Partial[]) { } export const loadScore: EPR = async (info, data, send) => { - const refid = $(data).str('refid'); + const refid = $(data).str('refid', $(data).attr().dataid); if (!refid) return send.deny(); const records = await DB.Find(refid, { collection: 'music' }); - send.object({ + const version = getVersion(info); + + if (version === 1) { + return send.object({ + music: records.map(r => (K.ATTR({ music_id: String(r.mid) }, { + type: (() => { + const records = []; + + for (let i = 1; i <= 3; i++) { + if (r.type != i) continue; + records.push(K.ATTR({ + type_id: String(i), + score: String(r.score), + clear_type: String(r.clear), + score_grade: String(r.grade), + cnt: "0" + })); + } + + return records; + })() + }))) + }); + } + + return send.object({ music: { info: records.map(r => ({ param: K.ARRAY('u32', [ @@ -62,9 +81,57 @@ export const loadScore: EPR = async (info, data, send) => { }; export const saveScore: EPR = async (info, data, send) => { - const refid = $(data).str('refid'); + const refid = $(data).str('refid', $(data).attr().dataid); if (!refid) return send.deny(); + const version = getVersion(info); + + // Booth - Save score + if (version === 1) { + try { + const mid = parseInt($(data).attr().music_id); + const type = parseInt($(data).attr().music_type); + + if (_.isNil(mid) || _.isNil(type)) return send.deny(); + + const record = (await DB.FindOne(refid, { + collection: 'music', + mid, + type, + })) || { + collection: 'music', + mid, + type, + score: 0, + clear: 0, + grade: 0, + buttonRate: 0, + longRate: 0, + volRate: 0, + }; + + const score = $(data).attr().score ? parseInt($(data).attr().score) : 0; + const clear = $(data).attr().clear_type ? parseInt($(data).attr().clear_type) : 0; + const grade = $(data).attr().score_grade ? parseInt($(data).attr().score_grade) : 0; + if (score > record.score) { + record.score = score; + } + + record.clear = Math.max(clear, record.clear); + record.grade = Math.max(grade, record.grade); + + await DB.Upsert( + refid, + { collection: 'music', mid, type }, + record + ); + + return send.success(); + } catch { + return send.deny(); + } + } + const mid = $(data).number('music_id'); const type = $(data).number('music_type'); @@ -103,7 +170,7 @@ export const saveScore: EPR = async (info, data, send) => { record ); - send.success(); + return send.success(); }; export const saveCourse: EPR = async (info, data, send) => { @@ -134,16 +201,47 @@ export const saveCourse: EPR = async (info, data, send) => { } ); - send.success(); + return send.success(); }; export const save: EPR = async (info, data, send) => { - const refid = $(data).str('refid'); + const refid = $(data).str('refid', $(data).attr().refid); if (!refid) return send.deny(); const version = getVersion(info); if (version == 0) return send.deny(); + if (version === 1) { + try { + // Save Profile + await DB.Update( + refid, + { collection: 'profile' }, + { + $set: { + headphone: $(data).number('headphone'), + hiSpeed: $(data).number('hispeed'), + appeal: $(data).number('appeal_id'), + boothFrame: [$(data).number('frame0'), $(data).number('frame1'), $(data).number('frame2'), $(data).number('frame3'), $(data).number('frame4')], + musicID: parseInt($(data).attr("last").music_id), + musicType: parseInt($(data).attr("last").music_type), + sortType: parseInt($(data).attr("last").sort_type), + mUserCnt: $(data).number('m_user_cnt'), + }, + $inc: { + expPoint: $(data).number('gain_exp'), + packets: $(data).number('earned_gamecoin_packet'), + blocks: $(data).number('earned_gamecoin_block'), + }, + } + ); + + return send.success(); + } catch { + return send.deny(); + } + } + // Save Profile await DB.Update( refid, @@ -226,11 +324,11 @@ export const save: EPR = async (info, data, send) => { } ); - send.success(); + return send.success(); }; export const load: EPR = async (info, data, send) => { - const refid = $(data).str('refid'); + const refid = $(data).str('refid', $(data).attr().dataid); if (!refid) return send.deny(); const version = getVersion(info); @@ -241,8 +339,8 @@ export const load: EPR = async (info, data, send) => { }); if (!profile) { - send.object({ result: K.ITEM('u8', 1) }); - return; + if (version === 1) return send.object(K.ATTR({ none: "1" })); + return send.object({ result: K.ITEM('u8', 1) }); } let skill = (await DB.FindOne(refid, { @@ -263,7 +361,11 @@ export const load: EPR = async (info, data, send) => { const currentTime = time.getTime(); const mixes = version == 5 ? await getAutomationMixes(params) : []; - send.pugFile('templates/load.pug', { + if (version === 1) { + return send.pugFile('templates/booth/load.pug', { code: IDToCode(profile.id), ...profile }); + } + + return send.pugFile('templates/load.pug', { courses, items: U.GetConfig('unlock_all_navigators') ? unlockNavigators(items) @@ -279,10 +381,10 @@ export const load: EPR = async (info, data, send) => { }; export const create: EPR = async (info, data, send) => { - const refid = $(data).str('refid'); + const refid = $(data).str('refid', $(data).attr().refid); if (!refid) return send.deny(); - const name = $(data).str('name', 'GUEST'); + const name = $(data).str('name', $(data).attr().name ? $(data).attr().name : 'GUEST'); let id = _.random(0, 99999999); while (await DB.FindOne(null, { collecttion: 'profile', id })) { id = _.random(0, 99999999); @@ -314,10 +416,13 @@ export const create: EPR = async (info, data, send) => { musicID: 0, musicType: 0, sortType: 0, + expPoint: 0, + mUserCnt: 0, + boothFrame: [0, 0, 0, 0, 0] }; await DB.Upsert(refid, { collection: 'profile' }, profile); - send.object({ result: K.ITEM('u8', 0) }); + return send.object({ result: K.ITEM('u8', 0) }); }; export const buy: EPR = async (info, data, send) => { @@ -356,11 +461,11 @@ export const buy: EPR = async (info, data, send) => { ); } - send.object({ + return send.object({ gamecoin_packet: K.ITEM('u32', updated.docs[0].packets), gamecoin_block: K.ITEM('u32', updated.docs[0].blocks), }); } else { - send.success(); + return send.success(); } }; diff --git a/sdvx@asphyxia/index.ts b/sdvx@asphyxia/index.ts index a34cb75..0e23872 100644 --- a/sdvx@asphyxia/index.ts +++ b/sdvx@asphyxia/index.ts @@ -1,5 +1,5 @@ -import { common } from './handlers/common'; -import { hiscore, rival, saveMix, loadMix } from './handlers/features'; +import {common} from './handlers/common'; +import {hiscore, rival, saveMix, loadMix} from './handlers/features'; import { updateProfile, updateMix, @@ -29,6 +29,7 @@ export function register() { const MultiRoute = (method: string, handler: EPR | boolean) => { // Helper for register multiple versions. + R.Route(`game.${method}`, handler); R.Route(`game.sv4_${method}`, handler); R.Route(`game.sv5_${method}`, handler); }; @@ -53,8 +54,12 @@ export function register() { MultiRoute('load_ap', loadMix); // Lazy - MultiRoute('lounge', false); - MultiRoute('shop', true); + MultiRoute('lounge', (_, __, send) => send.object({ + interval: K.ITEM('u32', 30) + })); + MultiRoute('shop', (_, __, send) => send.object({ + nxt_time: K.ITEM('u32', 1000 * 5 * 60) + })); MultiRoute('save_e', true); MultiRoute('play_e', true); MultiRoute('play_s', true); diff --git a/sdvx@asphyxia/models/profile.ts b/sdvx@asphyxia/models/profile.ts index 045fb67..e10e995 100644 --- a/sdvx@asphyxia/models/profile.ts +++ b/sdvx@asphyxia/models/profile.ts @@ -11,6 +11,9 @@ export interface Profile { packets: number; blocks: number; + expPoint: number; + mUserCnt: number; + musicID: number; musicType: number; sortType: number; @@ -28,4 +31,6 @@ export interface Profile { effCLeft: number; effCRight: number; narrowDown: number; + + boothFrame: number[]; } diff --git a/sdvx@asphyxia/templates/booth/common.pug b/sdvx@asphyxia/templates/booth/common.pug new file mode 100644 index 0000000..6882290 --- /dev/null +++ b/sdvx@asphyxia/templates/booth/common.pug @@ -0,0 +1,16 @@ +- let music = 0; +- let event = 0; +- let catalog = 0; + +game + limited + while music < 200 + music(id=music++, flag=2) + + event + while event < 16 + info(id=event++) + + catalog + while catalog < 256 + info(id=catalog++, currency=1, price=1) diff --git a/sdvx@asphyxia/templates/booth/load.pug b/sdvx@asphyxia/templates/booth/load.pug new file mode 100644 index 0000000..3562737 --- /dev/null +++ b/sdvx@asphyxia/templates/booth/load.pug @@ -0,0 +1,23 @@ +game + name(__type="str") #{name} + code(__type="str") #{code} + gamecoin_packet(__type="u32") #{packets} + gamecoin_block(__type="u32") #{blocks} + exp_point(__type="u32") #{expPoint ? expPoint : 0} + m_user_cnt(__type="u32") #{mUserCnt ? mUserCnt : 0} + have_item(__type="bool" __count=512) #{Array(512).fill(1).join(" ")} + have_note(__type="bool" __count=512) #{Array(512).fill(1).join(" ")} + + last( + music_id=musicID, + music_type=musicType, + sort_type=sortType, + headphone=headphone, + hispeed=hiSpeed, + appeal_id=appeal, + frame0=boothFrame ? boothFrame[0] : 0, + frame1=boothFrame ? boothFrame[1] : 0, + frame2=boothFrame ? boothFrame[2] : 0, + frame3=boothFrame ? boothFrame[3] : 0, + frame4=boothFrame ? boothFrame[4] : 0, + ) diff --git a/sdvx@asphyxia/utils.ts b/sdvx@asphyxia/utils.ts index 3fd5e88..93010c7 100644 --- a/sdvx@asphyxia/utils.ts +++ b/sdvx@asphyxia/utils.ts @@ -1,4 +1,5 @@ -import { Counter } from './models/counter'; +import {Counter} from './models/counter'; + export function IDToCode(id: number) { const padded = _.padStart(id.toString(), 8); return `${padded.slice(0, 4)}-${padded.slice(4)}`; @@ -12,3 +13,11 @@ export async function GetCounter(key: string) { ) ).docs[0].value; } + +export function getVersion(info: EamuseInfo) { + const dateCode = parseInt(info.model.split(":")[4]); + if (dateCode <= 2013052900) return 1; + if (info.method.startsWith('sv4')) return 4; + if (info.method.startsWith('sv5')) return 5; + return 0; +}