idz: Dispatch on declared protocol version
This commit is contained in:
@@ -18,7 +18,7 @@ import { loadRewardTable } from "./loadRewardTable";
|
||||
import { loadServerList } from "./loadServerList";
|
||||
import { loadStocker } from "./loadStocker";
|
||||
import { loadTeam } from "./loadTeam";
|
||||
import { loadTeamRanking, loadTeamRanking2 } from "./loadTeamRanking";
|
||||
import { loadTeamRanking1, loadTeamRanking2 } from "./loadTeamRanking";
|
||||
import { loadTopTen1 } from "./loadTopTen1";
|
||||
import { loadTopTen2 } from "./loadTopTen2";
|
||||
import { lockGarage } from "./lockGarage";
|
||||
@@ -48,7 +48,7 @@ import { updateTeamPoints } from "./updateTeamPoints";
|
||||
import { updateUiReport } from "./updateUiReport";
|
||||
import { updateUserLog } from "./updateUserLog";
|
||||
import { lockProfileExtend } from "./lockProfileExtend";
|
||||
import { BLOCK_SIZE } from "../../common";
|
||||
import { BLOCK_SIZE, ClientHello } from "../../common";
|
||||
import { ByteStream } from "../../../util/stream";
|
||||
|
||||
const debug = logger("app:idz:userdb:decoder");
|
||||
@@ -58,53 +58,55 @@ export type ReaderFn = ((buf: Buffer) => Request) & {
|
||||
msgLen: number;
|
||||
};
|
||||
|
||||
const funcList: ReaderFn[] = [
|
||||
function makeReaderMap(funcList: ReaderFn[]): Map<number, ReaderFn> {
|
||||
const result = new Map<number, ReaderFn>();
|
||||
|
||||
for (const fn of funcList) {
|
||||
result.set(fn.msgCode, fn);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO confirm v1.21.00 proto version
|
||||
const funcList110: ReaderFn[] = [
|
||||
checkTeamName,
|
||||
createAutoTeam,
|
||||
createProfile,
|
||||
createTeam,
|
||||
discoverProfile,
|
||||
load2on2_v1,
|
||||
load2on2_v2,
|
||||
loadConfig,
|
||||
loadConfig2,
|
||||
loadEventInfo,
|
||||
loadGacha,
|
||||
loadGarage,
|
||||
loadGeneralReward1,
|
||||
loadGeneralReward2,
|
||||
loadGhost,
|
||||
loadProfile2,
|
||||
loadProfile3,
|
||||
loadRewardTable,
|
||||
loadServerList,
|
||||
loadStocker,
|
||||
loadTeam,
|
||||
loadTeamRanking,
|
||||
loadTeamRanking2,
|
||||
loadTopTen1,
|
||||
loadTopTen2,
|
||||
loadTeamRanking1,
|
||||
lockGarage,
|
||||
lockProfile,
|
||||
lockProfileExtend,
|
||||
loadTopTen1,
|
||||
msg00AD,
|
||||
saveExpedition1,
|
||||
saveExpedition2,
|
||||
saveGarage,
|
||||
saveNewCar,
|
||||
saveProfile2,
|
||||
saveProfile3,
|
||||
saveSettings,
|
||||
saveStocker,
|
||||
saveTeamBanner,
|
||||
saveTimeAttack1,
|
||||
saveTimeAttack2,
|
||||
saveTopic,
|
||||
unlockProfile,
|
||||
updateProvisionalStoreRank,
|
||||
updateResult,
|
||||
updateStoryClearNum1,
|
||||
updateStoryClearNum2,
|
||||
updateTeamLeader,
|
||||
updateTeamMember,
|
||||
updateTeamPoints,
|
||||
@@ -112,15 +114,66 @@ const funcList: ReaderFn[] = [
|
||||
updateUserLog,
|
||||
];
|
||||
|
||||
const readerFns = new Map<number, ReaderFn>();
|
||||
const msgLengths = new Map<number, number>();
|
||||
const funcList130: ReaderFn[] = [
|
||||
checkTeamName,
|
||||
createAutoTeam,
|
||||
createProfile,
|
||||
createTeam,
|
||||
discoverProfile,
|
||||
load2on2_v2,
|
||||
updateStoryClearNum2,
|
||||
loadConfig,
|
||||
loadConfig2,
|
||||
loadEventInfo,
|
||||
loadGacha,
|
||||
loadGarage,
|
||||
loadGeneralReward2,
|
||||
loadGhost,
|
||||
loadProfile3,
|
||||
loadRewardTable,
|
||||
loadServerList,
|
||||
loadStocker,
|
||||
loadTeam,
|
||||
loadTeamRanking2,
|
||||
loadTopTen2,
|
||||
lockGarage,
|
||||
lockProfile,
|
||||
lockProfileExtend,
|
||||
msg00AD,
|
||||
saveExpedition2,
|
||||
saveGarage,
|
||||
saveNewCar,
|
||||
saveProfile3,
|
||||
saveSettings,
|
||||
saveStocker,
|
||||
saveTeamBanner,
|
||||
saveTimeAttack2,
|
||||
saveTopic,
|
||||
unlockProfile,
|
||||
updateProvisionalStoreRank,
|
||||
updateResult,
|
||||
updateTeamLeader,
|
||||
updateTeamMember,
|
||||
updateTeamPoints,
|
||||
updateUiReport,
|
||||
updateUserLog,
|
||||
];
|
||||
|
||||
for (const fn of funcList) {
|
||||
readerFns.set(fn.msgCode, fn);
|
||||
msgLengths.set(fn.msgCode, fn.msgLen);
|
||||
}
|
||||
const protocols = new Map<string, Map<number, ReaderFn>>();
|
||||
|
||||
protocols.set("110", makeReaderMap(funcList110));
|
||||
protocols.set("130", makeReaderMap(funcList130));
|
||||
|
||||
async function readRequest(
|
||||
clientHello: ClientHello,
|
||||
stm: ByteStream
|
||||
): Promise<Request | undefined> {
|
||||
const protocol = protocols.get(clientHello.protocol);
|
||||
|
||||
if (protocol === undefined) {
|
||||
throw new Error(`Unsupported protocol version ${clientHello.protocol}`);
|
||||
}
|
||||
|
||||
async function readRequest(stm: ByteStream): Promise<Request | undefined> {
|
||||
const head = await stm.read(BLOCK_SIZE);
|
||||
|
||||
if (head.length === 0) {
|
||||
@@ -129,16 +182,16 @@ async function readRequest(stm: ByteStream): Promise<Request | undefined> {
|
||||
}
|
||||
|
||||
const msgCode = head.readUInt16LE(0x0000);
|
||||
const msgLen = msgLengths.get(msgCode);
|
||||
const readerFn = protocol.get(msgCode);
|
||||
|
||||
if (msgLen === undefined) {
|
||||
if (readerFn === undefined) {
|
||||
throw new Error(`Message ${msgCode.toString(16)}: Unknown command code`);
|
||||
}
|
||||
|
||||
const tail = await stm.read(msgLen - BLOCK_SIZE);
|
||||
const tail = await stm.read(readerFn.msgLen - BLOCK_SIZE);
|
||||
const msg = Buffer.concat([head, tail]);
|
||||
|
||||
if (msg.length < msgLen) {
|
||||
if (msg.length < readerFn.msgLen) {
|
||||
throw new Error(`Message ${msgCode.toString(16)}: Truncated read`);
|
||||
}
|
||||
|
||||
@@ -146,22 +199,19 @@ async function readRequest(stm: ByteStream): Promise<Request | undefined> {
|
||||
debug("Raw: %s", msg.toString("hex"));
|
||||
}
|
||||
|
||||
const reader = readerFns.get(msgCode);
|
||||
|
||||
if (reader === undefined) {
|
||||
throw new Error(`Message ${msgCode.toString(16)}: No read handler`);
|
||||
}
|
||||
|
||||
const payload = reader(msg);
|
||||
const payload = readerFn(msg);
|
||||
|
||||
debug("Payload: %j", payload);
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
export default async function* readRequestStream(stm: ByteStream) {
|
||||
export default async function* readRequestStream(
|
||||
clientHello: ClientHello,
|
||||
stm: ByteStream
|
||||
) {
|
||||
while (true) {
|
||||
const req = await readRequest(stm);
|
||||
const req = await readRequest(clientHello, stm);
|
||||
|
||||
if (req === undefined) {
|
||||
return;
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { ExtId } from "../model/base";
|
||||
import { Team } from "../model/team";
|
||||
import { Load2on2Request1, Load2on2Request2 } from "../request/load2on2";
|
||||
import { Load2on2Request } from "../request/load2on2";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
load2on2_v1.msgCode = 0x00b0;
|
||||
load2on2_v1.msgLen = 0x0010;
|
||||
|
||||
export function load2on2_v1(buf: Buffer): Load2on2Request1 {
|
||||
export function load2on2_v1(buf: Buffer): Load2on2Request {
|
||||
return {
|
||||
type: "load_2on2_req",
|
||||
format: 1,
|
||||
field_0002: buf.readUInt16LE(0x0002),
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
teamId: buf.readUInt32LE(0x0008) as ExtId<Team>,
|
||||
@@ -19,10 +18,9 @@ export function load2on2_v1(buf: Buffer): Load2on2Request1 {
|
||||
load2on2_v2.msgCode = 0x0132;
|
||||
load2on2_v2.msgLen = 0x0010;
|
||||
|
||||
export function load2on2_v2(buf: Buffer): Load2on2Request2 {
|
||||
export function load2on2_v2(buf: Buffer): Load2on2Request {
|
||||
return {
|
||||
type: "load_2on2_req",
|
||||
format: 2,
|
||||
field_0002: buf.readUInt16LE(0x0002),
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
teamId: buf.readUInt32LE(0x0008) as ExtId<Team>,
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
import {
|
||||
LoadGeneralRewardRequest1,
|
||||
LoadGeneralRewardRequest2,
|
||||
} from "../request/loadGeneralReward";
|
||||
import { LoadGeneralRewardRequest } from "../request/loadGeneralReward";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
loadGeneralReward1.msgCode = 0x009c;
|
||||
loadGeneralReward1.msgLen = 0x0010;
|
||||
|
||||
export function loadGeneralReward1(buf: Buffer): LoadGeneralRewardRequest1 {
|
||||
export function loadGeneralReward1(buf: Buffer): LoadGeneralRewardRequest {
|
||||
return {
|
||||
type: "load_general_reward_req",
|
||||
format: 1,
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
};
|
||||
}
|
||||
@@ -18,10 +14,9 @@ export function loadGeneralReward1(buf: Buffer): LoadGeneralRewardRequest1 {
|
||||
loadGeneralReward2.msgCode = 0x013b;
|
||||
loadGeneralReward2.msgLen = 0x0010;
|
||||
|
||||
export function loadGeneralReward2(buf: Buffer): LoadGeneralRewardRequest2 {
|
||||
export function loadGeneralReward2(buf: Buffer): LoadGeneralRewardRequest {
|
||||
return {
|
||||
type: "load_general_reward_req",
|
||||
format: 2,
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
import {
|
||||
LoadProfileRequest2,
|
||||
LoadProfileRequest3,
|
||||
} from "../request/loadProfile";
|
||||
import { LoadProfileRequest } from "../request/loadProfile";
|
||||
import { AimeId } from "../../../model";
|
||||
import { readAsciiStr } from "../../util/bin";
|
||||
|
||||
loadProfile2.msgCode = 0x0067;
|
||||
loadProfile2.msgLen = 0x0020;
|
||||
|
||||
export function loadProfile2(buf: Buffer): LoadProfileRequest2 {
|
||||
export function loadProfile2(buf: Buffer): LoadProfileRequest {
|
||||
return {
|
||||
type: "load_profile_req",
|
||||
format: 2,
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 1,
|
||||
luid: readAsciiStr(buf, 0x0008, 0x0020),
|
||||
@@ -21,10 +17,9 @@ export function loadProfile2(buf: Buffer): LoadProfileRequest2 {
|
||||
loadProfile3.msgCode = 0x0012f;
|
||||
loadProfile3.msgLen = 0x0020;
|
||||
|
||||
export function loadProfile3(buf: Buffer): LoadProfileRequest3 {
|
||||
export function loadProfile3(buf: Buffer): LoadProfileRequest {
|
||||
return {
|
||||
type: "load_profile_req",
|
||||
format: 3,
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 1,
|
||||
luid: readAsciiStr(buf, 0x0008, 0x0020),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { LoadTeamRankingRequest } from "../request/loadTeamRanking";
|
||||
|
||||
loadTeamRanking.msgCode = 0x00b9;
|
||||
loadTeamRanking.msgLen = 0x0010;
|
||||
loadTeamRanking1.msgCode = 0x00b9;
|
||||
loadTeamRanking1.msgLen = 0x0010;
|
||||
|
||||
export function loadTeamRanking(buf: Buffer): LoadTeamRankingRequest {
|
||||
export function loadTeamRanking1(buf: Buffer): LoadTeamRankingRequest {
|
||||
return {
|
||||
type: "load_team_ranking_req",
|
||||
};
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import {
|
||||
SaveExpeditionRequest1,
|
||||
SaveExpeditionRequest2,
|
||||
} from "../request/saveExpedition";
|
||||
import { SaveExpeditionRequest } from "../request/saveExpedition";
|
||||
|
||||
saveExpedition1.msgCode = 0x008c;
|
||||
saveExpedition1.msgLen = 0x0010;
|
||||
|
||||
export function saveExpedition1(buf: Buffer): SaveExpeditionRequest1 {
|
||||
export function saveExpedition1(buf: Buffer): SaveExpeditionRequest {
|
||||
return {
|
||||
type: "save_expedition_req",
|
||||
format: 1,
|
||||
field_0004: buf.readUInt32LE(0x0004),
|
||||
};
|
||||
}
|
||||
@@ -17,10 +13,9 @@ export function saveExpedition1(buf: Buffer): SaveExpeditionRequest1 {
|
||||
saveExpedition2.msgCode = 0x013f;
|
||||
saveExpedition2.msgLen = 0x0010;
|
||||
|
||||
export function saveExpedition2(buf: Buffer): SaveExpeditionRequest2 {
|
||||
export function saveExpedition2(buf: Buffer): SaveExpeditionRequest {
|
||||
return {
|
||||
type: "save_expedition_req",
|
||||
format: 2,
|
||||
field_0004: buf.readUInt32LE(0x0004),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { car } from "./_car";
|
||||
import { mission } from "./_mission";
|
||||
import { BackgroundCode, CourseNo, TitleCode } from "../model/base";
|
||||
import { SaveProfileRequest2 } from "../request/saveProfile";
|
||||
import { SaveProfileRequest } from "../request/saveProfile";
|
||||
import { bitmap } from "./_bitmap";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
saveProfile2.msgCode = 0x0068;
|
||||
saveProfile2.msgLen = 0x0940;
|
||||
|
||||
export function saveProfile2(buf: Buffer): SaveProfileRequest2 {
|
||||
export function saveProfile2(buf: Buffer): SaveProfileRequest {
|
||||
const storyRows = new Array();
|
||||
|
||||
for (let i = 0; i < 9; i++) {
|
||||
@@ -45,7 +45,6 @@ export function saveProfile2(buf: Buffer): SaveProfileRequest2 {
|
||||
|
||||
return {
|
||||
type: "save_profile_req",
|
||||
format: 2,
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 1,
|
||||
lv: buf.readUInt16LE(0x0026),
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { car } from "./_car";
|
||||
import { mission } from "./_mission";
|
||||
import { BackgroundCode, CourseNo, TitleCode } from "../model/base";
|
||||
import { SaveProfileRequest2 } from "../request/saveProfile";
|
||||
import { SaveProfileRequest } from "../request/saveProfile";
|
||||
import { bitmap } from "./_bitmap";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
saveProfile3.msgCode = 0x0138;
|
||||
saveProfile3.msgLen = 0x0a70;
|
||||
|
||||
export function saveProfile3(buf: Buffer): SaveProfileRequest2 {
|
||||
export function saveProfile3(buf: Buffer): SaveProfileRequest {
|
||||
const storyRows = new Array();
|
||||
|
||||
// Story layout has changed somewhat...
|
||||
@@ -47,7 +47,6 @@ export function saveProfile3(buf: Buffer): SaveProfileRequest2 {
|
||||
|
||||
return {
|
||||
type: "save_profile_req",
|
||||
format: 2,
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 1,
|
||||
lv: buf.readUInt16LE(0x0026),
|
||||
|
||||
@@ -1,28 +1,19 @@
|
||||
import {
|
||||
UpdateStoryClearNumRequest1,
|
||||
UpdateStoryClearNumRequest2,
|
||||
} from "../request/updateStoryClearNum";
|
||||
import { UpdateStoryClearNumRequest } from "../request/updateStoryClearNum";
|
||||
|
||||
updateStoryClearNum1.msgCode = 0x007f;
|
||||
updateStoryClearNum1.msgLen = 0x0010;
|
||||
|
||||
export function updateStoryClearNum1(
|
||||
buf: Buffer
|
||||
): UpdateStoryClearNumRequest1 {
|
||||
export function updateStoryClearNum1(buf: Buffer): UpdateStoryClearNumRequest {
|
||||
return {
|
||||
type: "update_story_clear_num_req",
|
||||
format: 1,
|
||||
};
|
||||
}
|
||||
|
||||
updateStoryClearNum2.msgCode = 0x013d;
|
||||
updateStoryClearNum2.msgLen = 0x0010;
|
||||
|
||||
export function updateStoryClearNum2(
|
||||
buf: Buffer
|
||||
): UpdateStoryClearNumRequest2 {
|
||||
export function updateStoryClearNum2(buf: Buffer): UpdateStoryClearNumRequest {
|
||||
return {
|
||||
type: "update_story_clear_num_req",
|
||||
format: 2,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user