diff --git a/asphyxia-core.d.ts b/asphyxia-core.d.ts index 2285c0d..7d1bda3 100644 --- a/asphyxia-core.d.ts +++ b/asphyxia-core.d.ts @@ -81,7 +81,7 @@ declare interface EamuseInfo { /** * Detail of a config */ -declare interface CONFIG_OPTIONS { +declare interface ConfigOption { /** Provide a name to display in webui. If not provided, webui will use key as the name. */ name?: string; /** Provide a description for the option */ @@ -288,11 +288,11 @@ declare namespace R { * Register a configuration option. * * @param key config key - * @param options See [[CONFIG_OPTIONS]] + * @param options See [[ConfigOption]] * * __NOTE__: `options.validator` will only notify user about invalid value. It wouldn't stop user from saving invalid value. */ - function Config(key: string, options: CONFIG_OPTIONS): void; + function Config(key: string, options: ConfigOption): void; /** * Register a WebUI event callback @@ -967,7 +967,7 @@ type Update = Partial & { * If `refid` is a string, query will match a specific profile data in __ProfileSpace__. * * If `refid` is null, query will match all profile data in __ProfileSpace__. - * (doesn't apply to [[DB.FindOne]] and [[DB.Insert]]) + * (doesn't apply to [[DB.Insert]]) * * If `refid` is not provided, query will match data in ___PluginSpace___. * @@ -980,7 +980,7 @@ type Update = Partial & { * There will be 16 profiles maximum which is small enough to manage. */ declare namespace DB { - function FindOne(refid: string, query: Query): Promise>; + function FindOne(refid: string | null, query: Query): Promise>; function FindOne(query: Query): Promise>; function Find(refid: string | null, query: Query): Promise[]>; @@ -1029,3 +1029,9 @@ declare namespace DB { function Count(refid: string | null, query: Query): Promise; function Count(query: Query): Promise; } + +/** @ignore */ +declare namespace _ {} +/** @ignore */ +declare const _: any; +/// diff --git a/package.json b/package.json index ee9b16b..49a269e 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "name": "asphyxia-plugins", "version": "1.0.0", "description": "Community Plugins for Asphyxia CORE", - "dependencies": {}, - "devDependencies": { + "dependencies": { + "@types/lodash": "^4.14.153", "@types/node": "^14.0.5" } } diff --git a/sdvx@asphyxia/handlers/profile.ts b/sdvx@asphyxia/handlers/profile.ts index 290f3ee..f2f5f74 100644 --- a/sdvx@asphyxia/handlers/profile.ts +++ b/sdvx@asphyxia/handlers/profile.ts @@ -4,16 +4,102 @@ import { SDVX_AUTOMATION_SONGS } from '../data/vvw'; import { CourseRecord } from '../models/course_record'; import { Item } from '../models/item'; import { Param } from '../models/param'; +import { MusicRecord } from '../models/music_record'; + +function getVersion(info: EamuseInfo) { + if (info.module == 'game_3') return 0; + if (info.method.startsWith('sv4')) return 4; + if (info.method.startsWith('sv5')) return 5; + return 0; +} export const loadScores: EPR = async (info, data, send) => { const refid = $(data).str('refid'); - const records = await DB.Find(refid, { collection: 'music' }); + if (!refid) return send.deny(); - send.pugFile('templates/load_m.pug', { records }); + const records = await DB.Find(refid, { collection: 'music' }); + + send.object({ + music: { + info: records.map(r => ({ + param: K.ARRAY('u32', [ + r.mid, + r.type, + r.score, + r.clear, + r.grade, + 0, + 0, + r.buttonRate, + r.longRate, + r.volRate, + 0, + 0, + 0, + 0, + 0, + 0, + ]), + })), + }, + }); +}; + +export const saveScores: EPR = async (info, data, send) => { + const refid = $(data).str('refid'); + if (!refid) return send.deny(); + + const musicID = $(data).number('music_id'); + const musicType = $(data).number('music_type'); + + if (musicID == null || musicType == null) return send.deny(); + + const record = (await DB.FindOne(refid, { + collection: 'music', + mid: musicID, + type: musicType, + })) || { + collection: 'music', + mid: musicID, + type: musicType, + score: 0, + clear: 0, + grade: 0, + buttonRate: 0, + longRate: 0, + volRate: 0, + }; + + const score = $(data).number('score', 0); + if (score > record.score) { + record.score = score; + record.buttonRate = $(data).number('btn_rate', 0); + record.longRate = $(data).number('long_rate', 0); + record.volRate = $(data).number('vol_rate', 0); + } + + record.clear = Math.max($(data).number('clear_type', 0), record.clear); + record.grade = Math.max($(data).number('score_grade', 0), record.grade); + + await DB.Upsert( + refid, + { + collection: 'music', + mid: musicID, + type: musicType, + }, + record + ); + + send.success(); }; export const save: EPR = async (info, data, send) => { const refid = $(data).str('refid'); + if (!refid) return send.deny(); + + const version = getVersion(info); + if (version == 0) return send.deny(); await DB.Update( refid, @@ -47,21 +133,29 @@ export const save: EPR = async (info, data, send) => { } ); + await DB.Upsert( + { + collection: 'version', + version, + }, + { + $set: { + skillBase: $(data).number('skill_base_id'), + skillLevel: $(data).number('skill_level'), + skillName: $(data).number('skill_name_id'), + }, + } + ); + send.success(); }; export const load: EPR = async (info, data, send) => { const refid = $(data).str('refid'); + if (!refid) return send.deny(); - let version = 0; - switch (info.method) { - case 'sv4_load': - version = 4; - break; - case 'sv5_load': - version = 5; - break; - } + const version = getVersion(info); + if (version == 0) return send.deny(); const profile = await DB.FindOne(refid, { collection: 'profile', @@ -74,19 +168,9 @@ export const load: EPR = async (info, data, send) => { let versionData = await DB.FindOne(refid, { collection: 'version', + version, }); - if (!versionData) { - versionData = { - collection: 'version', - version, - skillBase: 0, - skillLevel: 0, - skillName: 0, - }; - await DB.Insert(refid, versionData); - } - const courses = await DB.Find(refid, { collection: 'course' }); const items = await DB.Find(refid, { collection: 'item' }); const params = await DB.Find(refid, { collection: 'param' }); @@ -103,6 +187,8 @@ export const load: EPR = async (info, data, send) => { export const create: EPR = async (info, data, send) => { const refid = $(data).str('refid'); + if (!refid) return send.deny(); + const name = $(data).str('name', 'GUEST'); const profile: Profile = { diff --git a/sdvx@asphyxia/index.ts b/sdvx@asphyxia/index.ts index 9fc930c..5373b5b 100644 --- a/sdvx@asphyxia/index.ts +++ b/sdvx@asphyxia/index.ts @@ -1,19 +1,32 @@ import { common } from './handlers/common'; -import { load, create, loadScores, save } from './handlers/profile'; +import { load, create, loadScores, save, saveScores } from './handlers/profile'; + export function register() { R.GameCode('KFC'); R.Config('unlock_all_songs', { type: 'boolean', default: false }); R.Config('unlock_all_navigators', { type: 'boolean', default: false }); - R.Route('game.sv4_common', common); - R.Route('game.sv4_load', load); - R.Route('game.sv4_load_m', loadScores); - R.Route('game.sv4_new', create); - R.Route('game.sv4_frozen', true); - R.Route('game.sv4_load_r', true); - R.Route('game.sv4_save', save); - R.Route('game.sv4_save_m', true); + const MultiRoute = (method: string, handler: EPR | boolean) => { + // Helper for register multiple versions. + R.Route(`game.sv4_${method}`, handler); + R.Route(`game.sv5_${method}`, handler); + }; - R.Route('game.sv5_common', common); + // Common + MultiRoute('common', common); + + // Profile + MultiRoute('new', create); + MultiRoute('load', load); + MultiRoute('load_m', loadScores); + MultiRoute('load_r', true); + MultiRoute('save', save); + MultiRoute('save_m', saveScores); + MultiRoute('frozen', true); + + // Useless + MultiRoute('lounge', false); + + R.Unhandled(); } diff --git a/sdvx@asphyxia/templates/load.pug b/sdvx@asphyxia/templates/load.pug index 4c561a8..70fc1e6 100644 --- a/sdvx@asphyxia/templates/load.pug +++ b/sdvx@asphyxia/templates/load.pug @@ -26,9 +26,9 @@ game narrow_down(__type="u8") #{narrowDown} kac_id(__type="str") #{name} - skill_level(__type="s16") #{skillLevel} - skill_base_id(__type="s16") #{skillBase} - skill_name_id(__type="s16") #{skillName} + skill_level(__type="s16") #{skillLevel || 0} + skill_base_id(__type="s16") #{skillBase || 0} + skill_name_id(__type="s16") #{skillName || 0} ea_shop packet_booster(__type="s32") 1 diff --git a/sdvx@asphyxia/templates/load_m.pug b/sdvx@asphyxia/templates/load_m.pug deleted file mode 100644 index 9abf807..0000000 --- a/sdvx@asphyxia/templates/load_m.pug +++ /dev/null @@ -1,15 +0,0 @@ -game - music - for record in records - info - param(__type="u32" __count="16") - | #{record.mid} - | #{record.type} - | #{record.score} - | #{record.type} - | #{record.grade} - | 0 0 - | #{record.buttonRate} - | #{record.longRate} - | #{record.volRate} - | 0 0 0 0 0 0 \ No newline at end of file