diff --git a/src/idz/decoder/index.ts b/src/idz/decoder/index.ts index 7b904db..79943c3 100644 --- a/src/idz/decoder/index.ts +++ b/src/idz/decoder/index.ts @@ -16,6 +16,7 @@ import { loadTeam } from "./loadTeam"; import { loadTeamRanking, loadTeamRanking2 } from "./loadTeamRanking"; import { lockGarage } from "./lockGarage"; import { lockProfile } from "./lockProfile"; +import { msg00AD } from "./msg00AD"; import { saveExpedition } from "./saveExpedition"; import { saveGarage } from "./saveGarage"; import { saveProfile } from "./saveProfile"; @@ -56,6 +57,7 @@ const funcList: ReaderFn[] = [ loadTopTen, lockGarage, lockProfile, + msg00AD, saveExpedition, saveGarage, saveProfile, diff --git a/src/idz/decoder/msg00AD.ts b/src/idz/decoder/msg00AD.ts new file mode 100644 index 0000000..a974cda --- /dev/null +++ b/src/idz/decoder/msg00AD.ts @@ -0,0 +1,9 @@ +import { RequestCode } from "./_defs"; +import { Message00AD } from "../request/msg00AD"; + +msg00AD.msgCode = 0x00ad as RequestCode; +msg00AD.msgLen = 0x061c; + +export function msg00AD(buf: Buffer): Message00AD { + return { type: "msg_00AD_req" }; +} diff --git a/src/idz/decoder/saveProfile.ts b/src/idz/decoder/saveProfile.ts index b20cfd2..331dc37 100644 --- a/src/idz/decoder/saveProfile.ts +++ b/src/idz/decoder/saveProfile.ts @@ -1,12 +1,44 @@ import { RequestCode } from "./_defs"; +import { Id, TitleCode } from "../model/base"; +import { Profile } from "../model/profile"; import { SaveProfileRequest } from "../request/saveProfile"; +import { bitmap } from "./_bitmap"; saveProfile.msgCode = 0x0068 as RequestCode; saveProfile.msgLen = 0x0940; export function saveProfile(buf: Buffer): SaveProfileRequest { + const storyRows = new Array(); + + for (let i = 0; i < 9; i++) { + const cells = new Array(); + 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 }; + + cells.push(cell); + } + + const row = { cells }; + + storyRows.push(row); + } + return { type: "save_profile_req", - // mega TODO + profileId: buf.readUInt32LE(0x0004) as Id, + lv: buf.readUInt16LE(0x0026), + exp: buf.readUInt32LE(0x0028), + fame: buf.readUInt32LE(0x0468), + dpoint: buf.readUInt32LE(0x0464), + titles: bitmap(buf.slice(0x0042, 0x00f6)) as TitleCode[], + story: { + x: buf.readUInt16LE(0x06fc), + y: buf.readUInt8(0x06e0), + rows: storyRows, + }, }; } diff --git a/src/idz/encoder/loadProfile2.ts b/src/idz/encoder/loadProfile2.ts index c4eadc1..8d1b448 100644 --- a/src/idz/encoder/loadProfile2.ts +++ b/src/idz/encoder/loadProfile2.ts @@ -6,9 +6,6 @@ import { chara } from "./_chara"; import { LoadProfileResponse2 } from "../response/loadProfile2"; export function loadProfile2(res: LoadProfileResponse2) { - // Story stuff - //buf.writeUInt32LE(0x1ff, 0x0228); - const settingsPack = ((res.settings.forceQuitEn ? 1 : 0) << 0) | (res.settings.steeringForce << 1) | @@ -21,6 +18,24 @@ export function loadProfile2(res: LoadProfileResponse2) { const buf = Buffer.alloc(0x0d30); + //buf.writeUInt16LE(0x0001, 0x06bc); // story_X + //buf.writeUInt8(0x00, 0x0670); // story_Y + //buf.writeUInt16LE(0x0001, 0x0228 + 0); // records[0].pairs[0].a + //buf.writeUInt16LE(0x0003, 0x0228 + 2); // records[0].pairs[0].b + + for (let i = 0; i < 9 && i < res.story.rows.length; i++) { + const row = res.story.rows[i]; + const rowOffset = 0x0228 + i * 0x26; + + for (let j = 0; j < 9 && j < row.cells.length; j++) { + const cell = row.cells[j]; + const cellOffset = rowOffset + j * 4; + + buf.writeUInt16LE(cell.a, cellOffset + 0); + buf.writeUInt16LE(cell.b, cellOffset + 2); + } + } + buf.writeInt16LE(0x0065, 0x0000); buf.writeInt32LE(res.profileId, 0x03b8); buf.writeUInt16LE(res.settings.bgMusic, 0x03c8); @@ -29,6 +44,8 @@ export function loadProfile2(res: LoadProfileResponse2) { buf.writeInt32LE(res.dpoint, 0x03e8); buf.writeInt32LE(res.fame, 0x0404); iconv.encode(res.name + "\0", "shift_jis").copy(buf, 0x03ee); + buf.writeUInt16LE(res.story.x, 0x06bc); + buf.writeUInt8(res.story.y, 0x0670); chara(res.chara).copy(buf, 0x070c); bitmap(res.titles, 0xb4).copy(buf, 0x720); buf.writeInt32LE(res.teamId || 0, 0x07e0); diff --git a/src/idz/handler/createProfile.ts b/src/idz/handler/createProfile.ts index 455e9bb..daf99ab 100644 --- a/src/idz/handler/createProfile.ts +++ b/src/idz/handler/createProfile.ts @@ -1,5 +1,7 @@ import { Id } from "../model/base"; import { Profile } from "../model/profile"; +import { Settings } from "../model/settings"; +import { Story } from "../model/story"; import { Team } from "../model/team"; import { CreateProfileRequest } from "../request/createProfile"; import { GenericResponse } from "../response/generic"; @@ -14,11 +16,12 @@ export async function createProfile( teamId: 2 as Id, name: req.name, lv: 1, + exp: 0, fame: 0, dpoint: 0, }; - const settings = { + const settings: Settings = { bgMusic: 0, forceQuitEn: false, steeringForce: 4, @@ -30,6 +33,8 @@ export async function createProfile( taResultSkip: false, }; + const story: Story = { x: 0, y: 0, rows: [] }; + await Promise.all([ w.profile().save(profile.id, profile), w.chara().save(profile.id, req.chara), diff --git a/src/idz/handler/index.ts b/src/idz/handler/index.ts index 11e01c6..5c2e2ae 100644 --- a/src/idz/handler/index.ts +++ b/src/idz/handler/index.ts @@ -14,6 +14,7 @@ import { loadTeamRanking } from "./loadTeamRanking"; import { loadTopTen } from "./loadTopTen"; import { lockGarage } from "./lockGarage"; import { lockProfile } from "./lockProfile"; +import { msg00AD } from "./msg00AD"; import { saveExpedition } from "./saveExpedition"; import { saveGarage } from "./saveGarage"; import { saveProfile } from "./saveProfile"; @@ -83,6 +84,9 @@ export async function dispatch(w: World, req: Request): Promise { case "load_team_ranking_req": return loadTeamRanking(w, req); + case "msg_00AD_req": + return msg00AD(w, req); + case "save_expedition_req": return saveExpedition(w, req); diff --git a/src/idz/handler/loadProfile.ts b/src/idz/handler/loadProfile.ts index 65e8daa..ba519de 100644 --- a/src/idz/handler/loadProfile.ts +++ b/src/idz/handler/loadProfile.ts @@ -6,11 +6,15 @@ export async function loadProfile( w: World, req: LoadProfileRequest ): Promise { + // Promise.all would be messy here, who cares anyway this isn't supposed to + // be a high-performance server. + const profile = await w.profile().loadByAimeId(req.aimeId); const settings = await w.settings().load(profile.id); const chara = await w.chara().load(profile.id); const titles = await w.titles().load(profile.id); const car = await w.car().load(profile.id); + const story = await w.story().load(profile.id); return { type: "load_profile_v2_res", @@ -24,5 +28,6 @@ export async function loadProfile( chara, titles, car, + story, }; } diff --git a/src/idz/handler/msg00AD.ts b/src/idz/handler/msg00AD.ts new file mode 100644 index 0000000..be7d754 --- /dev/null +++ b/src/idz/handler/msg00AD.ts @@ -0,0 +1,7 @@ +import { Message00AD } from "../request/msg00AD"; +import { GenericResponse } from "../response/generic"; +import { World } from "../world"; + +export function msg00AD(w: World, req: Message00AD): GenericResponse { + return { type: "generic_res" }; +} diff --git a/src/idz/handler/saveProfile.ts b/src/idz/handler/saveProfile.ts index 823d144..cf4dfe8 100644 --- a/src/idz/handler/saveProfile.ts +++ b/src/idz/handler/saveProfile.ts @@ -2,10 +2,24 @@ import { SaveProfileRequest } from "../request/saveProfile"; import { GenericResponse } from "../response/generic"; import { World } from "../world"; -export function saveProfile( +export async function saveProfile( w: World, req: SaveProfileRequest -): GenericResponse { +): Promise { + const profile = await w.profile().load(req.profileId); + + await Promise.all([ + w.profile().save(req.profileId, { + ...profile, + lv: req.lv, + exp: req.exp, + fame: req.fame, + dpoint: req.dpoint, + }), + w.story().save(req.profileId, req.story), + w.titles().save(req.profileId, req.titles), + ]); + return { type: "generic_res", status: 1, diff --git a/src/idz/model/index.ts b/src/idz/model/index.ts index 9ee2cfa..ef19a1c 100644 --- a/src/idz/model/index.ts +++ b/src/idz/model/index.ts @@ -3,4 +3,5 @@ export { Car } from "./car"; export { Chara } from "./chara"; export { Profile } from "./profile"; export { Settings } from "./settings"; +export { Story } from "./story"; export { Team } from "./team"; diff --git a/src/idz/model/profile.ts b/src/idz/model/profile.ts index 4f64c44..0bc111b 100644 --- a/src/idz/model/profile.ts +++ b/src/idz/model/profile.ts @@ -6,6 +6,7 @@ export interface Profile { teamId?: Id; name: string; lv: number; + exp: number; fame: number; dpoint: number; } diff --git a/src/idz/model/story.ts b/src/idz/model/story.ts new file mode 100644 index 0000000..9cff2c6 --- /dev/null +++ b/src/idz/model/story.ts @@ -0,0 +1,14 @@ +export interface StoryCell { + a: number; + b: number; +} + +export interface StoryRow { + cells: StoryCell[]; +} + +export interface Story { + x: number; + y: number; + rows: StoryRow[]; +} diff --git a/src/idz/request/index.ts b/src/idz/request/index.ts index 5d75534..7f7bb58 100644 --- a/src/idz/request/index.ts +++ b/src/idz/request/index.ts @@ -15,6 +15,7 @@ import { LoadTeamRankingRequest } from "./loadTeamRanking"; import { LoadTopTenRequest } from "./loadTopTen"; import { LockAccountRequest } from "./lockProfile"; import { LockGarageRequest } from "./lockGarage"; +import { Message00AD } from "./msg00AD"; import { SaveExpeditionRequest } from "./saveExpedition"; import { SaveGarageRequest } from "./saveGarage"; import { SaveProfileRequest } from "./saveProfile"; @@ -46,6 +47,7 @@ export type Request = | LoadTopTenRequest | LockAccountRequest | LockGarageRequest + | Message00AD | SaveExpeditionRequest | SaveGarageRequest | SaveProfileRequest diff --git a/src/idz/request/msg00AD.ts b/src/idz/request/msg00AD.ts new file mode 100644 index 0000000..f1bddc2 --- /dev/null +++ b/src/idz/request/msg00AD.ts @@ -0,0 +1,3 @@ +export interface Message00AD { + type: "msg_00AD_req"; +} diff --git a/src/idz/request/saveProfile.ts b/src/idz/request/saveProfile.ts index 426e435..058bec9 100644 --- a/src/idz/request/saveProfile.ts +++ b/src/idz/request/saveProfile.ts @@ -1,4 +1,14 @@ +import { Id, TitleCode } from "../model/base"; +import { Profile } from "../model/profile"; +import { Story } from "../model/story"; + export interface SaveProfileRequest { type: "save_profile_req"; - // giga TODO + profileId: Id; + lv: number; + exp: number; + fame: number; + dpoint: number; + titles: TitleCode[]; + story: Story; } diff --git a/src/idz/response/loadProfile2.ts b/src/idz/response/loadProfile2.ts index 5e709ae..3beddfe 100644 --- a/src/idz/response/loadProfile2.ts +++ b/src/idz/response/loadProfile2.ts @@ -3,6 +3,7 @@ import { Car } from "../model/car"; import { Chara } from "../model/chara"; import { Profile } from "../model/profile"; import { Settings } from "../model/settings"; +import { Story } from "../model/story"; export interface LoadProfileResponse2 { type: "load_profile_v2_res"; @@ -16,5 +17,6 @@ export interface LoadProfileResponse2 { chara: Chara; titles: number[]; car: Car; + story: Story; // giga TODO } diff --git a/src/idz/world/base.ts b/src/idz/world/base.ts index c59a064..258e056 100644 --- a/src/idz/world/base.ts +++ b/src/idz/world/base.ts @@ -25,5 +25,7 @@ export interface World { settings(): Repository; + story(): Repository; + titles(): Repository; } diff --git a/src/idz/world/index.ts b/src/idz/world/index.ts index cb69283..1980437 100644 --- a/src/idz/world/index.ts +++ b/src/idz/world/index.ts @@ -43,6 +43,13 @@ class WorldImpl implements World { ); } + story() { + return new SingletonJsonRepo( + this._root, + "story" + ); + } + titles() { return new SingletonTextRepo( this._root,