mirror of
https://github.com/laochan-eacnet/backend.git
synced 2026-09-22 22:28:11 +03:00
gitadora wip
This commit is contained in:
+72780
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@ export class DefaultService {
|
||||
|
||||
p2d()(undefined, undefined, descriptor);
|
||||
return descriptor.value();
|
||||
} else if (['sdvx', 'ddr'].includes(ctx.service.name)) {
|
||||
} else if (['sdvx', 'ddr', 'gitadora'].includes(ctx.service.name)) {
|
||||
const result = {
|
||||
status: v.s32(0),
|
||||
error_code: v.s32(0),
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import { singleton } from "tsyringe";
|
||||
import { Combine } from "../../utils/combine.js";
|
||||
import { EacGeneric } from "../eac-generic.js";
|
||||
import { User } from "./user.js";
|
||||
import { generic } from "../../decorators/eacnet.js";
|
||||
import { Serializable, v } from "../../utils/kxml-value.js";
|
||||
import { event, musicinfo } from "../../datas/gitadora.js";
|
||||
|
||||
@singleton()
|
||||
export default class extends Combine(EacGeneric, User) {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
@generic()
|
||||
knst_playablemusic_get(): Serializable {
|
||||
return {
|
||||
status: v.s32(0),
|
||||
error_code: v.s32(0),
|
||||
xrpc_status_code: v.s32(0),
|
||||
xrpc_fault_code: v.s32(0),
|
||||
response: {
|
||||
knst_playablemusic: {
|
||||
$status: 0,
|
||||
musicinfo,
|
||||
hot: {
|
||||
major: v.s32(1),
|
||||
minor: v.s32(0),
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@generic()
|
||||
knst_gameinfo_get(): Serializable {
|
||||
return {
|
||||
status: v.s32(0),
|
||||
error_code: v.s32(0),
|
||||
xrpc_status_code: v.s32(0),
|
||||
xrpc_fault_code: v.s32(0),
|
||||
response: {
|
||||
knst_gameinfo: {
|
||||
$status: 0,
|
||||
now_date: v.u64(Date.now()),
|
||||
extra: {
|
||||
extra_lv: v.u8(0),
|
||||
extramusic: {
|
||||
music: []
|
||||
}
|
||||
},
|
||||
unlock_challenge: {
|
||||
term: v.u8(0),
|
||||
},
|
||||
ctrl_movie: {},
|
||||
ng_jacket: {},
|
||||
// TODO: actual sort the musics by play count
|
||||
ranking: {
|
||||
skill_0_999: {},
|
||||
skill_1000_1499: {},
|
||||
skill_1500_1999: {},
|
||||
skill_2000_2499: {},
|
||||
skill_2500_2999: {},
|
||||
skill_3000_3499: {},
|
||||
skill_3500_3999: {},
|
||||
skill_4000_4499: {},
|
||||
skill_4500_4999: {},
|
||||
skill_5000_5499: {},
|
||||
skill_5500_5999: {},
|
||||
skill_6000_6499: {},
|
||||
skill_6500_6999: {},
|
||||
skill_7000_7499: {},
|
||||
skill_7500_7999: {},
|
||||
skill_8000_8499: {},
|
||||
skill_8500_9999: {},
|
||||
total: {},
|
||||
original: {},
|
||||
bemani: {},
|
||||
famous: {},
|
||||
anime: {},
|
||||
band: {},
|
||||
western: {},
|
||||
},
|
||||
processing_report_state: v.u8(0),
|
||||
data_ver_limit: {
|
||||
type: v.str('data_ver_limit'),
|
||||
term: v.u8(0),
|
||||
state: v.u8(0),
|
||||
start_date: v.str('1970-01-01 09:00:00'),
|
||||
end_date: v.str('1970-01-01 09:00:00'),
|
||||
start_date_ms: v.u64(0),
|
||||
end_date_ms: v.u64(0),
|
||||
},
|
||||
general_term: {},
|
||||
assert_report_state: v.u8(0),
|
||||
rockwave: {
|
||||
event_list: {
|
||||
event,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Context } from "../../types.js";
|
||||
import { Serializable } from "../../utils/kxml-value.js";
|
||||
|
||||
export class User {
|
||||
async knst_cardutil_check(ctx: Context): Promise<Serializable> {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { parser, toObject } from "../utils/kbinxml.js";
|
||||
import { Serializable, v } from "../utils/kxml-value.js";
|
||||
import { Mdb } from "../types/gitadora/data.js";
|
||||
|
||||
export const musicinfo: Serializable = (() => {
|
||||
if (!existsSync('data/mdb_knst.xml')) {
|
||||
throw new Error('data/mdb_knst.xml not found!!');
|
||||
}
|
||||
|
||||
const xml = readFileSync('data/mdb_knst.xml');
|
||||
const mdb = toObject(parser.parse(xml)).mdb as Mdb;
|
||||
|
||||
return {
|
||||
$nr: mdb.mdb_data.length,
|
||||
music: mdb.mdb_data.map(m => ({
|
||||
id: v.s32(m.music_id),
|
||||
diff: v.u16(m.xg_diff_list),
|
||||
cont_gf: v.bool(!!m.contain_stat[0]),
|
||||
cont_dm: v.bool(!!m.contain_stat[1]),
|
||||
is_cont: v.bool(true),
|
||||
is_secret: v.bool(false),
|
||||
is_hot: v.bool(((m.contain_stat[0] & 1) != 0) || ((m.contain_stat[1] & 1) != 0)),
|
||||
data_ver: v.s32(m.data_ver),
|
||||
knst_pack: v.s32(0), // v.s32(m.knst_pack),
|
||||
ifs_ver: v.s32(m.ifs_ver),
|
||||
}))
|
||||
}
|
||||
})();
|
||||
|
||||
export const event = [{
|
||||
data_id: v.s32(8),
|
||||
data_version: v.s32(200),
|
||||
event_id: v.s32(0),
|
||||
event_type: v.s32(18),
|
||||
start_date: v.u64(1615510800000),
|
||||
end_date: v.u64(4771493999000),
|
||||
is_open: v.bool(true),
|
||||
bg_no: v.s32(0),
|
||||
target_musicid: v.s32([-1, -1, -1, -1, -1, -1, -1, -1, -1, -1]),
|
||||
clear_border: v.s32(2),
|
||||
reward_musicid: v.s32([-1, -1, 2708, 2709]),
|
||||
reward_stickerid: v.s32(-1),
|
||||
firstbit: v.s32(0),
|
||||
event_skill_id: v.s32(0),
|
||||
quest_no: v.s32(0),
|
||||
url: v.str(''),
|
||||
},
|
||||
{
|
||||
data_id: v.s32(9),
|
||||
data_version: v.s32(200),
|
||||
event_id: v.s32(0),
|
||||
event_type: v.s32(18),
|
||||
start_date: v.u64(1618966800000),
|
||||
end_date: v.u64(4771493999000),
|
||||
is_open: v.bool(true),
|
||||
bg_no: v.s32(0),
|
||||
target_musicid: v.s32([-1, -1, -1, -1, -1, -1, -1, -1, -1, -1]),
|
||||
clear_border: v.s32(2),
|
||||
reward_musicid: v.s32([-1, -1, -1, 2710]),
|
||||
reward_stickerid: v.s32(-1),
|
||||
firstbit: v.s32(0),
|
||||
event_skill_id: v.s32(0),
|
||||
quest_no: v.s32(0),
|
||||
url: v.str(''),
|
||||
},
|
||||
{
|
||||
data_id: v.s32(87),
|
||||
data_version: v.s32(220),
|
||||
event_id: v.s32(0),
|
||||
event_type: v.s32(3),
|
||||
start_date: v.u64(1743469200000),
|
||||
end_date: v.u64(1745765999000),
|
||||
is_open: v.bool(true),
|
||||
bg_no: v.s32(0),
|
||||
target_musicid: v.s32([-1, -1, -1, -1, -1, -1, -1, -1, -1, -1]),
|
||||
clear_border: v.s32(25000000),
|
||||
reward_musicid: v.s32([-1, -1, -1, 1118]),
|
||||
reward_stickerid: v.s32(-1),
|
||||
firstbit: v.s32(0),
|
||||
event_skill_id: v.s32(0),
|
||||
quest_no: v.s32(62),
|
||||
url: v.str(''),
|
||||
}];
|
||||
@@ -0,0 +1,76 @@
|
||||
|
||||
export interface Mdb {
|
||||
header: {
|
||||
data: {
|
||||
id: number[];
|
||||
format: number;
|
||||
chksum: number;
|
||||
header_sz: number;
|
||||
record_sz: number;
|
||||
record_nr: number;
|
||||
course_sz: number;
|
||||
course_nr: number;
|
||||
}
|
||||
}
|
||||
mdb_data: MdbData[];
|
||||
mdb_course: MdbCourse[];
|
||||
}
|
||||
|
||||
export interface MdbCourse {
|
||||
course_id: number;
|
||||
course_flag: number;
|
||||
music_id: number[];
|
||||
classics_diff_list: number[];
|
||||
}
|
||||
|
||||
export interface MdbData {
|
||||
music_id: number;
|
||||
classics_diff_list: number[];
|
||||
xg_diff_list: number[];
|
||||
pad_diff: number;
|
||||
seq_flag: number;
|
||||
xg_seq_flag: number;
|
||||
contain_stat: number[];
|
||||
first_ver: number[];
|
||||
first_classic_ver: number[];
|
||||
b_long: boolean;
|
||||
b_eemall: boolean;
|
||||
b_konasta: boolean;
|
||||
bpm: number;
|
||||
bpm2: number;
|
||||
title_ascii?: string;
|
||||
order_ascii: number;
|
||||
order_kana: number;
|
||||
category_kana: number;
|
||||
artist_title_ascii?: string;
|
||||
artist_order_ascii: number;
|
||||
artist_order_kana: number;
|
||||
artist_category_kana: number;
|
||||
secret: number[];
|
||||
xg_secret: number[];
|
||||
b_session: boolean;
|
||||
xg_b_session: boolean;
|
||||
speed: number;
|
||||
life: number;
|
||||
gf_ofst: number;
|
||||
dm_ofst: number;
|
||||
chart_list: number[];
|
||||
origin: number;
|
||||
music_type: number;
|
||||
genre: number;
|
||||
xg_active_effect_type: number;
|
||||
xg_movie_disp_type: number;
|
||||
xg_movie_disp_id: number;
|
||||
is_remaster: number;
|
||||
title_name: string;
|
||||
license_disp: number;
|
||||
default_music: number[];
|
||||
disable_area: number[];
|
||||
type_category: number;
|
||||
data_ver: number;
|
||||
seq_id: number;
|
||||
is_classic_seq: number;
|
||||
knst_pack: number;
|
||||
ifs_ver: number;
|
||||
knst_course: number;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Long } from "mongodb";
|
||||
|
||||
export interface PlayerData {
|
||||
_id: string;
|
||||
gameSave: Record<'gf' | 'dm', {
|
||||
playCount: number;
|
||||
playTime: number;
|
||||
playTerm: number;
|
||||
// all s32
|
||||
playInfo: Record<string, number>;
|
||||
tutorial: {
|
||||
progress: number;
|
||||
displayState: number;
|
||||
};
|
||||
rewardStatus: number[];
|
||||
customData: {
|
||||
playStyle: number[];
|
||||
custom: number[];
|
||||
};
|
||||
skill: number;
|
||||
favoriteMusic: {
|
||||
list1: number[];
|
||||
list2: number[];
|
||||
list3: number[];
|
||||
};
|
||||
information: number[];
|
||||
maxRecord: Record<string, number>;
|
||||
diffRecord: Record<string, number>;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface MusicData {
|
||||
type: 'gf' | 'dm';
|
||||
player: string;
|
||||
musicId: number;
|
||||
|
||||
clearStatus: number;
|
||||
rank: number;
|
||||
|
||||
perfect: number;
|
||||
great: number;
|
||||
good: number;
|
||||
ok: number;
|
||||
miss: number;
|
||||
|
||||
maxCombo: number;
|
||||
score: number;
|
||||
flags: number;
|
||||
point: number;
|
||||
percent: number;
|
||||
|
||||
meter: Long;
|
||||
|
||||
phrase: {
|
||||
count: number;
|
||||
addr: number[];
|
||||
type: number[];
|
||||
status: number[];
|
||||
endAddr: number;
|
||||
comboAerc: number;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './data.js';
|
||||
export * from './db.js';
|
||||
+26
-3
@@ -17,6 +17,17 @@ export const parser = new XMLParser({
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: maybe have a better way to workaround this.
|
||||
const ALWAYS_BIGINT_FOR_64BIT_NUMBER = true;
|
||||
function process64BitInteger(v: string) {
|
||||
const bi = BigInt(v);
|
||||
if (ALWAYS_BIGINT_FOR_64BIT_NUMBER || bi < Number.MIN_SAFE_INTEGER || bi > Number.MAX_SAFE_INTEGER) {
|
||||
return bi;
|
||||
}
|
||||
|
||||
return Number(bi);
|
||||
}
|
||||
|
||||
function parseValue(node: { $__type: string; $__count?: unknown }): any {
|
||||
const isArray = '$__count' in node;
|
||||
|
||||
@@ -28,8 +39,6 @@ function parseValue(node: { $__type: string; $__count?: unknown }): any {
|
||||
'u16',
|
||||
's32',
|
||||
'u32',
|
||||
's64',
|
||||
'u64',
|
||||
].includes(node.$__type)
|
||||
) {
|
||||
if (isArray) {
|
||||
@@ -39,6 +48,20 @@ function parseValue(node: { $__type: string; $__count?: unknown }): any {
|
||||
return parseInt(node['__value']);
|
||||
}
|
||||
|
||||
// javascript Number can't support 64bit data
|
||||
if (
|
||||
[
|
||||
's64',
|
||||
'u64',
|
||||
].includes(node.$__type)
|
||||
) {
|
||||
if (isArray) {
|
||||
return node['__value'].split(' ').map(process64BitInteger);
|
||||
}
|
||||
|
||||
return process64BitInteger(node['__value']);
|
||||
}
|
||||
|
||||
if (['float', 'double'].includes(node.$__type)) {
|
||||
if (isArray) {
|
||||
return node['__value'].split(' ').map((v) => parseFloat(v));
|
||||
@@ -159,7 +182,7 @@ function serializeValue(value: any, type: string): string {
|
||||
|
||||
if (type == 'time') {
|
||||
if (value instanceof Date) {
|
||||
return Math.floor(value.valueOf() / 1000).toString();
|
||||
return Math.floor(value.valueOf()).toString();
|
||||
}
|
||||
|
||||
if (typeof value === 'number') {
|
||||
|
||||
@@ -72,8 +72,8 @@ export const v = {
|
||||
u16: vg<'u16', number>('u16'),
|
||||
s32: vg<'s32', number>('s32'),
|
||||
u32: vg<'u32', number>('u32'),
|
||||
s64: vg<'s64', number>('s64'),
|
||||
u64: vg<'u64', number>('u64'),
|
||||
s64: vg<'s64', bigint | number>('s64'),
|
||||
u64: vg<'u64', bigint | number>('u64'),
|
||||
float: vg<'float', number>('float'),
|
||||
double: vg<'double', number>('double'),
|
||||
b: vg<'b', boolean>('b'),
|
||||
|
||||
Reference in New Issue
Block a user