Compare commits
Vendored
+4
-1
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.rulers": [79],
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v016
|
||||
|
||||
- IDZ: Fix SQL syntax error (Tau)
|
||||
|
||||
## v015
|
||||
|
||||
- IDZ: Team fixes (BemaniWitch)
|
||||
|
||||
## v014
|
||||
|
||||
- IDZ: Add support for Initial D v2.1 (BemaniWitch)
|
||||
|
||||
## v013
|
||||
|
||||
- IDZ: Miscellaneous refactoring (Tau)
|
||||
|
||||
+52
-5
@@ -7,6 +7,10 @@ create table "idz_profile" (
|
||||
"player_id" integer not null
|
||||
references "aime_player"("id")
|
||||
on delete cascade,
|
||||
-- Major version of Initial D Zero, either 1 or 2.
|
||||
-- The two major versions are incompatible with each other and do not
|
||||
-- permit the player to carry progress over from one to the other.
|
||||
"version" integer not null,
|
||||
-- TODO shop_id
|
||||
"name" text not null,
|
||||
"lv" integer not null,
|
||||
@@ -16,7 +20,7 @@ create table "idz_profile" (
|
||||
"mileage" integer not null,
|
||||
"register_time" timestamp not null,
|
||||
"access_time" timestamp not null,
|
||||
constraint "idz_profile_player_uq" unique ("player_id")
|
||||
constraint "idz_profile_player_uq" unique ("player_id", "version")
|
||||
);
|
||||
|
||||
create table "idz_chara" (
|
||||
@@ -100,7 +104,27 @@ create table "idz_settings" (
|
||||
"pack" integer not null,
|
||||
"aura" integer not null,
|
||||
"paper_cup" integer not null, -- Not a boolean, oddly enough
|
||||
"gauges" integer not null
|
||||
"gauges" integer not null,
|
||||
"driving_style" integer not null
|
||||
);
|
||||
|
||||
create table "idz_stamp_selections" (
|
||||
"id" integer primary key not null
|
||||
references "idz_profile"("id")
|
||||
on delete cascade,
|
||||
"stamp_01" integer not null,
|
||||
"stamp_02" integer not null,
|
||||
"stamp_03" integer not null,
|
||||
"stamp_04" integer not null
|
||||
);
|
||||
|
||||
create table "idz_stamp_unlock" (
|
||||
"id" integer primary key not null,
|
||||
"profile_id" integer not null
|
||||
references "idz_profile"("id")
|
||||
on delete cascade,
|
||||
"stamp_no",
|
||||
constraint "idz_stamp_unlock_uq" unique ("profile_id", "stamp_no")
|
||||
);
|
||||
|
||||
create table "idz_story_state" (
|
||||
@@ -120,6 +144,7 @@ create table "idz_story_cell_state" (
|
||||
"col_no" integer not null,
|
||||
"a" integer not null,
|
||||
"b" integer not null,
|
||||
"c" integer not null,
|
||||
constraint "idz_story_cell_state_uq" unique (
|
||||
"profile_id",
|
||||
"row_no",
|
||||
@@ -202,12 +227,13 @@ create table "idz_unlocks" (
|
||||
|
||||
create table "idz_team" (
|
||||
"id" integer primary key not null,
|
||||
"version" integer not null,
|
||||
"ext_id" integer not null,
|
||||
"name" text not null,
|
||||
"name_bg" integer not null,
|
||||
"name_fx" integer not null,
|
||||
"register_time" timestamp not null,
|
||||
constraint "idz_team_uq" unique ("ext_id")
|
||||
constraint "idz_team_uq" unique ("version", "ext_id")
|
||||
);
|
||||
|
||||
create table "idz_team_auto" (
|
||||
@@ -215,8 +241,7 @@ create table "idz_team_auto" (
|
||||
references "idz_team"("id")
|
||||
on delete cascade,
|
||||
"serial_no" integer not null,
|
||||
"name_idx" integer not null,
|
||||
constraint "idz_team_auto_uq" unique ("serial_no", "name_idx")
|
||||
"name_idx" integer not null
|
||||
);
|
||||
|
||||
create table "idz_team_member" (
|
||||
@@ -240,3 +265,25 @@ create table "idz_team_reservation" (
|
||||
"join_time" timestamp not null,
|
||||
"leader" boolean not null
|
||||
);
|
||||
|
||||
create table "idz_weekly_missions" (
|
||||
"id" integer primary key not null
|
||||
references "idz_profile"("id")
|
||||
on delete cascade,
|
||||
"weekly_reset" timestamp not null,
|
||||
"mission_left" integer not null,
|
||||
"progress_left" integer not null,
|
||||
"params_left" integer not null,
|
||||
"mission_right" integer not null,
|
||||
"progress_right" integer not null,
|
||||
"params_right" integer not null
|
||||
);
|
||||
|
||||
create table "idz_my_chara" (
|
||||
"id" integer primary key not null,
|
||||
"profile_id" integer not null
|
||||
references "idz_profile"("id")
|
||||
on delete cascade,
|
||||
"my_chara_no" integer not null,
|
||||
constraint "idz_my_chara_uq" unique ("profile_id", "my_chara_no")
|
||||
);
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
create table "new_idz_profile" (
|
||||
"id" integer primary key not null,
|
||||
"player_id" integer not null
|
||||
references "aime_player"("id")
|
||||
on delete cascade,
|
||||
"version" integer not null,
|
||||
"name" text not null,
|
||||
"lv" integer not null,
|
||||
"exp" integer not null,
|
||||
"fame" integer not null,
|
||||
"dpoint" integer not null,
|
||||
"mileage" integer not null,
|
||||
"register_time" timestamp not null,
|
||||
"access_time" timestamp not null,
|
||||
constraint "idz_profile_player_uq" unique ("player_id", "version")
|
||||
);
|
||||
|
||||
create table "new_idz_team" (
|
||||
"id" integer primary key not null,
|
||||
"version" integer not null,
|
||||
"ext_id" integer not null,
|
||||
"name" text not null,
|
||||
"name_bg" integer not null,
|
||||
"name_fx" integer not null,
|
||||
"register_time" timestamp not null,
|
||||
constraint "idz_team_uq" unique ("version", "ext_id")
|
||||
);
|
||||
|
||||
insert into "new_idz_profile" (
|
||||
"id",
|
||||
"player_id",
|
||||
"version",
|
||||
"name",
|
||||
"lv",
|
||||
"exp",
|
||||
"fame",
|
||||
"dpoint",
|
||||
"mileage",
|
||||
"register_time",
|
||||
"access_time"
|
||||
) select
|
||||
x."id",
|
||||
x."player_id",
|
||||
1,
|
||||
x."name",
|
||||
x."lv",
|
||||
x."exp",
|
||||
x."fame",
|
||||
x."dpoint",
|
||||
x."mileage",
|
||||
x."register_time",
|
||||
x."access_time"
|
||||
from "idz_profile" as "x";
|
||||
|
||||
insert into "new_idz_team" (
|
||||
"id",
|
||||
"version",
|
||||
"ext_id",
|
||||
"name",
|
||||
"name_bg",
|
||||
"name_fx",
|
||||
"register_time"
|
||||
) select
|
||||
x."id",
|
||||
1,
|
||||
x."ext_id",
|
||||
x."name",
|
||||
x."name_bg",
|
||||
x."name_fx",
|
||||
x."register_time"
|
||||
from "idz_team" as "x";
|
||||
|
||||
drop table "idz_profile";
|
||||
drop table "idz_team";
|
||||
|
||||
alter table "new_idz_profile" rename to "idz_profile";
|
||||
alter table "new_idz_team" rename to "idz_team";
|
||||
@@ -0,0 +1,111 @@
|
||||
create table "idz_my_chara" (
|
||||
"id" integer primary key not null,
|
||||
"profile_id" integer not null
|
||||
references "idz_profile"("id")
|
||||
on delete cascade,
|
||||
"my_chara_no" integer not null,
|
||||
constraint "idz_my_chara_uq" unique ("profile_id", "my_chara_no")
|
||||
);
|
||||
|
||||
create table "new_idz_settings" (
|
||||
"id" integer primary key not null
|
||||
references "idz_profile"("id")
|
||||
on delete cascade,
|
||||
"music" integer not null,
|
||||
"pack" integer not null,
|
||||
"aura" integer not null,
|
||||
"paper_cup" integer not null, -- Not a boolean, oddly enough
|
||||
"gauges" integer not null,
|
||||
"driving_style" integer not null
|
||||
);
|
||||
|
||||
create table "idz_stamp_selections" (
|
||||
"id" integer primary key not null
|
||||
references "idz_profile"("id")
|
||||
on delete cascade,
|
||||
"stamp_01" integer not null,
|
||||
"stamp_02" integer not null,
|
||||
"stamp_03" integer not null,
|
||||
"stamp_04" integer not null
|
||||
);
|
||||
|
||||
create table "idz_stamp_unlock" (
|
||||
"id" integer primary key not null,
|
||||
"profile_id" integer not null
|
||||
references "idz_profile"("id")
|
||||
on delete cascade,
|
||||
"stamp_no",
|
||||
constraint "idz_stamp_unlock_uq" unique ("profile_id", "stamp_no")
|
||||
);
|
||||
|
||||
create table "new_idz_story_cell_state" (
|
||||
"id" integer primary key not null,
|
||||
"profile_id" integer not null
|
||||
references "idz_profile"("id")
|
||||
on delete cascade,
|
||||
"row_no" integer not null,
|
||||
"col_no" integer not null,
|
||||
"a" integer not null,
|
||||
"b" integer not null,
|
||||
"c" integer not null,
|
||||
constraint "idz_story_cell_state_uq" unique (
|
||||
"profile_id",
|
||||
"row_no",
|
||||
"col_no"
|
||||
)
|
||||
);
|
||||
|
||||
create table "idz_weekly_missions" (
|
||||
"id" integer primary key not null
|
||||
references "idz_profile"("id")
|
||||
on delete cascade,
|
||||
"weekly_reset" timestamp not null,
|
||||
"mission_left" integer not null,
|
||||
"progress_left" integer not null,
|
||||
"params_left" integer not null,
|
||||
"mission_right" integer not null,
|
||||
"progress_right" integer not null,
|
||||
"params_right" integer not null
|
||||
);
|
||||
|
||||
insert into "new_idz_settings" (
|
||||
"id",
|
||||
"music",
|
||||
"pack",
|
||||
"aura",
|
||||
"paper_cup",
|
||||
"gauges",
|
||||
"driving_style"
|
||||
) select
|
||||
x."id",
|
||||
x."music",
|
||||
x."pack",
|
||||
x."aura",
|
||||
x."paper_cup",
|
||||
x."gauges",
|
||||
0
|
||||
from "idz_settings" as x;
|
||||
|
||||
insert into "new_idz_story_cell_state" (
|
||||
"id",
|
||||
"profile_id",
|
||||
"row_no",
|
||||
"col_no",
|
||||
"a",
|
||||
"b",
|
||||
"c"
|
||||
) select
|
||||
x."id",
|
||||
x."profile_id",
|
||||
x."row_no",
|
||||
x."col_no",
|
||||
x."a",
|
||||
x."b",
|
||||
0
|
||||
from "idz_story_cell_state" as x;
|
||||
|
||||
drop table "idz_settings";
|
||||
drop table "idz_story_cell_state";
|
||||
|
||||
alter table "new_idz_settings" rename to "idz_settings";
|
||||
alter table "new_idz_story_cell_state" rename to "idz_story_cell_state";
|
||||
@@ -0,0 +1,13 @@
|
||||
create table "new_idz_team_auto" (
|
||||
"id" integer primary key not null
|
||||
references "idz_team"("id")
|
||||
on delete cascade,
|
||||
"serial_no" integer not null,
|
||||
"name_idx" integer not null
|
||||
);
|
||||
|
||||
insert into "new_idz_team_auto"
|
||||
select "id", "serial_no", "name_idx" from "idz_team_auto";
|
||||
|
||||
drop table "idz_team_auto";
|
||||
alter table "new_idz_team_auto" rename to "idz_team_auto";
|
||||
+20
-18
@@ -104,30 +104,32 @@ async function migratedb(
|
||||
}
|
||||
|
||||
export default async function checkdb(db: DataSource): Promise<void> {
|
||||
const stmt = sql.select("schemaver").from("meta");
|
||||
let maybe: number | undefined;
|
||||
let schemaver: number | undefined;
|
||||
|
||||
try {
|
||||
const row = await db.transaction(txn => txn.fetchRow(stmt));
|
||||
await db.maintenance(async txn => {
|
||||
const stmt = sql.select("schemaver").from("meta");
|
||||
|
||||
if (row !== undefined) {
|
||||
maybe = parseInt(row.schemaver!);
|
||||
try {
|
||||
const row = await txn.fetchRow(stmt);
|
||||
|
||||
if (row !== undefined) {
|
||||
schemaver = parseInt(row.schemaver!);
|
||||
}
|
||||
} catch (e) {
|
||||
return await initdb(txn);
|
||||
}
|
||||
} catch (e) {
|
||||
return db.transaction(initdb);
|
||||
}
|
||||
|
||||
if (maybe === undefined) {
|
||||
throw new Error(
|
||||
"Database corrupted: `meta` table singleton row is missing"
|
||||
);
|
||||
}
|
||||
if (schemaver === undefined) {
|
||||
throw new Error(
|
||||
"Database corrupted: `meta` table singleton row is missing"
|
||||
);
|
||||
}
|
||||
|
||||
const schemaver = maybe;
|
||||
const newver = await db.transaction(txn => migratedb(txn, schemaver));
|
||||
schemaver = await migratedb(txn, schemaver);
|
||||
});
|
||||
|
||||
if (newver !== undefined) {
|
||||
debug("Upgraded database to version %s", newver);
|
||||
if (schemaver !== undefined) {
|
||||
debug("Upgraded database to version %s", schemaver);
|
||||
|
||||
await db.vacuum();
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import setup from "./setup";
|
||||
|
||||
export { BLOCK_SIZE } from "./aes";
|
||||
export { ClientHello } from "./setup";
|
||||
export default setup;
|
||||
|
||||
+20
-3
@@ -2,7 +2,7 @@ import { Socket } from "net";
|
||||
|
||||
import AesEcbStream from "./aes";
|
||||
import { readBigInt, modPow, writeBigInt } from "./bigint";
|
||||
import IoByteStream from "../../util/stream";
|
||||
import IoByteStream, { ByteStream } from "../../util/stream";
|
||||
|
||||
interface RsaKey {
|
||||
N: bigint;
|
||||
@@ -11,6 +11,17 @@ interface RsaKey {
|
||||
hashN: number;
|
||||
}
|
||||
|
||||
export interface ClientHello {
|
||||
pcbId: string;
|
||||
protocol: string;
|
||||
model: string;
|
||||
}
|
||||
|
||||
export interface IdzConnection {
|
||||
aesStream: ByteStream;
|
||||
clientHello: ClientHello;
|
||||
}
|
||||
|
||||
// Proof-of-concept, so we only ever use one of the ten RSA key pairs
|
||||
const rsaKey = {
|
||||
N: 4922323266120814292574970172377860734034664704992758249880018618131907367614177800329506877981986877921220485681998287752778495334541127048495486311792061n,
|
||||
@@ -22,7 +33,7 @@ const rsaKey = {
|
||||
// Proof-of-concept, so we only use one fixed session key
|
||||
const aesKey = Buffer.from("ffddeeccbbaa99887766554433221100", "hex");
|
||||
|
||||
function writeServerHello(aesKey: Buffer, rsaKey: RsaKey) {
|
||||
function writeServerHello(aesKey: Buffer, rsaKey: RsaKey): Buffer {
|
||||
const M = readBigInt(aesKey);
|
||||
const keyEnc = modPow(M, rsaKey.e, rsaKey.N);
|
||||
const result = Buffer.alloc(0x48);
|
||||
@@ -37,6 +48,12 @@ function writeServerHello(aesKey: Buffer, rsaKey: RsaKey) {
|
||||
function readClientHello(buf: Buffer) {
|
||||
const magic = buf.readUInt32LE(0x00);
|
||||
|
||||
if (magic === 0xFE78571D) {
|
||||
throw new Error(
|
||||
"Server Box data, ignore."
|
||||
);
|
||||
}
|
||||
|
||||
if (magic !== 0x01020304) {
|
||||
throw new Error(
|
||||
"Invalid magic number, cryptographic processing probably incorrect."
|
||||
@@ -50,7 +67,7 @@ function readClientHello(buf: Buffer) {
|
||||
};
|
||||
}
|
||||
|
||||
export default async function setup(socket: Socket) {
|
||||
export default async function setup(socket: Socket): Promise<IdzConnection> {
|
||||
const tcpStream = new IoByteStream(socket);
|
||||
const serverHello = writeServerHello(aesKey, rsaKey);
|
||||
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import { CheckTeamNameRequest } from "../request/checkTeamName";
|
||||
|
||||
checkTeamName.msgCode = 0x00a2;
|
||||
checkTeamName.msgLen = 0x0040;
|
||||
checkTeamName1.msgCode = 0x00a2;
|
||||
checkTeamName1.msgLen = 0x0040;
|
||||
|
||||
export function checkTeamName(buf: Buffer): CheckTeamNameRequest {
|
||||
export function checkTeamName1(buf: Buffer): CheckTeamNameRequest {
|
||||
return { type: "check_team_name_req" };
|
||||
}
|
||||
|
||||
checkTeamName2.msgCode = 0x0097;
|
||||
checkTeamName2.msgLen = 0x0040;
|
||||
|
||||
export function checkTeamName2(buf: Buffer): CheckTeamNameRequest {
|
||||
return { type: "check_team_name_req" };
|
||||
}
|
||||
|
||||
@@ -1,13 +1,27 @@
|
||||
import { CreateAutoTeamRequest } from "../request/createAutoTeam";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
createAutoTeam.msgCode = 0x007b;
|
||||
createAutoTeam.msgLen = 0x0010;
|
||||
createAutoTeam1.msgCode = 0x007b;
|
||||
createAutoTeam1.msgLen = 0x0010;
|
||||
|
||||
export function createAutoTeam(buf: Buffer): CreateAutoTeamRequest {
|
||||
export function createAutoTeam1(buf: Buffer): CreateAutoTeamRequest {
|
||||
return {
|
||||
type: "create_auto_team_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 1,
|
||||
field_0008: buf.readUInt32LE(0x0008),
|
||||
field_000C: buf.readUInt8(0x000c),
|
||||
};
|
||||
}
|
||||
|
||||
createAutoTeam2.msgCode = 0x0077;
|
||||
createAutoTeam2.msgLen = 0x0010;
|
||||
|
||||
export function createAutoTeam2(buf: Buffer): CreateAutoTeamRequest {
|
||||
return {
|
||||
type: "create_auto_team_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 2,
|
||||
field_0008: buf.readUInt32LE(0x0008),
|
||||
field_000C: buf.readUInt8(0x000c),
|
||||
};
|
||||
|
||||
@@ -1,24 +1,37 @@
|
||||
import iconv from "iconv-lite";
|
||||
|
||||
import { car } from "./_car";
|
||||
import { chara } from "./_chara";
|
||||
import { CreateProfileRequest } from "../request/createProfile";
|
||||
import { AimeId } from "../../../model";
|
||||
import { readAsciiStr, readSjisStr } from "../../util/bin";
|
||||
|
||||
createProfile.msgCode = 0x0066;
|
||||
createProfile.msgLen = 0x00c0;
|
||||
createProfile1.msgCode = 0x0066;
|
||||
createProfile1.msgLen = 0x00c0;
|
||||
|
||||
export function createProfile(buf: Buffer): CreateProfileRequest {
|
||||
export function createProfile1(buf: Buffer): CreateProfileRequest {
|
||||
return {
|
||||
type: "create_profile_req",
|
||||
aimeId: buf.readInt32LE(0x0004) as AimeId,
|
||||
luid: buf.slice(0x0008, buf.indexOf("\0", 0x0008)).toString("ascii"),
|
||||
name: iconv.decode(
|
||||
buf.slice(0x001e, buf.indexOf("\0", 0x001e)),
|
||||
"shift_jis"
|
||||
),
|
||||
version: 1,
|
||||
luid: readAsciiStr(buf, 0x0008, 0x001e),
|
||||
name: readSjisStr(buf, 0x001e, 0x0034),
|
||||
field_0034: buf.readUInt32LE(0x0034),
|
||||
car: car(buf.slice(0x0040, 0x00a0)),
|
||||
chara: chara(buf.slice(0x00a0, 0x00b4)),
|
||||
};
|
||||
}
|
||||
|
||||
createProfile2.msgCode = 0x0064;
|
||||
createProfile2.msgLen = 0x00c0;
|
||||
|
||||
export function createProfile2(buf: Buffer): CreateProfileRequest {
|
||||
return {
|
||||
type: "create_profile_req",
|
||||
aimeId: buf.readInt32LE(0x0004) as AimeId,
|
||||
version: 2,
|
||||
luid: readAsciiStr(buf, 0x0008, 0x001e),
|
||||
name: readSjisStr(buf, 0x001e, 0x0034),
|
||||
field_0034: buf.readUInt32LE(0x0034),
|
||||
car: car(buf.slice(0x0040, 0x00a0)),
|
||||
chara: chara(buf.slice(0x00a8, 0x00bc)),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,24 +1,39 @@
|
||||
import iconv from "iconv-lite";
|
||||
|
||||
import { CreateTeamRequest } from "../request/createTeam";
|
||||
import { AimeId } from "../../../model";
|
||||
import { readAsciiStr, readSjisStr } from "../../util/bin";
|
||||
|
||||
createTeam.msgCode = 0x0071;
|
||||
createTeam.msgLen = 0x0050;
|
||||
createTeam1.msgCode = 0x0071;
|
||||
createTeam1.msgLen = 0x0050;
|
||||
|
||||
export function createTeam(buf: Buffer): CreateTeamRequest {
|
||||
export function createTeam1(buf: Buffer): CreateTeamRequest {
|
||||
return {
|
||||
type: "create_team_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
teamName: iconv.decode(
|
||||
buf.slice(0x0008, buf.indexOf("\0", 0x0008)),
|
||||
"shift_jis"
|
||||
),
|
||||
version: 1,
|
||||
teamName: readSjisStr(buf, 0x0008, 0x0028),
|
||||
field_0028: buf.readUInt16LE(0x0028),
|
||||
field_002C: buf.readUInt32LE(0x002c),
|
||||
nameBg: buf.readUInt8(0x0030),
|
||||
field_0032: buf.readUInt16LE(0x0032),
|
||||
prevTeamId: buf.readUInt32LE(0x0034),
|
||||
pcbId: buf.slice(0x0038, buf.indexOf("\0", 0x0038)).toString("ascii"),
|
||||
pcbId: readAsciiStr(buf, 0x0038, 0x0050),
|
||||
};
|
||||
}
|
||||
|
||||
createTeam2.msgCode = 0x006d;
|
||||
createTeam2.msgLen = 0x0050;
|
||||
|
||||
export function createTeam2(buf: Buffer): CreateTeamRequest {
|
||||
return {
|
||||
type: "create_team_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 2,
|
||||
teamName: readSjisStr(buf, 0x0008, 0x0028),
|
||||
field_0028: buf.readUInt16LE(0x0028),
|
||||
field_002C: buf.readUInt32LE(0x002c),
|
||||
nameBg: buf.readUInt8(0x0030),
|
||||
field_0032: buf.readUInt16LE(0x0032),
|
||||
prevTeamId: buf.readUInt32LE(0x0034),
|
||||
pcbId: readAsciiStr(buf, 0x0038, 0x0050),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
import { DiscoverProfileRequest } from "../request/discoverProfile";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
discoverProfile.msgCode = 0x006b;
|
||||
discoverProfile.msgLen = 0x0010;
|
||||
discoverProfile1.msgCode = 0x006b;
|
||||
discoverProfile1.msgLen = 0x0010;
|
||||
|
||||
export function discoverProfile(buf: Buffer): DiscoverProfileRequest {
|
||||
export function discoverProfile1(buf: Buffer): DiscoverProfileRequest {
|
||||
return {
|
||||
type: "discover_profile_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 1,
|
||||
};
|
||||
}
|
||||
|
||||
discoverProfile2.msgCode = 0x0067;
|
||||
discoverProfile2.msgLen = 0x0010;
|
||||
|
||||
export function discoverProfile2(buf: Buffer): DiscoverProfileRequest {
|
||||
return {
|
||||
type: "discover_profile_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 2,
|
||||
};
|
||||
}
|
||||
|
||||
+236
-110
@@ -1,55 +1,81 @@
|
||||
import logger from "debug";
|
||||
|
||||
import { checkTeamName } from "./checkTeamName";
|
||||
import { createProfile } from "./createProfile";
|
||||
import { createTeam } from "./createTeam";
|
||||
import { createAutoTeam } from "./createAutoTeam";
|
||||
import { discoverProfile } from "./discoverProfile";
|
||||
import { load2on2_v1, load2on2_v2 } from "./load2on2";
|
||||
import { loadConfig } from "./loadConfig";
|
||||
import { loadConfig2 } from "./loadConfig2";
|
||||
import { loadEventInfo } from "./loadEventInfo";
|
||||
import { loadGacha } from "./loadGacha";
|
||||
import { loadGarage } from "./loadGarage";
|
||||
import { loadGeneralReward1, loadGeneralReward2 } from "./loadGeneralReward";
|
||||
import { loadGhost } from "./loadGhost";
|
||||
import { loadProfile2, loadProfile3 } from "./loadProfile";
|
||||
import { loadRewardTable } from "./loadRewardTable";
|
||||
import { checkTeamName1, checkTeamName2 } from "./checkTeamName";
|
||||
import { createProfile1, createProfile2 } from "./createProfile";
|
||||
import { createTeam1, createTeam2 } from "./createTeam";
|
||||
import { createAutoTeam1, createAutoTeam2 } from "./createAutoTeam";
|
||||
import { discoverProfile1, discoverProfile2 } from "./discoverProfile";
|
||||
import {
|
||||
load2on2RankingPoints1,
|
||||
load2on2Info,
|
||||
load2on2RankingPoints2,
|
||||
} from "./load2on2";
|
||||
import {
|
||||
loadConfigA_1,
|
||||
loadConfigB_1,
|
||||
loadConfigA_2,
|
||||
loadConfigB_2,
|
||||
} from "./loadConfig";
|
||||
import { loadEventInfo1, loadEventInfo2 } from "./loadEventInfo";
|
||||
import { loadGacha1, loadGacha2 } from "./loadGacha";
|
||||
import { loadGarage1, loadGarage2 } from "./loadGarage";
|
||||
import {
|
||||
loadGeneralReward1,
|
||||
loadGeneralReward2,
|
||||
loadGeneralReward3,
|
||||
} from "./loadGeneralReward";
|
||||
import { loadGhost1, loadGhost2 } from "./loadGhost";
|
||||
import { loadProfile2, loadProfile3, loadProfile4 } from "./loadProfile";
|
||||
import { loadRewardTable1, loadRewardTable2 } from "./loadRewardTable";
|
||||
import { loadServerList } from "./loadServerList";
|
||||
import { loadStocker } from "./loadStocker";
|
||||
import { loadTeam } from "./loadTeam";
|
||||
import { loadTeamRanking, loadTeamRanking2 } from "./loadTeamRanking";
|
||||
import { loadStocker1, loadStocker2 } from "./loadStocker";
|
||||
import { loadTeam1, loadTeam2 } from "./loadTeam";
|
||||
import {
|
||||
loadTeamRanking1,
|
||||
loadTeamRanking2,
|
||||
loadTeamRanking3,
|
||||
loadTeamRanking4,
|
||||
} from "./loadTeamRanking";
|
||||
import { loadTopTen1 } from "./loadTopTen1";
|
||||
import { loadTopTen2 } from "./loadTopTen2";
|
||||
import { lockGarage } from "./lockGarage";
|
||||
import { lockProfile } from "./lockProfile";
|
||||
import { msg00AD } from "./msg00AD";
|
||||
import { loadTopTen2, loadTopTen3 } from "./loadTopTen2";
|
||||
import { lockGarage1, lockGarage2 } from "./lockGarage";
|
||||
import { lockProfile1, lockProfile2 } from "./lockProfile";
|
||||
import { saveExpedition1, saveExpedition2 } from "./saveExpedition";
|
||||
import { saveGarage } from "./saveGarage";
|
||||
import { saveNewCar } from "./saveNewCar";
|
||||
import { saveGarage1, saveGarage2 } from "./saveGarage";
|
||||
import { saveNewCar1, saveNewCar2 } from "./saveNewCar";
|
||||
import { saveProfile2 } from "./saveProfile2";
|
||||
import { saveProfile3 } from "./saveProfile3";
|
||||
import { saveSettings } from "./saveSettings";
|
||||
import { saveStocker } from "./saveStocker";
|
||||
import { saveTeamBanner } from "./saveTeamBanner";
|
||||
import { saveTimeAttack1, saveTimeAttack2 } from "./saveTimeAttack";
|
||||
import { saveTopic } from "./saveTopic";
|
||||
import { unlockProfile } from "./unlockProfile";
|
||||
import { updateProvisionalStoreRank } from "./updateProvisionalStoreRank";
|
||||
import { updateTeamLeader } from "./updateTeamLeader";
|
||||
import { updateTeamMember } from "./updateTeamMember";
|
||||
import { saveSettings1, saveSettings2 } from "./saveSettings";
|
||||
import { saveStocker1, saveStocker2 } from "./saveStocker";
|
||||
import { saveTeamBanner1, saveTeamBanner2 } from "./saveTeamBanner";
|
||||
import {
|
||||
saveTimeAttack1,
|
||||
saveTimeAttack2,
|
||||
saveTimeAttack3,
|
||||
} from "./saveTimeAttack";
|
||||
import { saveTopic1, saveTopic2 } from "./saveTopic";
|
||||
import { unknownA_1, unknownA_2 } from "./unknownA";
|
||||
import { unlockProfile1, unlockProfile2 } from "./unlockProfile";
|
||||
import {
|
||||
updateProvisionalStoreRank1,
|
||||
updateProvisionalStoreRank2,
|
||||
} from "./updateProvisionalStoreRank";
|
||||
import { updateTeamLeader1, updateTeamLeader2 } from "./updateTeamLeader";
|
||||
import { updateTeamMember1, updateTeamMember2 } from "./updateTeamMember";
|
||||
import {
|
||||
updateStoryClearNum1,
|
||||
updateStoryClearNum2,
|
||||
updateStoryClearNum3,
|
||||
} from "./updateStoryClearNum";
|
||||
import { Request } from "../request";
|
||||
import { updateResult } from "./updateResult";
|
||||
import { updateTeamPoints } from "./updateTeamPoints";
|
||||
import { updateUiReport } from "./updateUiReport";
|
||||
import { updateUserLog } from "./updateUserLog";
|
||||
import { lockProfileExtend } from "./lockProfileExtend";
|
||||
import { BLOCK_SIZE } from "../../common";
|
||||
import { updateTeamPoints1, updateTeamPoints2 } from "./updateTeamPoints";
|
||||
import { updateUiReport1, updateUiReport2 } from "./updateUiReport";
|
||||
import { updateUserLog1, updateUserLog2 } from "./updateUserLog";
|
||||
import { lockProfileExtend1, lockProfileExtend2 } from "./lockProfileExtend";
|
||||
import { BLOCK_SIZE, ClientHello } from "../../common";
|
||||
import { ByteStream } from "../../../util/stream";
|
||||
import { saveProfile4 } from "./saveProfile4";
|
||||
|
||||
const debug = logger("app:idz:userdb:decoder");
|
||||
|
||||
@@ -58,69 +84,172 @@ export type ReaderFn = ((buf: Buffer) => Request) & {
|
||||
msgLen: number;
|
||||
};
|
||||
|
||||
const funcList: 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,
|
||||
lockGarage,
|
||||
lockProfile,
|
||||
lockProfileExtend,
|
||||
msg00AD,
|
||||
saveExpedition1,
|
||||
saveExpedition2,
|
||||
saveGarage,
|
||||
saveNewCar,
|
||||
saveProfile2,
|
||||
saveProfile3,
|
||||
saveSettings,
|
||||
saveStocker,
|
||||
saveTeamBanner,
|
||||
saveTimeAttack1,
|
||||
saveTimeAttack2,
|
||||
saveTopic,
|
||||
unlockProfile,
|
||||
updateProvisionalStoreRank,
|
||||
updateResult,
|
||||
updateStoryClearNum1,
|
||||
updateStoryClearNum2,
|
||||
updateTeamLeader,
|
||||
updateTeamMember,
|
||||
updateTeamPoints,
|
||||
updateUiReport,
|
||||
updateUserLog,
|
||||
];
|
||||
function makeReaderMap(funcList: ReaderFn[]): Map<number, ReaderFn> {
|
||||
const result = new Map<number, ReaderFn>();
|
||||
|
||||
const readerFns = new Map<number, ReaderFn>();
|
||||
const msgLengths = new Map<number, number>();
|
||||
for (const fn of funcList) {
|
||||
result.set(fn.msgCode, fn);
|
||||
}
|
||||
|
||||
for (const fn of funcList) {
|
||||
readerFns.set(fn.msgCode, fn);
|
||||
msgLengths.set(fn.msgCode, fn.msgLen);
|
||||
return result;
|
||||
}
|
||||
|
||||
async function readRequest(stm: ByteStream): Promise<Request | undefined> {
|
||||
// TODO confirm v1.21.00 proto version
|
||||
const funcList110: ReaderFn[] = [
|
||||
checkTeamName1,
|
||||
createAutoTeam1,
|
||||
createProfile1,
|
||||
createTeam1,
|
||||
discoverProfile1,
|
||||
load2on2RankingPoints1,
|
||||
loadConfigA_1,
|
||||
loadConfigB_1,
|
||||
loadEventInfo1,
|
||||
loadGacha1,
|
||||
loadGarage1,
|
||||
loadGeneralReward1,
|
||||
loadGhost1,
|
||||
loadProfile2,
|
||||
loadRewardTable1,
|
||||
loadServerList,
|
||||
loadStocker1,
|
||||
loadTeam1,
|
||||
loadTeamRanking1,
|
||||
lockGarage1,
|
||||
lockProfile1,
|
||||
lockProfileExtend1,
|
||||
loadTopTen1,
|
||||
saveExpedition1,
|
||||
saveGarage1,
|
||||
saveNewCar1,
|
||||
saveProfile2,
|
||||
saveSettings1,
|
||||
saveStocker1,
|
||||
saveTeamBanner1,
|
||||
saveTimeAttack1,
|
||||
saveTopic1,
|
||||
unknownA_1,
|
||||
unlockProfile1,
|
||||
updateProvisionalStoreRank1,
|
||||
updateResult,
|
||||
updateStoryClearNum1,
|
||||
updateTeamLeader1,
|
||||
updateTeamMember1,
|
||||
updateTeamPoints1,
|
||||
updateUiReport1,
|
||||
updateUserLog1,
|
||||
];
|
||||
|
||||
const funcList130: ReaderFn[] = [
|
||||
checkTeamName1,
|
||||
createAutoTeam1,
|
||||
createProfile1,
|
||||
createTeam1,
|
||||
discoverProfile1,
|
||||
load2on2Info,
|
||||
updateStoryClearNum2,
|
||||
updateStoryClearNum3,
|
||||
loadConfigA_1,
|
||||
loadConfigB_1,
|
||||
loadEventInfo1,
|
||||
loadGacha1,
|
||||
loadGarage1,
|
||||
loadGeneralReward3,
|
||||
loadGhost1,
|
||||
loadProfile3,
|
||||
loadRewardTable1,
|
||||
loadServerList,
|
||||
loadStocker1,
|
||||
loadTeam1,
|
||||
loadTeamRanking1,
|
||||
loadTeamRanking3,
|
||||
loadTopTen2,
|
||||
lockGarage1,
|
||||
lockProfile1,
|
||||
lockProfileExtend1,
|
||||
saveExpedition2,
|
||||
saveGarage1,
|
||||
saveNewCar1,
|
||||
saveProfile3,
|
||||
saveSettings1,
|
||||
saveStocker1,
|
||||
saveTeamBanner1,
|
||||
saveTimeAttack2,
|
||||
saveTopic1,
|
||||
unknownA_1,
|
||||
unlockProfile1,
|
||||
updateProvisionalStoreRank1,
|
||||
updateResult,
|
||||
updateTeamLeader1,
|
||||
updateTeamMember1,
|
||||
updateTeamPoints1,
|
||||
updateUiReport1,
|
||||
updateUserLog1,
|
||||
];
|
||||
|
||||
const funcList210: ReaderFn[] = [
|
||||
checkTeamName2,
|
||||
createAutoTeam2,
|
||||
createProfile2,
|
||||
createTeam2,
|
||||
discoverProfile2,
|
||||
load2on2Info,
|
||||
load2on2RankingPoints2,
|
||||
updateStoryClearNum3,
|
||||
loadConfigA_2,
|
||||
loadConfigB_2,
|
||||
loadEventInfo2,
|
||||
loadGacha2,
|
||||
loadGarage2,
|
||||
loadGeneralReward3,
|
||||
loadGhost2,
|
||||
loadProfile4,
|
||||
loadRewardTable2,
|
||||
loadServerList,
|
||||
loadStocker2,
|
||||
loadTeam2,
|
||||
loadTeamRanking2,
|
||||
loadTeamRanking4,
|
||||
loadTopTen3,
|
||||
lockGarage2,
|
||||
lockProfile2,
|
||||
lockProfileExtend2,
|
||||
saveExpedition2,
|
||||
saveGarage2,
|
||||
saveNewCar2,
|
||||
saveProfile4,
|
||||
saveSettings2,
|
||||
saveStocker2,
|
||||
saveTeamBanner2,
|
||||
saveTimeAttack3,
|
||||
saveTopic2,
|
||||
unknownA_2,
|
||||
unlockProfile2,
|
||||
updateProvisionalStoreRank2,
|
||||
updateResult,
|
||||
updateTeamLeader2,
|
||||
updateTeamMember2,
|
||||
updateTeamPoints2,
|
||||
updateUiReport2,
|
||||
updateUserLog2,
|
||||
];
|
||||
|
||||
const protocols = new Map<string, Map<number, ReaderFn>>();
|
||||
|
||||
protocols.set("110", makeReaderMap(funcList110));
|
||||
protocols.set("130", makeReaderMap(funcList130));
|
||||
protocols.set("210", makeReaderMap(funcList210));
|
||||
|
||||
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}`);
|
||||
}
|
||||
|
||||
const head = await stm.read(BLOCK_SIZE);
|
||||
|
||||
if (head.length === 0) {
|
||||
@@ -129,16 +258,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 +275,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,28 +1,45 @@
|
||||
import { ExtId } from "../model/base";
|
||||
import { Team } from "../model/team";
|
||||
import { Load2on2Request1, Load2on2Request2 } from "../request/load2on2";
|
||||
import {
|
||||
Load2on2InfoRequest,
|
||||
Load2on2RankingPointsRequest,
|
||||
} from "../request/load2on2";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
load2on2_v1.msgCode = 0x00b0;
|
||||
load2on2_v1.msgLen = 0x0010;
|
||||
load2on2RankingPoints1.msgCode = 0x00b0;
|
||||
load2on2RankingPoints1.msgLen = 0x0010;
|
||||
|
||||
export function load2on2_v1(buf: Buffer): Load2on2Request1 {
|
||||
export function load2on2RankingPoints1(
|
||||
buf: Buffer
|
||||
): Load2on2RankingPointsRequest {
|
||||
return {
|
||||
type: "load_2on2_req",
|
||||
format: 1,
|
||||
type: "load_2on2_ranking_points_req",
|
||||
field_0002: buf.readUInt16LE(0x0002),
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
teamId: buf.readUInt32LE(0x0008) as ExtId<Team>,
|
||||
};
|
||||
}
|
||||
|
||||
load2on2_v2.msgCode = 0x0132;
|
||||
load2on2_v2.msgLen = 0x0010;
|
||||
load2on2RankingPoints2.msgCode = 0x00a3;
|
||||
load2on2RankingPoints2.msgLen = 0x0010;
|
||||
|
||||
export function load2on2_v2(buf: Buffer): Load2on2Request2 {
|
||||
export function load2on2RankingPoints2(
|
||||
buf: Buffer
|
||||
): Load2on2RankingPointsRequest {
|
||||
return {
|
||||
type: "load_2on2_req",
|
||||
format: 2,
|
||||
type: "load_2on2_ranking_points_req",
|
||||
field_0002: buf.readUInt16LE(0x0002),
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
teamId: buf.readUInt32LE(0x0008) as ExtId<Team>,
|
||||
};
|
||||
}
|
||||
|
||||
load2on2Info.msgCode = 0x0132;
|
||||
load2on2Info.msgLen = 0x0010;
|
||||
|
||||
export function load2on2Info(buf: Buffer): Load2on2InfoRequest {
|
||||
return {
|
||||
type: "load_2on2_info_req",
|
||||
field_0002: buf.readUInt16LE(0x0002),
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
teamId: buf.readUInt32LE(0x0008) as ExtId<Team>,
|
||||
|
||||
@@ -1,8 +1,29 @@
|
||||
import { LoadConfigRequest } from "../request/loadConfig";
|
||||
import { LoadConfigRequestA, LoadConfigRequestB } from "../request/loadConfig";
|
||||
|
||||
loadConfig.msgCode = 0x0004;
|
||||
loadConfig.msgLen = 0x0050;
|
||||
loadConfigA_1.msgCode = 0x0004;
|
||||
loadConfigA_1.msgLen = 0x0050;
|
||||
|
||||
export function loadConfig(): LoadConfigRequest {
|
||||
return { type: "load_config_req" };
|
||||
export function loadConfigA_1(): LoadConfigRequestA {
|
||||
return { type: "load_config_A_req" };
|
||||
}
|
||||
|
||||
loadConfigB_1.msgCode = 0x00ab;
|
||||
loadConfigB_1.msgLen = 0x0010;
|
||||
|
||||
export function loadConfigB_1(): LoadConfigRequestB {
|
||||
return { type: "load_config_B_req" };
|
||||
}
|
||||
|
||||
loadConfigA_2.msgCode = 0x0004;
|
||||
loadConfigA_2.msgLen = 0x0050;
|
||||
|
||||
export function loadConfigA_2(): LoadConfigRequestA {
|
||||
return { type: "load_config_A_req" };
|
||||
}
|
||||
|
||||
loadConfigB_2.msgCode = 0x00a0;
|
||||
loadConfigB_2.msgLen = 0x0010;
|
||||
|
||||
export function loadConfigB_2(): LoadConfigRequestB {
|
||||
return { type: "load_config_B_req" };
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import { LoadConfigRequest2 } from "../request/loadConfig2";
|
||||
|
||||
loadConfig2.msgCode = 0x00ab;
|
||||
loadConfig2.msgLen = 0x0010;
|
||||
|
||||
export function loadConfig2(): LoadConfigRequest2 {
|
||||
return { type: "load_config_v2_req" };
|
||||
}
|
||||
@@ -1,10 +1,20 @@
|
||||
import { LoadEventInfoRequest } from "../request/loadEventInfo";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
loadEventInfo.msgCode = 0x00be;
|
||||
loadEventInfo.msgLen = 0x0010;
|
||||
loadEventInfo1.msgCode = 0x00be;
|
||||
loadEventInfo1.msgLen = 0x0010;
|
||||
|
||||
export function loadEventInfo(buf: Buffer): LoadEventInfoRequest {
|
||||
export function loadEventInfo1(buf: Buffer): LoadEventInfoRequest {
|
||||
return {
|
||||
type: "load_event_info_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
};
|
||||
}
|
||||
|
||||
loadEventInfo2.msgCode = 0x00ac;
|
||||
loadEventInfo2.msgLen = 0x0010;
|
||||
|
||||
export function loadEventInfo2(buf: Buffer): LoadEventInfoRequest {
|
||||
return {
|
||||
type: "load_event_info_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import { LoadGachaRequest } from "../request/loadGacha";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
loadGacha.msgCode = 0x00c1;
|
||||
loadGacha.msgLen = 0x0010;
|
||||
loadGacha1.msgCode = 0x00c1;
|
||||
loadGacha1.msgLen = 0x0010;
|
||||
|
||||
export function loadGacha(buf: Buffer): LoadGachaRequest {
|
||||
export function loadGacha1(buf: Buffer): LoadGachaRequest {
|
||||
return {
|
||||
type: "load_gacha_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
};
|
||||
}
|
||||
|
||||
loadGacha2.msgCode = 0x00af;
|
||||
loadGacha2.msgLen = 0x0010;
|
||||
|
||||
export function loadGacha2(buf: Buffer): LoadGachaRequest {
|
||||
return {
|
||||
type: "load_gacha_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
|
||||
@@ -1,13 +1,27 @@
|
||||
import { LoadGarageRequest } from "../request/loadGarage";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
loadGarage.msgCode = 0x0090;
|
||||
loadGarage.msgLen = 0x0010;
|
||||
loadGarage1.msgCode = 0x0090;
|
||||
loadGarage1.msgLen = 0x0010;
|
||||
|
||||
export function loadGarage(buf: Buffer): LoadGarageRequest {
|
||||
export function loadGarage1(buf: Buffer): LoadGarageRequest {
|
||||
return {
|
||||
type: "load_garage_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 1,
|
||||
fetchOffset: buf.readUInt8(0x0008),
|
||||
field_000A: buf.readUInt16LE(0x000a),
|
||||
};
|
||||
}
|
||||
|
||||
loadGarage2.msgCode = 0x0087;
|
||||
loadGarage2.msgLen = 0x0010;
|
||||
|
||||
export function loadGarage2(buf: Buffer): LoadGarageRequest {
|
||||
return {
|
||||
type: "load_garage_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 2,
|
||||
fetchOffset: buf.readUInt8(0x0008),
|
||||
field_000A: buf.readUInt16LE(0x000a),
|
||||
};
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
loadGeneralReward2.msgCode = 0x013b;
|
||||
loadGeneralReward2.msgCode = 0x093b;
|
||||
loadGeneralReward2.msgLen = 0x0010;
|
||||
|
||||
export function loadGeneralReward2(buf: Buffer): LoadGeneralRewardRequest2 {
|
||||
export function loadGeneralReward2(buf: Buffer): LoadGeneralRewardRequest {
|
||||
return {
|
||||
type: "load_general_reward_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
};
|
||||
}
|
||||
|
||||
loadGeneralReward3.msgCode = 0x013b;
|
||||
loadGeneralReward3.msgLen = 0x0010;
|
||||
|
||||
export function loadGeneralReward3(buf: Buffer): LoadGeneralRewardRequest {
|
||||
return {
|
||||
type: "load_general_reward_req",
|
||||
format: 2,
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
import { LoadGhostRequest } from "../request/loadGhost";
|
||||
|
||||
loadGhost.msgCode = 0x00a0;
|
||||
loadGhost.msgLen = 0x0010;
|
||||
loadGhost1.msgCode = 0x00a0;
|
||||
loadGhost1.msgLen = 0x0010;
|
||||
|
||||
export function loadGhost(buf: Buffer): LoadGhostRequest {
|
||||
export function loadGhost1(buf: Buffer): LoadGhostRequest {
|
||||
return {
|
||||
type: "load_ghost_req",
|
||||
field_0002: buf.readUInt16LE(0x0002),
|
||||
field_0004: buf.readUInt16LE(0x0004),
|
||||
field_0008: buf.readUInt32LE(0x0008),
|
||||
field_000C: buf.readUInt16LE(0x000c),
|
||||
field_000E: buf.readUInt16LE(0x000e),
|
||||
};
|
||||
}
|
||||
|
||||
loadGhost2.msgCode = 0x0095;
|
||||
loadGhost2.msgLen = 0x0010;
|
||||
|
||||
export function loadGhost2(buf: Buffer): LoadGhostRequest {
|
||||
return {
|
||||
type: "load_ghost_req",
|
||||
field_0002: buf.readUInt16LE(0x0002),
|
||||
|
||||
@@ -1,29 +1,39 @@
|
||||
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,
|
||||
luid: buf.slice(0x0008, buf.indexOf("\0", 0x0008)).toString("ascii"),
|
||||
version: 1,
|
||||
luid: readAsciiStr(buf, 0x0008, 0x0020),
|
||||
};
|
||||
}
|
||||
|
||||
loadProfile3.msgCode = 0x0012f;
|
||||
loadProfile3.msgCode = 0x012f;
|
||||
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,
|
||||
luid: buf.slice(0x0008, buf.indexOf("\0", 0x0008)).toString("ascii"),
|
||||
version: 1,
|
||||
luid: readAsciiStr(buf, 0x0008, 0x0020),
|
||||
};
|
||||
}
|
||||
|
||||
loadProfile4.msgCode = 0x012f;
|
||||
loadProfile4.msgLen = 0x0020;
|
||||
|
||||
export function loadProfile4(buf: Buffer): LoadProfileRequest {
|
||||
return {
|
||||
type: "load_profile_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 2,
|
||||
luid: readAsciiStr(buf, 0x0008, 0x0020),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
import { LoadRewardTableRequest } from "../request/loadRewardTable";
|
||||
|
||||
loadRewardTable.msgCode = 0x0086;
|
||||
loadRewardTable.msgLen = 0x0010;
|
||||
loadRewardTable1.msgCode = 0x0086;
|
||||
loadRewardTable1.msgLen = 0x0010;
|
||||
|
||||
export function loadRewardTable(): LoadRewardTableRequest {
|
||||
export function loadRewardTable1(): LoadRewardTableRequest {
|
||||
return {
|
||||
type: "load_reward_table_req",
|
||||
};
|
||||
}
|
||||
|
||||
loadRewardTable2.msgCode = 0x007f;
|
||||
loadRewardTable2.msgLen = 0x0010;
|
||||
|
||||
export function loadRewardTable2(): LoadRewardTableRequest {
|
||||
return {
|
||||
type: "load_reward_table_req",
|
||||
};
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
import { LoadStockerRequest } from "../request/loadStocker";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
loadStocker.msgCode = 0x00a7;
|
||||
loadStocker.msgLen = 0x0010;
|
||||
loadStocker1.msgCode = 0x00a7;
|
||||
loadStocker1.msgLen = 0x0010;
|
||||
|
||||
export function loadStocker(buf: Buffer): LoadStockerRequest {
|
||||
export function loadStocker1(buf: Buffer): LoadStockerRequest {
|
||||
return {
|
||||
type: "load_stocker_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 1,
|
||||
};
|
||||
}
|
||||
|
||||
loadStocker2.msgCode = 0x009c;
|
||||
loadStocker2.msgLen = 0x0010;
|
||||
|
||||
export function loadStocker2(buf: Buffer): LoadStockerRequest {
|
||||
return {
|
||||
type: "load_stocker_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 2,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,15 +2,30 @@ import { LoadTeamRequest } from "../request/loadTeam";
|
||||
import { ExtId } from "../model/base";
|
||||
import { Team } from "../model/team";
|
||||
|
||||
loadTeam.msgCode = 0x0077;
|
||||
loadTeam.msgLen = 0x0010;
|
||||
loadTeam1.msgCode = 0x0077;
|
||||
loadTeam1.msgLen = 0x0010;
|
||||
|
||||
export function loadTeam(buf: Buffer): LoadTeamRequest {
|
||||
export function loadTeam1(buf: Buffer): LoadTeamRequest {
|
||||
const extId = buf.readUInt32LE(0x0008);
|
||||
|
||||
return {
|
||||
type: "load_team_req",
|
||||
aimeId: buf.readUInt32LE(0x0004),
|
||||
version: 1,
|
||||
teamExtId: extId !== 0xffffffff ? (extId as ExtId<Team>) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
loadTeam2.msgCode = 0x0073;
|
||||
loadTeam2.msgLen = 0x0010;
|
||||
|
||||
export function loadTeam2(buf: Buffer): LoadTeamRequest {
|
||||
const extId = buf.readUInt32LE(0x0008);
|
||||
|
||||
return {
|
||||
type: "load_team_req",
|
||||
aimeId: buf.readUInt32LE(0x0004),
|
||||
version: 2,
|
||||
teamExtId: extId !== 0xffffffff ? (extId as ExtId<Team>) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
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",
|
||||
};
|
||||
}
|
||||
|
||||
// not sure what the difference is...
|
||||
|
||||
loadTeamRanking2.msgCode = 0x00bb;
|
||||
// unused? Not sure where this came from.
|
||||
loadTeamRanking2.msgCode = 0x00a7;
|
||||
loadTeamRanking2.msgLen = 0x0010;
|
||||
|
||||
export function loadTeamRanking2(buf: Buffer): LoadTeamRankingRequest {
|
||||
@@ -19,3 +18,23 @@ export function loadTeamRanking2(buf: Buffer): LoadTeamRankingRequest {
|
||||
type: "load_team_ranking_req",
|
||||
};
|
||||
}
|
||||
|
||||
// not sure what the difference is...
|
||||
|
||||
loadTeamRanking3.msgCode = 0x00bb;
|
||||
loadTeamRanking3.msgLen = 0x0010;
|
||||
|
||||
export function loadTeamRanking3(buf: Buffer): LoadTeamRankingRequest {
|
||||
return {
|
||||
type: "load_team_ranking_req",
|
||||
};
|
||||
}
|
||||
|
||||
loadTeamRanking4.msgCode = 0x00a9;
|
||||
loadTeamRanking4.msgLen = 0x0010;
|
||||
|
||||
export function loadTeamRanking4(buf: Buffer): LoadTeamRankingRequest {
|
||||
return {
|
||||
type: "load_team_ranking_req",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ export function loadTopTen1(buf: Buffer): LoadTopTenRequest {
|
||||
|
||||
return {
|
||||
type: "load_top_ten_req",
|
||||
version: 1,
|
||||
field_2: buf.readUInt16LE(0x0002), // Bitmask selector
|
||||
selectors,
|
||||
field_C4: buf.readUInt8(0x00c4), // Boolean, true if profile ID is set
|
||||
|
||||
@@ -24,6 +24,7 @@ export function loadTopTen2(buf: Buffer): LoadTopTenRequest {
|
||||
|
||||
return {
|
||||
type: "load_top_ten_req",
|
||||
version: 1,
|
||||
field_2: buf.readUInt16LE(0x0002), // Bitmask selector
|
||||
selectors,
|
||||
field_C4: buf.readUInt8(0x00f4), // Boolean, true if profile ID is set
|
||||
@@ -33,3 +34,34 @@ export function loadTopTen2(buf: Buffer): LoadTopTenRequest {
|
||||
teamId: teamId !== 0xffffffff ? (teamId as ExtId<Team>) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
loadTopTen3.msgCode = 0x012c;
|
||||
loadTopTen3.msgLen = 0x0110;
|
||||
|
||||
export function loadTopTen3(buf: Buffer): LoadTopTenRequest {
|
||||
const selectors = new Array<LoadTopTenRequestSelector>();
|
||||
|
||||
for (let i = 0; i < 40; i++) {
|
||||
selectors.push({
|
||||
routeNo: (buf.readUInt16LE(0x0004 + 2 + 2 * i) >> 1) as RouteNo,
|
||||
minTimestamp: new Date(
|
||||
buf.readUInt32LE(0x0054 + 4 + 4 * i) * 1000 + 1000
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
const profileId = buf.readUInt32LE(0x00fc);
|
||||
const teamId = buf.readUInt32LE(0x0100);
|
||||
|
||||
return {
|
||||
type: "load_top_ten_req",
|
||||
version: 2,
|
||||
field_2: buf.readUInt16LE(0x0004), // Bitmask selector
|
||||
selectors,
|
||||
field_C4: buf.readUInt8(0x00f8), // Boolean, true if profile ID is set
|
||||
field_C5: buf.readUInt8(0x00f9), // Always zero
|
||||
field_C6: buf.readUInt16LE(0x00fa),
|
||||
aimeId: profileId !== 0 ? (profileId as AimeId) : undefined,
|
||||
teamId: teamId !== 0xffffffff ? (teamId as ExtId<Team>) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
import { LockGarageRequest } from "../request/lockGarage";
|
||||
|
||||
lockGarage.msgCode = 0x00a9;
|
||||
lockGarage.msgLen = 0x0010;
|
||||
lockGarage1.msgCode = 0x00a9;
|
||||
lockGarage1.msgLen = 0x0010;
|
||||
|
||||
export function lockGarage(buf: Buffer): LockGarageRequest {
|
||||
export function lockGarage1(buf: Buffer): LockGarageRequest {
|
||||
return {
|
||||
type: "lock_garage_request",
|
||||
field_0004: buf.readUInt32LE(0x0004),
|
||||
};
|
||||
}
|
||||
|
||||
lockGarage2.msgCode = 0x009e;
|
||||
lockGarage2.msgLen = 0x0010;
|
||||
|
||||
export function lockGarage2(buf: Buffer): LockGarageRequest {
|
||||
return {
|
||||
type: "lock_garage_request",
|
||||
field_0004: buf.readUInt32LE(0x0004),
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
import { readAsciiStr } from "../../util/bin";
|
||||
import { LockProfileRequest } from "../request/lockProfile";
|
||||
|
||||
lockProfile.msgCode = 0x0069;
|
||||
lockProfile.msgLen = 0x0020;
|
||||
lockProfile1.msgCode = 0x0069;
|
||||
lockProfile1.msgLen = 0x0020;
|
||||
|
||||
export function lockProfile(buf: Buffer): LockProfileRequest {
|
||||
export function lockProfile1(buf: Buffer): LockProfileRequest {
|
||||
return {
|
||||
type: "lock_profile_req",
|
||||
aimeId: buf.readUInt32LE(0x0004),
|
||||
pcbId: buf.slice(0x0008, buf.indexOf("\0", 0x0008)).toString("ascii"),
|
||||
pcbId: readAsciiStr(buf, 0x0008, 0x0018),
|
||||
field_0018: buf.readUInt16LE(0x0018),
|
||||
};
|
||||
}
|
||||
|
||||
lockProfile2.msgCode = 0x0065;
|
||||
lockProfile2.msgLen = 0x0020;
|
||||
|
||||
export function lockProfile2(buf: Buffer): LockProfileRequest {
|
||||
return {
|
||||
type: "lock_profile_req",
|
||||
aimeId: buf.readUInt32LE(0x0004),
|
||||
pcbId: readAsciiStr(buf, 0x0008, 0x0018),
|
||||
field_0018: buf.readUInt16LE(0x0018),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
import { LockProfileExtendRequest } from "../request/lockProfileExtend";
|
||||
import { AimeId } from "../../../model";
|
||||
import { readAsciiStr } from "../../util/bin";
|
||||
|
||||
lockProfileExtend.msgCode = 0x006d;
|
||||
lockProfileExtend.msgLen = 0x0020;
|
||||
lockProfileExtend1.msgCode = 0x006d;
|
||||
lockProfileExtend1.msgLen = 0x0020;
|
||||
|
||||
export function lockProfileExtend(buf: Buffer): LockProfileExtendRequest {
|
||||
export function lockProfileExtend1(buf: Buffer): LockProfileExtendRequest {
|
||||
return {
|
||||
type: "lock_profile_extend_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
luid: readAsciiStr(buf, 0x0008, 0x0020),
|
||||
};
|
||||
}
|
||||
|
||||
lockProfileExtend2.msgCode = 0x0069;
|
||||
lockProfileExtend2.msgLen = 0x0020;
|
||||
|
||||
export function lockProfileExtend2(buf: Buffer): LockProfileExtendRequest {
|
||||
return {
|
||||
type: "lock_profile_extend_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import { Message00AD } from "../request/msg00AD";
|
||||
|
||||
msg00AD.msgCode = 0x00ad;
|
||||
msg00AD.msgLen = 0x0620;
|
||||
|
||||
export function msg00AD(buf: Buffer): Message00AD {
|
||||
return { type: "msg_00AD_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,10 +1,11 @@
|
||||
import { car } from "./_car";
|
||||
import { SaveGarageRequest } from "../request/saveGarage";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
saveGarage.msgCode = 0x008e;
|
||||
saveGarage.msgLen = 0x0090;
|
||||
saveGarage1.msgCode = 0x008e;
|
||||
saveGarage1.msgLen = 0x0090;
|
||||
|
||||
export function saveGarage(buf: Buffer): SaveGarageRequest {
|
||||
export function saveGarage1(buf: Buffer): SaveGarageRequest {
|
||||
const field_0068: number[] = [];
|
||||
|
||||
for (let offset = 0x0068; offset < 0x007c; offset += 2) {
|
||||
@@ -13,10 +14,32 @@ export function saveGarage(buf: Buffer): SaveGarageRequest {
|
||||
|
||||
return {
|
||||
type: "save_garage_req",
|
||||
aimeId: buf.readUInt32LE(0x0004),
|
||||
payload: car(buf.slice(0x0008, 0x0068)),
|
||||
version: 1,
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
car: car(buf.slice(0x0008, 0x0068)),
|
||||
field_0068,
|
||||
field_0080: buf.readUInt8(0x0080),
|
||||
field_0081: buf.readUInt8(0x0081) !== 0,
|
||||
};
|
||||
}
|
||||
|
||||
saveGarage2.msgCode = 0x0085;
|
||||
saveGarage2.msgLen = 0x0090;
|
||||
|
||||
export function saveGarage2(buf: Buffer): SaveGarageRequest {
|
||||
const field_0068: number[] = [];
|
||||
|
||||
for (let offset = 0x0068; offset < 0x007c; offset += 2) {
|
||||
field_0068.push(buf.readUInt16LE(offset));
|
||||
}
|
||||
|
||||
return {
|
||||
type: "save_garage_req",
|
||||
version: 2,
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
car: car(buf.slice(0x0008, 0x0068)),
|
||||
field_0068,
|
||||
field_0080: buf.readUInt8(0x0088),
|
||||
field_0081: buf.readUInt8(0x0089) !== 0,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,15 +1,31 @@
|
||||
import { car } from "./_car";
|
||||
import { SaveNewCarRequest } from "../request/saveNewCar";
|
||||
import { readAsciiStr } from "../../util/bin";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
saveNewCar.msgCode = 0x0079;
|
||||
saveNewCar.msgLen = 0x0090;
|
||||
saveNewCar1.msgCode = 0x0079;
|
||||
saveNewCar1.msgLen = 0x0090;
|
||||
|
||||
export function saveNewCar(buf: Buffer): SaveNewCarRequest {
|
||||
export function saveNewCar1(buf: Buffer): SaveNewCarRequest {
|
||||
return {
|
||||
type: "save_new_car_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
luid: buf.slice(0x0008, buf.indexOf(0, 0x0008)).toString("ascii"),
|
||||
version: 1,
|
||||
luid: readAsciiStr(buf, 0x0008, 0x001e),
|
||||
car: car(buf.slice(0x0020, 0x0080)),
|
||||
field_0080: buf.readUInt32LE(0x0080),
|
||||
};
|
||||
}
|
||||
|
||||
saveNewCar2.msgCode = 0x0075;
|
||||
saveNewCar2.msgLen = 0x0090;
|
||||
|
||||
export function saveNewCar2(buf: Buffer): SaveNewCarRequest {
|
||||
return {
|
||||
type: "save_new_car_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 2,
|
||||
luid: readAsciiStr(buf, 0x0008, 0x001e),
|
||||
car: car(buf.slice(0x0020, 0x0080)),
|
||||
field_0080: buf.readUInt32LE(0x0080),
|
||||
};
|
||||
|
||||
@@ -1,31 +1,33 @@
|
||||
import { car } from "./_car";
|
||||
import { mission } from "./_mission";
|
||||
import { BackgroundCode, CourseNo, TitleCode } from "../model/base";
|
||||
import { SaveProfileRequest2 } from "../request/saveProfile";
|
||||
import { StoryCell, StoryRow } from "../model/story";
|
||||
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 {
|
||||
const storyRows = new Array();
|
||||
export function saveProfile2(buf: Buffer): SaveProfileRequest {
|
||||
const storyRows = new Map<number, StoryRow>();
|
||||
|
||||
for (let i = 0; i < 9; i++) {
|
||||
const cells = new Array();
|
||||
const cells = new Map<number, StoryCell>();
|
||||
const rowOffset = 0x01a8 + i * 0x3c;
|
||||
|
||||
for (let j = 0; j < 9; j++) {
|
||||
const a = buf.readUInt32LE(rowOffset + 0x04 + j * 4);
|
||||
const b = buf.readUInt16LE(rowOffset + 0x28 + j * 2);
|
||||
const cell = { a, b };
|
||||
const c = 0; // Added in idz2
|
||||
const cell = { a, b, c };
|
||||
|
||||
cells.push(cell);
|
||||
cells.set(j, cell);
|
||||
}
|
||||
|
||||
const row = { cells };
|
||||
|
||||
storyRows.push(row);
|
||||
storyRows.set(i, row);
|
||||
}
|
||||
|
||||
const coursePlays = new Map<CourseNo, number>();
|
||||
@@ -45,8 +47,8 @@ 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),
|
||||
exp: buf.readUInt32LE(0x0028),
|
||||
fame: buf.readUInt32LE(0x0468),
|
||||
@@ -94,6 +96,7 @@ export function saveProfile2(buf: Buffer): SaveProfileRequest2 {
|
||||
aura: buf.readUInt8(0x002c),
|
||||
paperCup: buf.readUInt8(0x00f6),
|
||||
gauges: buf.readUInt8(0x00f7),
|
||||
drivingStyle: 0, // Not supported until idz2
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,33 +1,35 @@
|
||||
import { car } from "./_car";
|
||||
import { mission } from "./_mission";
|
||||
import { BackgroundCode, CourseNo, TitleCode } from "../model/base";
|
||||
import { SaveProfileRequest2 } from "../request/saveProfile";
|
||||
import { StoryCell, StoryRow } from "../model/story";
|
||||
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 {
|
||||
const storyRows = new Array();
|
||||
export function saveProfile3(buf: Buffer): SaveProfileRequest {
|
||||
const storyRows = new Map<number, StoryRow>();
|
||||
|
||||
// Story layout has changed somewhat...
|
||||
|
||||
for (let i = 0; i < 27; i++) {
|
||||
const cells = new Array();
|
||||
const cells = new Map<number, StoryCell>();
|
||||
const rowOffset = 0x01ac + i * 0x18;
|
||||
|
||||
for (let j = 0; j < 9; j++) {
|
||||
const a = buf.readUInt8(rowOffset + 0x00 + j);
|
||||
const b = buf.readUInt8(rowOffset + 0x09 + j);
|
||||
const cell = { a, b };
|
||||
const c = 0; // Added in idz2
|
||||
const cell = { a, b, c };
|
||||
|
||||
cells.push(cell);
|
||||
cells.set(j, cell);
|
||||
}
|
||||
|
||||
const row = { cells };
|
||||
|
||||
storyRows.push(row);
|
||||
storyRows.set(i, row);
|
||||
}
|
||||
|
||||
const coursePlays = new Map<CourseNo, number>();
|
||||
@@ -47,8 +49,8 @@ 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),
|
||||
exp: buf.readUInt32LE(0x0028),
|
||||
fame: buf.readUInt32LE(0x04fc),
|
||||
@@ -96,6 +98,7 @@ export function saveProfile3(buf: Buffer): SaveProfileRequest2 {
|
||||
aura: buf.readUInt8(0x002c),
|
||||
paperCup: buf.readUInt8(0x00f6),
|
||||
gauges: buf.readUInt8(0x00f7),
|
||||
drivingStyle: 0, // Not supported until idz2
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
import { car } from "./_car";
|
||||
import { mission } from "./_mission";
|
||||
import { BackgroundCode, CourseNo, StampCode, TitleCode } from "../model/base";
|
||||
import { StoryCell, StoryRow } from "../model/story";
|
||||
import { SaveProfileRequest } from "../request/saveProfile";
|
||||
import { bitmap } from "./_bitmap";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
saveProfile4.msgCode = 0x0138;
|
||||
saveProfile4.msgLen = 0x0eb0;
|
||||
|
||||
export function saveProfile4(buf: Buffer): SaveProfileRequest {
|
||||
const storyRows = new Map<number, StoryRow>();
|
||||
|
||||
// Story layout got another rework in idz2
|
||||
// First two bytes per row denote the chapter, however
|
||||
// since this is in completely linear order (in 2.12) we can
|
||||
// just skip saving/reading this for our convenience.
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
const cells = new Map<number, StoryCell>();
|
||||
const rowOffset = 0x026c + 0x02 + i * 0x7a;
|
||||
|
||||
for (let j = 0; j < 28; j++) {
|
||||
const a = buf.readUInt8(rowOffset + 0x00 + j * 4);
|
||||
const b = buf.readUInt8(rowOffset + 0x01 + j * 4);
|
||||
const c = buf.readUInt8(rowOffset + 0x02 + j * 4);
|
||||
const cell = { a, b, c };
|
||||
|
||||
cells.set(j, cell);
|
||||
}
|
||||
|
||||
const row = { cells };
|
||||
|
||||
storyRows.set(i, row);
|
||||
}
|
||||
|
||||
const coursePlays = new Map<CourseNo, number>();
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
coursePlays.set(i as CourseNo, buf.readUInt16LE(0x07dc + 2 * i));
|
||||
}
|
||||
|
||||
const freeCar = {
|
||||
validFrom: buf.readUInt32LE(0x01fc),
|
||||
};
|
||||
|
||||
const freeContinue = {
|
||||
validFrom: buf.readUInt32LE(0x0038),
|
||||
validTo: buf.readUInt32LE(0x003c),
|
||||
};
|
||||
|
||||
const weeklyReset = {
|
||||
endDate: buf.readUInt32LE(0x0c90),
|
||||
};
|
||||
|
||||
return {
|
||||
type: "save_profile_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 2,
|
||||
lv: buf.readUInt16LE(0x0026),
|
||||
exp: buf.readUInt32LE(0x0028),
|
||||
fame: buf.readUInt32LE(0x0784),
|
||||
dpoint: buf.readUInt32LE(0x0780),
|
||||
mileage: buf.readUInt32LE(0x0008),
|
||||
title: buf.readUInt16LE(0x0040) as TitleCode,
|
||||
titles: bitmap(buf.slice(0x0042, 0x01b9)),
|
||||
background: buf.readUInt8(0x0afc) as BackgroundCode,
|
||||
coursePlays,
|
||||
missions: {
|
||||
team: mission(buf.slice(0x06c0, 0x06e4)),
|
||||
solo: mission(buf.slice(0x0ad0, 0x0af2)),
|
||||
},
|
||||
car: car(buf.slice(0x0b80, 0x0be0)),
|
||||
story: {
|
||||
x: buf.readUInt16LE(0x0aa0),
|
||||
y: buf.readUInt8(0x0a84),
|
||||
rows: storyRows,
|
||||
},
|
||||
unlocks: {
|
||||
auras: buf.readUInt16LE(0x01d0),
|
||||
cup: buf.readUInt8(0x01d4),
|
||||
gauges: buf.readUInt32LE(0x01d8),
|
||||
music: buf.readUInt16LE(0x0204),
|
||||
lastMileageReward: buf.readUInt32LE(0x0200),
|
||||
},
|
||||
tickets: {
|
||||
freeCar:
|
||||
freeCar.validFrom !== 0
|
||||
? {
|
||||
validFrom: new Date(freeCar.validFrom * 1000),
|
||||
}
|
||||
: undefined,
|
||||
freeContinue:
|
||||
freeContinue.validFrom !== 0 && freeContinue.validTo !== 0
|
||||
? {
|
||||
validFrom: new Date(freeContinue.validFrom * 1000),
|
||||
validTo: new Date(freeContinue.validTo * 1000),
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
selectedStamps: {
|
||||
stamp01: buf.readUInt16LE(0x0d74) as StampCode,
|
||||
stamp02: buf.readUInt16LE(0x0d76) as StampCode,
|
||||
stamp03: buf.readUInt16LE(0x0d78) as StampCode,
|
||||
stamp04: buf.readUInt16LE(0x0d7a) as StampCode,
|
||||
},
|
||||
stamps: bitmap(buf.slice(0x0d28, 0x0d4e)),
|
||||
settings: {
|
||||
music: buf.readUInt16LE(0x0776),
|
||||
pack: buf.readUInt32LE(0x0034),
|
||||
aura: buf.readUInt8(0x002c),
|
||||
paperCup: buf.readUInt8(0x01b9),
|
||||
gauges: buf.readUInt8(0x01ba),
|
||||
drivingStyle: buf.readUInt8(0x0dae),
|
||||
},
|
||||
weeklyMissions: {
|
||||
weeklyReset: new Date(weeklyReset.endDate * 1000),
|
||||
weeklyMissionLeft: buf.readUInt16LE(0x0c84),
|
||||
weeklyProgressLeft: buf.readUInt16LE(0x0c86),
|
||||
weeklyParamsLeft: buf.readUInt16LE(0x0c88),
|
||||
weeklyMissionRight: buf.readUInt16LE(0x0c8a),
|
||||
weeklyProgressRight: buf.readUInt16LE(0x0c8c),
|
||||
weeklyParamsRight: buf.readUInt16LE(0x0c8e),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
import { SaveSettingsRequest } from "../request/saveSettings";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
saveSettings.msgCode = 0x00a5;
|
||||
saveSettings.msgLen = 0x0020;
|
||||
|
||||
export function saveSettings(buf: Buffer): SaveSettingsRequest {
|
||||
const pack = buf.readUInt32LE(0x000c);
|
||||
saveSettings1.msgCode = 0x00a5;
|
||||
saveSettings1.msgLen = 0x0020;
|
||||
|
||||
export function saveSettings1(buf: Buffer): SaveSettingsRequest {
|
||||
return {
|
||||
type: "save_settings_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 1,
|
||||
dpoint: buf.readUInt32LE(0x0008),
|
||||
settings: {
|
||||
music: buf.readUInt16LE(0x0002),
|
||||
@@ -17,7 +16,29 @@ export function saveSettings(buf: Buffer): SaveSettingsRequest {
|
||||
paperCup: buf.readUInt8(0x0011),
|
||||
gauges: buf.readUInt8(0x0012),
|
||||
aura: buf.readUInt8(0x0013),
|
||||
drivingStyle: 0, // Not supported until idz2
|
||||
},
|
||||
field_0010: buf.readUInt8(0x0010),
|
||||
};
|
||||
}
|
||||
|
||||
saveSettings2.msgCode = 0x009a;
|
||||
saveSettings2.msgLen = 0x0020;
|
||||
|
||||
export function saveSettings2(buf: Buffer): SaveSettingsRequest {
|
||||
return {
|
||||
type: "save_settings_req",
|
||||
aimeId: buf.readUInt32LE(0x0008) as AimeId,
|
||||
version: 2,
|
||||
dpoint: buf.readUInt32LE(0x000c),
|
||||
settings: {
|
||||
music: buf.readUInt16LE(0x0004),
|
||||
pack: buf.readUInt32LE(0x0010),
|
||||
paperCup: buf.readUInt8(0x0015),
|
||||
gauges: buf.readUInt8(0x0016),
|
||||
aura: buf.readUInt8(0x0017),
|
||||
drivingStyle: buf.readUInt8(0x0018),
|
||||
},
|
||||
field_0010: buf.readUInt32LE(0x0014),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,19 +1,42 @@
|
||||
import { bitmap } from "./_bitmap";
|
||||
import { chara } from "./_chara";
|
||||
import { StampCode } from "../model/base";
|
||||
import { CarSelector } from "../model/car";
|
||||
import { SaveStockerRequest } from "../request/saveStocker";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
saveStocker.msgCode = 0x00a6;
|
||||
saveStocker.msgLen = 0x00c0;
|
||||
saveStocker1.msgCode = 0x00a6;
|
||||
saveStocker1.msgLen = 0x00c0;
|
||||
|
||||
export function saveStocker(buf: Buffer): SaveStockerRequest {
|
||||
export function saveStocker1(buf: Buffer): SaveStockerRequest {
|
||||
return {
|
||||
type: "save_stocker_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
|
||||
version: 1,
|
||||
backgrounds: bitmap(buf.slice(0x0008, 0x002c)),
|
||||
selectedCar: buf.readUInt16LE(0x009c) as CarSelector,
|
||||
chara: chara(buf.slice(0x009e, 0x00b2)),
|
||||
};
|
||||
}
|
||||
|
||||
saveStocker2.msgCode = 0x009b;
|
||||
saveStocker2.msgLen = 0x0110;
|
||||
|
||||
export function saveStocker2(buf: Buffer): SaveStockerRequest {
|
||||
return {
|
||||
type: "save_stocker_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 2,
|
||||
backgrounds: bitmap(buf.slice(0x0008, 0x0034)),
|
||||
selectedCar: buf.readUInt16LE(0x009c) as CarSelector,
|
||||
chara: chara(buf.slice(0x009e, 0x00b2)),
|
||||
myChara: bitmap(buf.slice(0x0034, 0x098)),
|
||||
selectedStamps: {
|
||||
stamp01: buf.readUInt16LE(0x00da) as StampCode,
|
||||
stamp02: buf.readUInt16LE(0x00dc) as StampCode,
|
||||
stamp03: buf.readUInt16LE(0x00de) as StampCode,
|
||||
stamp04: buf.readUInt16LE(0x00e0) as StampCode,
|
||||
},
|
||||
stamps: bitmap(buf.slice(0x00b3, 0x00d9)),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,13 +2,27 @@ import { SaveTeamBannerRequest } from "../request/saveTeamBanner";
|
||||
import { ExtId } from "../model/base";
|
||||
import { Team } from "../model/team";
|
||||
|
||||
saveTeamBanner.msgCode = 0x0089;
|
||||
saveTeamBanner.msgLen = 0x0010;
|
||||
saveTeamBanner1.msgCode = 0x0089;
|
||||
saveTeamBanner1.msgLen = 0x0010;
|
||||
|
||||
export function saveTeamBanner(buf: Buffer): SaveTeamBannerRequest {
|
||||
export function saveTeamBanner1(buf: Buffer): SaveTeamBannerRequest {
|
||||
return {
|
||||
type: "save_team_banner_req",
|
||||
teamExtId: buf.readUInt32LE(0x0004) as ExtId<Team>,
|
||||
version: 1,
|
||||
nameBg: buf.readUInt32LE(0x0008),
|
||||
nameFx: buf.readUInt32LE(0x000c),
|
||||
};
|
||||
}
|
||||
|
||||
saveTeamBanner2.msgCode = 0x0082;
|
||||
saveTeamBanner2.msgLen = 0x0010;
|
||||
|
||||
export function saveTeamBanner2(buf: Buffer): SaveTeamBannerRequest {
|
||||
return {
|
||||
type: "save_team_banner_req",
|
||||
teamExtId: buf.readUInt32LE(0x0004) as ExtId<Team>,
|
||||
version: 2,
|
||||
nameBg: buf.readUInt32LE(0x0008),
|
||||
nameFx: buf.readUInt32LE(0x000c),
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ function saveTimeAttack(buf: Buffer): SaveTimeAttackRequest {
|
||||
return {
|
||||
type: "save_time_attack_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 1,
|
||||
dayNight: buf.readUInt8(0x0054) & 1,
|
||||
payload: {
|
||||
routeNo: (buf.readUInt8(0x0054) >> 1) as RouteNo,
|
||||
@@ -48,3 +49,35 @@ saveTimeAttack2.msgLen = 0x0080;
|
||||
export function saveTimeAttack2(buf: Buffer): SaveTimeAttackRequest {
|
||||
return saveTimeAttack(buf);
|
||||
}
|
||||
|
||||
saveTimeAttack3.msgCode = 0x0136;
|
||||
saveTimeAttack3.msgLen = 0x0080;
|
||||
|
||||
export function saveTimeAttack3(buf: Buffer): SaveTimeAttackRequest {
|
||||
return {
|
||||
type: "save_time_attack_req",
|
||||
aimeId: buf.readUInt32LE(0x0008) as AimeId,
|
||||
version: 2,
|
||||
dayNight: buf.readUInt8(0x0058) & 1,
|
||||
payload: {
|
||||
routeNo: (buf.readUInt8(0x0058) >> 1) as RouteNo,
|
||||
timestamp: new Date(buf.readUInt32LE(0x005c) * 1000),
|
||||
flags: buf.readUInt8(0x0060),
|
||||
totalTime: buf.readUInt32LE(0x001c) / 1000,
|
||||
sectionTimes: [
|
||||
buf.readUInt32LE(0x0028) / 1000,
|
||||
buf.readUInt32LE(0x002c) / 1000,
|
||||
buf.readUInt32LE(0x0030) / 1000,
|
||||
],
|
||||
grade: buf.readUInt8(0x0066),
|
||||
carSelector: buf.readUInt16LE(0x0010) as CarSelector,
|
||||
},
|
||||
field_0002: buf.readUInt16LE(0x0004),
|
||||
field_0008: buf.readUInt32LE(0x000c),
|
||||
field_0012: buf.readUInt8(0x0016),
|
||||
field_0015: buf.readUInt8(0x0019),
|
||||
field_005D: buf.readUInt8(0x0061),
|
||||
field_005E: buf.readUInt16LE(0x0062),
|
||||
field_0060: buf.readUInt16LE(0x0064),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
import { SaveTopicRequest } from "../request/saveTopic";
|
||||
|
||||
saveTopic.msgCode = 0x009a;
|
||||
saveTopic.msgLen = 0x0010;
|
||||
saveTopic1.msgCode = 0x009a;
|
||||
saveTopic1.msgLen = 0x0010;
|
||||
|
||||
export function saveTopic(buf: Buffer): SaveTopicRequest {
|
||||
export function saveTopic1(buf: Buffer): SaveTopicRequest {
|
||||
const aimeId = buf.readUInt32LE(0x0004);
|
||||
|
||||
return {
|
||||
type: "save_topic_req",
|
||||
aimeId: aimeId !== 0xffffffff ? aimeId : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
saveTopic2.msgCode = 0x0091;
|
||||
saveTopic2.msgLen = 0x0010;
|
||||
|
||||
export function saveTopic2(buf: Buffer): SaveTopicRequest {
|
||||
const aimeId = buf.readUInt32LE(0x0004);
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { UnknownRequestA } from "../request/unknownA";
|
||||
|
||||
unknownA_1.msgCode = 0x00ad;
|
||||
unknownA_1.msgLen = 0x0620;
|
||||
|
||||
export function unknownA_1(buf: Buffer): UnknownRequestA {
|
||||
return { type: "unknown_A_req" };
|
||||
}
|
||||
|
||||
unknownA_2.msgCode = 0x00a2;
|
||||
unknownA_2.msgLen = 0x0620;
|
||||
|
||||
export function unknownA_2(buf: Buffer): UnknownRequestA {
|
||||
return { type: "unknown_A_req" };
|
||||
}
|
||||
@@ -1,9 +1,20 @@
|
||||
import { UnlockProfileRequest } from "../request/unlockProfile";
|
||||
|
||||
unlockProfile.msgCode = 0x006f;
|
||||
unlockProfile.msgLen = 0x0020;
|
||||
unlockProfile1.msgCode = 0x006f;
|
||||
unlockProfile1.msgLen = 0x0020;
|
||||
|
||||
export function unlockProfile(buf: Buffer): UnlockProfileRequest {
|
||||
export function unlockProfile1(buf: Buffer): UnlockProfileRequest {
|
||||
return {
|
||||
type: "unlock_profile_req",
|
||||
aimeId: buf.readUInt32LE(0x0004),
|
||||
pcbId: buf.slice(0x0008, buf.indexOf("\0", 0x0008)).toString("ascii"),
|
||||
};
|
||||
}
|
||||
|
||||
unlockProfile2.msgCode = 0x006b;
|
||||
unlockProfile2.msgLen = 0x0020;
|
||||
|
||||
export function unlockProfile2(buf: Buffer): UnlockProfileRequest {
|
||||
return {
|
||||
type: "unlock_profile_req",
|
||||
aimeId: buf.readUInt32LE(0x0004),
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { UpdateExpeditionRequest } from "../request/updateExpedition";
|
||||
|
||||
updateExpedition.msgCode = 0x013F;
|
||||
updateExpedition.msgLen = 0x0010;
|
||||
|
||||
export function updateExpedition(
|
||||
buf: Buffer
|
||||
): UpdateExpeditionRequest {
|
||||
return {
|
||||
type: "update_expedition_req",
|
||||
expeditionRequestType: buf.readUInt32LE(0x0004),
|
||||
};
|
||||
}
|
||||
@@ -1,9 +1,21 @@
|
||||
import { UpdateProvisionalStoreRankRequest } from "../request/updateProvisionalStoreRank";
|
||||
|
||||
updateProvisionalStoreRank.msgCode = 0x0082;
|
||||
updateProvisionalStoreRank.msgLen = 0x0010;
|
||||
updateProvisionalStoreRank1.msgCode = 0x0082;
|
||||
updateProvisionalStoreRank1.msgLen = 0x0010;
|
||||
|
||||
export function updateProvisionalStoreRank(
|
||||
export function updateProvisionalStoreRank1(
|
||||
buf: Buffer
|
||||
): UpdateProvisionalStoreRankRequest {
|
||||
return {
|
||||
type: "update_provisional_store_rank_req",
|
||||
aimeId: buf.readUInt32LE(0x0004),
|
||||
};
|
||||
}
|
||||
|
||||
updateProvisionalStoreRank2.msgCode = 0x007c;
|
||||
updateProvisionalStoreRank2.msgLen = 0x0010;
|
||||
|
||||
export function updateProvisionalStoreRank2(
|
||||
buf: Buffer
|
||||
): UpdateProvisionalStoreRankRequest {
|
||||
return {
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
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.msgCode = 0x097f;
|
||||
updateStoryClearNum2.msgLen = 0x0010;
|
||||
|
||||
export function updateStoryClearNum2(
|
||||
buf: Buffer
|
||||
): UpdateStoryClearNumRequest2 {
|
||||
export function updateStoryClearNum2(buf: Buffer): UpdateStoryClearNumRequest {
|
||||
return {
|
||||
type: "update_story_clear_num_req",
|
||||
};
|
||||
}
|
||||
|
||||
updateStoryClearNum3.msgCode = 0x013d;
|
||||
updateStoryClearNum3.msgLen = 0x0010;
|
||||
|
||||
export function updateStoryClearNum3(buf: Buffer): UpdateStoryClearNumRequest {
|
||||
return {
|
||||
type: "update_story_clear_num_req",
|
||||
format: 2,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,15 +2,30 @@ import { ExtId } from "../model/base";
|
||||
import { Team } from "../model/team";
|
||||
import { UpdateTeamLeaderRequest } from "../request/updateTeamLeader";
|
||||
import { AimeId } from "../../../model";
|
||||
import { readAsciiStr } from "../../util/bin";
|
||||
|
||||
updateTeamLeader.msgCode = 0x008a;
|
||||
updateTeamLeader.msgLen = 0x0020;
|
||||
updateTeamLeader1.msgCode = 0x008a;
|
||||
updateTeamLeader1.msgLen = 0x0020;
|
||||
|
||||
export function updateTeamLeader(buf: Buffer): UpdateTeamLeaderRequest {
|
||||
export function updateTeamLeader1(buf: Buffer): UpdateTeamLeaderRequest {
|
||||
return {
|
||||
type: "update_team_leader_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 1,
|
||||
teamExtId: buf.readUInt32LE(0x0008) as ExtId<Team>,
|
||||
field_000C: buf.slice(0x000c, buf.indexOf("\0", 0x000c)).toString("ascii"),
|
||||
field_000C: readAsciiStr(buf, 0x000c, 0x0020),
|
||||
};
|
||||
}
|
||||
|
||||
updateTeamLeader2.msgCode = 0x0083;
|
||||
updateTeamLeader2.msgLen = 0x0020;
|
||||
|
||||
export function updateTeamLeader2(buf: Buffer): UpdateTeamLeaderRequest {
|
||||
return {
|
||||
type: "update_team_leader_req",
|
||||
aimeId: buf.readUInt32LE(0x0004) as AimeId,
|
||||
version: 2,
|
||||
teamExtId: buf.readUInt32LE(0x0008) as ExtId<Team>,
|
||||
field_000C: readAsciiStr(buf, 0x000c, 0x0020),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,14 +3,28 @@ import { Team } from "../model/team";
|
||||
import { UpdateTeamMemberRequest } from "../request/updateTeamMember";
|
||||
import { AimeId } from "../../../model";
|
||||
|
||||
updateTeamMember.msgCode = 0x0073;
|
||||
updateTeamMember.msgLen = 0x0010;
|
||||
updateTeamMember1.msgCode = 0x0073;
|
||||
updateTeamMember1.msgLen = 0x0010;
|
||||
|
||||
export function updateTeamMember(buf: Buffer): UpdateTeamMemberRequest {
|
||||
export function updateTeamMember1(buf: Buffer): UpdateTeamMemberRequest {
|
||||
return {
|
||||
type: "update_team_member_req",
|
||||
action: buf.readUInt8(0x0004) === 0 ? "add" : "remove",
|
||||
aimeId: buf.readUInt32LE(0x0008) as AimeId,
|
||||
version: 1,
|
||||
teamExtId: buf.readUInt32LE(0x000c) as ExtId<Team>,
|
||||
};
|
||||
}
|
||||
|
||||
updateTeamMember2.msgCode = 0x006f;
|
||||
updateTeamMember2.msgLen = 0x0010;
|
||||
|
||||
export function updateTeamMember2(buf: Buffer): UpdateTeamMemberRequest {
|
||||
return {
|
||||
type: "update_team_member_req",
|
||||
action: buf.readUInt8(0x0004) === 0 ? "add" : "remove",
|
||||
aimeId: buf.readUInt32LE(0x0008) as AimeId,
|
||||
version: 2,
|
||||
teamExtId: buf.readUInt32LE(0x000c) as ExtId<Team>,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
import { UpdateTeamPointsRequest } from "../request/updateTeamPoints";
|
||||
|
||||
updateTeamPoints.msgCode = 0x0081;
|
||||
updateTeamPoints.msgLen = 0x0010;
|
||||
updateTeamPoints1.msgCode = 0x0081;
|
||||
updateTeamPoints1.msgLen = 0x0010;
|
||||
|
||||
export function updateTeamPoints(buf: Buffer): UpdateTeamPointsRequest {
|
||||
export function updateTeamPoints1(buf: Buffer): UpdateTeamPointsRequest {
|
||||
return {
|
||||
type: "update_team_points_req",
|
||||
field_0004: buf.readUInt32LE(0x0004),
|
||||
field_0008: buf.readUInt32LE(0x0008),
|
||||
};
|
||||
}
|
||||
|
||||
updateTeamPoints2.msgCode = 0x007b;
|
||||
updateTeamPoints2.msgLen = 0x0010;
|
||||
|
||||
export function updateTeamPoints2(buf: Buffer): UpdateTeamPointsRequest {
|
||||
return {
|
||||
type: "update_team_points_req",
|
||||
field_0004: buf.readUInt32LE(0x0004),
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
import { UpdateUiReportRequest } from "../request/updateUiReport";
|
||||
|
||||
updateUiReport.msgCode = 0x0084;
|
||||
updateUiReport.msgLen = 0x0410;
|
||||
updateUiReport1.msgCode = 0x0084;
|
||||
updateUiReport1.msgLen = 0x0410;
|
||||
|
||||
export function updateUiReport(buf: Buffer): UpdateUiReportRequest {
|
||||
export function updateUiReport1(buf: Buffer): UpdateUiReportRequest {
|
||||
return {
|
||||
type: "update_ui_report_req",
|
||||
field_02: buf.readUInt16LE(0x0002),
|
||||
field_04: buf.readUInt16LE(0x0004),
|
||||
};
|
||||
}
|
||||
|
||||
updateUiReport2.msgCode = 0x007e;
|
||||
updateUiReport2.msgLen = 0x0410;
|
||||
|
||||
export function updateUiReport2(buf: Buffer): UpdateUiReportRequest {
|
||||
return {
|
||||
type: "update_ui_report_req",
|
||||
field_02: buf.readUInt16LE(0x0002),
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import { UpdateUserLogRequest } from "../request/updateUserLog";
|
||||
|
||||
updateUserLog.msgCode = 0x00bd;
|
||||
updateUserLog.msgLen = 0x0050;
|
||||
updateUserLog1.msgCode = 0x00bd;
|
||||
updateUserLog1.msgLen = 0x0050;
|
||||
|
||||
export function updateUserLog(buf: Buffer): UpdateUserLogRequest {
|
||||
export function updateUserLog1(buf: Buffer): UpdateUserLogRequest {
|
||||
return { type: "update_user_log_req" };
|
||||
}
|
||||
|
||||
updateUserLog2.msgCode = 0x00ab;
|
||||
updateUserLog2.msgLen = 0x0050;
|
||||
|
||||
export function updateUserLog2(buf: Buffer): UpdateUserLogRequest {
|
||||
return { type: "update_user_log_req" };
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Chara } from "../model/chara";
|
||||
|
||||
export function encodeChara(chara: Chara): Buffer {
|
||||
export function encodeChara1(chara: Chara): Buffer {
|
||||
const buf = Buffer.alloc(0x0014);
|
||||
|
||||
buf.writeUInt8(chara.gender === "male" ? 0 : 1, 0x00);
|
||||
@@ -16,3 +16,20 @@ export function encodeChara(chara: Chara): Buffer {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function encodeChara2(chara: Chara): Buffer {
|
||||
const buf = Buffer.alloc(0x0016);
|
||||
|
||||
buf.writeUInt8(chara.gender === "male" ? 0 : 1, 0x00);
|
||||
buf.writeUInt16LE(chara.field_02, 0x02);
|
||||
buf.writeUInt16LE(chara.field_04, 0x04);
|
||||
buf.writeUInt16LE(chara.field_06, 0x06);
|
||||
buf.writeUInt16LE(chara.field_08, 0x08);
|
||||
buf.writeUInt16LE(chara.field_0a, 0x0a);
|
||||
buf.writeUInt16LE(chara.field_0c, 0x0c);
|
||||
buf.writeUInt16LE(chara.field_0e, 0x0e);
|
||||
buf.writeUInt16LE(chara.background, 0x10);
|
||||
buf.writeUInt16LE(chara.title, 0x14);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
import iconv from "iconv-lite";
|
||||
|
||||
import { writeSjisStr } from "../../util/bin";
|
||||
import { CreateAutoTeamResponse } from "../response/createAutoTeam";
|
||||
import { LoadTeamResponse } from "../response/loadTeam";
|
||||
import { encodeChara } from "./_chara";
|
||||
import { encodeChara1 } from "./_chara";
|
||||
|
||||
export function _team(res: CreateAutoTeamResponse | LoadTeamResponse) {
|
||||
function _team1(
|
||||
msgCode: number,
|
||||
res: CreateAutoTeamResponse | LoadTeamResponse
|
||||
) {
|
||||
const buf = Buffer.alloc(0x0ca0);
|
||||
|
||||
if (res.type === "create_auto_team_res") {
|
||||
buf.writeInt16LE(0x007c, 0x0000);
|
||||
} else {
|
||||
buf.writeInt16LE(0x0078, 0x0000);
|
||||
}
|
||||
|
||||
const leader = res.members.find(item => item.leader === true);
|
||||
|
||||
buf.writeInt16LE(msgCode, 0x0000);
|
||||
buf.writeUInt32LE(res.team.extId, 0x000c);
|
||||
iconv.encode(leader ? leader.profile.name : "Error\0", "shift_jis").copy(buf, 0x0010);
|
||||
iconv.encode(res.team.name, "shift_jis").copy(buf, 0x0024);
|
||||
iconv.encode(process.env.SHOP_NAME ? process.env.SHOP_NAME : "\0", "shift_jis").copy(buf, 0x0044);
|
||||
writeSjisStr(buf, 0x0010, 0x0024, leader ? leader.profile.name : "Error");
|
||||
writeSjisStr(buf, 0x0024, 0x0044, res.team.name);
|
||||
writeSjisStr(buf, 0x0044, 0x00d8, process.env.SHOP_NAME || "");
|
||||
buf.writeUInt32LE(res.team.nameBg, 0x00d8);
|
||||
buf.writeUInt32LE(res.team.nameFx, 0x00dc);
|
||||
buf.fill(0xff, 0x00e0, 0x00f9); // Bitset: Unlocked BGs probably
|
||||
@@ -25,7 +22,7 @@ export function _team(res: CreateAutoTeamResponse | LoadTeamResponse) {
|
||||
buf.writeUInt32LE(leader ? leader.profile.aimeId : 0, 0x0080);
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
const base = 0x011c + i * 0x005c;
|
||||
const base = 0x011c + i * 0x005c; // Differs between v1 and v2
|
||||
const member = res.members[i];
|
||||
|
||||
if (member === undefined) {
|
||||
@@ -36,11 +33,11 @@ export function _team(res: CreateAutoTeamResponse | LoadTeamResponse) {
|
||||
const accessTime = (profile.accessTime.getTime() / 1000) | 0;
|
||||
|
||||
buf.writeInt32LE(profile.aimeId, base + 0x0000);
|
||||
iconv.encode(profile.name + "\0", "shift_jis").copy(buf, base + 0x0004);
|
||||
writeSjisStr(buf, base + 0x0004, base + 0x0018, profile.name);
|
||||
buf.writeInt32LE(profile.lv, base + 0x0018);
|
||||
buf.writeInt32LE(0, base + 0x0024); // Month points, TODO
|
||||
buf.writeUInt32LE(accessTime, base + 0x0034);
|
||||
encodeChara(chara).copy(buf, base + 0x0044);
|
||||
encodeChara1(chara).copy(buf, base + 0x0044);
|
||||
}
|
||||
|
||||
// Team Time Attack:
|
||||
@@ -57,3 +54,71 @@ export function _team(res: CreateAutoTeamResponse | LoadTeamResponse) {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
function _team2(
|
||||
msgCode: number,
|
||||
res: CreateAutoTeamResponse | LoadTeamResponse
|
||||
) {
|
||||
const buf = Buffer.alloc(0x0ca0);
|
||||
const leader = res.members.find(item => item.leader === true);
|
||||
|
||||
buf.writeInt16LE(msgCode, 0x0000);
|
||||
buf.writeUInt32LE(res.team.extId, 0x000c);
|
||||
writeSjisStr(buf, 0x0010, 0x0024, leader ? leader.profile.name : "Error");
|
||||
writeSjisStr(buf, 0x0024, 0x0044, res.team.name);
|
||||
writeSjisStr(buf, 0x0044, 0x00d8, process.env.SHOP_NAME || "");
|
||||
buf.writeUInt32LE(res.team.nameBg, 0x00d8);
|
||||
buf.writeUInt32LE(res.team.nameFx, 0x00dc);
|
||||
buf.fill(0xff, 0x00e0, 0x00f9); // Bitset: Unlocked BGs probably
|
||||
buf.fill(0xff, 0x00f9, 0x0101); // Bitset: Unlocked FX probably
|
||||
buf.writeUInt32LE(leader ? leader.profile.aimeId : 0, 0x0080);
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
const base = 0x0120 + i * 0x005c; // Differs between v1 and v2
|
||||
const member = res.members[i];
|
||||
|
||||
if (member === undefined) {
|
||||
break;
|
||||
}
|
||||
|
||||
const { profile, chara } = member;
|
||||
const accessTime = (profile.accessTime.getTime() / 1000) | 0;
|
||||
|
||||
buf.writeInt32LE(profile.aimeId, base + 0x0000);
|
||||
writeSjisStr(buf, base + 0x0004, base + 0x0018, profile.name);
|
||||
buf.writeInt32LE(profile.lv, base + 0x0018);
|
||||
buf.writeInt32LE(0, base + 0x0024); // Month points, TODO
|
||||
buf.writeUInt32LE(accessTime, base + 0x0034);
|
||||
encodeChara1(chara).copy(buf, base + 0x0044);
|
||||
}
|
||||
|
||||
// Team Time Attack:
|
||||
|
||||
/*for (let i = 0; i < 6; i++) {
|
||||
const base = 0x0344 + 0x20 * i;
|
||||
|
||||
buf.writeInt16LE(0x00001, base + 0x0000);
|
||||
buf.writeInt8(0x02, base + 0x0003);
|
||||
buf.writeInt32LE(0x00000003, base + 0x0004);
|
||||
iconv.encode("str\0", "shift_jis").copy(buf, base + 0x0008);
|
||||
buf.writeInt32LE(0x00000004, base + 0x001c);
|
||||
}*/
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function createAutoTeam1(res: CreateAutoTeamResponse): Buffer {
|
||||
return _team1(0x007c, res);
|
||||
}
|
||||
|
||||
export function loadTeam1(res: LoadTeamResponse): Buffer {
|
||||
return _team1(0x0078, res);
|
||||
}
|
||||
|
||||
export function createAutoTeam2(res: CreateAutoTeamResponse): Buffer {
|
||||
return _team2(0x0078, res);
|
||||
}
|
||||
|
||||
export function loadTeam2(res: LoadTeamResponse): Buffer {
|
||||
return _team2(0x0074, res);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CheckTeamNameResponse } from "../response/checkTeamName";
|
||||
|
||||
export function checkTeamName(res: CheckTeamNameResponse): Buffer {
|
||||
export function checkTeamName1(res: CheckTeamNameResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x00a3, 0x0000);
|
||||
@@ -8,3 +8,12 @@ export function checkTeamName(res: CheckTeamNameResponse): Buffer {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function checkTeamName2(res: CheckTeamNameResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x0098, 0x0000);
|
||||
buf.writeUInt32LE(res.status, 0x0004);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { CreateProfileResponse } from "../response/createProfile";
|
||||
|
||||
export function createProfile1(res: CreateProfileResponse) {
|
||||
const buf = Buffer.alloc(0x0020);
|
||||
|
||||
// Shares message type code with the "generic" response
|
||||
buf.writeInt16LE(0x0001, 0x0000);
|
||||
buf.writeInt32LE(res.aimeId, 0x0004);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function createProfile2(res: CreateProfileResponse) {
|
||||
const buf = Buffer.alloc(0x0030);
|
||||
|
||||
buf.writeInt16LE(0x0001, 0x0000);
|
||||
buf.writeInt32LE(res.aimeId, 0x0008);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CreateTeamResponse } from "../response/createTeam";
|
||||
|
||||
export function createTeam(res: CreateTeamResponse): Buffer {
|
||||
export function createTeam1(res: CreateTeamResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x0072, 0x0000);
|
||||
@@ -9,3 +9,13 @@ export function createTeam(res: CreateTeamResponse): Buffer {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function createTeam2(res: CreateTeamResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x006e, 0x0000);
|
||||
buf.writeUInt32LE(res.status, 0x0004);
|
||||
buf.writeUInt32LE(res.teamExtId, 0x0008);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DiscoverProfileResponse } from "../response/discoverProfile";
|
||||
|
||||
export function discoverProfile(res: DiscoverProfileResponse) {
|
||||
export function discoverProfile1(res: DiscoverProfileResponse) {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeInt16LE(0x006c, 0x0000);
|
||||
@@ -8,3 +8,12 @@ export function discoverProfile(res: DiscoverProfileResponse) {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function discoverProfile2(res: DiscoverProfileResponse) {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeInt16LE(0x0068, 0x0000);
|
||||
buf.writeInt8(res.exists ? 1 : 0, 0x0004);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { GenericResponse } from "../response/generic";
|
||||
|
||||
export function generic(res: GenericResponse) {
|
||||
export function generic1(res: GenericResponse) {
|
||||
const buf = Buffer.alloc(0x0020);
|
||||
|
||||
buf.writeInt16LE(0x0001, 0x0000);
|
||||
@@ -8,3 +8,15 @@ export function generic(res: GenericResponse) {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function generic2(res: GenericResponse) {
|
||||
const buf = Buffer.alloc(0x0030);
|
||||
|
||||
buf.writeInt16LE(0x0001, 0x0000);
|
||||
buf.writeInt32LE(res.status || 0, 0x0004);
|
||||
|
||||
// write the AIME ID for createProfile in 2.12, kinda awkward but whatever.
|
||||
buf.writeInt32LE(res.status || 0, 0x0008);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
+339
-67
@@ -1,138 +1,169 @@
|
||||
import logger from "debug";
|
||||
import { Transform } from "stream";
|
||||
|
||||
import { _team } from "./_team";
|
||||
import { checkTeamName } from "./checkTeamName";
|
||||
import { createTeam } from "./createTeam";
|
||||
import { discoverProfile } from "./discoverProfile";
|
||||
import { generic } from "./generic";
|
||||
import { lockProfile } from "./lockProfile";
|
||||
import { lockProfileExtend } from "./lockProfileExtend";
|
||||
import { load2on2 } from "./load2on2";
|
||||
import { loadConfig } from "./loadConfig";
|
||||
import { loadConfig2 } from "./loadConfig2";
|
||||
import { loadEventInfo } from "./loadEventInfo";
|
||||
import { loadGacha } from "./loadGacha";
|
||||
import { loadGarage } from "./loadGarage";
|
||||
import {
|
||||
createAutoTeam1,
|
||||
createAutoTeam2,
|
||||
loadTeam1,
|
||||
loadTeam2,
|
||||
} from "./_team";
|
||||
import { checkTeamName1, checkTeamName2 } from "./checkTeamName";
|
||||
import { createProfile1, createProfile2 } from "./createProfile";
|
||||
import { createTeam1, createTeam2 } from "./createTeam";
|
||||
import { discoverProfile1, discoverProfile2 } from "./discoverProfile";
|
||||
import { generic1, generic2 } from "./generic";
|
||||
import { lockProfile1, lockProfile2 } from "./lockProfile";
|
||||
import { lockProfileExtend1, lockProfileExtend2 } from "./lockProfileExtend";
|
||||
import {
|
||||
load2on2RankingPoints1,
|
||||
load2on2Info1,
|
||||
load2on2RankingPoints2,
|
||||
load2on2Info2,
|
||||
} from "./load2on2";
|
||||
import {
|
||||
loadConfigA_1,
|
||||
loadConfigB_1,
|
||||
loadConfigA_2,
|
||||
loadConfigB_2,
|
||||
} from "./loadConfig";
|
||||
import { loadEventInfo1, loadEventInfo2 } from "./loadEventInfo";
|
||||
import { loadGacha1, loadGacha2 } from "./loadGacha";
|
||||
import { loadGarage1, loadGarage2 } from "./loadGarage";
|
||||
import { loadGeneralReward } from "./loadGeneralReward";
|
||||
import { loadGhost } from "./loadGhost";
|
||||
import { loadProfile } from "./loadProfile";
|
||||
import { loadRewardTable } from "./loadRewardTable";
|
||||
import { loadServerList } from "./loadServerList";
|
||||
import { loadStocker } from "./loadStocker";
|
||||
import { loadTeamRanking } from "./loadTeamRanking";
|
||||
import { loadTopTen } from "./loadTopTen";
|
||||
import { saveExpedition } from "./saveExpedition";
|
||||
import { saveGarage } from "./saveGarage";
|
||||
import { saveNewCar } from "./saveNewCar";
|
||||
import { saveTimeAttack } from "./saveTimeAttack";
|
||||
import { saveTopic } from "./saveTopic";
|
||||
import { unlockProfile } from "./unlockProfile";
|
||||
import { updateProvisionalStoreRank } from "./updateProvisionalStoreRank";
|
||||
import { updateStoryClearNum } from "./updateStoryClearNum";
|
||||
import { updateTeamLeader } from "./updateTeamLeader";
|
||||
import { updateTeamMember } from "./updateTeamMember";
|
||||
import { loadGhost1, loadGhost2 } from "./loadGhost";
|
||||
import { loadProfile2 } from "./loadProfile2";
|
||||
import { loadProfile3 } from "./loadProfile3";
|
||||
import { loadProfile4 } from "./loadProfile4";
|
||||
import { loadRewardTable1, loadRewardTable2 } from "./loadRewardTable";
|
||||
import { loadServerList1, loadServerList2 } from "./loadServerList";
|
||||
import { loadStocker1, loadStocker2 } from "./loadStocker";
|
||||
import { loadTeamRanking1, loadTeamRanking2 } from "./loadTeamRanking";
|
||||
import { loadTopTen } from "./loadTopTen1";
|
||||
import { loadTopTen2 } from "./loadTopTen2";
|
||||
import { saveExpedition1, saveExpedition2 } from "./saveExpedition";
|
||||
import { saveGarage1, saveGarage2 } from "./saveGarage";
|
||||
import { saveNewCar1, saveNewCar2 } from "./saveNewCar";
|
||||
import { saveTimeAttack1, saveTimeAttack2 } from "./saveTimeAttack";
|
||||
import { saveTopic1, saveTopic2 } from "./saveTopic";
|
||||
import { unlockProfile1, unlockProfile2 } from "./unlockProfile";
|
||||
import {
|
||||
updateProvisionalStoreRank1,
|
||||
updateProvisionalStoreRank2,
|
||||
} from "./updateProvisionalStoreRank";
|
||||
import {
|
||||
updateStoryClearNum1,
|
||||
updateStoryClearNum2,
|
||||
updateStoryClearNum3,
|
||||
} from "./updateStoryClearNum";
|
||||
import { updateTeamLeader1, updateTeamLeader2 } from "./updateTeamLeader";
|
||||
import { updateTeamMember1, updateTeamMember2 } from "./updateTeamMember";
|
||||
import { Response } from "../response";
|
||||
import { ClientHello } from "../../common";
|
||||
|
||||
const debug = logger("app:idz:userdb:encoder");
|
||||
|
||||
function encode(res: Response): Buffer {
|
||||
function encode110(res: Response): Buffer {
|
||||
switch (res.type) {
|
||||
case "check_team_name_res":
|
||||
return checkTeamName(res);
|
||||
return checkTeamName1(res);
|
||||
|
||||
case "create_auto_team_res":
|
||||
return _team(res);
|
||||
return createAutoTeam1(res);
|
||||
|
||||
case "create_profile_res":
|
||||
return createProfile1(res);
|
||||
|
||||
case "create_team_res":
|
||||
return createTeam(res);
|
||||
return createTeam1(res);
|
||||
|
||||
case "discover_profile_res":
|
||||
return discoverProfile(res);
|
||||
return discoverProfile1(res);
|
||||
|
||||
case "generic_res":
|
||||
return generic(res);
|
||||
return generic1(res);
|
||||
|
||||
case "load_2on2_res":
|
||||
return load2on2(res);
|
||||
case "load_2on2_ranking_points_res":
|
||||
return load2on2RankingPoints1(res);
|
||||
|
||||
case "load_config_res":
|
||||
return loadConfig(res);
|
||||
case "load_2on2_info_res":
|
||||
return load2on2Info1(res);
|
||||
|
||||
case "load_config_v2_res":
|
||||
return loadConfig2(res);
|
||||
case "load_config_A_res":
|
||||
return loadConfigA_1(res);
|
||||
|
||||
case "load_config_B_res":
|
||||
return loadConfigB_1(res);
|
||||
|
||||
case "load_event_info_res":
|
||||
return loadEventInfo(res);
|
||||
return loadEventInfo1(res);
|
||||
|
||||
case "load_gacha_res":
|
||||
return loadGacha(res);
|
||||
return loadGacha1(res);
|
||||
|
||||
case "load_garage_res":
|
||||
return loadGarage(res);
|
||||
return loadGarage1(res);
|
||||
|
||||
case "load_general_reward_res":
|
||||
return loadGeneralReward(res);
|
||||
|
||||
case "load_ghost_res":
|
||||
return loadGhost(res);
|
||||
return loadGhost1(res);
|
||||
|
||||
case "load_profile_res":
|
||||
return loadProfile(res);
|
||||
return loadProfile2(res);
|
||||
|
||||
case "load_reward_table_res":
|
||||
return loadRewardTable(res);
|
||||
return loadRewardTable1(res);
|
||||
|
||||
case "load_server_list_res":
|
||||
return loadServerList(res);
|
||||
return loadServerList1(res);
|
||||
|
||||
case "load_stocker_res":
|
||||
return loadStocker(res);
|
||||
return loadStocker1(res);
|
||||
|
||||
case "load_team_res":
|
||||
return _team(res);
|
||||
return loadTeam1(res);
|
||||
|
||||
case "load_team_ranking_res":
|
||||
return loadTeamRanking(res);
|
||||
return loadTeamRanking1(res);
|
||||
|
||||
case "load_top_ten_res":
|
||||
return loadTopTen(res);
|
||||
|
||||
case "lock_profile_extend_res":
|
||||
return lockProfileExtend(res);
|
||||
return lockProfileExtend1(res);
|
||||
|
||||
case "lock_profile_res":
|
||||
return lockProfile(res);
|
||||
return lockProfile1(res);
|
||||
|
||||
case "save_expedition_res":
|
||||
return saveExpedition(res);
|
||||
return saveExpedition1(res);
|
||||
|
||||
case "save_garage_res":
|
||||
return saveGarage(res);
|
||||
return saveGarage1(res);
|
||||
|
||||
case "save_new_car_res":
|
||||
return saveNewCar(res);
|
||||
return saveNewCar1(res);
|
||||
|
||||
case "save_time_attack_res":
|
||||
return saveTimeAttack(res);
|
||||
return saveTimeAttack1(res);
|
||||
|
||||
case "unlock_profile_res":
|
||||
return unlockProfile(res);
|
||||
return unlockProfile1(res);
|
||||
|
||||
case "update_provisional_store_rank_res":
|
||||
return updateProvisionalStoreRank(res);
|
||||
return updateProvisionalStoreRank1(res);
|
||||
|
||||
case "update_story_clear_num_res":
|
||||
return updateStoryClearNum(res);
|
||||
return updateStoryClearNum1(res);
|
||||
|
||||
case "update_team_leader_res":
|
||||
return updateTeamLeader(res);
|
||||
return updateTeamLeader1(res);
|
||||
|
||||
case "update_team_member_res":
|
||||
return updateTeamMember(res);
|
||||
return updateTeamMember1(res);
|
||||
|
||||
case "save_topic_res":
|
||||
return saveTopic(res);
|
||||
return saveTopic1(res);
|
||||
|
||||
default:
|
||||
const exhaustCheck: never = res;
|
||||
@@ -141,10 +172,251 @@ function encode(res: Response): Buffer {
|
||||
}
|
||||
}
|
||||
|
||||
export default function writeResponse(res: Response) {
|
||||
function encode130(res: Response): Buffer {
|
||||
switch (res.type) {
|
||||
case "check_team_name_res":
|
||||
return checkTeamName1(res);
|
||||
|
||||
case "create_auto_team_res":
|
||||
return createAutoTeam1(res);
|
||||
|
||||
case "create_profile_res":
|
||||
return createProfile1(res);
|
||||
|
||||
case "create_team_res":
|
||||
return createTeam1(res);
|
||||
|
||||
case "discover_profile_res":
|
||||
return discoverProfile1(res);
|
||||
|
||||
case "generic_res":
|
||||
return generic1(res);
|
||||
|
||||
case "load_2on2_ranking_points_res":
|
||||
return load2on2RankingPoints1(res);
|
||||
|
||||
case "load_2on2_info_res":
|
||||
return load2on2Info1(res);
|
||||
|
||||
case "load_config_A_res":
|
||||
return loadConfigA_1(res);
|
||||
|
||||
case "load_config_B_res":
|
||||
return loadConfigB_1(res);
|
||||
|
||||
case "load_event_info_res":
|
||||
return loadEventInfo1(res);
|
||||
|
||||
case "load_gacha_res":
|
||||
return loadGacha1(res);
|
||||
|
||||
case "load_garage_res":
|
||||
return loadGarage1(res);
|
||||
|
||||
case "load_general_reward_res":
|
||||
return loadGeneralReward(res);
|
||||
|
||||
case "load_ghost_res":
|
||||
return loadGhost1(res);
|
||||
|
||||
case "load_profile_res":
|
||||
return loadProfile3(res);
|
||||
|
||||
case "load_reward_table_res":
|
||||
return loadRewardTable1(res);
|
||||
|
||||
case "load_server_list_res":
|
||||
return loadServerList1(res);
|
||||
|
||||
case "load_stocker_res":
|
||||
return loadStocker1(res);
|
||||
|
||||
case "load_team_res":
|
||||
return loadTeam1(res);
|
||||
|
||||
case "load_team_ranking_res":
|
||||
return loadTeamRanking1(res);
|
||||
|
||||
case "load_top_ten_res":
|
||||
return loadTopTen(res);
|
||||
|
||||
case "lock_profile_extend_res":
|
||||
return lockProfileExtend1(res);
|
||||
|
||||
case "lock_profile_res":
|
||||
return lockProfile1(res);
|
||||
|
||||
case "save_expedition_res":
|
||||
return saveExpedition1(res);
|
||||
|
||||
case "save_garage_res":
|
||||
return saveGarage1(res);
|
||||
|
||||
case "save_new_car_res":
|
||||
return saveNewCar1(res);
|
||||
|
||||
case "save_time_attack_res":
|
||||
return saveTimeAttack1(res);
|
||||
|
||||
case "unlock_profile_res":
|
||||
return unlockProfile1(res);
|
||||
|
||||
case "update_provisional_store_rank_res":
|
||||
return updateProvisionalStoreRank1(res);
|
||||
|
||||
case "update_story_clear_num_res":
|
||||
return updateStoryClearNum2(res);
|
||||
|
||||
case "update_team_leader_res":
|
||||
return updateTeamLeader1(res);
|
||||
|
||||
case "update_team_member_res":
|
||||
return updateTeamMember1(res);
|
||||
|
||||
case "save_topic_res":
|
||||
return saveTopic1(res);
|
||||
|
||||
default:
|
||||
const exhaustCheck: never = res;
|
||||
|
||||
throw new Error(`No writer fn for ${res["type"]}`);
|
||||
}
|
||||
}
|
||||
|
||||
function encode210(res: Response): Buffer {
|
||||
switch (res.type) {
|
||||
case "check_team_name_res":
|
||||
return checkTeamName2(res);
|
||||
|
||||
case "create_auto_team_res":
|
||||
return createAutoTeam2(res);
|
||||
|
||||
case "create_profile_res":
|
||||
return createProfile2(res);
|
||||
|
||||
case "create_team_res":
|
||||
return createTeam2(res);
|
||||
|
||||
case "discover_profile_res":
|
||||
return discoverProfile2(res);
|
||||
|
||||
case "generic_res":
|
||||
return generic2(res);
|
||||
|
||||
case "load_2on2_ranking_points_res":
|
||||
return load2on2RankingPoints2(res);
|
||||
|
||||
case "load_2on2_info_res":
|
||||
return load2on2Info2(res);
|
||||
|
||||
case "load_config_A_res":
|
||||
return loadConfigA_2(res);
|
||||
|
||||
case "load_config_B_res":
|
||||
return loadConfigB_2(res);
|
||||
|
||||
case "load_event_info_res":
|
||||
return loadEventInfo2(res);
|
||||
|
||||
case "load_gacha_res":
|
||||
return loadGacha2(res);
|
||||
|
||||
case "load_garage_res":
|
||||
return loadGarage2(res);
|
||||
|
||||
case "load_general_reward_res":
|
||||
return loadGeneralReward(res);
|
||||
|
||||
case "load_ghost_res":
|
||||
return loadGhost2(res);
|
||||
|
||||
case "load_profile_res":
|
||||
return loadProfile4(res);
|
||||
|
||||
case "load_reward_table_res":
|
||||
return loadRewardTable2(res);
|
||||
|
||||
case "load_server_list_res":
|
||||
return loadServerList2(res);
|
||||
|
||||
case "load_stocker_res":
|
||||
return loadStocker2(res);
|
||||
|
||||
case "load_team_res":
|
||||
return loadTeam2(res);
|
||||
|
||||
case "load_team_ranking_res":
|
||||
return loadTeamRanking2(res);
|
||||
|
||||
case "load_top_ten_res":
|
||||
return loadTopTen2(res);
|
||||
|
||||
case "lock_profile_extend_res":
|
||||
return lockProfileExtend2(res);
|
||||
|
||||
case "lock_profile_res":
|
||||
return lockProfile2(res);
|
||||
|
||||
case "save_expedition_res":
|
||||
return saveExpedition2(res);
|
||||
|
||||
case "save_garage_res":
|
||||
return saveGarage2(res);
|
||||
|
||||
case "save_new_car_res":
|
||||
return saveNewCar2(res);
|
||||
|
||||
case "save_time_attack_res":
|
||||
return saveTimeAttack2(res);
|
||||
|
||||
case "unlock_profile_res":
|
||||
return unlockProfile2(res);
|
||||
|
||||
case "update_provisional_store_rank_res":
|
||||
return updateProvisionalStoreRank2(res);
|
||||
|
||||
case "update_story_clear_num_res":
|
||||
return updateStoryClearNum3(res);
|
||||
|
||||
case "update_team_leader_res":
|
||||
return updateTeamLeader2(res);
|
||||
|
||||
case "update_team_member_res":
|
||||
return updateTeamMember2(res);
|
||||
|
||||
case "save_topic_res":
|
||||
return saveTopic2(res);
|
||||
|
||||
default:
|
||||
const exhaustCheck: never = res;
|
||||
|
||||
throw new Error(`No writer fn for ${res["type"]}`);
|
||||
}
|
||||
}
|
||||
|
||||
function encode(res: Response, clientHello: ClientHello) {
|
||||
switch (clientHello.protocol) {
|
||||
case "110":
|
||||
return encode110(res);
|
||||
|
||||
case "130":
|
||||
return encode130(res);
|
||||
|
||||
case "210":
|
||||
return encode210(res);
|
||||
|
||||
default:
|
||||
throw new Error(`Unsupported protocol version ${clientHello.protocol}`);
|
||||
}
|
||||
}
|
||||
|
||||
export default function writeResponse(
|
||||
res: Response,
|
||||
clientHello: ClientHello
|
||||
) {
|
||||
debug("Object: %j", res);
|
||||
|
||||
const buf = encode(res);
|
||||
const buf = encode(res, clientHello);
|
||||
|
||||
if (debug.enabled) {
|
||||
debug("Encoded: %s", buf.toString("hex"));
|
||||
|
||||
@@ -1,25 +1,11 @@
|
||||
import {
|
||||
Load2on2Response,
|
||||
Load2on2Response1,
|
||||
Load2on2Response2,
|
||||
Load2on2InfoResponse,
|
||||
Load2on2RankingPointsResponse,
|
||||
} from "../response/load2on2";
|
||||
|
||||
export function load2on2(res: Load2on2Response): Buffer {
|
||||
switch (res.format) {
|
||||
case 1:
|
||||
return load2on2_v1(res);
|
||||
|
||||
case 2:
|
||||
return load2on2_v2(res);
|
||||
|
||||
default:
|
||||
const exhaust: never = res;
|
||||
|
||||
throw new Error(`Unsupported 2on2 response format ${res["format"]}`);
|
||||
}
|
||||
}
|
||||
|
||||
function load2on2_v1(res: Load2on2Response1): Buffer {
|
||||
export function load2on2RankingPoints1(
|
||||
res: Load2on2RankingPointsResponse
|
||||
): Buffer {
|
||||
const buf = Buffer.alloc(0x04c0);
|
||||
|
||||
buf.writeInt16LE(0x00b1, 0x0000);
|
||||
@@ -27,11 +13,28 @@ function load2on2_v1(res: Load2on2Response1): Buffer {
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Same size but presumably incompatible somehow
|
||||
function load2on2_v2(res: Load2on2Response2): Buffer {
|
||||
export function load2on2Info1(res: Load2on2InfoResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x04c0);
|
||||
|
||||
buf.writeInt16LE(0x0133, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function load2on2RankingPoints2(
|
||||
res: Load2on2RankingPointsResponse
|
||||
): Buffer {
|
||||
const buf = Buffer.alloc(0x1290);
|
||||
|
||||
buf.writeInt16LE(0x00a4, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function load2on2Info2(res: Load2on2InfoResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0540);
|
||||
|
||||
buf.writeInt16LE(0x0133, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { LoadConfigResponse } from "../response/loadConfig";
|
||||
import {
|
||||
LoadConfigResponseA,
|
||||
LoadConfigResponseB,
|
||||
} from "../response/loadConfig";
|
||||
|
||||
export function loadConfig(res: LoadConfigResponse) {
|
||||
export function loadConfigA_1(res: LoadConfigResponseA) {
|
||||
const buf = Buffer.alloc(0x01a0);
|
||||
|
||||
buf.writeInt16LE(0x0005, 0x0000);
|
||||
@@ -9,3 +12,31 @@ export function loadConfig(res: LoadConfigResponse) {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function loadConfigB_1(res: LoadConfigResponseB) {
|
||||
const buf = Buffer.alloc(0x0230);
|
||||
|
||||
buf.writeInt16LE(0x00ac, 0x0000);
|
||||
buf.writeInt8(res.status, 0x0002);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function loadConfigA_2(res: LoadConfigResponseA) {
|
||||
const buf = Buffer.alloc(0x05e0);
|
||||
|
||||
buf.writeInt16LE(0x0005, 0x0000);
|
||||
buf.writeInt8(res.status, 0x0002);
|
||||
buf.writeUInt16LE(res.serverVersion, 0x0016);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function loadConfigB_2(res: LoadConfigResponseB) {
|
||||
const buf = Buffer.alloc(0x0240);
|
||||
|
||||
buf.writeInt16LE(0x00a1, 0x0000);
|
||||
buf.writeInt8(res.status, 0x0002);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { LoadConfigResponse2 } from "../response/loadConfig2";
|
||||
|
||||
export function loadConfig2(res: LoadConfigResponse2) {
|
||||
const buf = Buffer.alloc(0x0230);
|
||||
|
||||
buf.writeInt16LE(0x00ac, 0x0000);
|
||||
buf.writeInt8(res.status, 0x0002);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -1,9 +1,17 @@
|
||||
import { LoadEventInfoResponse } from "../response/loadEventInfo";
|
||||
|
||||
export function loadEventInfo(res: LoadEventInfoResponse): Buffer {
|
||||
export function loadEventInfo1(res: LoadEventInfoResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x01b0);
|
||||
|
||||
buf.writeUInt16LE(0x00bf, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function loadEventInfo2(res: LoadEventInfoResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x01b0);
|
||||
|
||||
buf.writeUInt16LE(0x00ad, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LoadGachaResponse } from "../response/loadGacha";
|
||||
|
||||
export function loadGacha(res: LoadGachaResponse): Buffer {
|
||||
export function loadGacha1(res: LoadGachaResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0090);
|
||||
|
||||
buf.writeUInt16LE(0x00c2, 0x0000);
|
||||
@@ -8,3 +8,12 @@ export function loadGacha(res: LoadGachaResponse): Buffer {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function loadGacha2(res: LoadGachaResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0090);
|
||||
|
||||
buf.writeUInt16LE(0x00b0, 0x0000);
|
||||
buf.writeUInt8(res.awardedToday ? 0x01 : 0x00, 0x0004);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { encodeCar } from "./_car";
|
||||
import { LoadGarageResponse } from "../response/loadGarage";
|
||||
|
||||
export function loadGarage(res: LoadGarageResponse): Buffer {
|
||||
export function loadGarage1(res: LoadGarageResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x03d0);
|
||||
|
||||
buf.writeUInt16LE(0x0091, 0x0000);
|
||||
@@ -13,3 +13,16 @@ export function loadGarage(res: LoadGarageResponse): Buffer {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function loadGarage2(res: LoadGarageResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0420);
|
||||
|
||||
buf.writeUInt16LE(0x0088, 0x0000);
|
||||
buf.writeUInt16LE(res.cars.length, 0x0004);
|
||||
|
||||
for (let i = 0; i < res.cars.length; i++) {
|
||||
encodeCar(res.cars[i]).copy(buf, 0x0008 + 0x0068 * i);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import iconv from "iconv-lite";
|
||||
|
||||
import { LoadGeneralRewardResponse } from "../response/loadGeneralReward";
|
||||
import { writeSjisStr } from "../../util/bin";
|
||||
|
||||
export function loadGeneralReward(res: LoadGeneralRewardResponse) {
|
||||
const buf = Buffer.alloc(0x0330);
|
||||
@@ -15,7 +14,7 @@ export function loadGeneralReward(res: LoadGeneralRewardResponse) {
|
||||
const item = res.items[i];
|
||||
const base = 0x04 + 0x50 * i;
|
||||
|
||||
iconv.encode(item.field_04, "shift_jis").copy(buf, base + 0x04);
|
||||
writeSjisStr(buf, base + 0x04, base + 0x2c, item.field_04);
|
||||
buf.writeUInt32LE(item.field_2C, base + 0x2c);
|
||||
buf.writeUInt8(item.field_38, base + 0x38);
|
||||
buf.writeUInt8(item.field_39, base + 0x39);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { LoadGhostResponse } from "../response/loadGhost";
|
||||
|
||||
export function loadGhost(res: LoadGhostResponse): Buffer {
|
||||
function _loadGhost(msgCode: number, res: LoadGhostResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0070);
|
||||
|
||||
// No idea what any of this even does.
|
||||
|
||||
buf.writeUInt16LE(0x00a1, 0x0000);
|
||||
buf.writeUInt16LE(msgCode, 0x0000);
|
||||
buf.writeUInt16LE(0x0005, 0x0002); // Chunk presence flags: 4 | 1
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
@@ -29,3 +29,11 @@ export function loadGhost(res: LoadGhostResponse): Buffer {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function loadGhost1(res: LoadGhostResponse): Buffer {
|
||||
return _loadGhost(0x00a1, res);
|
||||
}
|
||||
|
||||
export function loadGhost2(res: LoadGhostResponse): Buffer {
|
||||
return _loadGhost(0x0096, res);
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import { loadProfile1 } from "./loadProfile1";
|
||||
import { loadProfile2 } from "./loadProfile2";
|
||||
import { loadProfile3 } from "./loadProfile3";
|
||||
import { LoadProfileResponse } from "../response/loadProfile";
|
||||
|
||||
export function loadProfile(res: LoadProfileResponse) {
|
||||
switch (res.format) {
|
||||
case 1:
|
||||
return loadProfile1(res);
|
||||
|
||||
case 2:
|
||||
return loadProfile2(res);
|
||||
|
||||
case 3:
|
||||
return loadProfile3(res);
|
||||
|
||||
default:
|
||||
const exhaust: never = res;
|
||||
|
||||
throw new Error(`Unsupported profile response format ${res["format"]}`);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { LoadProfileResponse1 } from "../response/loadProfile";
|
||||
import { LoadProfileResponse } from "../response/loadProfile";
|
||||
|
||||
// Sending this causes an error in v1.21, so it is currently unmapped and
|
||||
// unimplemented.
|
||||
|
||||
export function loadProfile1(res: LoadProfileResponse1) {
|
||||
export function loadProfile1(res: LoadProfileResponse) {
|
||||
const buf = Buffer.alloc(0x0c60);
|
||||
|
||||
buf.writeInt16LE(0x0064, 0x0000);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import iconv from "iconv-lite";
|
||||
|
||||
import { encodeBitmap } from "./_bitmap";
|
||||
import { encodeCar } from "./_car";
|
||||
import { encodeChara } from "./_chara";
|
||||
import { encodeChara1 } from "./_chara";
|
||||
import { encodeMission } from "./_mission";
|
||||
import { LoadProfileResponse2 } from "../response/loadProfile";
|
||||
import { LoadProfileResponse } from "../response/loadProfile";
|
||||
import { writeSjisStr } from "../../util/bin";
|
||||
|
||||
export function loadProfile2(res: LoadProfileResponse2) {
|
||||
export function loadProfile2(res: LoadProfileResponse) {
|
||||
const buf = Buffer.alloc(0x0d30);
|
||||
|
||||
// FLAMETHROWER ANALYSIS (watch out for C strings)
|
||||
@@ -38,14 +37,22 @@ export function loadProfile2(res: LoadProfileResponse2) {
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < 9 && i < res.story.rows.length; i++) {
|
||||
const row = res.story.rows[i];
|
||||
for (let i = 0; i < 9; i++) {
|
||||
const row = res.story.rows.get(i);
|
||||
const rowOffset = 0x0228 + i * 0x26;
|
||||
|
||||
for (let j = 0; j < 9 && j < row.cells.length; j++) {
|
||||
const cell = row.cells[j];
|
||||
if (row === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let j = 0; j < 9; j++) {
|
||||
const cell = row.cells.get(j);
|
||||
const cellOffset = rowOffset + j * 4;
|
||||
|
||||
if (cell === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buf.writeUInt16LE(cell.a, cellOffset + 0);
|
||||
buf.writeUInt16LE(cell.b, cellOffset + 2);
|
||||
}
|
||||
@@ -87,11 +94,11 @@ export function loadProfile2(res: LoadProfileResponse2) {
|
||||
buf.writeUInt32LE(res.settings.pack, 0x03d8);
|
||||
buf.writeUInt32LE(res.dpoint, 0x03e8);
|
||||
buf.writeUInt32LE(res.fame, 0x0404);
|
||||
iconv.encode(res.name + "\0", "shift_jis").copy(buf, 0x03ee);
|
||||
writeSjisStr(buf, 0x03ee, 0x40e, res.name);
|
||||
buf.writeUInt8(res.story.y, 0x0670);
|
||||
buf.writeUInt16LE(res.story.x, 0x06bc);
|
||||
encodeMission(res.missions.solo).copy(buf, 0x06e4);
|
||||
encodeChara(res.chara).copy(buf, 0x070c);
|
||||
encodeChara1(res.chara).copy(buf, 0x070c);
|
||||
encodeBitmap(res.titles, 0xb4).copy(buf, 0x720);
|
||||
buf.writeUInt8(res.settings.aura, 0x07d6);
|
||||
buf.writeUInt8(res.settings.paperCup, 0x07d9);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import iconv from "iconv-lite";
|
||||
|
||||
import { encodeBitmap } from "./_bitmap";
|
||||
import { encodeCar } from "./_car";
|
||||
import { encodeChara } from "./_chara";
|
||||
import { encodeChara1 } from "./_chara";
|
||||
import { encodeMission } from "./_mission";
|
||||
import { LoadProfileResponse3 } from "../response/loadProfile";
|
||||
import { LoadProfileResponse } from "../response/loadProfile";
|
||||
import { writeSjisStr } from "../../util/bin";
|
||||
|
||||
export function loadProfile3(res: LoadProfileResponse3) {
|
||||
export function loadProfile3(res: LoadProfileResponse) {
|
||||
const buf = Buffer.alloc(0x0ea0);
|
||||
|
||||
// Initialize all TA grades to uhh... fuck knows
|
||||
@@ -38,14 +37,22 @@ export function loadProfile3(res: LoadProfileResponse3) {
|
||||
// space for story cells, and 27 rows * 19 bytes per row = 513 bytes, which
|
||||
// is the max that will fit (the final byte of each row is unused).
|
||||
|
||||
for (let i = 0; i < 27 && i < res.story.rows.length; i++) {
|
||||
const row = res.story.rows[i];
|
||||
for (let i = 0; i < 27; i++) {
|
||||
const row = res.story.rows.get(i);
|
||||
const rowOffset = 0x0256 + i * 0x13;
|
||||
|
||||
for (let j = 0; j < 9 && j < row.cells.length; j++) {
|
||||
const cell = row.cells[j];
|
||||
if (row === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let j = 0; j < 9; j++) {
|
||||
const cell = row.cells.get(j);
|
||||
const cellOffset = rowOffset + j * 2;
|
||||
|
||||
if (cell === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buf.writeUInt8(cell.a, cellOffset + 0);
|
||||
buf.writeUInt8(cell.b, cellOffset + 1);
|
||||
}
|
||||
@@ -87,11 +94,11 @@ export function loadProfile3(res: LoadProfileResponse3) {
|
||||
buf.writeUInt32LE(res.settings.pack, 0x04b4);
|
||||
buf.writeUInt32LE(res.dpoint, 0x04c4);
|
||||
buf.writeUInt32LE(res.fame, 0x04e0);
|
||||
iconv.encode(res.name + "\0", "shift_jis").copy(buf, 0x04ca);
|
||||
writeSjisStr(buf, 0x04ca, 0x04ea, res.name);
|
||||
buf.writeUInt8(res.story.y, 0x080c);
|
||||
buf.writeUInt16LE(res.story.x, 0x0828);
|
||||
encodeMission(res.missions.solo).copy(buf, 0x0858);
|
||||
encodeChara(res.chara).copy(buf, 0x0880);
|
||||
encodeChara1(res.chara).copy(buf, 0x0880);
|
||||
encodeBitmap(res.titles, 0xb4).copy(buf, 0x0894);
|
||||
buf.writeUInt8(res.settings.aura, 0x094a);
|
||||
buf.writeUInt8(res.settings.paperCup, 0x094d);
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
import { encodeBitmap } from "./_bitmap";
|
||||
import { encodeCar } from "./_car";
|
||||
import { encodeChara2 } from "./_chara";
|
||||
import { encodeMission } from "./_mission";
|
||||
import { LoadProfileResponse } from "../response/loadProfile";
|
||||
import { writeSjisStr } from "../../util/bin";
|
||||
|
||||
export function loadProfile4(res: LoadProfileResponse) {
|
||||
const buf = Buffer.alloc(0x1360);
|
||||
|
||||
buf.writeUInt16LE(0x012e, 0x0000);
|
||||
buf.writeUInt16LE(res.lv, 0x06f0);
|
||||
buf.writeUInt32LE(res.exp, 0x06f4);
|
||||
buf.writeUInt32LE(res.dpoint, 0x070c);
|
||||
buf.writeUInt32LE(res.fame, 0x0728);
|
||||
buf.writeUInt32LE(res.aimeId, 0x06dc);
|
||||
buf.writeUInt32LE(res.teamId || 0xffffffff, 0x0c60);
|
||||
buf.writeUInt32LE(res.mileage, 0x06e0);
|
||||
encodeMission(res.missions.solo).copy(buf, 0x0aa0);
|
||||
encodeChara2(res.chara).copy(buf, 0x0ac8);
|
||||
encodeBitmap(res.titles, 0xb4).copy(buf, 0x0ade);
|
||||
buf.writeUInt32LE(res.settings.pack, 0x06fc);
|
||||
buf.writeUInt8(res.settings.aura, 0x0c57);
|
||||
buf.writeUInt8(res.settings.paperCup, 0x0c5a);
|
||||
buf.writeUInt8(res.settings.gauges, 0x0c5b);
|
||||
buf.writeUInt8(res.settings.drivingStyle, 0x1184);
|
||||
buf.writeUInt16LE(res.settings.music, 0x06ec);
|
||||
writeSjisStr(buf, 0x0712, 0x0732, res.name);
|
||||
encodeCar(res.car).copy(buf, 0x1290);
|
||||
buf.writeUInt32LE(res.carCount, 0x1288);
|
||||
buf.writeUInt16LE(res.unlocks.auras, 0x00b0);
|
||||
buf.writeUInt8(res.unlocks.cup, 0x00b4);
|
||||
buf.writeUInt32LE(res.unlocks.gauges, 0x00b8);
|
||||
buf.writeUInt32LE(res.unlocks.lastMileageReward, 0x0218);
|
||||
buf.writeUInt16LE(res.unlocks.music, 0x021c);
|
||||
buf.writeUInt16LE(res.teamLeader ? 1 : 0, 0x06a0);
|
||||
|
||||
// Weekly Missions
|
||||
buf.writeUInt32LE(
|
||||
(new Date(res.weeklyMissions.weeklyReset).getTime() / 1000) | 0,
|
||||
0x1068
|
||||
);
|
||||
buf.writeUInt16LE(res.weeklyMissions.weeklyMissionLeft, 0x105a);
|
||||
buf.writeUInt16LE(res.weeklyMissions.weeklyProgressLeft, 0x105c);
|
||||
buf.writeUInt16LE(res.weeklyMissions.weeklyParamsLeft, 0x105e);
|
||||
buf.writeUInt16LE(res.weeklyMissions.weeklyMissionRight, 0x1060);
|
||||
buf.writeUInt16LE(res.weeklyMissions.weeklyProgressRight, 0x1062);
|
||||
buf.writeUInt16LE(res.weeklyMissions.weeklyParamsRight, 0x1064);
|
||||
|
||||
// send twice, once as new stamps, once as old stamps,
|
||||
// because we don't keep track of the "new!" state.
|
||||
encodeBitmap(res.stamps, 0x26).copy(buf, 0x10f8);
|
||||
encodeBitmap(res.stamps, 0x26).copy(buf, 0x111e);
|
||||
|
||||
// Selected Stamps
|
||||
const selectedStamps = res.selectedStamps;
|
||||
buf.writeUInt16LE(selectedStamps.stamp01, 0x1144);
|
||||
buf.writeUInt16LE(selectedStamps.stamp02, 0x1146);
|
||||
buf.writeUInt16LE(selectedStamps.stamp03, 0x1148);
|
||||
buf.writeUInt16LE(selectedStamps.stamp04, 0x114a);
|
||||
|
||||
const { freeCar, freeContinue } = res.tickets;
|
||||
|
||||
if (freeCar) {
|
||||
buf.writeUInt32LE((freeCar.validFrom.getTime() / 1000) | 0, 0x0214);
|
||||
}
|
||||
|
||||
if (freeContinue) {
|
||||
buf.writeUInt32LE((freeContinue.validFrom.getTime() / 1000) | 0, 0x0700);
|
||||
buf.writeUInt32LE((freeContinue.validTo.getTime() / 1000) | 0, 0x0704);
|
||||
}
|
||||
|
||||
// Course plays
|
||||
for (const [courseId, playCount] of res.coursePlays.entries()) {
|
||||
if (courseId < 0 || courseId >= 20) {
|
||||
throw new Error(`Course id out of range: ${courseId}`);
|
||||
}
|
||||
|
||||
buf.writeUInt16LE(playCount, 0x0784 + 2 * courseId);
|
||||
}
|
||||
|
||||
for (const score of res.timeAttack) {
|
||||
const { routeNo } = score;
|
||||
|
||||
buf.writeUInt32LE(
|
||||
(new Date(score.timestamp).getTime() / 1000) | 0, // Date ctor hack
|
||||
0x00e4 + routeNo * 4
|
||||
);
|
||||
|
||||
buf.writeUInt16LE(0xffff, 0x0184 + 2 * routeNo); // National rank
|
||||
buf.writeUInt32LE((score.totalTime * 1000) | 0, 0x0824 + 4 * routeNo); // Total Time in MSEC // DONE
|
||||
buf.writeUInt8(score.flags, 0x0914 + routeNo); // FLAGS
|
||||
buf.writeUInt8(score.grade, 0x0a2c + routeNo); // MEDALS
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
buf.writeUInt16LE(
|
||||
(score.sectionTimes[i] * 1000) >> 2,
|
||||
0x093c + 6 * routeNo + 2 * i // SECTION TIMES DONE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// the format has changed quite a bit in v2
|
||||
// seems like it's just split into the big chapters now
|
||||
// with more cells of course, enough space for 30ish
|
||||
// the biggest chapter is chapter 1 with a total of 22 races
|
||||
// but for "security" let's go with up to 28
|
||||
// first two bytes at the start seem to declare the chapter number
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
const row = res.story.rows.get(i);
|
||||
const rowOffset = 0x0258 + i * 0x7a;
|
||||
|
||||
if (row === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let j = 0; j < 28; j++) {
|
||||
const cell = row.cells.get(j);
|
||||
// Four bytes per column
|
||||
const cellOffset = rowOffset + j * 4;
|
||||
|
||||
if (cell === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buf.writeUInt8(cell.a, cellOffset + 0);
|
||||
buf.writeUInt8(cell.b, cellOffset + 1);
|
||||
buf.writeUInt16LE(cell.c, cellOffset + 2);
|
||||
}
|
||||
}
|
||||
|
||||
buf.writeUInt8(res.story.y, 0x0a54);
|
||||
buf.writeUInt16LE(res.story.x, 0x0a70);
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -1,9 +1,17 @@
|
||||
import { LoadRewardTableResponse } from "../response/loadRewardTable";
|
||||
|
||||
export function loadRewardTable(res: LoadRewardTableResponse) {
|
||||
export function loadRewardTable1(res: LoadRewardTableResponse) {
|
||||
const buf = Buffer.alloc(0x01c0);
|
||||
|
||||
buf.writeInt16LE(0x0087, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function loadRewardTable2(res: LoadRewardTableResponse) {
|
||||
const buf = Buffer.alloc(0x01c0);
|
||||
|
||||
buf.writeInt16LE(0x0080, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LoadServerListResponse } from "../response/loadServerList";
|
||||
|
||||
export function loadServerList(res: LoadServerListResponse) {
|
||||
export function loadServerList1(res: LoadServerListResponse) {
|
||||
const buf = Buffer.alloc(0x04b0);
|
||||
|
||||
buf.writeInt16LE(0x0007, 0x0000);
|
||||
@@ -29,3 +29,33 @@ export function loadServerList(res: LoadServerListResponse) {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function loadServerList2(res: LoadServerListResponse) {
|
||||
const buf = Buffer.alloc(0x04b0);
|
||||
|
||||
buf.writeInt16LE(0x0007, 0x0000);
|
||||
buf.writeInt16LE(res.status, 0x0004);
|
||||
buf.write(res.userDb.addr, 0x0006);
|
||||
buf.writeInt16LE(res.userDb.tcp, 0x0086);
|
||||
buf.writeInt16LE(res.userDb.http, 0x0088);
|
||||
buf.write(res.matchAddr, 0x008a);
|
||||
buf.writeInt16LE(res.matchPort.tcp, 0x010a);
|
||||
buf.writeInt16LE(res.matchPort.udpSend, 0x010c);
|
||||
buf.writeInt16LE(res.matchPort.udpRecv, 0x010e);
|
||||
buf.writeInt16LE(res.tagMatchPort.tcp, 0x0110);
|
||||
buf.writeInt16LE(res.tagMatchPort.udpSend, 0x0112);
|
||||
buf.writeInt16LE(res.tagMatchPort.udpRecv, 0x0114);
|
||||
buf.write(res.event.addr, 0x0116);
|
||||
buf.writeInt16LE(res.event.tcp, 0x0196);
|
||||
buf.write(res.screenshot.addr, 0x019a);
|
||||
buf.writeInt16LE(res.screenshot.tcp, 0x021a);
|
||||
buf.write(res.pingReturn, 0x021e);
|
||||
buf.write(res.echo1.addr, 0x029e);
|
||||
buf.write(res.echo2.addr, 0x031e);
|
||||
buf.writeInt16LE(res.echo1.udp, 0x39e);
|
||||
buf.writeInt16LE(res.echo2.udp, 0x3a0);
|
||||
buf.write(res.newsUrl, 0x03a2);
|
||||
buf.write(res.reportErrorUrl, 0x0426);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { encodeBitmap } from "./_bitmap";
|
||||
import { LoadStockerResponse } from "../response/loadStocker";
|
||||
|
||||
export function loadStocker(res: LoadStockerResponse) {
|
||||
export function loadStocker1(res: LoadStockerResponse) {
|
||||
const buf = Buffer.alloc(0x00a0);
|
||||
|
||||
buf.writeInt16LE(0x00a8, 0x0000);
|
||||
@@ -10,3 +10,14 @@ export function loadStocker(res: LoadStockerResponse) {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function loadStocker2(res: LoadStockerResponse) {
|
||||
const buf = Buffer.alloc(0x00a0);
|
||||
|
||||
buf.writeInt16LE(0x009d, 0x0000);
|
||||
buf.writeUInt8(res.status, 0x0004);
|
||||
encodeBitmap(res.backgrounds, 0x2c).copy(buf, 0x0005);
|
||||
encodeBitmap(res.myChara, 0x98).copy(buf, 0x0031);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LoadTeamRankingResponse } from "../response/loadTeamRanking";
|
||||
|
||||
export function loadTeamRanking(res: LoadTeamRankingResponse): Buffer {
|
||||
export function loadTeamRanking1(res: LoadTeamRankingResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0ba0);
|
||||
|
||||
buf.writeUInt16LE(0x00ba, 0x0000);
|
||||
@@ -8,3 +8,11 @@ export function loadTeamRanking(res: LoadTeamRankingResponse): Buffer {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function loadTeamRanking2(res: LoadTeamRankingResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0ba0);
|
||||
|
||||
buf.writeUInt16LE(0x00a8, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import iconv from "iconv-lite";
|
||||
|
||||
import { writeSjisStr } from "../../util/bin";
|
||||
import { LoadTopTenResponse } from "../response/loadTopTen";
|
||||
|
||||
export function loadTopTen(res: LoadTopTenResponse): Buffer {
|
||||
@@ -49,9 +48,9 @@ export function loadTopTen(res: LoadTopTenResponse): Buffer {
|
||||
buf.writeUInt8(row.field_0E ? 1 : 0, innerOff + 0x000e); // Boolean
|
||||
buf.writeUInt8(row.field_0F ? 1 : 0, innerOff + 0x000f); // Boolean
|
||||
buf.writeUInt8(row.field_10, innerOff + 0x0010);
|
||||
iconv.encode(row.driverName, "shift_jis").copy(buf, innerOff + 0x0014);
|
||||
iconv.encode(row.team.name, "shift_jis").copy(buf, innerOff + 0x0028);
|
||||
iconv.encode(row.shopName, "shift_jis").copy(buf, innerOff + 0x0048);
|
||||
writeSjisStr(buf, innerOff + 0x0014, innerOff + 0x0028, row.driverName);
|
||||
writeSjisStr(buf, innerOff + 0x0028, innerOff + 0x0048, row.team.name);
|
||||
writeSjisStr(buf, innerOff + 0x0048, innerOff + 0x0074, row.shopName);
|
||||
buf.writeUInt32LE(row.team.nameBg, innerOff + 0x0074);
|
||||
buf.writeUInt16LE(row.team.nameFx, innerOff + 0x0078);
|
||||
buf.writeUInt8(row.field_7C, innerOff + 0x007c);
|
||||
@@ -70,7 +69,7 @@ export function loadTopTen(res: LoadTopTenResponse): Buffer {
|
||||
buf.writeUInt8(trailer.courseId, offset + 0x02);
|
||||
buf.writeUInt8(trailer.isNight ? 1 : 0, offset + 0x03);
|
||||
buf.writeUInt32LE(trailer.totalMsec, offset + 0x04);
|
||||
iconv.encode(trailer.name, "shift_jis").copy(buf, offset + 0x08);
|
||||
writeSjisStr(buf, offset + 0x08, offset + 0x1c, trailer.name);
|
||||
} else {
|
||||
buf.writeUInt8(0xff, offset + 0x02);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import { writeSjisStr } from "../../util/bin";
|
||||
import { LoadTopTenResponse } from "../response/loadTopTen";
|
||||
|
||||
export function loadTopTen2(res: LoadTopTenResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x1720);
|
||||
|
||||
buf.writeUInt16LE(0x00ce, 0x0000);
|
||||
buf.writeUInt16LE(res.courseCount, 0x0004);
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (i >= res.courses.length) {
|
||||
break;
|
||||
}
|
||||
|
||||
const course = res.courses[i];
|
||||
const outerOff = 0x0006 + 0x794 * i;
|
||||
|
||||
buf.writeUInt16LE(course.routeNo << 1, outerOff + 0x0002);
|
||||
buf.writeUInt16LE(course.field_02, outerOff + 0x0004); // Bitmask-y?
|
||||
|
||||
if (course.rows.length > 0) {
|
||||
// Section times for the top result (and only top result) are sent OOB
|
||||
const best = course.rows[0];
|
||||
|
||||
for (let j = 0; j < 3; j++) {
|
||||
buf.writeUInt32LE(
|
||||
(best.ta.sectionTimes[j] * 1000) | 0,
|
||||
outerOff + 0x0004 + 4 * j
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (let j = 0; j < 10; j++) {
|
||||
if (j >= course.rows.length) {
|
||||
break;
|
||||
}
|
||||
|
||||
const row = course.rows[j];
|
||||
const innerOff = outerOff + 0x0012 + 0xc0 * j;
|
||||
|
||||
buf.writeUInt32LE(row.field_00, innerOff + 0x0000);
|
||||
buf.writeUInt32LE((row.ta.totalTime * 1000) | 0, innerOff + 0x0004);
|
||||
buf.writeUInt32LE(
|
||||
(row.ta.timestamp.getTime() / 1000) | 0,
|
||||
innerOff + 0x0008
|
||||
);
|
||||
buf.writeUInt16LE(row.ta.carSelector, innerOff + 0x000c); // CAR
|
||||
buf.writeUInt8(row.field_0E ? 1 : 0, innerOff + 0x000e); // Boolean
|
||||
buf.writeUInt8(row.field_0F ? 1 : 0, innerOff + 0x000f); // Boolean
|
||||
buf.writeUInt8(row.field_10, innerOff + 0x0010);
|
||||
writeSjisStr(buf, innerOff + 0x0014, innerOff + 0x0028, row.driverName);
|
||||
writeSjisStr(buf, innerOff + 0x0028, innerOff + 0x0048, row.team.name);
|
||||
writeSjisStr(buf, innerOff + 0x0048, innerOff + 0x0074, row.shopName);
|
||||
buf.writeUInt32LE(row.team.nameBg, innerOff + 0x0074);
|
||||
buf.writeUInt16LE(row.team.nameFx, innerOff + 0x0078);
|
||||
buf.writeUInt8(row.field_7C, innerOff + 0x007c);
|
||||
buf.writeUInt8(row.field_7D, innerOff + 0x007d);
|
||||
// 66 bytes of empty space at the end. Maybe a string used to live here?
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const offset = 0x16c0 + 0x1c * i;
|
||||
|
||||
if (i < res.trailers.length) {
|
||||
const trailer = res.trailers[i];
|
||||
|
||||
buf.writeUInt16LE(trailer.yearMonth, offset + 0x00);
|
||||
buf.writeUInt8(trailer.courseId, offset + 0x02);
|
||||
buf.writeUInt8(trailer.isNight ? 1 : 0, offset + 0x03);
|
||||
buf.writeUInt32LE(trailer.totalMsec, offset + 0x04);
|
||||
writeSjisStr(buf, offset + 0x08, offset + 0x1c, trailer.name);
|
||||
} else {
|
||||
buf.writeUInt8(0xff, offset + 0x02);
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -6,7 +6,7 @@ const statusCodes = {
|
||||
obsolete: 0x0002,
|
||||
};
|
||||
|
||||
export function lockProfile(res: LockProfileResponse) {
|
||||
export function lockProfile1(res: LockProfileResponse) {
|
||||
const buf = Buffer.alloc(0x0020);
|
||||
|
||||
buf.writeInt16LE(0x006a, 0x0000);
|
||||
@@ -16,3 +16,14 @@ export function lockProfile(res: LockProfileResponse) {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function lockProfile2(res: LockProfileResponse) {
|
||||
const buf = Buffer.alloc(0x0020);
|
||||
|
||||
buf.writeInt16LE(0x0066, 0x0000);
|
||||
buf.writeInt8(statusCodes[res.status], 0x0018);
|
||||
buf.writeInt16LE(res.field_001A, 0x001a);
|
||||
buf.writeInt32LE(res.lockExpiry.getTime() / 1000, 0x001c);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LockProfileExtendResponse } from "../response/lockProfileExtend";
|
||||
|
||||
export function lockProfileExtend(res: LockProfileExtendResponse): Buffer {
|
||||
export function lockProfileExtend1(res: LockProfileExtendResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x006e, 0x0000);
|
||||
@@ -8,3 +8,12 @@ export function lockProfileExtend(res: LockProfileExtendResponse): Buffer {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function lockProfileExtend2(res: LockProfileExtendResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x006a, 0x0000);
|
||||
buf.writeUInt8(res.status, 0x0004);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,25 +1,6 @@
|
||||
import {
|
||||
SaveExpeditionResponse,
|
||||
SaveExpeditionResponse1,
|
||||
SaveExpeditionResponse2,
|
||||
} from "../response/saveExpedition";
|
||||
import { SaveExpeditionResponse } from "../response/saveExpedition";
|
||||
|
||||
export function saveExpedition(res: SaveExpeditionResponse): Buffer {
|
||||
switch (res.format) {
|
||||
case 1:
|
||||
return saveExpedition1(res);
|
||||
|
||||
case 2:
|
||||
return saveExpedition2(res);
|
||||
|
||||
default:
|
||||
const exhaust: never = res;
|
||||
|
||||
throw new Error(`Unsupported data format ${res["format"]}`);
|
||||
}
|
||||
}
|
||||
|
||||
function saveExpedition1(res: SaveExpeditionResponse1): Buffer {
|
||||
export function saveExpedition1(res: SaveExpeditionResponse): Buffer {
|
||||
// in awe of the size of this lad
|
||||
const buf = Buffer.alloc(0x17c0);
|
||||
|
||||
@@ -28,7 +9,7 @@ function saveExpedition1(res: SaveExpeditionResponse1): Buffer {
|
||||
return buf;
|
||||
}
|
||||
|
||||
function saveExpedition2(res: SaveExpeditionResponse2): Buffer {
|
||||
export function saveExpedition2(res: SaveExpeditionResponse): Buffer {
|
||||
// absolute unit
|
||||
const buf = Buffer.alloc(0x18ac);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SaveGarageResponse } from "../response/saveGarage";
|
||||
|
||||
export function saveGarage(res: SaveGarageResponse): Buffer {
|
||||
export function saveGarage1(res: SaveGarageResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x008f, 0x0000);
|
||||
@@ -8,3 +8,12 @@ export function saveGarage(res: SaveGarageResponse): Buffer {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function saveGarage2(res: SaveGarageResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x0086, 0x0000);
|
||||
buf.writeUInt16LE(res.status, 0x0004);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SaveNewCarResponse } from "../response/saveNewCar";
|
||||
|
||||
export function saveNewCar(res: SaveNewCarResponse): Buffer {
|
||||
export function saveNewCar1(res: SaveNewCarResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x007a, 0x0000);
|
||||
@@ -8,3 +8,12 @@ export function saveNewCar(res: SaveNewCarResponse): Buffer {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function saveNewCar2(res: SaveNewCarResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x0076, 0x0000);
|
||||
buf.writeUInt8(res.status, 0x0004);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import { SaveTimeAttackResponse } from "../response/saveTimeAttack";
|
||||
|
||||
export function saveTimeAttack(res: SaveTimeAttackResponse): Buffer {
|
||||
export function saveTimeAttack1(res: SaveTimeAttackResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x00b0);
|
||||
|
||||
buf.writeUInt16LE(0x00ce, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function saveTimeAttack2(res: SaveTimeAttackResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x00f0);
|
||||
|
||||
buf.writeUInt16LE(0x00cd, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import { SaveTopicResponse } from "../response/saveTopic";
|
||||
|
||||
export function saveTopic(res: SaveTopicResponse) {
|
||||
export function saveTopic1(res: SaveTopicResponse) {
|
||||
const buf = Buffer.alloc(0x05d0);
|
||||
|
||||
buf.writeInt16LE(0x009b, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function saveTopic2(res: SaveTopicResponse) {
|
||||
const buf = Buffer.alloc(0x05d0);
|
||||
|
||||
buf.writeInt16LE(0x0092, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UnlockProfileResponse } from "../response/unlockProfile";
|
||||
|
||||
export function unlockProfile(res: UnlockProfileResponse) {
|
||||
export function unlockProfile1(res: UnlockProfileResponse) {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeInt16LE(0x0070, 0x0000);
|
||||
@@ -8,3 +8,12 @@ export function unlockProfile(res: UnlockProfileResponse) {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function unlockProfile2(res: UnlockProfileResponse) {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeInt16LE(0x006c, 0x0000);
|
||||
buf.writeInt8(res.status, 0x0004);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { UpdateExpeditionResponse } from "../response/updateExpedition";
|
||||
|
||||
export function updateExpedition(res: UpdateExpeditionResponse) {
|
||||
let buf: Buffer;
|
||||
|
||||
if (res.expeditionType == 0) {
|
||||
buf = Buffer.alloc(0x0040);
|
||||
buf.writeInt16LE(1, 0x0000);
|
||||
} else {
|
||||
buf = Buffer.alloc(0x19f0);
|
||||
buf.writeInt16LE(0x0140, 0x0000);
|
||||
// Experiments used to live here, removed because they're a not-really
|
||||
// working mess. Hopefully, one day there will be beautiful code
|
||||
// here, that works and makes people happy. One day.
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -1,14 +1,35 @@
|
||||
import iconv from "iconv-lite";
|
||||
|
||||
import { UpdateProvisionalStoreRankResponse } from "../response/updateProvisionalStoreRank";
|
||||
import { writeSjisStr } from "../../util/bin";
|
||||
|
||||
export function updateProvisionalStoreRank(
|
||||
export function updateProvisionalStoreRank1(
|
||||
res: UpdateProvisionalStoreRankResponse
|
||||
) {
|
||||
const buf = Buffer.alloc(0x02b0);
|
||||
|
||||
buf.writeInt16LE(0x0083, 0x0000);
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const offset = 0x0008 + i * 0x44;
|
||||
const row = res.rows[i];
|
||||
|
||||
if (row !== undefined) {
|
||||
buf.writeInt16LE(row.field_0000, offset + 0x0000);
|
||||
buf.writeInt32LE(row.field_0004, offset + 0x0004);
|
||||
writeSjisStr(buf, offset + 0x0010, offset + 0x003b, row.field_0010);
|
||||
writeSjisStr(buf, offset + 0x003b, offset + 0x0044, row.field_003B);
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function updateProvisionalStoreRank2(
|
||||
res: UpdateProvisionalStoreRankResponse
|
||||
) {
|
||||
const buf = Buffer.alloc(0x02b0);
|
||||
|
||||
buf.writeInt16LE(0x007d, 0x0000);
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const offset = 0x44 + i;
|
||||
const row = res.rows[i];
|
||||
@@ -16,8 +37,8 @@ export function updateProvisionalStoreRank(
|
||||
if (row !== undefined) {
|
||||
buf.writeInt16LE(row.field_0000, offset + 0x0000);
|
||||
buf.writeInt32LE(row.field_0004, offset + 0x0004);
|
||||
iconv.encode(row.field_0010, "shift_jis").copy(buf, offset + 0x0010);
|
||||
iconv.encode(row.field_003B, "shift_jis").copy(buf, offset + 0x003b);
|
||||
writeSjisStr(buf, offset + 0x0010, offset + 0x003b, row.field_0010);
|
||||
writeSjisStr(buf, offset + 0x003b, offset + 0x0044, row.field_003B);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,8 @@
|
||||
import {
|
||||
UpdateStoryClearNumResponse,
|
||||
UpdateStoryClearNumResponse1,
|
||||
UpdateStoryClearNumResponse2,
|
||||
} from "../response/updateStoryClearNum";
|
||||
import { UpdateStoryClearNumResponse } from "../response/updateStoryClearNum";
|
||||
|
||||
export function updateStoryClearNum(res: UpdateStoryClearNumResponse): Buffer {
|
||||
switch (res.format) {
|
||||
case 1:
|
||||
return updateStoryClearNum1(res);
|
||||
|
||||
case 2:
|
||||
return updateStoryClearNum2(res);
|
||||
|
||||
default:
|
||||
const exhaust: never = res;
|
||||
|
||||
throw new Error(`Unsupported data format ${res["format"]}`);
|
||||
}
|
||||
}
|
||||
|
||||
function updateStoryClearNum1(res: UpdateStoryClearNumResponse1): Buffer {
|
||||
export function updateStoryClearNum1(
|
||||
res: UpdateStoryClearNumResponse
|
||||
): Buffer {
|
||||
const buf = Buffer.alloc(0x0220);
|
||||
|
||||
buf.writeInt16LE(0x0080, 0x0000);
|
||||
@@ -27,10 +10,22 @@ function updateStoryClearNum1(res: UpdateStoryClearNumResponse1): Buffer {
|
||||
return buf;
|
||||
}
|
||||
|
||||
function updateStoryClearNum2(res: UpdateStoryClearNumResponse2): Buffer {
|
||||
export function updateStoryClearNum2(
|
||||
res: UpdateStoryClearNumResponse
|
||||
): Buffer {
|
||||
const buf = Buffer.alloc(0x04f0);
|
||||
|
||||
buf.writeInt16LE(0x013e, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function updateStoryClearNum3(
|
||||
res: UpdateStoryClearNumResponse
|
||||
): Buffer {
|
||||
const buf = Buffer.alloc(0x0510);
|
||||
|
||||
buf.writeInt16LE(0x013e, 0x0000);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UpdateTeamLeaderResponse } from "../response/updateTeamLeader";
|
||||
|
||||
export function updateTeamLeader(res: UpdateTeamLeaderResponse): Buffer {
|
||||
export function updateTeamLeader1(res: UpdateTeamLeaderResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x008b, 0x0000);
|
||||
@@ -8,3 +8,12 @@ export function updateTeamLeader(res: UpdateTeamLeaderResponse): Buffer {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function updateTeamLeader2(res: UpdateTeamLeaderResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x0084, 0x0000);
|
||||
buf.writeUInt32LE(res.status, 0x0004);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UpdateTeamMemberResponse } from "../response/updateTeamMember";
|
||||
|
||||
export function updateTeamMember(res: UpdateTeamMemberResponse): Buffer {
|
||||
export function updateTeamMember1(res: UpdateTeamMemberResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x0074, 0x0000);
|
||||
@@ -8,3 +8,12 @@ export function updateTeamMember(res: UpdateTeamMemberResponse): Buffer {
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function updateTeamMember2(res: UpdateTeamMemberResponse): Buffer {
|
||||
const buf = Buffer.alloc(0x0010);
|
||||
|
||||
buf.writeUInt16LE(0x0070, 0x0000);
|
||||
buf.writeUInt32LE(res.status, 0x0004);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ export async function _fixupPrevTeam(
|
||||
// (need to look up new leader's db id from aime id. ick)
|
||||
|
||||
const newLeader = remaining[remaining.length - 1];
|
||||
const newLeaderId = await w.profile().find(newLeader.profile.aimeId);
|
||||
const newLeaderId = await w
|
||||
.profile()
|
||||
.find(newLeader.profile.aimeId, newLeader.profile.version);
|
||||
|
||||
await w.teamMembers().makeLeader(prevTeamId, newLeaderId);
|
||||
}
|
||||
|
||||
@@ -44,9 +44,9 @@ export async function createAutoTeam(
|
||||
req: CreateAutoTeamRequest
|
||||
): Promise<CreateAutoTeamResponse> {
|
||||
const now = new Date();
|
||||
const { aimeId } = req;
|
||||
const { aimeId, version } = req;
|
||||
|
||||
const peek = await w.teamAuto().peek();
|
||||
const peek = await w.teamAuto().peek(version);
|
||||
let nextAuto: TeamAuto;
|
||||
|
||||
//
|
||||
@@ -100,6 +100,7 @@ export async function createAutoTeam(
|
||||
// Register the new team, make the requestor its leader
|
||||
|
||||
const spec = {
|
||||
version,
|
||||
name,
|
||||
nameBg: autoTeams[nameIdx].nameBg,
|
||||
nameFx: 0,
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import { MissionState } from "../model/mission";
|
||||
import { Profile } from "../model/profile";
|
||||
import { Settings } from "../model/settings";
|
||||
import { Story } from "../model/story";
|
||||
import { Story, StoryRow } from "../model/story";
|
||||
import { Unlocks } from "../model/unlocks";
|
||||
import { CreateProfileRequest } from "../request/createProfile";
|
||||
import { GenericResponse } from "../response/generic";
|
||||
import { CreateProfileResponse } from "../response/createProfile";
|
||||
import { Repositories } from "../repo";
|
||||
|
||||
export async function createProfile(
|
||||
w: Repositories,
|
||||
req: CreateProfileRequest
|
||||
): Promise<GenericResponse> {
|
||||
const { aimeId, name } = req;
|
||||
): Promise<CreateProfileResponse> {
|
||||
const { aimeId, version, name } = req;
|
||||
const now = new Date();
|
||||
|
||||
const profile: Profile = {
|
||||
aimeId,
|
||||
version,
|
||||
name,
|
||||
lv: 1,
|
||||
exp: 0,
|
||||
@@ -27,8 +28,19 @@ export async function createProfile(
|
||||
};
|
||||
|
||||
const missions: MissionState = { team: [], solo: [] };
|
||||
const settings: Settings = { music: 0, pack: 13640, aura: 0, paperCup: 0, gauges: 5 };
|
||||
const story: Story = { x: 0, y: 0, rows: [] };
|
||||
const settings: Settings = {
|
||||
music: 0,
|
||||
pack: 13640,
|
||||
aura: 0,
|
||||
paperCup: 0,
|
||||
gauges: 5,
|
||||
drivingStyle: 0, // Not supported until idz2
|
||||
};
|
||||
const story: Story = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
rows: new Map<number, StoryRow>(),
|
||||
};
|
||||
const unlocks: Unlocks = {
|
||||
auras: 1,
|
||||
cup: 0,
|
||||
@@ -51,7 +63,7 @@ export async function createProfile(
|
||||
await w.teamReservations().commitHack(aimeId);
|
||||
|
||||
return {
|
||||
type: "generic_res",
|
||||
status: aimeId, // "Generic response" my fucking *ass*
|
||||
type: "create_profile_res",
|
||||
aimeId: aimeId,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export async function createTeam(
|
||||
w: Repositories,
|
||||
req: CreateTeamRequest
|
||||
): Promise<CreateTeamResponse> {
|
||||
const profileId = await w.profile().find(req.aimeId);
|
||||
const profileId = await w.profile().find(req.aimeId, req.version);
|
||||
const prevTeamId = await w.teamMembers().findTeam(profileId);
|
||||
const now = new Date();
|
||||
|
||||
@@ -15,6 +15,7 @@ export async function createTeam(
|
||||
|
||||
const teamSpec = {
|
||||
name: req.teamName,
|
||||
version: req.version,
|
||||
nameBg: req.nameBg,
|
||||
nameFx: 0,
|
||||
registerTime: now,
|
||||
|
||||
@@ -6,7 +6,7 @@ export async function discoverProfile(
|
||||
w: Repositories,
|
||||
req: DiscoverProfileRequest
|
||||
): Promise<DiscoverProfileResponse> {
|
||||
const profileId = await w.profile().peek(req.aimeId);
|
||||
const profileId = await w.profile().peek(req.aimeId, req.version);
|
||||
|
||||
return {
|
||||
type: "discover_profile_res",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user