mirror of
https://github.com/asphyxia-core/plugins.git
synced 2026-03-21 17:34:46 -05:00
mix
This commit is contained in:
parent
510453ce09
commit
0a35d3f544
126
asphyxia-core.d.ts
vendored
126
asphyxia-core.d.ts
vendored
|
|
@ -1,4 +1,5 @@
|
|||
/// <reference types="node" />
|
||||
/// <reference types="lodash" />
|
||||
|
||||
declare type KNumberType =
|
||||
| 's8'
|
||||
|
|
@ -657,6 +658,54 @@ declare namespace $ {
|
|||
function STR(data: any, path: string, def?: string): string;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare interface KITEM<
|
||||
S extends
|
||||
| KNumberType
|
||||
| KBigIntType
|
||||
| KNumberGroupType
|
||||
| KBigIntGroupType
|
||||
| 'str'
|
||||
| 'bool'
|
||||
| 'bin'
|
||||
| 'ip4'
|
||||
> {
|
||||
'@attr': {
|
||||
__type: S;
|
||||
};
|
||||
'@content': S extends 'str'
|
||||
? string
|
||||
: S extends 'bin'
|
||||
? Buffer
|
||||
: S extends KNumberType | 'ip4' | 'bool'
|
||||
? [number]
|
||||
: S extends KBigIntType
|
||||
? [bigint]
|
||||
: S extends KNumberGroupType
|
||||
? number[]
|
||||
: S extends KBigIntGroupType
|
||||
? bigint[]
|
||||
: unknown;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare interface KARRAY<S extends KNumberType | KBigIntType> {
|
||||
'@attr': {
|
||||
__count: number;
|
||||
__type: S;
|
||||
};
|
||||
'@content': S extends KNumberType
|
||||
? number[]
|
||||
: S extends KBigIntType
|
||||
? bigint[]
|
||||
: unknown;
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
declare interface KATTR<M> {
|
||||
'@attr': M;
|
||||
}
|
||||
|
||||
/**
|
||||
* K stands for `Konstruct`
|
||||
*
|
||||
|
|
@ -682,7 +731,7 @@ declare namespace K {
|
|||
* @param attr Attribute map
|
||||
* @param inner Inner tag/data
|
||||
*/
|
||||
function ATTR(attr: KAttrMap, inner?: any): any;
|
||||
function ATTR<M extends KAttrMap, T>(attr: M, inner?: T): KATTR<M> & T;
|
||||
|
||||
/**
|
||||
* Example:
|
||||
|
|
@ -699,22 +748,30 @@ declare namespace K {
|
|||
* @param content data of specified type
|
||||
* @param attr attribute map in addition to **__type**
|
||||
*/
|
||||
function ITEM(type: 'str', content: string, attr?: KAttrMap): any;
|
||||
function ITEM(type: 'bin', content: Buffer, attr?: KAttrMap): any;
|
||||
function ITEM(type: 'ip4', content: string, attr?: KAttrMap): any;
|
||||
function ITEM(type: 'bool', content: boolean, attr?: KAttrMap): any;
|
||||
function ITEM(type: KNumberType, content: number, attr?: KAttrMap): any;
|
||||
function ITEM(type: KBigIntType, content: bigint, attr?: KAttrMap): any;
|
||||
function ITEM(
|
||||
type: KNumberGroupType,
|
||||
function ITEM(type: 'str', content: string, attr?: KAttrMap): KITEM<'str'>;
|
||||
function ITEM(type: 'bin', content: Buffer, attr?: KAttrMap): KITEM<'bin'>;
|
||||
function ITEM(type: 'ip4', content: string, attr?: KAttrMap): KITEM<'ip4'>;
|
||||
function ITEM(type: 'bool', content: boolean, attr?: KAttrMap): KITEM<'bool'>;
|
||||
function ITEM<S extends KNumberType>(
|
||||
type: S,
|
||||
content: number,
|
||||
attr?: KAttrMap
|
||||
): KITEM<S>;
|
||||
function ITEM<S extends KBigIntType>(
|
||||
type: S,
|
||||
content: bigint,
|
||||
attr?: KAttrMap
|
||||
): KITEM<S>;
|
||||
function ITEM<S extends KNumberGroupType>(
|
||||
type: S,
|
||||
content: number[],
|
||||
attr?: KAttrMap
|
||||
): any;
|
||||
function ITEM(
|
||||
type: KBigIntGroupType,
|
||||
): KITEM<S>;
|
||||
function ITEM<S extends KBigIntGroupType>(
|
||||
type: S,
|
||||
content: bigint[],
|
||||
attr?: KAttrMap
|
||||
): any;
|
||||
): KITEM<S>;
|
||||
|
||||
/**
|
||||
* Example:
|
||||
|
|
@ -731,9 +788,21 @@ declare namespace K {
|
|||
* @param content array of data, ____count__ attribute will be automatically set to `content.length`
|
||||
* @param attr attribute map in addition to **__type** and **__count**
|
||||
*/
|
||||
function ARRAY(type: 'u8' | 's8', content: Buffer, attr?: KAttrMap): any;
|
||||
function ARRAY(type: KNumberType, content: number[], attr?: KAttrMap): any;
|
||||
function ARRAY(type: KBigIntType, content: bigint[], attr?: KAttrMap): any;
|
||||
function ARRAY<S extends 'u8' | 's8'>(
|
||||
type: S,
|
||||
content: Buffer,
|
||||
attr?: KAttrMap
|
||||
): KARRAY<S>;
|
||||
function ARRAY<S extends KNumberType>(
|
||||
type: S,
|
||||
content: number[],
|
||||
attr?: KAttrMap
|
||||
): KARRAY<S>;
|
||||
function ARRAY<S extends KBigIntType>(
|
||||
type: S,
|
||||
content: bigint[],
|
||||
attr?: KAttrMap
|
||||
): KARRAY<S>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -867,6 +936,8 @@ declare namespace U {
|
|||
/** @ignore */
|
||||
type Doc<T> = { _id?: string } & T;
|
||||
/** @ignore */
|
||||
type ProfileDoc<T> = { _id?: string; __refid?: string } & T;
|
||||
/** @ignore */
|
||||
type Query<T> = {
|
||||
[P in keyof T]?:
|
||||
| T[P]
|
||||
|
|
@ -978,15 +1049,24 @@ type Update<T> = Partial<T> & {
|
|||
*
|
||||
* If you need to make rival/friend feature, we recommend you to get all profile data by passing null to `refid`.
|
||||
* There will be 16 profiles maximum which is small enough to manage.
|
||||
*
|
||||
* All query and doc should not have any fields start with "__" with "__refid" being the only exception.
|
||||
* However, "__refid" field will still be ignored while other "__" starting fields will cause an error to be thrown.
|
||||
*/
|
||||
declare namespace DB {
|
||||
function FindOne<T>(refid: string | null, query: Query<T>): Promise<Doc<T>>;
|
||||
function FindOne<T>(
|
||||
refid: string | null,
|
||||
query: Query<T>
|
||||
): Promise<ProfileDoc<T>>;
|
||||
function FindOne<T>(query: Query<T>): Promise<Doc<T>>;
|
||||
|
||||
function Find<T>(refid: string | null, query: Query<T>): Promise<Doc<T>[]>;
|
||||
function Find<T>(
|
||||
refid: string | null,
|
||||
query: Query<T>
|
||||
): Promise<ProfileDoc<T>[]>;
|
||||
function Find<T>(query: Query<T>): Promise<Doc<T>[]>;
|
||||
|
||||
function Insert<T>(refid: string, doc: T): Promise<Doc<T>>;
|
||||
function Insert<T>(refid: string, doc: T): Promise<ProfileDoc<T>>;
|
||||
function Insert<T>(doc: T): Promise<Doc<T>>;
|
||||
|
||||
function Remove<T>(refid: string | null, query: Query<T>): Promise<number>;
|
||||
|
|
@ -998,7 +1078,7 @@ declare namespace DB {
|
|||
update: Update<T>
|
||||
): Promise<{
|
||||
updated: number;
|
||||
docs: Doc<T>[];
|
||||
docs: ProfileDoc<T>[];
|
||||
}>;
|
||||
function Update<T>(
|
||||
query: Query<T>,
|
||||
|
|
@ -1014,7 +1094,7 @@ declare namespace DB {
|
|||
update: Update<T>
|
||||
): Promise<{
|
||||
updated: number;
|
||||
docs: Doc<T>[];
|
||||
docs: ProfileDoc<T>[];
|
||||
upsert: boolean;
|
||||
}>;
|
||||
function Upsert<T>(
|
||||
|
|
@ -1031,7 +1111,5 @@ declare namespace DB {
|
|||
}
|
||||
|
||||
/** @ignore */
|
||||
declare namespace _ {}
|
||||
/** @ignore */
|
||||
// @ts-ignore
|
||||
declare const _: any;
|
||||
/// <reference types="lodash" />
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export const EVENT5 = [
|
|||
'STANDARD_UNLOCK_ENABLE',
|
||||
'PLAYERJUDGEADJ_ENABLE',
|
||||
'MIXID_INPUT_ENABLE',
|
||||
'SERIALCODE_JAPAN',
|
||||
'EVENTDATE_ONIGO',
|
||||
'EVENTDATE_GOTT',
|
||||
'GENERATOR_ABLE',
|
||||
|
|
@ -2588,7 +2589,18 @@ export const SDVX_AUTOMATION_SONGS = [
|
|||
export const EXTENDS5 = [
|
||||
{
|
||||
id: 91,
|
||||
type: 14,
|
||||
params: [0, 1, 0, 0, 1, SDVX_AUTOMATION_SONGS.join(','), '', '', '', ''],
|
||||
type: 17,
|
||||
params: [
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
SDVX_AUTOMATION_SONGS.join(','),
|
||||
'0',
|
||||
'0',
|
||||
'0',
|
||||
'0',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { EVENT4, COURSES4, EXTENDS4 } from '../data/hvn';
|
||||
import { EVENT5, COURSES5, EXTENDS5 } from '../data/vvw';
|
||||
|
||||
export const common: EPR = async (info, data, send) => {
|
||||
let events = [];
|
||||
let courses = [];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
import { Profile } from '../models/profile';
|
||||
import { MusicRecord } from '../models/music_record';
|
||||
import { IDToCode, GetCounter } from '../utils';
|
||||
import { Mix } from '../models/mix';
|
||||
|
||||
export const hiscore: EPR = async (info, data, send) => {
|
||||
const records = await DB.Find<MusicRecord>(null, { collection: 'music' });
|
||||
|
||||
const profiles = _.groupBy(
|
||||
await DB.Find<Profile>(null, { collection: 'profile' }),
|
||||
'__refid'
|
||||
);
|
||||
|
||||
send.object({
|
||||
sc: {
|
||||
d: _.map(
|
||||
_.groupBy(records, r => {
|
||||
return `${r.mid}:${r.type}`;
|
||||
}),
|
||||
r => _.maxBy(r, 'score')
|
||||
).map(r => ({
|
||||
id: K.ITEM('u32', r.mid),
|
||||
ty: K.ITEM('u32', r.type),
|
||||
a_sq: K.ITEM('str', IDToCode(profiles[r.__refid][0].id)),
|
||||
a_nm: K.ITEM('str', profiles[r.__refid][0].name),
|
||||
a_sc: K.ITEM('u32', r.score),
|
||||
l_sq: K.ITEM('str', IDToCode(profiles[r.__refid][0].id)),
|
||||
l_nm: K.ITEM('str', profiles[r.__refid][0].name),
|
||||
l_sc: K.ITEM('u32', r.score),
|
||||
})),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const rival: EPR = async (info, data, send) => {
|
||||
const refid = $(data).str('refid');
|
||||
if (!refid) return send.deny();
|
||||
|
||||
const rivals = (
|
||||
await DB.Find<Profile>(null, { collection: 'profile' })
|
||||
).filter(p => p.__refid != refid);
|
||||
|
||||
send.object({
|
||||
rival: await Promise.all(
|
||||
rivals.map(async (p, index) => {
|
||||
return {
|
||||
no: K.ITEM('s16', index),
|
||||
seq: K.ITEM('str', IDToCode(p.id)),
|
||||
name: K.ITEM('str', p.name),
|
||||
music: (
|
||||
await DB.Find<MusicRecord>(p.__refid, { collection: 'music' })
|
||||
).map(r => ({
|
||||
param: K.ARRAY('u32', [r.mid, r.type, r.score, r.clear, r.grade]),
|
||||
})),
|
||||
};
|
||||
})
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
export const saveMix: EPR = async (info, data, send) => {
|
||||
const refid = $(data).str('ref_id');
|
||||
if (!refid) return send.deny();
|
||||
|
||||
const profile = await DB.FindOne<Profile>(refid, { collection: 'profile' });
|
||||
if (!profile) return send.deny();
|
||||
|
||||
const mix = $(data).element('automation');
|
||||
|
||||
const id = await GetCounter('mix');
|
||||
let code = _.padStart(_.random(0, 999999999999).toString(), 12, '0');
|
||||
while (await DB.FindOne<Mix>(null, { code })) {
|
||||
code = _.padStart(_.random(0, 999999999999).toString(), 12, '0');
|
||||
}
|
||||
|
||||
const doc = await DB.Insert<Mix>(refid, {
|
||||
collection: 'mix',
|
||||
id,
|
||||
code,
|
||||
name: mix.str('mix_name'),
|
||||
creator: profile.name,
|
||||
param: mix.str('generate_param'),
|
||||
tag: mix.number('tag_bit'),
|
||||
jacket: mix.number('jacket_id'),
|
||||
});
|
||||
|
||||
send.object({
|
||||
automation: {
|
||||
mix_id: K.ITEM('s32', id),
|
||||
mix_code: K.ITEM('str', doc.code),
|
||||
seq: K.ITEM('str', doc.code),
|
||||
mix_name: K.ITEM('str', doc.name),
|
||||
player_name: K.ITEM('str', doc.creator),
|
||||
generate_param: K.ITEM('str', doc.param),
|
||||
distribution_date: K.ITEM('u32', 19990101),
|
||||
jacket_id: K.ITEM('s32', doc.jacket),
|
||||
tag_bit: K.ITEM('s32', doc.tag),
|
||||
like_flg: K.ITEM('bool', 0),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const loadMix: EPR = async (info, data, send) => {
|
||||
const code = $(data).str('mix_code');
|
||||
|
||||
const mix = await DB.FindOne<Mix>(null, { collection: 'mix', code });
|
||||
if (!mix) {
|
||||
send.object({ result: K.ITEM('s32', 1) });
|
||||
return;
|
||||
}
|
||||
|
||||
send.object({
|
||||
automation: {
|
||||
mix_id: K.ITEM('s32', mix.id),
|
||||
mix_code: K.ITEM('str', mix.code),
|
||||
seq: K.ITEM('str', mix.code),
|
||||
mix_name: K.ITEM('str', mix.name),
|
||||
player_name: K.ITEM('str', mix.creator),
|
||||
generate_param: K.ITEM('str', mix.param),
|
||||
distribution_date: K.ITEM('u32', 19990101),
|
||||
jacket_id: K.ITEM('s32', mix.jacket),
|
||||
tag_bit: K.ITEM('s32', mix.tag),
|
||||
like_flg: K.ITEM('bool', 0),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -1,19 +1,35 @@
|
|||
import { Profile } from '../models/profile';
|
||||
import { VersionData } from '../models/version_data';
|
||||
import { Skill } from '../models/skill';
|
||||
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';
|
||||
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.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) => {
|
||||
async function getAutomationMixes(params: Param[]) {
|
||||
const mixids = params
|
||||
.filter(p => p.id == 3)
|
||||
.reduce((res, p) => _.union(res, p.param), []);
|
||||
return await DB.Find<Mix>(null, { collection: 'mix', id: { $in: mixids } });
|
||||
}
|
||||
|
||||
function unlockNavigators(items: Partial<Item>[]) {
|
||||
for (let i = 0; i < 300; ++i) items.push({ type: 11, id: i, param: 15 });
|
||||
|
||||
// 10 genesis card for MITSURU's voice
|
||||
items.push({ type: 4, id: 599, param: 10 });
|
||||
return items;
|
||||
}
|
||||
|
||||
export const loadScore: EPR = async (info, data, send) => {
|
||||
const refid = $(data).str('refid');
|
||||
if (!refid) return send.deny();
|
||||
|
||||
|
|
@ -45,23 +61,23 @@ export const loadScores: EPR = async (info, data, send) => {
|
|||
});
|
||||
};
|
||||
|
||||
export const saveScores: EPR = async (info, data, send) => {
|
||||
export const saveScore: 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');
|
||||
const mid = $(data).number('music_id');
|
||||
const type = $(data).number('music_type');
|
||||
|
||||
if (musicID == null || musicType == null) return send.deny();
|
||||
if (_.isNil(mid) || _.isNil(type)) return send.deny();
|
||||
|
||||
const record = (await DB.FindOne<MusicRecord>(refid, {
|
||||
collection: 'music',
|
||||
mid: musicID,
|
||||
type: musicType,
|
||||
mid,
|
||||
type,
|
||||
})) || {
|
||||
collection: 'music',
|
||||
mid: musicID,
|
||||
type: musicType,
|
||||
mid,
|
||||
type,
|
||||
score: 0,
|
||||
clear: 0,
|
||||
grade: 0,
|
||||
|
|
@ -83,17 +99,44 @@ export const saveScores: EPR = async (info, data, send) => {
|
|||
|
||||
await DB.Upsert<MusicRecord>(
|
||||
refid,
|
||||
{
|
||||
collection: 'music',
|
||||
mid: musicID,
|
||||
type: musicType,
|
||||
},
|
||||
{ collection: 'music', mid, type },
|
||||
record
|
||||
);
|
||||
|
||||
send.success();
|
||||
};
|
||||
|
||||
export const saveCourse: 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();
|
||||
|
||||
const sid = $(data).number('ssnid');
|
||||
const cid = $(data).number('crsid');
|
||||
|
||||
if (_.isNil(sid) || _.isNil(cid)) return send.deny();
|
||||
|
||||
await DB.Upsert<CourseRecord>(
|
||||
refid,
|
||||
{ collection: 'course', sid, cid, version },
|
||||
{
|
||||
$max: {
|
||||
score: $(data).number('sc', 0),
|
||||
clear: $(data).number('ct', 0),
|
||||
grade: $(data).number('gr', 0),
|
||||
rate: $(data).number('ar', 0),
|
||||
},
|
||||
$inc: {
|
||||
count: 1,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
send.success();
|
||||
};
|
||||
|
||||
export const save: EPR = async (info, data, send) => {
|
||||
const refid = $(data).str('refid');
|
||||
if (!refid) return send.deny();
|
||||
|
|
@ -101,6 +144,7 @@ export const save: EPR = async (info, data, send) => {
|
|||
const version = getVersion(info);
|
||||
if (version == 0) return send.deny();
|
||||
|
||||
// Save Profile
|
||||
await DB.Update<Profile>(
|
||||
refid,
|
||||
{ collection: 'profile' },
|
||||
|
|
@ -133,16 +177,51 @@ export const save: EPR = async (info, data, send) => {
|
|||
}
|
||||
);
|
||||
|
||||
await DB.Upsert<VersionData>(
|
||||
// Save Items
|
||||
const items = $(data).elements('item.info');
|
||||
|
||||
for (const i of items) {
|
||||
const type = i.number('type');
|
||||
const id = i.number('id');
|
||||
const param = i.number('param');
|
||||
|
||||
if (_.isNil(type) || _.isNil(id) || _.isNil(param)) continue;
|
||||
|
||||
await DB.Upsert<Item>(
|
||||
refid,
|
||||
{ collection: 'item', type, id },
|
||||
{ $set: { param } }
|
||||
);
|
||||
}
|
||||
|
||||
// Save Param
|
||||
const params = $(data).elements('param.info');
|
||||
for (const p of params) {
|
||||
const type = p.number('type');
|
||||
const id = p.number('id');
|
||||
const param = p.numbers('param');
|
||||
|
||||
if (_.isNil(type) || _.isNil(id) || _.isNil(param)) continue;
|
||||
|
||||
await DB.Upsert<Param>(
|
||||
refid,
|
||||
{ collection: 'param', type, id },
|
||||
{ $set: { param } }
|
||||
);
|
||||
}
|
||||
|
||||
// Save version specific data
|
||||
await DB.Upsert<Skill>(
|
||||
refid,
|
||||
{
|
||||
collection: 'version',
|
||||
collection: 'skill',
|
||||
version,
|
||||
},
|
||||
{
|
||||
$set: {
|
||||
skillBase: $(data).number('skill_base_id'),
|
||||
skillLevel: $(data).number('skill_level'),
|
||||
skillName: $(data).number('skill_name_id'),
|
||||
base: $(data).number('skill_base_id'),
|
||||
level: $(data).number('skill_level'),
|
||||
name: $(data).number('skill_name_id'),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
|
@ -166,22 +245,28 @@ export const load: EPR = async (info, data, send) => {
|
|||
return;
|
||||
}
|
||||
|
||||
let versionData = await DB.FindOne<VersionData>(refid, {
|
||||
collection: 'version',
|
||||
let skill = (await DB.FindOne<Skill>(refid, {
|
||||
collection: 'skill',
|
||||
version,
|
||||
});
|
||||
})) || { base: 0, name: 0, level: 0 };
|
||||
|
||||
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' });
|
||||
|
||||
const mixes = version == 5 ? await getAutomationMixes(params) : [];
|
||||
|
||||
send.pugFile('templates/load.pug', {
|
||||
courses,
|
||||
items,
|
||||
items: U.GetConfig('unlock_all_navigators')
|
||||
? unlockNavigators(items)
|
||||
: items,
|
||||
params,
|
||||
mixes: version == 5 ? SDVX_AUTOMATION_SONGS : [],
|
||||
skill,
|
||||
mixes,
|
||||
automation: version == 5 ? SDVX_AUTOMATION_SONGS : [],
|
||||
code: IDToCode(profile.id),
|
||||
...profile,
|
||||
...versionData,
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -190,11 +275,16 @@ export const create: EPR = async (info, data, send) => {
|
|||
if (!refid) return send.deny();
|
||||
|
||||
const name = $(data).str('name', 'GUEST');
|
||||
let id = _.random(0, 99999999);
|
||||
while (await DB.FindOne<Profile>(null, { collecttion: 'profile', id })) {
|
||||
id = _.random(0, 99999999);
|
||||
}
|
||||
|
||||
const profile: Profile = {
|
||||
pluginVer: 1,
|
||||
|
||||
collection: 'profile',
|
||||
id,
|
||||
name,
|
||||
appeal: 0,
|
||||
akaname: 0,
|
||||
|
|
@ -221,3 +311,48 @@ export const create: EPR = async (info, data, send) => {
|
|||
await DB.Upsert(refid, { collection: 'profile' }, profile);
|
||||
send.object({ result: K.ITEM('u8', 0) });
|
||||
};
|
||||
|
||||
export const buy: EPR = async (info, data, send) => {
|
||||
const refid = $(data).str('refid');
|
||||
if (!refid) return send.deny();
|
||||
|
||||
const growth = {
|
||||
blocks: $(data).number('earned_gamecoin_block', 0),
|
||||
packets: $(data).number('earned_gamecoin_packet', 0),
|
||||
};
|
||||
|
||||
const currency = $(data).bool('currency_type') ? 'blocks' : 'packets';
|
||||
|
||||
const cost = _.sum($(data).numbers('item.price', []));
|
||||
const balanceChange = growth[currency] - cost;
|
||||
|
||||
const updated = await DB.Update<Profile>(
|
||||
refid,
|
||||
{ collection: 'profile', [currency]: { $gte: -balanceChange } },
|
||||
{ $inc: { [currency]: balanceChange } }
|
||||
);
|
||||
|
||||
if (updated.updated) {
|
||||
const items = _.zipWith(
|
||||
$(data).numbers('item.item_type', []),
|
||||
$(data).numbers('item.item_id', []),
|
||||
$(data).numbers('item.param', []),
|
||||
(type, id, param) => ({ type, id, param })
|
||||
);
|
||||
|
||||
for (const item of items) {
|
||||
await DB.Upsert<Item>(
|
||||
refid,
|
||||
{ collection: 'item', type: item.type, id: item.id },
|
||||
{ $set: { param: item.param } }
|
||||
);
|
||||
}
|
||||
|
||||
send.object({
|
||||
gamecoin_packet: K.ITEM('u32', updated.docs[0].packets),
|
||||
gamecoin_block: K.ITEM('u32', updated.docs[0].blocks),
|
||||
});
|
||||
} else {
|
||||
send.success();
|
||||
}
|
||||
};
|
||||
|
|
@ -1,5 +1,14 @@
|
|||
import { common } from './handlers/common';
|
||||
import { load, create, loadScores, save, saveScores } from './handlers/profile';
|
||||
import { hiscore, rival, saveMix, loadMix } from './handlers/features';
|
||||
import {
|
||||
load,
|
||||
create,
|
||||
loadScore,
|
||||
save,
|
||||
saveScore,
|
||||
saveCourse,
|
||||
buy,
|
||||
} from './handlers/profiles';
|
||||
|
||||
export function register() {
|
||||
R.GameCode('KFC');
|
||||
|
|
@ -19,14 +28,29 @@ export function register() {
|
|||
// Profile
|
||||
MultiRoute('new', create);
|
||||
MultiRoute('load', load);
|
||||
MultiRoute('load_m', loadScores);
|
||||
MultiRoute('load_r', true);
|
||||
MultiRoute('load_m', loadScore);
|
||||
MultiRoute('save', save);
|
||||
MultiRoute('save_m', saveScores);
|
||||
MultiRoute('save_m', saveScore);
|
||||
MultiRoute('save_c', saveCourse);
|
||||
MultiRoute('frozen', true);
|
||||
MultiRoute('buy', buy);
|
||||
|
||||
// Useless
|
||||
// Features
|
||||
MultiRoute('hiscore', hiscore);
|
||||
MultiRoute('load_r', rival);
|
||||
MultiRoute('save_ap', saveMix);
|
||||
MultiRoute('load_ap', loadMix);
|
||||
|
||||
// Lazy
|
||||
MultiRoute('lounge', false);
|
||||
MultiRoute('shop', true);
|
||||
MultiRoute('save_e', true);
|
||||
MultiRoute('play_e', true);
|
||||
MultiRoute('play_s', true);
|
||||
MultiRoute('entry_s', true);
|
||||
MultiRoute('entry_e', true);
|
||||
MultiRoute('exception', true);
|
||||
R.Route('eventlog.write', true);
|
||||
|
||||
R.Unhandled();
|
||||
}
|
||||
|
|
|
|||
6
sdvx@asphyxia/models/counter.ts
Normal file
6
sdvx@asphyxia/models/counter.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export interface Counter {
|
||||
collection: 'counter';
|
||||
|
||||
key: string;
|
||||
value: number;
|
||||
}
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
export interface CourseRecord {
|
||||
collection: 'course';
|
||||
|
||||
version: number;
|
||||
|
||||
sid: number;
|
||||
cid: number;
|
||||
score: number;
|
||||
clearType: number;
|
||||
clear: number;
|
||||
grade: number;
|
||||
achieveRate: number;
|
||||
playCount: number;
|
||||
rate: number;
|
||||
count: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
export interface Item {
|
||||
collection: 'item';
|
||||
|
||||
type: number;
|
||||
id: number;
|
||||
param: number;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
export interface Mix {
|
||||
collection: 'mix';
|
||||
|
||||
id: number;
|
||||
code: string;
|
||||
name: string;
|
||||
creator: string;
|
||||
param: string;
|
||||
jacket: number;
|
||||
tag: number;
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ export interface Profile {
|
|||
|
||||
pluginVer: number;
|
||||
|
||||
id: number;
|
||||
name: string;
|
||||
appeal: number;
|
||||
akaname: number;
|
||||
|
|
|
|||
9
sdvx@asphyxia/models/skill.ts
Normal file
9
sdvx@asphyxia/models/skill.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export interface Skill {
|
||||
collection: 'skill';
|
||||
|
||||
version: number;
|
||||
|
||||
level: number;
|
||||
base: number;
|
||||
name: number;
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
// Version specific data (e.g. skills level)
|
||||
export interface VersionData {
|
||||
collection: 'version';
|
||||
|
||||
version: number;
|
||||
|
||||
skillLevel: number;
|
||||
skillBase: number;
|
||||
skillName: number;
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
game
|
||||
result(__type="u8") 0
|
||||
name(__type="str") #{name}
|
||||
code(__type="str") 1337-6666
|
||||
sdvx_id(__type="str") 1337-6666
|
||||
code(__type="str") #{code}
|
||||
sdvx_id(__type="str") #{code}
|
||||
gamecoin_packet(__type="u32") #{packets}
|
||||
gamecoin_block(__type="u32") #{blocks}
|
||||
appeal_id(__type="u16") #{appeal}
|
||||
|
|
@ -26,10 +26,11 @@ game
|
|||
narrow_down(__type="u8") #{narrowDown}
|
||||
|
||||
kac_id(__type="str") #{name}
|
||||
skill_level(__type="s16") #{skillLevel || 0}
|
||||
skill_base_id(__type="s16") #{skillBase || 0}
|
||||
skill_name_id(__type="s16") #{skillName || 0}
|
||||
|
||||
skill_level(__type="s16") #{skill.level}
|
||||
skill_base_id(__type="s16") #{skill.base}
|
||||
skill_name_id(__type="s16") #{skill.name}
|
||||
|
||||
ea_shop
|
||||
packet_booster(__type="s32") 1
|
||||
if version != 5
|
||||
|
|
@ -47,10 +48,10 @@ game
|
|||
ssnid(__type="s16") #{course.sid}
|
||||
crsid(__type="s16") #{course.cid}
|
||||
sc(__type="s32") #{course.score}
|
||||
ct(__type="s16") #{course.clearType}
|
||||
ct(__type="s16") #{course.clear}
|
||||
gr(__type="s16") #{course.grade}
|
||||
ar(__type="s16") #{course.achieveRate}
|
||||
cnt(__type="s16") #{course.playCount}
|
||||
ar(__type="s16") #{course.rate}
|
||||
cnt(__type="s16") #{course.count}
|
||||
|
||||
item
|
||||
each item in items
|
||||
|
|
@ -60,7 +61,7 @@ game
|
|||
param(__type="u32") #{item.param}
|
||||
|
||||
//- Unlock automation songs
|
||||
each song in mixes
|
||||
each song in automation
|
||||
info
|
||||
type(__type="u8") 15
|
||||
id(__type="u32") #{song}
|
||||
|
|
@ -69,9 +70,9 @@ game
|
|||
param
|
||||
each param in params
|
||||
info
|
||||
type(__type="u8") #{param.type}
|
||||
id(__type="u32") #{param.id}
|
||||
param(__type="u32" __count=param.param.length) #{param.param.join(" ")}
|
||||
type(__type="s32") #{param.type}
|
||||
id(__type="s32") #{param.id}
|
||||
param(__type="s32" __count=param.param.length) #{param.param.join(" ")}
|
||||
|
||||
//- Akaname
|
||||
each id in [0, 1, 2]
|
||||
|
|
@ -99,7 +100,7 @@ game
|
|||
mix_name(__type="str") #{mix.name}
|
||||
player_name(__type="str") #{mix.creator}
|
||||
generate_param(__type="str") #{mix.param}
|
||||
distribution_date(__type="u32") 19990101
|
||||
jacket_id(__type="s32") #{mix.jacketID}
|
||||
distribution_date(__type="u32") 20200101
|
||||
jacket_id(__type="s32") #{mix.jacket}
|
||||
tag_bit(__type="s32") #{mix.tag}
|
||||
like_flg(__type="u8") 0
|
||||
14
sdvx@asphyxia/utils.ts
Normal file
14
sdvx@asphyxia/utils.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { Counter } from './models/counter';
|
||||
export function IDToCode(id: number) {
|
||||
const padded = _.padStart(id.toString(), 8);
|
||||
return `${padded.slice(0, 4)}-${padded.slice(4)}`;
|
||||
}
|
||||
|
||||
export async function GetCounter(key: string) {
|
||||
return (
|
||||
await DB.Upsert<Counter>(
|
||||
{ collection: 'counter', key: 'mix' },
|
||||
{ $inc: { value: 1 } }
|
||||
)
|
||||
).docs[0].value;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user