diff --git a/src/idz/userdb/decoder/index.ts b/src/idz/userdb/decoder/index.ts index 157ada9..f3f316b 100644 --- a/src/idz/userdb/decoder/index.ts +++ b/src/idz/userdb/decoder/index.ts @@ -37,7 +37,7 @@ import { loadTeamRanking4, } from "./loadTeamRanking"; import { loadTopTen1 } from "./loadTopTen1"; -import { loadTopTen2 } from "./loadTopTen2"; +import { loadTopTen2, loadTopTen3 } from "./loadTopTen2"; import { lockGarage1, lockGarage2 } from "./lockGarage"; import { lockProfile1, lockProfile2 } from "./lockProfile"; import { saveExpedition1, saveExpedition2 } from "./saveExpedition"; @@ -205,7 +205,7 @@ const funcList210: ReaderFn[] = [ loadTeam2, loadTeamRanking2, loadTeamRanking4, - loadTopTen2, + loadTopTen3, lockGarage2, lockProfile2, lockProfileExtend2, diff --git a/src/idz/userdb/decoder/loadTopTen1.ts b/src/idz/userdb/decoder/loadTopTen1.ts index b827545..cdf856a 100644 --- a/src/idz/userdb/decoder/loadTopTen1.ts +++ b/src/idz/userdb/decoder/loadTopTen1.ts @@ -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 diff --git a/src/idz/userdb/decoder/loadTopTen2.ts b/src/idz/userdb/decoder/loadTopTen2.ts index 2573c51..b8b88c1 100644 --- a/src/idz/userdb/decoder/loadTopTen2.ts +++ b/src/idz/userdb/decoder/loadTopTen2.ts @@ -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) : undefined, }; } + +loadTopTen3.msgCode = 0x012c; +loadTopTen3.msgLen = 0x0110; + +export function loadTopTen3(buf: Buffer): LoadTopTenRequest { + const selectors = new Array(); + + 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) : undefined, + }; +} diff --git a/src/idz/userdb/encoder/index.ts b/src/idz/userdb/encoder/index.ts index 0d8024a..219a499 100644 --- a/src/idz/userdb/encoder/index.ts +++ b/src/idz/userdb/encoder/index.ts @@ -38,6 +38,7 @@ import { loadServerList } 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"; @@ -347,7 +348,7 @@ function encode210(res: Response): Buffer { return loadTeamRanking1(res); case "load_top_ten_res": - return loadTopTen(res); + return loadTopTen2(res); case "lock_profile_extend_res": return lockProfileExtend1(res); diff --git a/src/idz/userdb/handler/loadTopTen.ts b/src/idz/userdb/handler/loadTopTen.ts index c5d1c65..1f5744e 100644 --- a/src/idz/userdb/handler/loadTopTen.ts +++ b/src/idz/userdb/handler/loadTopTen.ts @@ -18,10 +18,18 @@ export async function loadTopTen( } const { routeNo, minTimestamp } = selector; - const src = await w.timeAttack().loadTop(routeNo, minTimestamp, 10); + var src = await w + .timeAttack() + .loadTop(req.version, routeNo, minTimestamp, 10); + // Hacky solution but force full reload per course if there's an updated time. + // Otherwise, the updated time will replace the top 1 record. if (src.length === 0) { continue; + } else { + src = await w + .timeAttack() + .loadTop(req.version, routeNo, new Date(100), 10); } const dest = new Array(); diff --git a/src/idz/userdb/repo.ts b/src/idz/userdb/repo.ts index 2e88570..fd66d23 100644 --- a/src/idz/userdb/repo.ts +++ b/src/idz/userdb/repo.ts @@ -143,6 +143,7 @@ export interface TopTenResult { export interface TimeAttackRepository { loadTop( + version: number, routeNo: Model.RouteNo, minTimestamp: Date, limit: number diff --git a/src/idz/userdb/request/loadTopTen.ts b/src/idz/userdb/request/loadTopTen.ts index aeb60a3..c4a4b1c 100644 --- a/src/idz/userdb/request/loadTopTen.ts +++ b/src/idz/userdb/request/loadTopTen.ts @@ -9,6 +9,7 @@ export interface LoadTopTenRequestSelector { export interface LoadTopTenRequest { type: "load_top_ten_req"; + version: number; field_2: number; selectors: LoadTopTenRequestSelector[]; field_C4: number; diff --git a/src/idz/userdb/sql/timeAttack.ts b/src/idz/userdb/sql/timeAttack.ts index 4b91a05..9ccee59 100644 --- a/src/idz/userdb/sql/timeAttack.ts +++ b/src/idz/userdb/sql/timeAttack.ts @@ -25,6 +25,7 @@ export class SqlTimeAttackRepository implements TimeAttackRepository { constructor(private readonly _txn: Transaction) {} async loadTop( + version: number, routeNo: RouteNo, minTimestamp: Date, limit: number @@ -54,6 +55,7 @@ export class SqlTimeAttackRepository implements TimeAttackRepository { // case that we probably don't need to worry about. .join("idz_team_member tm", { "ta.profile_id": "tm.id" }) .join("idz_team t", { "tm.team_id": "t.id" }) + .where("p.version", version) .where("ta.route_no", routeNo) .where(sql.gt("ta.timestamp", minTimestamp)) .orderBy(["ta.total_time asc", "ta.timestamp asc"])