mirror of
https://github.com/asphyxia-core/plugins.git
synced 2026-04-25 08:07:39 -05:00
Add pnm 23/24 plugin
This commit is contained in:
parent
01016aef8f
commit
10207c1044
18
popn@asphyxia/README.md
Normal file
18
popn@asphyxia/README.md
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Pop'n Music
|
||||||
|
|
||||||
|
Plugin Version: **v1.0.0**
|
||||||
|
|
||||||
|
Supported Versions
|
||||||
|
-------------------
|
||||||
|
- pop'n music 23 Eclale
|
||||||
|
- pop'n music 24 Usagi to Neko to Shōnen no Yume
|
||||||
|
|
||||||
|
Changelog
|
||||||
|
=========
|
||||||
|
1.0.0
|
||||||
|
-----
|
||||||
|
Initial Release.
|
||||||
|
|
||||||
|
TODO
|
||||||
|
====
|
||||||
|
- Import of old Asphyxia data
|
||||||
278
popn@asphyxia/handler/common.ts
Normal file
278
popn@asphyxia/handler/common.ts
Normal file
|
|
@ -0,0 +1,278 @@
|
||||||
|
import { getVersion } from './utils';
|
||||||
|
|
||||||
|
const PHASE23 = [
|
||||||
|
{ id: 0, p: 16 },
|
||||||
|
{ id: 1, p: 3 },
|
||||||
|
{ id: 2, p: 1 },
|
||||||
|
{ id: 3, p: 2 },
|
||||||
|
{ id: 4, p: 1 },
|
||||||
|
{ id: 5, p: 1 },
|
||||||
|
{ id: 6, p: 1 },
|
||||||
|
{ id: 7, p: 4 },
|
||||||
|
{ id: 8, p: 3 },
|
||||||
|
{ id: 9, p: 4 },
|
||||||
|
{ id: 10, p: 4 },
|
||||||
|
{ id: 11, p: 1 },
|
||||||
|
{ id: 13, p: 4 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const PHASE24 = [
|
||||||
|
{ id: 3, p: 1 },
|
||||||
|
// { id: 5, p: 1 },
|
||||||
|
{ id: 6, p: 1 },
|
||||||
|
{ id: 16, p: 1 },
|
||||||
|
{ id: 17, p: 1 },
|
||||||
|
{ id: 18, p: 1 },
|
||||||
|
{ id: 19, p: 1 },
|
||||||
|
{ id: 20, p: 1 },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const getInfo = (req) => {
|
||||||
|
const version = getVersion(req);
|
||||||
|
|
||||||
|
if (version == 'v23') {
|
||||||
|
return getInfo23();
|
||||||
|
} else if (version == 'v24') {
|
||||||
|
return getInfo24();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getInfo23 = () => {
|
||||||
|
const result: any = {
|
||||||
|
phase: [],
|
||||||
|
area: [],
|
||||||
|
goods: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const phase of PHASE23) {
|
||||||
|
result.phase.push({
|
||||||
|
event_id: K.ITEM('s16', phase.id),
|
||||||
|
phase: K.ITEM('s16', phase.p),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 1; i <= 100; ++i) {
|
||||||
|
result.area.push({
|
||||||
|
area_id: K.ITEM('s16', i),
|
||||||
|
end_date: K.ITEM('u64', BigInt(0)),
|
||||||
|
medal_id: K.ITEM('s16', i),
|
||||||
|
is_limit: K.ITEM('bool', 0),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 1; i <= 420; ++i) {
|
||||||
|
result.goods.push({
|
||||||
|
goods_id: K.ITEM('s16', i),
|
||||||
|
price: K.ITEM('s32', i <= 80 ? 60 : 100),
|
||||||
|
goods_type: K.ITEM('s16', 0),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getInfo24 = () => {
|
||||||
|
const result: any = {
|
||||||
|
phase: [],
|
||||||
|
goods: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const phase of PHASE24) {
|
||||||
|
result.phase.push({
|
||||||
|
event_id: K.ITEM('s16', phase.id),
|
||||||
|
phase: K.ITEM('s16', phase.p),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 3; i <= 96; ++i) {
|
||||||
|
result.goods.push({
|
||||||
|
item_id: K.ITEM('s32', i),
|
||||||
|
item_type: K.ITEM('s16', 3),
|
||||||
|
price: K.ITEM('s32', 60),
|
||||||
|
goods_type: K.ITEM('s16', 0),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const M39_EXTRA_DATA: {
|
||||||
|
[ver: string]: {
|
||||||
|
[field: string]: {
|
||||||
|
path: string;
|
||||||
|
type: string;
|
||||||
|
default: any;
|
||||||
|
isArray?: true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} = {
|
||||||
|
v23: {
|
||||||
|
tutorial: { type: 's8', path: 'account', default: 0 },
|
||||||
|
area_id: { type: 's16', path: 'account', default: 0 },
|
||||||
|
lumina: { type: 's16', path: 'account', default: 300 },
|
||||||
|
medal_set: { type: 's16', path: 'account', default: [0, 0, 0, 0], isArray: true },
|
||||||
|
read_news: { type: 's16', path: 'account', default: 0 },
|
||||||
|
staff: { type: 's8', path: 'account', default: 0 },
|
||||||
|
item_type: { type: 's16', path: 'account', default: 0 },
|
||||||
|
item_id: { type: 's16', path: 'account', default: 0 },
|
||||||
|
is_conv: { type: 's8', path: 'account', default: 0 },
|
||||||
|
active_fr_num: { type: 'u8', path: 'account', default: 0 },
|
||||||
|
nice: { type: 's16', path: 'account', default: Array(30).fill(-1), isArray: true },
|
||||||
|
favorite_chara: { type: 's16', path: 'account', default: Array(20).fill(-1), isArray: true },
|
||||||
|
special_area: { type: 's16', path: 'account', default: Array(8).fill(0), isArray: true },
|
||||||
|
chocolate_charalist: {
|
||||||
|
type: 's16',
|
||||||
|
path: 'account',
|
||||||
|
default: Array(5).fill(-1),
|
||||||
|
isArray: true,
|
||||||
|
},
|
||||||
|
teacher_setting: { type: 's16', path: 'account', default: Array(10).fill(0), isArray: true },
|
||||||
|
license_data: { type: 's16', path: 'account', default: [-1, -1], isArray: true },
|
||||||
|
welcom_pack: { type: 'bool', path: 'account', default: 1 },
|
||||||
|
meteor_flg: { type: 'bool', path: 'account', default: 1 },
|
||||||
|
|
||||||
|
hispeed: { type: 's16', path: 'option', default: 0 },
|
||||||
|
popkun: { type: 'u8', path: 'option', default: 0 },
|
||||||
|
hidden: { type: 'bool', path: 'option', default: 0 },
|
||||||
|
hidden_rate: { type: 's16', path: 'option', default: 0 },
|
||||||
|
sudden: { type: 'bool', path: 'option', default: 0 },
|
||||||
|
sudden_rate: { type: 's16', path: 'option', default: 0 },
|
||||||
|
randmir: { type: 's8', path: 'option', default: 0 },
|
||||||
|
gauge_type: { type: 's8', path: 'option', default: 0 },
|
||||||
|
ojama_0: { type: 'u8', path: 'option', default: 0 },
|
||||||
|
ojama_1: { type: 'u8', path: 'option', default: 0 },
|
||||||
|
forever_0: { type: 'bool', path: 'option', default: 0 },
|
||||||
|
forever_1: { type: 'bool', path: 'option', default: 0 },
|
||||||
|
full_setting: { type: 'bool', path: 'option', default: 0 },
|
||||||
|
judge: { type: 'u8', path: 'option', default: 0 },
|
||||||
|
|
||||||
|
ep: { type: 'u16', path: 'info', default: 0 },
|
||||||
|
|
||||||
|
effect_left: { type: 'u16', path: 'customize', default: 0 },
|
||||||
|
effect_center: { type: 'u16', path: 'customize', default: 0 },
|
||||||
|
effect_right: { type: 'u16', path: 'customize', default: 0 },
|
||||||
|
hukidashi: { type: 'u16', path: 'customize', default: 0 },
|
||||||
|
comment_1: { type: 'u16', path: 'customize', default: 0 },
|
||||||
|
comment_2: { type: 'u16', path: 'customize', default: 0 },
|
||||||
|
|
||||||
|
mode: { type: 'u8', path: 'config', default: 0 },
|
||||||
|
chara: { type: 's16', path: 'config', default: -1 },
|
||||||
|
music: { type: 's16', path: 'config', default: -1 },
|
||||||
|
sheet: { type: 'u8', path: 'config', default: 0 },
|
||||||
|
category: { type: 's8', path: 'config', default: -1 },
|
||||||
|
sub_category: { type: 's8', path: 'config', default: -1 },
|
||||||
|
chara_category: { type: 's8', path: 'config', default: -1 },
|
||||||
|
course_id: { type: 's16', path: 'config', default: 0 },
|
||||||
|
course_folder: { type: 's8', path: 'config', default: 0 },
|
||||||
|
ms_banner_disp: { type: 's8', path: 'config', default: 0 },
|
||||||
|
ms_down_info: { type: 's8', path: 'config', default: 0 },
|
||||||
|
ms_side_info: { type: 's8', path: 'config', default: 0 },
|
||||||
|
ms_raise_type: { type: 's8', path: 'config', default: 0 },
|
||||||
|
ms_rnd_type: { type: 's8', path: 'config', default: 0 },
|
||||||
|
|
||||||
|
enemy_medal: { type: 's16', path: 'event', default: 0 },
|
||||||
|
hp: { type: 's16', path: 'event', default: 0 },
|
||||||
|
|
||||||
|
valid: { type: 's8', path: 'custom_cate', default: 0 },
|
||||||
|
lv_min: { type: 's8', path: 'custom_cate', default: -1 },
|
||||||
|
lv_max: { type: 's8', path: 'custom_cate', default: -1 },
|
||||||
|
medal_min: { type: 's8', path: 'custom_cate', default: -1 },
|
||||||
|
medal_max: { type: 's8', path: 'custom_cate', default: -1 },
|
||||||
|
friend_no: { type: 's8', path: 'custom_cate', default: -1 },
|
||||||
|
score_flg: { type: 's8', path: 'custom_cate', default: -1 },
|
||||||
|
},v24: {
|
||||||
|
enemy_medal: { type: 's16', path: 'event', default: 0 },
|
||||||
|
hp: { type: 's16', path: 'event', default: 0 },
|
||||||
|
|
||||||
|
tutorial: { type: 's16', path: 'account', default: -1 },
|
||||||
|
area_id: { type: 's16', path: 'account', default: 51 },
|
||||||
|
lumina: { type: 's16', path: 'account', default: 0 },
|
||||||
|
medal_set: { type: 's16', path: 'account', default: [0, 0], isArray: true },
|
||||||
|
read_news: { type: 's16', path: 'account', default: 0 },
|
||||||
|
staff: { type: 's8', path: 'account', default: 0 },
|
||||||
|
is_conv: { type: 's8', path: 'account', default: 0 },
|
||||||
|
item_type: { type: 's16', path: 'account', default: 0 },
|
||||||
|
item_id: { type: 's16', path: 'account', default: 0 },
|
||||||
|
license_data: { type: 's16', path: 'account', default: Array(10).fill(-1), isArray: true },
|
||||||
|
active_fr_num: { type: 'u8', path: 'account', default: 0 },
|
||||||
|
nice: { type: 's16', path: 'account', default: Array(30).fill(-1), isArray: true },
|
||||||
|
favorite_chara: { type: 's16', path: 'account', default: Array(10).fill(-1), isArray: true },
|
||||||
|
special_area: { type: 's16', path: 'account', default: Array(8).fill(-1), isArray: true },
|
||||||
|
chocolate_charalist: {
|
||||||
|
type: 's16',
|
||||||
|
path: 'account',
|
||||||
|
default: Array(5).fill(-1),
|
||||||
|
isArray: true,
|
||||||
|
},
|
||||||
|
chocolate_sp_chara: { type: 's32', path: 'account', default: 0 },
|
||||||
|
chocolate_pass_cnt: { type: 's32', path: 'account', default: 0 },
|
||||||
|
chocolate_hon_cnt: { type: 's32', path: 'account', default: 0 },
|
||||||
|
chocolate_giri_cnt: { type: 's32', path: 'account', default: 0 },
|
||||||
|
chocolate_kokyu_cnt: { type: 's32', path: 'account', default: 0 },
|
||||||
|
teacher_setting: { type: 's16', path: 'account', default: Array(10).fill(-1), isArray: true },
|
||||||
|
welcom_pack: { type: 'bool', path: 'account', default: 0 },
|
||||||
|
meteor_flg: { type: 'bool', path: 'account', default: 0 },
|
||||||
|
use_navi: { type: 's16', path: 'account', default: 0 },
|
||||||
|
ranking_node: { type: 's32', path: 'account', default: 0 },
|
||||||
|
chara_ranking_kind_id: { type: 's32', path: 'account', default: 0 },
|
||||||
|
navi_evolution_flg: { type: 's8', path: 'account', default: 0 },
|
||||||
|
ranking_news_last_no: { type: 's32', path: 'account', default: 0 },
|
||||||
|
power_point: { type: 's32', path: 'account', default: 0 },
|
||||||
|
player_point: { type: 's32', path: 'account', default: 0 },
|
||||||
|
power_point_list: { type: 's32', path: 'account', default: [0], isArray: true },
|
||||||
|
|
||||||
|
mode: { type: 'u8', path: 'config', default: 0 },
|
||||||
|
chara: { type: 's16', path: 'config', default: 0 },
|
||||||
|
music: { type: 's16', path: 'config', default: 0 },
|
||||||
|
sheet: { type: 'u8', path: 'config', default: 0 },
|
||||||
|
category: { type: 's8', path: 'config', default: 0 },
|
||||||
|
sub_category: { type: 's8', path: 'config', default: 0 },
|
||||||
|
chara_category: { type: 's8', path: 'config', default: 0 }, // check
|
||||||
|
story_id: { type: 's16', path: 'config', default: 0 },
|
||||||
|
ms_banner_disp: { type: 's8', path: 'config', default: 0 },
|
||||||
|
ms_down_info: { type: 's8', path: 'config', default: 0 },
|
||||||
|
ms_side_info: { type: 's8', path: 'config', default: 0 },
|
||||||
|
ms_raise_type: { type: 's8', path: 'config', default: 0 },
|
||||||
|
ms_rnd_type: { type: 's8', path: 'config', default: 0 },
|
||||||
|
banner_sort: { type: 's8', path: 'config', default: 0 },
|
||||||
|
course_id: { type: 's16', path: 'config', default: 0 },
|
||||||
|
course_folder: { type: 's8', path: 'config', default: 0 },
|
||||||
|
story_folder: { type: 's8', path: 'config', default: 0 },
|
||||||
|
|
||||||
|
hispeed: { type: 's16', path: 'option', default: 10 },
|
||||||
|
popkun: { type: 'u8', path: 'option', default: 0 },
|
||||||
|
hidden: { type: 'bool', path: 'option', default: 0 },
|
||||||
|
hidden_rate: { type: 's16', path: 'option', default: -1 },
|
||||||
|
sudden: { type: 'bool', path: 'option', default: 0 },
|
||||||
|
sudden_rate: { type: 's16', path: 'option', default: -1 },
|
||||||
|
randmir: { type: 's8', path: 'option', default: 0 },
|
||||||
|
gauge_type: { type: 's8', path: 'option', default: 0 },
|
||||||
|
ojama_0: { type: 'u8', path: 'option', default: 0 },
|
||||||
|
ojama_1: { type: 'u8', path: 'option', default: 0 },
|
||||||
|
forever_0: { type: 'bool', path: 'option', default: 0 },
|
||||||
|
forever_1: { type: 'bool', path: 'option', default: 0 },
|
||||||
|
full_setting: { type: 'bool', path: 'option', default: 0 },
|
||||||
|
guide_se: { type: 's8', path: 'option', default: 0 },
|
||||||
|
judge: { type: 'u8', path: 'option', default: 0 },
|
||||||
|
slow: { type: 's16', path: 'option', default: 0 },
|
||||||
|
fast: { type: 's16', path: 'option', default: 0 },
|
||||||
|
|
||||||
|
valid: { type: 's8', path: 'custom_cate', default: 0 },
|
||||||
|
lv_min: { type: 's8', path: 'custom_cate', default: 0 },
|
||||||
|
lv_max: { type: 's8', path: 'custom_cate', default: 0 },
|
||||||
|
medal_min: { type: 's8', path: 'custom_cate', default: 0 },
|
||||||
|
medal_max: { type: 's8', path: 'custom_cate', default: 0 },
|
||||||
|
friend_no: { type: 's8', path: 'custom_cate', default: 0 },
|
||||||
|
score_flg: { type: 's8', path: 'custom_cate', default: 0 },
|
||||||
|
|
||||||
|
ep: { type: 'u16', path: 'info', default: 0 },
|
||||||
|
ap: { type: 'u16', path: 'info', default: 0 },
|
||||||
|
|
||||||
|
effect_left: { type: 'u16', path: 'customize', default: 0 },
|
||||||
|
effect_center: { type: 'u16', path: 'customize', default: 0 },
|
||||||
|
effect_right: { type: 'u16', path: 'customize', default: 0 },
|
||||||
|
hukidashi: { type: 'u16', path: 'customize', default: 0 },
|
||||||
|
comment_1: { type: 'u16', path: 'customize', default: 0 },
|
||||||
|
comment_2: { type: 'u16', path: 'customize', default: 0 },
|
||||||
|
},
|
||||||
|
};
|
||||||
519
popn@asphyxia/handler/player.ts
Normal file
519
popn@asphyxia/handler/player.ts
Normal file
|
|
@ -0,0 +1,519 @@
|
||||||
|
import { Profile } from '../models/profile';
|
||||||
|
import { Scores } from '../models/scores';
|
||||||
|
import { getInfo, M39_EXTRA_DATA } from './common';
|
||||||
|
import { getVersion } from './utils';
|
||||||
|
|
||||||
|
const getPlayer = async (refid: string, version: string, name?: string) => {
|
||||||
|
const profile = await readProfile(refid);
|
||||||
|
|
||||||
|
if (name && name.length > 0) {
|
||||||
|
profile.name = name;
|
||||||
|
await writeProfile(refid, profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
let player: any = {
|
||||||
|
result: K.ITEM('s8', 0),
|
||||||
|
account: {
|
||||||
|
name: K.ITEM('str', profile.name),
|
||||||
|
g_pm_id: K.ITEM('str', 'ASPHYXIAPLAY'),
|
||||||
|
|
||||||
|
// Fixed stats
|
||||||
|
total_play_cnt: K.ITEM('s16', 100),
|
||||||
|
today_play_cnt: K.ITEM('s16', 50),
|
||||||
|
consecutive_days: K.ITEM('s16', 365),
|
||||||
|
total_days: K.ITEM('s16', 366),
|
||||||
|
interval_day: K.ITEM('s16', 1),
|
||||||
|
|
||||||
|
// TODO: do these
|
||||||
|
my_best: K.ARRAY('s16', Array(10).fill(-1)),
|
||||||
|
latest_music: K.ARRAY('s16', [-1, -1, -1, -1, -1]),
|
||||||
|
},
|
||||||
|
|
||||||
|
netvs: {
|
||||||
|
record: K.ARRAY('s16', [0, 0, 0, 0, 0, 0]),
|
||||||
|
dialog: [
|
||||||
|
K.ITEM('str', 'dialog#0'),
|
||||||
|
K.ITEM('str', 'dialog#1'),
|
||||||
|
K.ITEM('str', 'dialog#2'),
|
||||||
|
K.ITEM('str', 'dialog#3'),
|
||||||
|
K.ITEM('str', 'dialog#4'),
|
||||||
|
K.ITEM('str', 'dialog#5'),
|
||||||
|
],
|
||||||
|
ojama_condition: K.ARRAY('s8', Array(74).fill(0)),
|
||||||
|
set_ojama: K.ARRAY('s8', [0, 0, 0]),
|
||||||
|
set_recommend: K.ARRAY('s8', [0, 0, 0]),
|
||||||
|
netvs_play_cnt: K.ITEM('u32', 0),
|
||||||
|
},
|
||||||
|
|
||||||
|
eaappli: {
|
||||||
|
relation: K.ITEM('s8', 0),
|
||||||
|
},
|
||||||
|
|
||||||
|
stamp: [],
|
||||||
|
item: [],
|
||||||
|
chara_param: [],
|
||||||
|
medal: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const profileStamps = profile.stamps[version] || { '0': 0 };
|
||||||
|
|
||||||
|
for (const stamp in profileStamps) {
|
||||||
|
player.stamp.push({
|
||||||
|
stamp_id: K.ITEM('s16', parseInt(stamp, 10)),
|
||||||
|
cnt: K.ITEM('s16', profileStamps[stamp]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const profileCharas = profile.charas[version] || {};
|
||||||
|
|
||||||
|
for (const chara_id in profileCharas) {
|
||||||
|
player.chara_param.push({
|
||||||
|
chara_id: K.ITEM('u16', parseInt(chara_id, 10)),
|
||||||
|
friendship: K.ITEM('u16', profileCharas[chara_id]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const profileMedals = profile.medals[version] || {};
|
||||||
|
|
||||||
|
for (const medal_id in profileMedals) {
|
||||||
|
const medal = profileMedals[medal_id];
|
||||||
|
player.medal.push({
|
||||||
|
medal_id: K.ITEM('s16', parseInt(medal_id, 10)),
|
||||||
|
level: K.ITEM('s16', medal.level),
|
||||||
|
exp: K.ITEM('s32', medal.exp),
|
||||||
|
set_count: K.ITEM('s32', medal.set_count),
|
||||||
|
get_count: K.ITEM('s32', medal.get_count),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const profileItems = profile.items[version] || {};
|
||||||
|
|
||||||
|
for (const key in profileItems) {
|
||||||
|
const keyData = key.split(':');
|
||||||
|
const type = parseInt(keyData[0], 10);
|
||||||
|
const id = parseInt(keyData[1], 10);
|
||||||
|
|
||||||
|
const item: any = {
|
||||||
|
type: K.ITEM('u8', type),
|
||||||
|
id: K.ITEM('u16', id),
|
||||||
|
param: K.ITEM('u16', profileItems[key]),
|
||||||
|
is_new: K.ITEM('bool', 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (version != 'v23') {
|
||||||
|
item.get_time = K.ITEM('u64', BigInt(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
player.item.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXTRA DATA
|
||||||
|
if (M39_EXTRA_DATA[version]) {
|
||||||
|
for (const field in M39_EXTRA_DATA[version]) {
|
||||||
|
const fieldMetaData = M39_EXTRA_DATA[version][field];
|
||||||
|
if (fieldMetaData.isArray) {
|
||||||
|
_.set(
|
||||||
|
player,
|
||||||
|
`${fieldMetaData.path}.${field}`,
|
||||||
|
K.ARRAY(
|
||||||
|
fieldMetaData.type as any,
|
||||||
|
_.get(profile, `extras.${version}.${field}`, fieldMetaData.default)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
_.set(
|
||||||
|
player,
|
||||||
|
`${fieldMetaData.path}.${field}`,
|
||||||
|
K.ITEM(
|
||||||
|
fieldMetaData.type as any,
|
||||||
|
_.get(profile, `extras.${version}.${field}`, fieldMetaData.default)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extra Fixed Data
|
||||||
|
if (version == 'v24') {
|
||||||
|
player = {
|
||||||
|
...player,
|
||||||
|
navi_data: {
|
||||||
|
raisePoint: K.ARRAY('s32', [-1, -1, -1, -1, -1]),
|
||||||
|
navi_param: {
|
||||||
|
navi_id: K.ITEM('u16', 0),
|
||||||
|
friendship: K.ITEM('s32', 0),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
area: {
|
||||||
|
area_id: K.ITEM('u32', 0),
|
||||||
|
chapter_index: K.ITEM('u8', 0),
|
||||||
|
gauge_point: K.ITEM('u16', 0),
|
||||||
|
is_cleared: K.ITEM('bool', 0),
|
||||||
|
diary: K.ITEM('u32', 0),
|
||||||
|
},
|
||||||
|
|
||||||
|
mission: [
|
||||||
|
{
|
||||||
|
mission_id: K.ITEM('u32', 170),
|
||||||
|
gauge_point: K.ITEM('u32', 0),
|
||||||
|
mission_comp: K.ITEM('u32', 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mission_id: K.ITEM('u32', 157),
|
||||||
|
gauge_point: K.ITEM('u32', 0),
|
||||||
|
mission_comp: K.ITEM('u32', 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mission_id: K.ITEM('u32', 47),
|
||||||
|
gauge_point: K.ITEM('u32', 0),
|
||||||
|
mission_comp: K.ITEM('u32', 0),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return player;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const newPlayer: EPR = async (req, data, send) => {
|
||||||
|
const refid = $(data).str('ref_id');
|
||||||
|
if (!refid) return send.deny();
|
||||||
|
|
||||||
|
const version = getVersion(req);
|
||||||
|
const name = $(data).str('name');
|
||||||
|
|
||||||
|
send.object(await getPlayer(refid, version, name));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const read: EPR = async (req, data, send) => {
|
||||||
|
const refid = $(data).str('ref_id');
|
||||||
|
if (!refid) return send.deny();
|
||||||
|
|
||||||
|
const version = getVersion(req);
|
||||||
|
|
||||||
|
send.object(await getPlayer(refid, version));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const readScore: EPR = async (req, data, send) => {
|
||||||
|
const refid = $(data).str('ref_id');
|
||||||
|
if (!refid) return send.deny();
|
||||||
|
|
||||||
|
const scoresData = await readScores(refid);
|
||||||
|
const version = getVersion(req);
|
||||||
|
const result: any = {
|
||||||
|
music: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
if(version == 'v24') {
|
||||||
|
for (const key in scoresData.scores) {
|
||||||
|
const keyData = key.split(':');
|
||||||
|
const score = scoresData.scores[key];
|
||||||
|
const music = parseInt(keyData[0], 10);
|
||||||
|
const sheet = parseInt(keyData[1], 10);
|
||||||
|
result.music.push({
|
||||||
|
music_num: K.ITEM('s16', music),
|
||||||
|
sheet_num: K.ITEM('u8', sheet),
|
||||||
|
score: K.ITEM('s32', score.score),
|
||||||
|
clear_type: K.ITEM('u8', score.clear_type || 0),
|
||||||
|
clear_rank: K.ITEM('u8', score.clear_rank || 0),
|
||||||
|
cnt: K.ITEM('s16', score.cnt),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if(version == 'v23') {
|
||||||
|
for (const key in scoresData.scores) {
|
||||||
|
const keyData = key.split(':');
|
||||||
|
const score = scoresData.scores[key];
|
||||||
|
const music = parseInt(keyData[0], 10);
|
||||||
|
const sheet = parseInt(keyData[1], 10);
|
||||||
|
result.music.push({
|
||||||
|
music_num: K.ITEM('s16', music),
|
||||||
|
sheet_num: K.ITEM('u8', sheet),
|
||||||
|
score: K.ITEM('s32', score.score),
|
||||||
|
clear_type: K.ITEM('u8', score.clearmedal || 0),
|
||||||
|
cnt: K.ITEM('s16', score.cnt),
|
||||||
|
old_score: K.ITEM('s32', 0),
|
||||||
|
old_clear_type: K.ITEM('u8', 0),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send.object(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const writeMusic: EPR = async (req, data, send) => {
|
||||||
|
const refid = $(data).str('ref_id');
|
||||||
|
if (!refid) return send.deny();
|
||||||
|
|
||||||
|
const music = $(data).number('music_num', -1);
|
||||||
|
const sheet = $(data).number('sheet_num', -1);
|
||||||
|
const clear_type = $(data).number('clear_type');
|
||||||
|
const clear_rank = $(data).number('clear_rank');
|
||||||
|
const clearmedal = $(data).number('clearmedal');
|
||||||
|
const score = $(data).number('score', 0);
|
||||||
|
|
||||||
|
if (music < 0 || sheet < 0) {
|
||||||
|
return send.deny();
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = `${music}:${sheet}`;
|
||||||
|
|
||||||
|
const scoresData = await readScores(refid);
|
||||||
|
if (!scoresData.scores[key]) {
|
||||||
|
scoresData.scores[key] = {
|
||||||
|
score,
|
||||||
|
cnt: 1,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
scoresData.scores[key] = {
|
||||||
|
score: Math.max(score, scoresData.scores[key].score),
|
||||||
|
cnt: scoresData.scores[key].cnt + 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clear_type) {
|
||||||
|
scoresData.scores[key].clear_type = Math.max(clear_type, scoresData.scores[key].clear_type || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clear_rank) {
|
||||||
|
scoresData.scores[key].clear_rank = Math.max(clear_rank, scoresData.scores[key].clear_rank || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clearmedal) {
|
||||||
|
scoresData.scores[key].clearmedal = Math.max(clearmedal, scoresData.scores[key].clearmedal || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeScores(refid, scoresData);
|
||||||
|
|
||||||
|
const version = getVersion(req);
|
||||||
|
if (version == 'v24') {
|
||||||
|
|
||||||
|
const p = await readProfile(refid);
|
||||||
|
|
||||||
|
const settings = [
|
||||||
|
'hispeed',
|
||||||
|
'popkun',
|
||||||
|
'hidden',
|
||||||
|
'hidden_rate',
|
||||||
|
'sudden',
|
||||||
|
'sudden_rate',
|
||||||
|
'randmir',
|
||||||
|
'ojama_0',
|
||||||
|
'ojama_1',
|
||||||
|
'forever_0',
|
||||||
|
'forever_1',
|
||||||
|
'full_setting',
|
||||||
|
'guide_se',
|
||||||
|
'judge',
|
||||||
|
'slow',
|
||||||
|
'fast',
|
||||||
|
'mode',
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const setting of settings) {
|
||||||
|
_.set(
|
||||||
|
p,
|
||||||
|
`extras.v24.${setting}`,
|
||||||
|
_.get(data, `${setting}.@content.0`, _.get(p, `extras.v24.${setting}`, 0))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_.set(p, `extras.v24.tutorial`, 32767);
|
||||||
|
|
||||||
|
const chara = $(data).number('chara_num');
|
||||||
|
if (chara) {
|
||||||
|
_.set(p, 'extras.v24.chara', chara);
|
||||||
|
}
|
||||||
|
|
||||||
|
const music = $(data).number('music_num');
|
||||||
|
if (music) {
|
||||||
|
_.set(p, 'extras.v24.music', music);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sheet = $(data).number('sheet_num');
|
||||||
|
if (sheet) {
|
||||||
|
_.set(p, 'extras.v24.sheet', sheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeProfile(refid, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
send.success();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const write: EPR = async (req, data, send) => {
|
||||||
|
const refid = $(data).str('ref_id');
|
||||||
|
if (!refid) return send.deny();
|
||||||
|
|
||||||
|
const version = getVersion(req);
|
||||||
|
const profile = await readProfile(refid);
|
||||||
|
|
||||||
|
const writeData: Partial<Profile> = {};
|
||||||
|
|
||||||
|
if (M39_EXTRA_DATA[version]) {
|
||||||
|
const extraFields = M39_EXTRA_DATA[version];
|
||||||
|
for (const field in extraFields) {
|
||||||
|
const fieldMetaData = extraFields[field];
|
||||||
|
let value = _.get(data, `${fieldMetaData.path}.${field}.@content`);
|
||||||
|
if ( value == 'undefined' && value == null ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.isArray(value) && value.length == 1) {
|
||||||
|
value = value[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
_.set(writeData, `extras.${version}.${field}`, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const newProfile:Profile = {
|
||||||
|
...profile,
|
||||||
|
...writeData,
|
||||||
|
};
|
||||||
|
|
||||||
|
// stamps
|
||||||
|
let stamps = _.get(data, 'stamp', []);
|
||||||
|
if (!newProfile.stamps[version]) {
|
||||||
|
newProfile.stamps[version] = { '0': 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_.isArray(stamps)) {
|
||||||
|
stamps = [stamps];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const stamp of stamps) {
|
||||||
|
const id = $(stamp).number('stamp_id');
|
||||||
|
const cnt = $(stamp).number('cnt');
|
||||||
|
|
||||||
|
newProfile.stamps[version][id] = cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// medals
|
||||||
|
let medals = _.get(data, 'medal', []);
|
||||||
|
if (!newProfile.medals[version]) {
|
||||||
|
newProfile.medals[version] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_.isArray(medals)) {
|
||||||
|
medals = [medals];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const medal of medals) {
|
||||||
|
const id = $(medal).number('medal_id');
|
||||||
|
const level = $(medal).number('level');
|
||||||
|
const exp = $(medal).number('exp');
|
||||||
|
const set_count = $(medal).number('set_count');
|
||||||
|
const get_count = $(medal).number('get_count');
|
||||||
|
|
||||||
|
newProfile.medals[version][id] = {
|
||||||
|
level,
|
||||||
|
exp,
|
||||||
|
set_count,
|
||||||
|
get_count,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// items
|
||||||
|
let items = _.get(data, 'item', []);
|
||||||
|
if (!newProfile.items[version]) {
|
||||||
|
newProfile.items[version] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_.isArray(items)) {
|
||||||
|
items = [items];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
const type = $(item).number('type');
|
||||||
|
const id = $(item).number('id');
|
||||||
|
const param = $(item).number('param');
|
||||||
|
|
||||||
|
const key = `${type}:${id}`;
|
||||||
|
|
||||||
|
newProfile.items[version][key] = param;
|
||||||
|
}
|
||||||
|
|
||||||
|
// charas
|
||||||
|
let charas = _.get(data, 'chara_param', []);
|
||||||
|
if (!newProfile.charas[version]) {
|
||||||
|
newProfile.charas[version] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_.isArray(charas)) {
|
||||||
|
charas = [charas];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const chara of charas) {
|
||||||
|
const id = $(chara).number('chara_id');
|
||||||
|
const param = $(chara).number('friendship');
|
||||||
|
|
||||||
|
newProfile.charas[version][id] = param;
|
||||||
|
}
|
||||||
|
|
||||||
|
await writeProfile(refid, newProfile);
|
||||||
|
send.success();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const start: EPR = async (req, data, send) => {
|
||||||
|
const result = {
|
||||||
|
play_id: K.ITEM('s32', 1),
|
||||||
|
...getInfo(req),
|
||||||
|
};
|
||||||
|
await send.object(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const buy: EPR = async (req, data, send) => {
|
||||||
|
const refid = $(data).str('ref_id');
|
||||||
|
if (!refid) return send.deny();
|
||||||
|
|
||||||
|
const type = $(data).number('type', -1);
|
||||||
|
const id = $(data).number('id', -1);
|
||||||
|
const param = $(data).number('param', 0);
|
||||||
|
const version = getVersion(req);
|
||||||
|
|
||||||
|
if (type < 0 || id < 0) {
|
||||||
|
return send.deny();
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = `${type}:${id}`;
|
||||||
|
|
||||||
|
const profile = await readProfile(refid);
|
||||||
|
if (!profile.items[version]) {
|
||||||
|
profile.items[version] = {};
|
||||||
|
}
|
||||||
|
profile.items[version][key] = param;
|
||||||
|
await writeProfile(refid, profile);
|
||||||
|
send.success();
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultProfile:Profile = {
|
||||||
|
collection: 'profile',
|
||||||
|
|
||||||
|
name: 'ゲスト',
|
||||||
|
|
||||||
|
stamps: {},
|
||||||
|
medals: {},
|
||||||
|
items: {},
|
||||||
|
charas: {},
|
||||||
|
|
||||||
|
extras: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
async function readProfile(refid: string): Promise<Profile> {
|
||||||
|
const profile = await DB.FindOne<Profile>(refid, { collection: 'profile'} )
|
||||||
|
return profile || defaultProfile
|
||||||
|
}
|
||||||
|
|
||||||
|
async function writeProfile(refid: string, profile: Profile) {
|
||||||
|
await DB.Upsert<Profile>(refid, { collection: 'profile'}, profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readScores(refid: string): Promise<Scores> {
|
||||||
|
const score = await DB.FindOne<Scores>(refid, { collection: 'scores'} )
|
||||||
|
return score || { collection: 'scores', scores: {}}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function writeScores(refid: string, scores: Scores) {
|
||||||
|
await DB.Upsert<Scores>(refid, { collection: 'scores'}, scores)
|
||||||
|
}
|
||||||
4
popn@asphyxia/handler/utils.ts
Normal file
4
popn@asphyxia/handler/utils.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
export const getVersion = (info: EamuseInfo) => {
|
||||||
|
const moduleName: string = info.module;
|
||||||
|
return `v${moduleName.match(/[0-9]+/)[0]}`;
|
||||||
|
};
|
||||||
30
popn@asphyxia/index.ts
Normal file
30
popn@asphyxia/index.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { getInfo } from "./handler/common";
|
||||||
|
import { newPlayer, read, readScore, start, writeMusic, write, buy} from "./handler/player"
|
||||||
|
|
||||||
|
export function register() {
|
||||||
|
R.GameCode('M39');
|
||||||
|
|
||||||
|
const PlayerRoute = (method: string, handler: EPR | boolean) => {
|
||||||
|
R.Route(`player24.${method}`, handler);
|
||||||
|
R.Route(`player23.${method}`, handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
const CommonRoute = (method: string, handler: EPR | boolean) => {
|
||||||
|
R.Route(`info24.${method}`, handler);
|
||||||
|
R.Route(`info23.${method}`, handler);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Common
|
||||||
|
CommonRoute('common', (req, data, send) => {
|
||||||
|
return send.object(getInfo(req));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Player
|
||||||
|
PlayerRoute('new', newPlayer);
|
||||||
|
PlayerRoute('read', read);
|
||||||
|
PlayerRoute('read_score', readScore);
|
||||||
|
PlayerRoute('write_music', writeMusic);
|
||||||
|
PlayerRoute('write', write);
|
||||||
|
PlayerRoute('start', start);
|
||||||
|
PlayerRoute('buy', buy);
|
||||||
|
}
|
||||||
40
popn@asphyxia/models/profile.ts
Normal file
40
popn@asphyxia/models/profile.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
export interface Profile {
|
||||||
|
collection: 'profile',
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
stamps: {
|
||||||
|
[ver: string]: {
|
||||||
|
[stamp_id: string]: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
medals: {
|
||||||
|
[ver: string]: {
|
||||||
|
[id: string]: {
|
||||||
|
level: number;
|
||||||
|
exp: number;
|
||||||
|
set_count: number;
|
||||||
|
get_count: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
items: {
|
||||||
|
[ver: string]: {
|
||||||
|
[key: string]: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
charas: {
|
||||||
|
[ver: string]: {
|
||||||
|
[chara_id: string]: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
extras: {
|
||||||
|
[ver: string]: {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
13
popn@asphyxia/models/scores.ts
Normal file
13
popn@asphyxia/models/scores.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
export interface Scores {
|
||||||
|
collection: 'scores',
|
||||||
|
|
||||||
|
scores: {
|
||||||
|
[key: string]: {
|
||||||
|
clearmedal?: number;
|
||||||
|
clear_type?: number;
|
||||||
|
clear_rank?: number;
|
||||||
|
score: number;
|
||||||
|
cnt: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user