IIDX: Added Shop Ranking support

This commit is contained in:
duel0213 2024-02-15 02:30:06 +09:00
parent 998589c21b
commit 05a500f6c2
8 changed files with 447 additions and 119 deletions

View File

@ -1,6 +1,6 @@
# beatmaniaIIDX
Plugin Version: **v0.1.10**
Plugin Version: **v0.1.11**
---
@ -26,10 +26,10 @@ Features
- STEP UP (Partial)
- SKILL ANALYZER
- EVENT
- ARENA (Local)
- EVENT (Partial)
- ARENA (Partial)
- RANDOME LANE TICKET
- SONG SELECTION NOTES
- FAVORITE/SONG SELECTION NOTES (Partial)
---
@ -88,3 +88,8 @@ Changelogs
**v0.1.10**
- Added Initial support for SINOBUZ ~ Rootage
- Converted from asphyxia_route_public
**v0.1.11**
- Added Shop Ranking support
- Changed pc.common/gameSystem.systemInfo response not to use pugFile.
- IIDX_CPUS on models/arena.ts came from asphyxia_route_public

View File

@ -1,9 +1,81 @@
import { IIDX_CPUS } from "../models/arena";
import { GetVersion } from "../util";
export const gssysteminfo: EPR = async (info, data, send) => {
const version = GetVersion(info);
if (version < 24) return send.success();
return send.pugFile(`pug/LDJ/${version}systeminfo.pug`);
let result: any = {
arena_schedule: {
phase: K.ITEM("u8", 2),
start: K.ITEM("u32", 1605784800),
end: K.ITEM("u32", 4102326000)
},
arena_music_difficult: [],
maching_class_range: [],
arena_cpu_define: [],
}
for (let s = 0; s < 2; ++s) {
for (let c = 0; c < 20; ++c) {
result.arena_music_difficult.push({
play_style: K.ITEM("s32", s),
arena_class: K.ITEM("s32", c),
low_difficult: K.ITEM("s32", 1),
high_difficult: K.ITEM("s32", 12),
is_leggendaria: K.ITEM("bool", 1),
force_music_list_id: K.ITEM("s32", 0),
});
result.maching_class_range.push({
play_style: K.ITEM("s32", s),
matching_class: K.ITEM("s32", c),
low_arena_class: K.ITEM("s32", 1),
high_arena_class: K.ITEM("s32", 20),
});
result.arena_cpu_define.push({
play_style: K.ITEM("s32", s),
arena_class: K.ITEM("s32", c),
grade_id: K.ITEM("s32", IIDX_CPUS[s][c][0]),
low_music_difficult: K.ITEM("s32", IIDX_CPUS[s][c][1]),
high_music_difficult: K.ITEM("s32", IIDX_CPUS[s][c][2]),
is_leggendaria: K.ITEM("bool", IIDX_CPUS[s][c][3]),
});
}
}
switch (version) {
case 29:
result = {
...result,
CommonBossPhase: K.ATTR({ val: String(3) }),
Event1InternalPhase: K.ATTR({ val: String(5) }),
ExtraBossEventPhase: K.ATTR({ val: String(3) }),
isNewSongAnother12OpenFlg: K.ATTR({ val: String(1) }),
gradeOpenPhase: K.ATTR({ val: String(2) }),
isEiseiOpenFlg: K.ATTR({ val: String(1) }),
WorldTourismOpenList: K.ATTR({ val: String(-1) }),
BPLBattleOpenPhase: K.ATTR({ val: String(2) }),
}
break;
case 30:
result = {
...result,
CommonBossPhase: K.ATTR({ val: String(3) }),
Event1InternalPhase: K.ATTR({ val: String(5) }),
ExtraBossEventPhase: K.ATTR({ val: String(3) }),
isNewSongAnother12OpenFlg: K.ATTR({ val: String(1) }),
gradeOpenPhase: K.ATTR({ val: String(2) }),
isEiseiOpenFlg: K.ATTR({ val: String(1) }),
WorldTourismOpenList: K.ATTR({ val: String(-1) }),
BPLBattleOpenPhase: K.ATTR({ val: String(2) }),
}
break;
default:
break;
}
return send.object(result);
};

View File

