gitadora wip

This commit is contained in:
GEEKiDoS
2025-04-17 17:01:22 +08:00
parent 4cb1980de2
commit 0b8c544dcc
10 changed files with 73147 additions and 6 deletions
+72780
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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),
+106
View File
@@ -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,
}
}
}
}
};
}
}
+8
View File
@@ -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> {
}
}
+84
View File
@@ -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(''),
}];
+76
View File
@@ -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;
}
+62
View File
@@ -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;
}
}
+2
View File
@@ -0,0 +1,2 @@
export * from './data.js';
export * from './db.js';
+26 -3
View File
@@ -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') {
+2 -2
View File
@@ -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'),