diff --git a/iidx@asphyxia/README.md b/iidx@asphyxia/README.md index 6f8b8dd..8cda96e 100644 --- a/iidx@asphyxia/README.md +++ b/iidx@asphyxia/README.md @@ -6,6 +6,7 @@ Plugin Version: **v0.1.12** Supported Versions + - beatmaniaIIDX 15 DJ TROOPERS - beatmaniaIIDX 17 SIRIUS - beatmaniaIIDX 18 Resort Anthem - beatmaniaIIDX 19 Lincle @@ -107,10 +108,13 @@ Changelogs - Added Experimental WebUI (WIP) - Added music.crate/music.breg response - CLEAR RATE and BEGINNER clear lamp may not work on certain versions - - Added Initial support for SIRIUS (profile only) + - Added Initial support for SIRIUS - Fixed where Venue Top didn't save correctly (BISTROVER ~) - Fixed where music.appoint send empty response even rival has score data when player doesn't have score data - Fixed where FAVORITE may work only on specific version - Fixed where shop name always displayed as "CORE" instead of saved one - Fixed where rlist STEP UP achieve value was fixed value instead of saved one - Fixed where fcombo isn't saving (Resort Anthem) + +**v0.1.13** + - Added Initial support for DJ TROOPERS (WIP) diff --git a/iidx@asphyxia/handlers/music.ts b/iidx@asphyxia/handlers/music.ts index 5dfb152..05a1dc1 100644 --- a/iidx@asphyxia/handlers/music.ts +++ b/iidx@asphyxia/handlers/music.ts @@ -1,4 +1,4 @@ -import { IDtoRef, Base64toBuffer, GetVersion, OldMidToNewMid, NewMidToOldMid, ReftoProfile, ReftoPcdata, ClidToPlaySide, ReftoQPRO } from "../util"; +import { IDtoRef, Base64toBuffer, GetVersion, OldMidToNewMid, NewMidToOldMid, ReftoProfile, ReftoPcdata, ClidToPlaySide, ReftoQPRO, NumArrayToString } from "../util"; import { score, score_top } from "../models/score"; import { profile } from "../models/profile"; import { shop_data } from "../models/shop"; @@ -25,7 +25,48 @@ export const musicgetrank: EPR = async (info, data, send) => { let m = [], top = [], b = [], t = []; let score_data: number[]; let indices, temp_mid = 0; - if (version < 20) { + if (version == 15) { // TODO:: Debug NumArrayToString, theres weird records (invalid exscore) // + let result = { + r: [], // v - (-1, beginner/-2, tutorial) // + }; + indices = cltype === 0 ? [1, 2, 3] : [6, 7, 8]; + music_data.forEach((res: score) => { + temp_mid = NewMidToOldMid(res.mid); + let mVersion = Math.floor(temp_mid / 100); + let mMid = temp_mid % 100; + + if (mVersion > version) return; + for (let a = 0; a < 3; a++) { + if (res.esArray[indices[a]] == 0) continue; + result.r.push( + K.ITEM("str", NumArrayToString( + [7, 4, 13, 3, 3], + [mMid, a, res.esArray[indices[a]], -1, res.cArray[indices[a]]] // mid , diff , score , rid (rank_id) , flg // + ), { v: String(mVersion) } ) + ); + } + }); + + // rival data seems to be retrieve from getralive // + + // tutorial // + const tutorial = await DB.Find(refid, { + collection: "tutorial", + version: version + }); + tutorial.sort((a: tutorial, b: tutorial) => a.tid - b.tid); + tutorial.forEach((res) => { + result.r.push( + K.ITEM("str", NumArrayToString( + [5, 1], + [res.tid, res.clr] + ), { v: String("-2") }) + ); + }); + + return send.object(result); + } + else if (version < 20) { indices = cltype === 0 ? [1, 2, 3] : [6, 7, 8]; music_data.forEach((res: score) => { temp_mid = NewMidToOldMid(res.mid); @@ -103,11 +144,11 @@ export const musicgetrank: EPR = async (info, data, send) => { }); if (score_top.length > 0) { - if (version >= 27) { + if (version >= 27) { score_top.forEach((res) => { let mVersion = Math.floor(res.mid / 1000); if (mVersion > version) return; - + top.push({ "@attr": ({ name0: res.names[0], @@ -123,7 +164,7 @@ export const musicgetrank: EPR = async (info, data, send) => { score_top.forEach((res) => { let mVersion = Math.floor(res.mid / 1000); if (mVersion > version) return; - + top.push({ "@attr": ({ name0: res.names[1], @@ -346,7 +387,8 @@ export const musicreg: EPR = async (info, data, send) => { let opt2Array = Array(10).fill(0); // USED OPTION (CastHour) // let update = 0; - if (version >= 17) ghost = $(data).buffer("ghost").toString("base64"); + if (version == 15) ghost = Buffer.from($(data).str("ghost"), "hex").toString("base64"); + else ghost = $(data).buffer("ghost").toString("base64"); if (version >= 27) { ghost_gauge = $(data).buffer("ghost_gauge").toString("base64"); diff --git a/iidx@asphyxia/handlers/pc.ts b/iidx@asphyxia/handlers/pc.ts index 2820164..dade5ed 100644 --- a/iidx@asphyxia/handlers/pc.ts +++ b/iidx@asphyxia/handlers/pc.ts @@ -1,7 +1,7 @@ -import { pcdata, KDZ_pcdata, IIDX27_pcdata, IIDX28_pcdata, IIDX29_pcdata, IIDX30_pcdata, JDZ_pcdata, LDJ_pcdata, IIDX21_pcdata, IIDX22_pcdata, IIDX23_pcdata, IIDX24_pcdata, IIDX25_pcdata, IIDX26_pcdata, JDJ_pcdata } from "../models/pcdata"; +import { pcdata, KDZ_pcdata, IIDX27_pcdata, IIDX28_pcdata, IIDX29_pcdata, IIDX30_pcdata, JDZ_pcdata, LDJ_pcdata, IIDX21_pcdata, IIDX22_pcdata, IIDX23_pcdata, IIDX24_pcdata, IIDX25_pcdata, IIDX26_pcdata, JDJ_pcdata, HDD_pcdata } from "../models/pcdata"; import { grade } from "../models/grade"; import { custom, default_custom } from "../models/custom"; -import { IDtoCode, IDtoRef, Base64toBuffer, GetVersion, ReftoProfile, ReftoPcdata, ReftoQPRO, appendSettingConverter } from "../util"; +import { IDtoCode, IDtoRef, Base64toBuffer, GetVersion, ReftoProfile, ReftoPcdata, ReftoQPRO, appendSettingConverter, NumArrayToString } from "../util"; import { eisei_grade, eisei_grade_data, lightning_musicmemo, lightning_musicmemo_new, lightning_playdata, lightning_settings, lm_playdata, lm_settings, lm_settings_new, musicmemo_data, musicmemo_data_new } from "../models/lightning"; import { profile, default_profile } from "../models/profile"; import { rival, rival_data } from "../models/rival"; @@ -23,6 +23,8 @@ export const pccommon: EPR = async (info, data, send) => { // have no idea what some of attribute or value does // // exposing these to plugin setting or use static value // switch (version) { + case 15: + break; case 17: result = { ...result, @@ -239,6 +241,9 @@ export const pcreg: EPR = async (info, data, send) => { let lightning_settings: object; let lightning_playdata: object; switch (version) { + case 15: + pcdata = HDD_pcdata; + break; case 17: pcdata = JDJ_pcdata; break; @@ -398,7 +403,7 @@ export const pcget: EPR = async (info, data, send) => { custom.rival_played_folder, custom.hide_iidxid, ); - let dArray = [], eArray = [], rArray = [], mArray = [], bArray = []; + let dArray = [], eArray = [], rArray = [], mArray = [], bArray = [], gArray = []; grade.forEach((res: grade) => { dArray.push([res.style, res.gradeId, res.maxStage, res.archive]); @@ -454,7 +459,24 @@ export const pcget: EPR = async (info, data, send) => { wArray.sort((a, b) => a.tour_id - b.tour_id); } - let event; + let event, gradeStr, exStr, skinStr; + if (version == 15) { + dArray.forEach((res: grade) => { + gArray.concat([res.gradeId, res.maxStage, res.style, res.archive]); + }); + gradeStr = NumArrayToString([6, 3, 2, 7], gArray); + exStr = ""; // TODO:: // + skinStr = NumArrayToString([12], [custom.frame, custom.turntable, custom.note_burst, custom.menu_music, appendsettings, custom.lane_cover, 0, custom.category_vox]); + + return send.pugFile("pug/HDD/pcget.pug", { + profile, + pcdata, + gradeStr, + exStr, + skinStr, + rArray, + }); + } if (version == 17) { expert.sort((a: expert, b: expert) => a.coid - b.coid); expert.forEach((res) => { @@ -770,6 +792,9 @@ export const pctakeover: EPR = async (info, data, send) => { let lightning_settings: object; let lightning_playdata: object; switch (version) { + case 15: + pcdata = HDD_pcdata; + break; case 17: pcdata = JDJ_pcdata; break; @@ -936,7 +961,42 @@ export const pcsave: EPR = async (info, data, send) => { pcdata.mode = parseInt($(data).attr().mode); pcdata.pmode = parseInt($(data).attr().pmode); - if (version == 17) { + if (version == 15) { + if (cltype == 0) { + pcdata.sach = parseInt($(data).attr().achi); + pcdata.sp_opt = parseInt($(data).attr().opt); + } + else { + pcdata.dach = parseInt($(data).attr().achi); + pcdata.dp_opt = parseInt($(data).attr().opt); + pcdata.dp_opt2 = parseInt($(data).attr().opt2); + } + + pcdata.gno = parseInt($(data).attr().gno); + pcdata.sflg0 = parseInt($(data).attr().sflg0); + pcdata.sflg1 = parseInt($(data).attr().sflg1); + pcdata.sflg2 = parseInt($(data).attr().sflg2); + pcdata.sdhd = parseInt($(data).attr().sdhd); + pcdata.ncomb = parseInt($(data).attr().ncomb); + pcdata.mcomb = parseInt($(data).attr().mcomb); + + if (!_.isNil($(data).element("tutorial"))) { + let clr = parseInt($(data).attr("tutorial").clr); + await DB.Upsert(refid, + { + collection: "tutorial", + version: version, + tid: parseInt($(data).attr("tutorial").tid), + }, + { + $set: { + clr + } + } + ); + } + } + else if (version == 17) { if (cltype == 0) { pcdata.sach = parseInt($(data).attr().achi); pcdata.sp_opt = parseInt($(data).attr().opt); diff --git a/iidx@asphyxia/index.ts b/iidx@asphyxia/index.ts index 883372f..98f40e8 100644 --- a/iidx@asphyxia/index.ts +++ b/iidx@asphyxia/index.ts @@ -15,6 +15,7 @@ export function register() { R.Contributor("duel0213"); + R.GameCode("HDD"); R.GameCode("JDJ"); R.GameCode("JDZ"); R.GameCode("KDZ"); diff --git a/iidx@asphyxia/models/pcdata.ts b/iidx@asphyxia/models/pcdata.ts index ed6592b..612813c 100644 --- a/iidx@asphyxia/models/pcdata.ts +++ b/iidx@asphyxia/models/pcdata.ts @@ -9,6 +9,7 @@ export interface pcdata { dach: number; sflg0: number; sflg1: number; + sflg2: number; gno: number; timing: number; sdhd: number; @@ -214,6 +215,30 @@ export interface pcdata { tourism_secret_flg2: string[]; } +export const HDD_pcdata = { + version: 15, + + spnum: 0, + dpnum: 0, + sach: 0, + dach: 0, + sflg0: 0, + sflg1: 0, + sflg2: 0, + gno: 0, + sdhd: 0, + sp_opt: 0, + dp_opt: 0, + dp_opt2: 0, + mcomb: 0, + ncomb: 0, + mode: 0, + pmode: 0, + + sgid: -1, + dgid: -1, +} + export const JDJ_pcdata = { version: 17, diff --git a/iidx@asphyxia/pug/HDD/pcget.pug b/iidx@asphyxia/pug/HDD/pcget.pug new file mode 100644 index 0000000..98623be --- /dev/null +++ b/iidx@asphyxia/pug/HDD/pcget.pug @@ -0,0 +1,9 @@ +pc(status="0") + pcdata(id=profile.id idstr=profile.idstr name=profile.name pid=profile.pid spnum=pcdata.spnum dpnum=pcdata.dpnum sach=pcdata.sach dach=pcdata.dach sflg0=pcdata.sflg0 sflg1=pcdata.sflg1 sflg2=pcdata.sflg2 gno=pcdata.gno sdhd=pcdata.sdhd sp_opt=pcdata.sp_opt dp_opt=pcdata.dp_opt dp_opt2=pcdata.dp_opt2 mcomb=pcdata.mcomb ncomb=pcdata.ncomb mode=pcdata.mode pmode=pcdata.pmode) + grade(sgid=pcdata.sgid dgid=pcdata.dgid __type="str") #{gradeStr} + ex(__type="str") #{exStr} + skin(__type="str") #{skinStr} + rlist + - for (let rd of rArray) + rival(spdp=rd.play_style id=rd.profile[2] id_str=rd.profile[3] djname=rd.profile[0] pid=rd.profile[1] sg=rd.pcdata[0] dg=rd.pcdata[1] sa=rd.pcdata[2] da=rd.pcdata[3]) + visitor(anum="10" snum="10" pnum="10" vs_flg="1") diff --git a/iidx@asphyxia/util.ts b/iidx@asphyxia/util.ts index d638ada..2c03c26 100644 --- a/iidx@asphyxia/util.ts +++ b/iidx@asphyxia/util.ts @@ -61,9 +61,58 @@ export function Base64toBuffer(s: string) { return Buffer.from(t); } +export function NumArrayToString(bits: number[], numArray: number[]): string { + const characters = "0123456789:;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + let byteSum = 0; + let byteIndex = 0; + if (bits.length > 0) { + do { + byteSum = bits[byteIndex] + byteSum; + byteIndex++; + } while (byteIndex < bits.length); + } + + let result = ""; + let numIdx = 0; + if (numArray != null && !_.isNaN(numArray[0])) { + let numArrayIdx = 0; + if (numArray.length > 0) { + let combined = 0; + do { + if (numIdx == 0) combined = 0; + + const b = bits[numArrayIdx]; + combined = ((numArray[numIdx] & (1 << b) - 1) | combined << b); + numArrayIdx++; + if (numArrayIdx == bits.length) { + combined <<= 32 - byteSum; + + const characterCount = Math.floor((byteSum + 5) / 6); + if (characterCount > 0) { + let charaIdx = 26; + let charaLoopCnt = characterCount; + do { + const character = (combined >> charaIdx) & 63; + result += characters.charAt(character); + + charaIdx -= 6; + charaLoopCnt--; + } while (charaLoopCnt > 0); + } + numArrayIdx = 0; + } + numIdx++; + } while (numIdx < numArray.length); + } + } + + return result; +} + export function GetVersion(info: EamuseInfo) { let version = -1; switch (info.model.substring(0, 3)) { + case "HDD": return 15; case "JDJ": return 17; case "JDZ": return 18; case "KDZ": return 19;