@ -1,6 +1,7 @@
import { IDtoRef, Base64toBuffer, GetVersion, OldMidToNewMid, NewMidToOldMid, ReftoProfile, ReftoPcdata, ClidToPlaySide } from "../util";
import { IDtoRef, Base64toBuffer, GetVersion, OldMidToNewMid, NewMidToOldMid, ReftoProfile, ReftoPcdata, ClidToPlaySide, ReftoQPRO } from "../util";
import { score, score_top } from "../models/score";
import { profile } from "../models/profile";
import { shop_data } from "../models/shop";
export const musicgetrank: EPR = async (info, data, send) => {
const version = GetVersion(info);
@ -305,6 +306,9 @@ export const musicappoint: EPR = async (info, data, send) => {
export const musicreg: EPR = async (info, data, send) => {
const version = GetVersion(info);
const shop_data = await DB.FindOne<shop_data>({
collection: "shop_data",
});
// wid, oppid, opname, opt, opt2, pside, nocnt, anum //
const refid = await IDtoRef(parseInt($(data).attr().iidxid));
@ -318,7 +322,8 @@ export const musicreg: EPR = async (info, data, send) => {
let ghost = null, ghost_gauge = null; // Heroic Verse //
let style = 0, option = 0, option_2 = 0;
// TODO:: SPADA Leggendaria has seperate music_id //
// TODO:: Leggendaria until HEROIC VERSE has seperate music_id //
// TODO:: SUPER FUTURE 2323 has seperate music_id //
const mapping = [1, 2, 3, 6, 7, 8];
if (version == -1) return send.deny();
else if (version < 20) {
@ -349,6 +354,7 @@ export const musicreg: EPR = async (info, data, send) => {
let esArray = Array<number>(10).fill(0); // EXSCORE //
let optArray = Array<number>(10).fill(0); // USED OPTION (CastHour) //
let opt2Array = Array<number>(10).fill(0); // USED OPTION (CastHour) //
let update = 0;
if (version >= 18) ghost = $(data).buffer("ghost").toString("base64");
@ -389,6 +395,7 @@ export const musicreg: EPR = async (info, data, send) => {
esArray[clid] = Math.max(esArray[clid], exscore);
optArray[clid] = option;
opt2Array[clid] = option_2;
update = 1;
} else {
ghost = music_data[clid];
if (version >= 27) ghost_gauge = music_data[clid + 10];
@ -470,15 +477,98 @@ export const musicreg: EPR = async (info, data, send) => {
}
);
send.object(
K.ATTR({
status: "0",
let shop_rank = -1, shop_rank_data = [];
let scores: any[][];
scores = (
await DB.Find(null, {
collection: "score",
mid: mid,
cArray: { $exists: true },
esArray: { $exists: true },
})
).map((r) => [r.esArray[clid], r.cArray[clid], r.__refid]);
scores.sort((a, b) => b[0] - a[0]);
shop_rank = scores.findIndex((a) => a[2] == refid);
scores = await Promise.all(
scores.map(async (r) => [
r[0],
r[1],
await ReftoProfile(r[2]),
await ReftoQPRO(r[2], version),
await ReftoPcdata(r[2], version),
])
);
scores.forEach((rankscore, index) => {
if (index == shop_rank) {
shop_rank_data.push(
K.ATTR({
iidx_id: String(rankscore[2][2]),
name: String(rankscore[2][0]),
opname: shop_data.opname,
rnum: String(index + 1),
score: String(rankscore[0]),
clflg: String(rankscore[1]),
pid: String(rankscore[2][1]),
sgrade: String(rankscore[4][0]),
dgrade: String(rankscore[4][1]),
head: String(rankscore[3][1]),
hair: String(rankscore[3][0]),
face: String(rankscore[3][2]),
body: String(rankscore[3][3]),
hand: String(rankscore[3][4]),
myFlg: String(1),
s_baron: String(0),
p_baron: String(0),
achieve: String(0),
update: String(update),
})
);
}
else if (rankscore[0] != 0 || rankscore[1] != 0) {
shop_rank_data.push(
K.ATTR({
iidx_id: String(rankscore[2][2]),
name: String(rankscore[2][0]),
opname: shop_data.opname,
rnum: String(index + 1),
score: String(rankscore[0]),
clflg: String(rankscore[1]),
pid: String(rankscore[2][1]),
sgrade: String(rankscore[4][0]),
dgrade: String(rankscore[4][1]),
head: String(rankscore[3][1]),
hair: String(rankscore[3][0]),
face: String(rankscore[3][2]),
body: String(rankscore[3][3]),
hand: String(rankscore[3][4]),
myFlg: String(0),
s_baron: String(0),
p_baron: String(0),
achieve: String(0),
update: String(0),
})
);
}
});
let result: any = {
"@attr": {
mid: String(mid),
clid: String(clid),
crate: "0",
frate: "0",
})
);
rankside: String(style),
},
ranklist: {
"@attr": { total_user_num: String(shop_rank_data.length) },
data: shop_rank_data,
},
shopdata: K.ATTR({ rank: String(shop_rank) }),
}
return send.object(result);
}
// this is not valid response //

View File

@ -10,98 +10,218 @@ import { world_tourism } from "../models/worldtourism";
export const pccommon: EPR = async (info, data, send) => {
const version = GetVersion(info);
if (version == 18) {
return send.object({
"@attr": {
expire: 600,
},
ir: K.ATTR({
beat: String(U.GetConfig("BeatPhase")),
}),
cmd: K.ATTR({
gmbl: "1",
gmbla: "1",
regl: "1",
rndp: "1",
hrnd: "1",
alls: "1",
}),
lg: K.ATTR({
lea: "0",
}),
lf: K.ATTR({
life: "0",
}),
ev: K.ATTR({
pha: "3",
}),
lincle: K.ATTR({
phase: "1",
})
});
}
else if (version == 19) {
return send.object({
"@attr": {
expire: 600,
},
ir: K.ATTR({
beat: String(U.GetConfig("BeatPhase")),
}),
lincle: K.ATTR({
phase: String(2),
}),
boss: K.ATTR({
phase: String(2),
}),
mr_secret: K.ATTR({
flg: String(-1),
}),
travel: K.ATTR({
flg: String(-1),
}),
});
}
else if (version == 20) {
return send.object({
"@attr": {
expire: 600,
},
ir: K.ATTR({
beat: String(U.GetConfig("BeatPhase")),
}),
limit: K.ATTR({
phase: String(4),
}),
boss: K.ATTR({
phase: String(3),
}),
red: K.ATTR({
phase: String(3),
}),
yellow: K.ATTR({
phase: String(3),
}),
medal: K.ATTR({
phase: String(3),
}),
cafe: K.ATTR({
open: String(1),
}),
tricolettepark: K.ATTR({
open: String(1),
}),
});
}
else if (version >= 21) {
return send.pugFile(`pug/LDJ/${version}pccommon.pug`, {
beat: U.GetConfig("BeatPhase"),
movie_upload: U.GetConfig("MovieUpload"),
system_voice_phase: Math.floor(Math.random() * 8),
});
let result: any = {
"@attr": {
expire: 300,
},
ir: K.ATTR({
beat: String(U.GetConfig("BeatPhase")),
}),
}
return send.deny();
switch (version) {
case 18:
result = {
...result,
cmd: K.ATTR({
gmbl: String(1),
gmbla: String(1),
regl: String(1),
rndp: String(1),
hrnd: String(1),
alls: String(1),
}),
lg: K.ATTR({ lea: String(0) }),
lf: K.ATTR({ life: String(0) }),
ev: K.ATTR({ pha: String(3) }),
lincle: K.ATTR({ phase: String(1) })
}
break;
case 19:
result = {
...result,
lincle: K.ATTR({ phase: String(2) }),
boss: K.ATTR({ phase: String(2) }),
mr_secret: K.ATTR({ flg: String(-1) }),
travel: K.ATTR({ flg: String(-1) }),
}
break;
case 20:
result = {
...result,
limit: K.ATTR({ phase: String(4) }),
boss: K.ATTR({ phase: String(3) }),
red: K.ATTR({ phase: String(3) }),
yellow: K.ATTR({ phase: String(3) }),
medal: K.ATTR({ phase: String(3) }),
cafe: K.ATTR({ open: String(1) }),
tricolettepark: K.ATTR({ open: String(1) }),
}
break;
case 21:
result = {
...result,
limit: K.ATTR({ phase: String(4) }),
boss: K.ATTR({ phase: String(3) }),
boss1: K.ATTR({ phase: String(4) }),
medal: K.ATTR({ phase: String(1) }),
vip_pass_black: {},
cafe: K.ATTR({ open: String(1) }),
tricolettepark: K.ATTR({ open: String(1) }),
tricolettepark_skip: K.ATTR({ phase: String(2) }),
deller_bonus: K.ATTR({ open: String(1) }),
gumi_event: {},
newsong_another: K.ATTR({ open: String(1) }),
superstar: K.ATTR({ phase: String(2) }),
}
break;
case 22:
result = {
...result,
pre_play: K.ATTR({ phase: String(2) }),
expert: K.ATTR({ phase: String(2) }),
toho_remix: K.ATTR({ phase: String(2) }),
expert_random_secret: K.ATTR({ phase: String(2) }),
limit: K.ATTR({ phase: String(9) }),
boss: K.ATTR({ phase: String(3) }),
chrono_diver: K.ATTR({ phase: String(3) }),
qpronicle_chord: K.ATTR({ phase: String(2) }),
vip_pass_black: {},
cc_collabo_event: K.ATTR({ phase: String(3) }),
cc_collabo_license: {},
deller_bonus: K.ATTR({ open: String(1) }),
newsong_another: K.ATTR({ open: String(1) }),
common_timeshift_phase: K.ATTR({ phase: String(0) }),
expert_secret_full_open: {},
eappli_expert: {},
eaorder: {},
}
break;
case 23:
result = {
...result,
expert: K.ATTR({ phase: String(1) }),
expert_random_secret: K.ATTR({ phase: String(2) }),
boss: K.ATTR({ phase: String(3) }),
event1_phase: K.ATTR({ phase: String(1) }),
event2_phase: K.ATTR({ phase: String(2) }),
extra_boss_event: K.ATTR({ phase: String(30) }),
vip_pass_black: {},
event1_ranbow_ticket: {},
deller_bonus: K.ATTR({ open: String(1) }),
newsong_another: K.ATTR({ open: String(1) }),
expert_secret_full_open: {},
remocon_collabo: {},
ravemania_collabo: {},
djlevel_result: {},
virtual_coin: K.ATTR({ phase: String(1) }),
reflec_volzza_collabo: {},
bemani_summer2016: K.ATTR({ phase: String(2) }),
}
break;
case 24: // asphyix_route_public //
case 25:
case 26:
result = {
...result,
newsong_another: K.ATTR({ open: String(1) }),
expert_secret_full_open: {},
system_voice_phase: K.ATTR({ phase: String(_.random(0, 8)) }),
expert: K.ATTR({ phase: String(1) })
}
break;
case 27:
result = {
...result,
expert: K.ATTR({ phase: String(1) }),
expert_random_secret: K.ATTR({ phase: String(1) }),
boss: K.ATTR({ phase: String(1) }),
vip_pass_black: {},
deller_bonus: K.ATTR({ open: String(1) }),
newsong_another: K.ATTR({ open: String(1) }),
expert_secret_full_open: {},
system_voice_phase: K.ATTR({ phase: String(_.random(0, 8)) }),
extra_boss_event: K.ATTR({ phase: String(1) }),
event1_phase: K.ATTR({ phase: String(4) }),
premium_area_news: K.ATTR({ open: String(1) }),
premium_area_qpro: K.ATTR({ open: String(1) }),
play_video: {},
display_asio_logo: {},
}
break;
case 28:
result = {
...result,
movie_agreement: K.ATTR({ version: String(1) }),
movie_upload: K.ATTR({ url: String(U.GetConfig("MovieUpload")) }),
expert: K.ATTR({ phase: String(1) }),
expert_random_secret: K.ATTR({ phase: String(1) }),
boss: K.ATTR({ phase: String(1) }),
vip_pass_black: {},
eisei: K.ATTR({ open: String(1) }),
deller_bonus: K.ATTR({ open: String(1) }),
newsong_another: K.ATTR({ open: String(1) }),
expert_secret_full_open: {},
system_voice_phase: K.ATTR({ phase: String(_.random(0, 8)) }),
extra_boss_event: K.ATTR({ phase: String(1) }),
event1_phase: K.ATTR({ phase: String(4) }),
premium_area_news: K.ATTR({ open: String(1) }),
premium_area_qpro: K.ATTR({ open: String(1) }),
play_video: {},
world_tourism: K.ATTR({ open_list: String(-1) }),
bpl_battle: K.ATTR({ phase: String(1) }),
display_asio_logo: {},
}
break;
case 29:
result = {
...result,
movie_agreement: K.ATTR({ version: String(1) }),
movie_upload: K.ATTR({ url: String(U.GetConfig("MovieUpload")) }),
expert: K.ATTR({ phase: String(1) }),
expert_random_secret: K.ATTR({ phase: String(1) }),
boss: K.ATTR({ phase: String(1) }),
vip_pass_black: {},
eisei: K.ATTR({ open: String(1) }),
deller_bonus: K.ATTR({ open: String(1) }),
newsong_another: K.ATTR({ open: String(1) }),
expert_secret_full_open: {},
system_voice_phase: K.ATTR({ phase: String(_.random(0, 8)) }),
extra_boss_event: K.ATTR({ phase: String(1) }),
event1_phase: K.ATTR({ phase: String(4) }),
premium_area_news: K.ATTR({ open: String(1) }),
premium_area_qpro: K.ATTR({ open: String(1) }),
play_video: {},
world_tourism: K.ATTR({ open_list: String(-1) }),
bpl_battle: K.ATTR({ phase: String(1) }),
display_asio_logo: {},
lane_gacha: {},
}
break;
case 30:
result = {
...result,
movie_agreement: K.ATTR({ version: String(1) }),
movie_upload: K.ATTR({ url: String(U.GetConfig("MovieUpload")) }),
vip_pass_black: {},
deller_bonus: K.ATTR({ open: String(1) }),
newsong_another: K.ATTR({ open: String(1) }),
system_voice_phase: K.ATTR({ phase: String(_.random(0, 8)) }),
premium_area_news: K.ATTR({ open: String(1) }),
premium_area_qpro: K.ATTR({ open: String(1) }),
play_video: {},
display_asio_logo: {},
lane_gacha: {},
tourism_booster: {},
ameto_event: {},
}
break;
default:
return send.deny();
}
return send.object(result);
};
export const pcreg: EPR = async (info, data, send) => {
@ -364,8 +484,11 @@ export const pcget: EPR = async (info, data, send) => {
});
}
else if (version == 20) {
if (!_.isNil(pcdata.st_stamp)) pcdata.st_stamp = Base64toBuffer(pcdata.st_stamp).toString("hex");
if (!_.isNil(pcdata.st_help)) pcdata.st_help = Base64toBuffer(pcdata.st_help).toString("hex");
if (_.isNil(pcdata.st_stamp)) pcdata.st_stamp = ""; // temp //
let link5 = await DB.FindOne(refid, { collection: "event_1", version: version, event_name: "link5" });
let tricolettepark = await DB.FindOne(refid, { collection: "event_1", version: version, event_name: "tricolettepark" });
let redboss = await DB.FindOne(refid, { collection: "event_1", version: version, event_name: "redboss" });
@ -547,7 +670,6 @@ export const pcget: EPR = async (info, data, send) => {
return send.deny();
};
// TODO:: migration (oldget/getname/takeover) //
export const pcoldget: EPR = async (info, data, send) => {
const refid = $(data).attr().rid;
const pcdata = await DB.FindOne<pcdata>(refid, { collection: "pcdata" }); // version check removed //
@ -928,6 +1050,7 @@ export const pcsave: EPR = async (info, data, send) => {
pcdata.st_dp_mplay = parseInt($(data).attr("step").dp_mplay);
}
pcdata.st_review = parseInt($(data).attr("step").review);
pcdata.st_stamp = $(data).buffer("step").toString("base64"); // TODO:: verify //
pcdata.st_help = $(data).element("step").buffer("help").toString("base64");
}

View File

@ -0,0 +1,46 @@
export const IIDX_CPUS = [
[
[6, 4, 5, 0],
[7, 5, 6, 0],
[8, 6, 6, 0],
[9, 6, 7, 0],
[10, 7, 7, 0],
[10, 7, 8, 0],
[11, 8, 8, 0],
[11, 8, 9, 0],
[12, 9, 9, 0],
[12, 9, 10, 0],
[13, 9, 10, 0],
[13, 10, 10, 0],
[14, 10, 11, 0],
[14, 10, 11, 1],
[15, 11, 11, 1],
[15, 11, 12, 1],
[16, 11, 12, 1],
[16, 11, 12, 1],
[17, 12, 12, 1],
[18, 12, 12, 1],
],
[
[6, 3, 5, 0],
[7, 3, 5, 0],
[8, 4, 5, 0],
[8, 4, 5, 0],
[9, 5, 6, 0],
[9, 5, 6, 0],
[10, 6, 6, 0],
[10, 6, 7, 0],
[11, 7, 7, 0],
[11, 7, 8, 0],
[12, 8, 8, 0],
[12, 8, 9, 0],
[13, 9, 9, 0],
[13, 9, 10, 0],
[14, 9, 10, 0],
[15, 10, 10, 0],
[15, 10, 11, 0],
[16, 11, 11, 1],
[17, 11, 12, 1],
[18, 12, 12, 1],
],
];

View File

@ -131,6 +131,7 @@ export interface pcdata {
st_sp_round: number;
st_dp_round: number;
st_review: number;
st_stamp: any;
st_help: any; // save as base64 string, sent as buffer //
st_damage: number; // spada //
@ -320,7 +321,8 @@ export const LDJ_pcdata = {
st_dp_round: 0,
st_dp_mplay: 0,
st_review: 0,
st_help: "",
st_stamp: null,
st_help: null,
achi_lastweekly: 0,
achi_pack: 0,

View File

@ -24,7 +24,7 @@ pc(status="0")
join_shop(joinflg="1" join_cflg="1" join_id="0" join_name="CORE")
fcombo(__type="s16" __count="2") #{pcdata.fcombo[0]} #{pcdata.fcombo[1]}
step(sp_ach=pcdata.st_sp_ach dp_ach=pcdata.st_dp_ach sp_hdpt=pcdata.st_sp_hdpt dp_hdpt=pcdata.st_dp_hdpt sp_level=pcdata.st_sp_level dp_level=pcdata.st_dp_level sp_round=pcdata.st_sp_round dp_round=pcdata.st_dp_round sp_mplay=pcdata.st_sp_mplay dp_mplay=pcdata.st_dp_mplay review=pcdata.st_review)
//-stamp(__type="bin")
stamp(__type="bin") #{pcdata.st_stamp}
help(__type="bin") #{pcdata.st_help}
achievements(last_weekly=pcdata.achi_lastweekly pack=pcdata.achi_pack pack_comp=pcdata.achi_packcomp rival_crush=pcdata.achi_rivalcrush visit_flg=pcdata.achi_visitflg weekly_num=pcdata.achi_weeklynum)
trophy(__type="s64" __count="10") #{pcdata.achi_trophy[0]} #{pcdata.achi_trophy[1]} #{pcdata.achi_trophy[2]} #{pcdata.achi_trophy[3]} #{pcdata.achi_trophy[4]} #{pcdata.achi_trophy[5]} #{pcdata.achi_trophy[6]} #{pcdata.achi_trophy[7]} #{pcdata.achi_trophy[8]} #{pcdata.achi_trophy[9]}

View File

@ -4,6 +4,7 @@ import { profile } from "./models/profile";
export function IDtoCode(id: number) {
const padded = _.padStart(String(id), 8);
return `${padded.slice(0, 4)}-${padded.slice(4)}`;
}
@ -32,19 +33,7 @@ export function NewMidToOldMid(mid: number) {
}
export function ClidToPlaySide(clid: number) {
switch (clid) {
case 0: // SPB //
case 1:
case 2:
case 3:
case 4:
return 0; // SPA //
default:
break;
}
return 1;
return clid < 5 ? 0 : 1;
}
export function Base64toBuffer(s: string) {
@ -159,6 +148,7 @@ export async function ReftoPcdata(refid: string, version: number) {
return p_data;
}
export async function ReftoQPRO(refid: string, version: number) {
const custom = await DB.FindOne<custom>(refid, {
collection: "custom",