Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d8d5845c9 | ||
|
|
143f534ba1 | ||
|
|
4db3d94ee8 | ||
|
|
e195cf77cd | ||
|
|
ac9622f1bd | ||
|
|
e8535b1a80 |
Generated
+6
-6
@@ -2614,9 +2614,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"handlebars": {
|
||||
"version": "4.5.1",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz",
|
||||
"integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==",
|
||||
"version": "4.5.3",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
|
||||
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"neo-async": "^2.6.0",
|
||||
@@ -5376,9 +5376,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.6.8",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.8.tgz",
|
||||
"integrity": "sha512-XhHJ3S3ZyMwP8kY1Gkugqx3CJh2C3O0y8NPiSxtm1tyD/pktLAkFZsFGpuNfTZddKDQ/bbDBLAd2YyA1pbi8HQ==",
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.2.tgz",
|
||||
"integrity": "sha512-uhRwZcANNWVLrxLfNFEdltoPNhECUR3lc+UdJoG9CBpMcSnKyWA94tc3eAujB1GcMY5Uwq8ZMp4qWpxWYDQmaA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
|
||||
@@ -82,6 +82,29 @@ create table "cm_user_activity" (
|
||||
)
|
||||
);
|
||||
|
||||
create table "cm_user_course" (
|
||||
"id" integer primary key not null,
|
||||
"profile_id" integer not null
|
||||
references "cm_user_data"("id")
|
||||
on delete cascade,
|
||||
"course_id" integer not null,
|
||||
"class_id" integer not null,
|
||||
"play_count" integer not null,
|
||||
"score_max" integer not null,
|
||||
"is_full_combo" text not null,
|
||||
"is_all_justice" text not null,
|
||||
"is_success" text not null,
|
||||
"score_rank" integer not null,
|
||||
"event_id" integer not null,
|
||||
"last_play_date" text not null,
|
||||
"param1" integer not null,
|
||||
"param2" integer not null,
|
||||
"param3" integer not null,
|
||||
"param4" integer not null,
|
||||
"is_clear" text not null,
|
||||
constraint "cm_user_course_uq" unique ("profile_id", "course_id")
|
||||
);
|
||||
|
||||
create table "cm_user_data_ex" (
|
||||
"id" integer primary key not null
|
||||
references "cm_user_data"("id")
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
-- This was not present in new DBs initialized to schema version 11.
|
||||
create table if not exists "cm_user_course" (
|
||||
"id" integer primary key not null,
|
||||
"profile_id" integer not null
|
||||
references "cm_user_data"("id")
|
||||
on delete cascade,
|
||||
"course_id" integer not null,
|
||||
"class_id" integer not null,
|
||||
"play_count" integer not null,
|
||||
"score_max" integer not null,
|
||||
"is_full_combo" text not null,
|
||||
"is_all_justice" text not null,
|
||||
"is_success" text not null,
|
||||
"score_rank" integer not null,
|
||||
"event_id" integer not null,
|
||||
"last_play_date" text not null,
|
||||
"param1" integer not null,
|
||||
"param2" integer not null,
|
||||
"param3" integer not null,
|
||||
"param4" integer not null,
|
||||
"is_clear" text not null,
|
||||
constraint "cm_user_course_uq" unique ("profile_id", "course_id")
|
||||
);
|
||||
@@ -50,13 +50,13 @@ export function loadTopTen(res: LoadTopTenResponse): Buffer {
|
||||
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.teamName, "shift_jis").copy(buf, innerOff + 0x0028);
|
||||
iconv.encode(row.team.name, "shift_jis").copy(buf, innerOff + 0x0028);
|
||||
iconv.encode(row.shopName, "shift_jis").copy(buf, innerOff + 0x0048);
|
||||
buf.writeUInt32LE(row.field_74, innerOff + 0x0074);
|
||||
buf.writeUInt16LE(row.field_78, innerOff + 0x0078);
|
||||
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 fucking nothing what
|
||||
// 66 bytes of empty space at the end. Maybe a string used to live here?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ export async function loadTopTen(
|
||||
}
|
||||
|
||||
const { routeNo, minTimestamp } = selector;
|
||||
const src = await w.timeAttack().loadTopTen(routeNo, minTimestamp);
|
||||
const src = await w.timeAttack().loadTop(routeNo, minTimestamp, 10);
|
||||
|
||||
if (src.length === 0) {
|
||||
continue;
|
||||
@@ -33,10 +33,8 @@ export async function loadTopTen(
|
||||
field_0F: false,
|
||||
field_10: 0,
|
||||
driverName: srcItem.driverName,
|
||||
teamName: process.env.TEAM_NAME || "",
|
||||
shopName: process.env.SHOP_NAME || "",
|
||||
field_74: 0,
|
||||
field_78: 0,
|
||||
team: srcItem.team,
|
||||
field_7C: 0,
|
||||
field_7D: 0,
|
||||
ta: srcItem.ta,
|
||||
|
||||
+4
-2
@@ -111,13 +111,15 @@ export interface TeamReservationRepository {
|
||||
// TODO extend and factorize
|
||||
export interface TopTenResult {
|
||||
driverName: string;
|
||||
team: Model.Team;
|
||||
ta: Model.TimeAttackScore;
|
||||
}
|
||||
|
||||
export interface TimeAttackRepository {
|
||||
loadTopTen(
|
||||
loadTop(
|
||||
routeNo: Model.RouteNo,
|
||||
minTimestamp: Date
|
||||
minTimestamp: Date,
|
||||
limit: number
|
||||
): Promise<TopTenResult[]>;
|
||||
|
||||
loadAll(profileId: Id<Model.Profile>): Promise<Model.TimeAttackScore[]>;
|
||||
|
||||
@@ -7,10 +7,12 @@ export interface LoadTopTenResponseRow {
|
||||
field_0F: boolean;
|
||||
field_10: number;
|
||||
driverName: string;
|
||||
teamName: string;
|
||||
shopName: string;
|
||||
field_74: number;
|
||||
field_78: number;
|
||||
team: {
|
||||
name: string;
|
||||
nameBg: number;
|
||||
nameFx: number;
|
||||
};
|
||||
field_7C: number;
|
||||
field_7D: number;
|
||||
ta: TimeAttackScore;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import sql from "sql-bricks-postgres";
|
||||
|
||||
import { RouteNo } from "../model/base";
|
||||
import { ExtId, RouteNo } from "../model/base";
|
||||
import { CarSelector } from "../model/car";
|
||||
import { Team } from "../model/team";
|
||||
import { Profile } from "../model/profile";
|
||||
import { TimeAttackScore } from "../model/timeAttack";
|
||||
import { TimeAttackRepository, TopTenResult } from "../repo";
|
||||
@@ -23,23 +24,51 @@ function _extractRow(row: Row): TimeAttackScore {
|
||||
export class SqlTimeAttackRepository implements TimeAttackRepository {
|
||||
constructor(private readonly _txn: Transaction) {}
|
||||
|
||||
async loadTopTen(
|
||||
async loadTop(
|
||||
routeNo: RouteNo,
|
||||
minTimestamp: Date
|
||||
minTimestamp: Date,
|
||||
limit: number
|
||||
): Promise<TopTenResult[]> {
|
||||
// We're not using an ORM here so this join-heavy SQL is unfortunately
|
||||
// going to be a boilerplated mess.
|
||||
|
||||
const loadSql = sql
|
||||
.select("p.name", "ta.*")
|
||||
.select(
|
||||
// Profile
|
||||
"p.name as profile_name",
|
||||
// Team
|
||||
"t.ext_id as team_ext_id",
|
||||
"t.name as team_name",
|
||||
"t.name_bg as team_name_bg",
|
||||
"t.name_fx as team_name_fx",
|
||||
"t.register_time as team_register_time",
|
||||
// Time Attack
|
||||
"ta.*"
|
||||
)
|
||||
.from("idz_ta_best ta")
|
||||
.join("idz_profile p", { "ta.profile_id": "p.id" })
|
||||
// This is an inner join, so it will exclude anybody who is not currently
|
||||
// a member of a team from the leader boards. Since the only way to play
|
||||
// without a team is to be ejected from one we can consider this an edge
|
||||
// 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("ta.route_no", routeNo)
|
||||
.where(sql.gt("ta.timestamp", minTimestamp))
|
||||
.orderBy(["ta.total_time asc", "ta.timestamp asc"])
|
||||
.limit(10);
|
||||
.limit(limit);
|
||||
|
||||
const rows = await this._txn.fetchRows(loadSql);
|
||||
|
||||
return rows.map(row => ({
|
||||
driverName: row.name,
|
||||
driverName: row.profile_name,
|
||||
team: {
|
||||
extId: parseInt(row.team_ext_id) as ExtId<Team>,
|
||||
name: row.team_name,
|
||||
nameBg: parseInt(row.team_name_bg),
|
||||
nameFx: parseInt(row.team_name_fx),
|
||||
registerTime: new Date(row.team_register_time),
|
||||
},
|
||||
ta: _extractRow(row),
|
||||
}));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user