[sdvx] score saving

This commit is contained in:
Freddie 2020-05-30 02:48:58 +01:00
parent 3a1952a478
commit 510453ce09
6 changed files with 147 additions and 57 deletions

16
asphyxia-core.d.ts vendored
View File

@ -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<T> = Partial<T> & {
* 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<T> = Partial<T> & {
* There will be 16 profiles maximum which is small enough to manage.
*/
declare namespace DB {
function FindOne<T>(refid: string, query: Query<T>): Promise<Doc<T>>;
function FindOne<T>(refid: string | null, query: Query<T>): Promise<Doc<T>>;
function FindOne<T>(query: Query<T>): Promise<Doc<T>>;
function Find<T>(refid: string | null, query: Query<T>): Promise<Doc<T>[]>;
@ -1029,3 +1029,9 @@ declare namespace DB {
function Count<T>(refid: string | null, query: Query<T>): Promise<number>;
function Count<T>(query: Query<T>): Promise<number>;
}
/** @ignore */
declare namespace _ {}
/** @ignore */
declare const _: any;
/// <reference types="lodash" />

View File

@ -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"
}
}

View File

@ -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<MusicRecord>(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<MusicRecord>(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<MusicRecord>(
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<Profile>(
refid,
@ -47,21 +133,29 @@ export const save: EPR = async (info, data, send) => {
}
);
await DB.Upsert<VersionData>(
{
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<Profile>(refid, {
collection: 'profile',
@ -74,19 +168,9 @@ export const load: EPR = async (info, data, send) => {
let versionData = await DB.FindOne<VersionData>(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<CourseRecord>(refid, { collection: 'course' });
const items = await DB.Find<Item>(refid, { collection: 'item' });
const params = await DB.Find<Param>(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 = {

View File

@ -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();
}

View File

@ -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

View File

@ -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