feat: transition to protobug

This commit is contained in:
TrèsAbhi committed 2024-09-29 20:56:52 -05:00
1 parent 45dc99e1ce
commit 370ef2df65
16 files changed
+105 -387

No files matched your search

+1
View File
@@ -22,3 +22,4 @@ depots
public/sitemap*
/firebase.json
target
packages/core/src/protos/generated/*
BIN
View File
Binary file not shown.
@@ -1,41 +1,6 @@
import { decodeProtobuf } from '../../protobuf/decodeProtobuf';
import { BlitzkitStats } from '../../statistics';
import { AverageDefinitions } from '../../protos';
import { asset } from '../asset';
export interface AverageDefinitionsEntry {
mu: BlitzkitStats;
sigma: BlitzkitStats;
r: BlitzkitStats;
samples: Samples;
}
export interface AverageDefinitionsEntrySubPartial {
mu: Partial<BlitzkitStats>;
sigma: Partial<BlitzkitStats>;
r: Partial<BlitzkitStats>;
samples: Samples;
}
export interface AverageDefinitionsEntryWithId extends AverageDefinitionsEntry {
id: number;
}
export interface AverageDefinitions {
averages: Record<number, AverageDefinitionsEntry>;
samples: Samples;
time: number;
}
export interface Samples {
d_1: number;
d_7: number;
d_30: number;
d_60: number;
d_90: number;
d_120: number;
total: number;
}
export interface AverageDefinitionsManifest {
version: 1;
/**
@@ -44,30 +9,18 @@ export interface AverageDefinitionsManifest {
latest: number;
}
export const averageDefinitions = fetch(asset('averages/manifest.json'), {
cache: 'no-store',
})
.then((response) => response.json() as Promise<AverageDefinitionsManifest>)
.then((manifest) => fetch(asset(`averages/${manifest.latest}.pb`)))
.then((response) => response.arrayBuffer())
.then((buffer) =>
decodeProtobuf<AverageDefinitions>(
'average_definitions',
'blitzkit.AverageDefinitions',
new Uint8Array(buffer),
),
export async function fetchAverageDefinitions() {
const manifestResponse = await fetch(asset('averages/manifest.json'));
const manifestJson =
(await manifestResponse.json()) as AverageDefinitionsManifest;
const averageDefinitionsResponse = await fetch(
asset(`averages/${manifestJson.latest}.pb`),
);
const averageDefinitionsBuffer =
await averageDefinitionsResponse.arrayBuffer();
const averageDefinitionsArray = new Uint8Array(averageDefinitionsBuffer);
export const averageDefinitionsArray = averageDefinitions.then((data) =>
Object.entries(data.averages)
.map(
([key, value]) =>
({
id: Number(key),
...(value as AverageDefinitionsEntry),
}) satisfies AverageDefinitionsEntryWithId,
)
.filter((tank) => tank.mu.battles > 0),
);
return AverageDefinitions.deserializeBinary(averageDefinitionsArray);
}
export * from './constants';
+6 -22
View File
@@ -1,26 +1,10 @@
import { decodeProtobuf } from '../protobuf';
import { Reviews } from '../protos';
import { asset } from './asset';
export interface Reviews {
reviews: Record<number, Review>;
}
export async function fetchReviews() {
const response = await fetch(asset('definitions/reviews.pb'));
const buffer = await response.arrayBuffer();
const array = new Uint8Array(buffer);
interface Review {
last_updated: number;
videos?: Video[];
return Reviews.deserializeBinary(array);
}
export interface Video {
id: string;
author: string;
}
export const reviews = fetch(asset('definitions/reviews.pb'))
.then((response) => response.arrayBuffer())
.then((buffer) =>
decodeProtobuf<Reviews>(
'reviews',
'blitzkit.Reviews',
new Uint8Array(buffer),
),
);
@@ -1,224 +1,12 @@
import { Vector2Tuple } from 'three';
import { TankDefinitions } from '../../protos';
import { asset } from '../asset';
import { fetchCdonLz4 } from '../fetchCdonLz4';
export enum TankClass {
Unspecified,
Light,
Medium,
Heavy,
TankDestroyer,
}
export enum TankType {
Unspecified,
Researchable,
Premium,
Collector,
}
export async function fetchTankDefinitions() {
const response = await fetch(asset('definitions/tanks.pb'));
const buffer = await response.arrayBuffer();
const array = new Uint8Array(buffer);
export enum ShellType {
Unspecified,
AP,
APCR,
HEAT,
HE,
}
export enum CrewType {
Unspecified,
Commander,
Radioman,
Gunner,
Driver,
Loader,
}
export type TankDefinitions = Record<number, TankDefinition>;
export enum ModuleType {
Unspecified,
Vehicle,
Engine,
Tracks,
Turret,
Gun,
}
export interface Unlock {
type: ModuleType;
id: number;
cost: {
// string being the season coins
type: 'xp' | string;
value: number;
};
}
export interface Crew {
type: CrewType;
count?: number;
substitute?: CrewType[];
}
export type ModuleDefinition =
| TrackDefinition
| EngineDefinition
| TurretDefinition
| GunDefinition;
export interface TankDefinition {
id: number;
roles: Record<number, number>;
description?: string;
fixed_camouflage: boolean;
camouflages: number[];
ancestors: number[];
successors: number[];
crew: Crew[];
health: number;
nation: string;
name: string;
nameFull?: string;
type: TankType;
max_consumables: number;
max_provisions: number;
tier: Tier;
class: TankClass;
testing: boolean;
deprecated: boolean;
turrets: TurretDefinition[];
engines: EngineDefinition[];
tracks: TrackDefinition[];
price: TankPrice;
xp?: number;
speed_forwards: number;
speed_backwards: number;
camouflage_still: number;
camouflage_moving: number;
camouflage_onFire: number;
equipment_preset: string;
weight: number;
}
export interface TrackDefinition {
id: number;
tier: Tier;
name: string;
weight: number;
traverse_speed: number;
xp?: number;
dispersion_move: number;
dispersion_traverse: number;
resistance_hard: number;
resistance_medium: number;
resistance_soft: number;
unlocks?: Unlock[];
}
export interface EngineDefinition {
id: number;
name: string;
xp?: number;
tier: Tier;
fire_chance: number;
power: number;
weight: number;
unlocks?: Unlock[];
}
export type TankPrice = {
type: TankPriceType;
value: number;
};
enum TankPriceType {
Unspecified,
Credits,
Gold,
}
export interface TurretDefinition {
health: number;
view_range: number;
traverse_speed: number;
xp?: number;
id: number;
name: string;
tier: Tier;
guns: GunDefinition[];
weight: number;
unlocks?: Unlock[];
}
export type GunDefinition =
| GunDefinitionRegular
| GunDefinitionAutoLoader
| GunDefinitionAutoReloader;
interface GunDefinitionBase {
rotation_speed: number;
xp?: number;
weight: number;
id: number;
name: string;
tier: Tier;
shells: ShellDefinition[];
camouflage_loss: number;
aim_time: number;
dispersion_base: number;
dispersion_traverse: number;
dispersion_shot: number;
dispersion_damaged: number;
unlocks?: Unlock[];
}
interface GunDefinitionRegular {
gun: GunDefinitionBase;
regular: GunDefinitionRegularProperties;
}
interface GunDefinitionRegularProperties {
reload: number;
}
interface GunDefinitionAutoLoader {
gun: GunDefinitionBase;
auto_loader: GunDefinitionAutoLoaderProperties;
}
interface GunDefinitionAutoLoaderProperties {
reload: number;
intra_clip: number;
count: number;
}
interface GunDefinitionAutoReloader {
gun: GunDefinitionBase;
auto_reloader: GunDefinitionAutoReloaderProperties;
}
interface GunDefinitionAutoReloaderProperties {
reload: number[];
intraClip: number;
count: number;
}
export interface ShellDefinition {
id: number;
name: string;
velocity: number;
armor_damage: number;
module_damage: number;
caliber: number;
icon: string;
penetration: number | Vector2Tuple;
type: ShellType;
normalization?: number;
ricochet?: number;
explosion_radius?: number;
}
export const tankDefinitions = fetchCdonLz4<TankDefinitions>(
asset('definitions/tanks.cdon.lz4'),
);
export const tankDefinitionsArray = tankDefinitions.then((tanks) =>
Object.values(tanks),
);
export enum Tier {
Unspecified,
I,
II,
III,
IV,
V,
VI,
VII,
VIII,
IX,
X,
return TankDefinitions.deserializeBinary(array);
}
export * from './constants';
+1 -1
View File
@@ -1,11 +1,11 @@
export * from './blitz';
export * from './blitzkit';
export * from './protos';
// export * from './blitzstars';
// export * from './databases';
export * from './imgur';
export * from './math';
export * from './patreon';
// export * from './protobuf';
export * from './statistics';
// export * from './streams';
// export * from './types';
@@ -1,9 +0,0 @@
import { lookupProtobufType, ProtoSource } from './lookupProtobufType';
export function decodeProtobuf<Type>(
source: ProtoSource,
type: string,
data: Uint8Array,
) {
return lookupProtobufType(source, type).decode(data).toJSON() as Type;
}
@@ -1,14 +0,0 @@
import { lookupProtobufType, ProtoSource } from './lookupProtobufType';
export function encodeProtobuf(
source: ProtoSource,
type: string,
data: Record<string, any>,
) {
const message = lookupProtobufType(source, type);
const verification = message.verify(data);
if (verification !== null) throw new Error(verification);
return message.encode(message.create(data)).finish();
}
@@ -1,11 +0,0 @@
import { encodeProtobuf } from './encodeProtobuf';
import { ProtoSource } from './lookupProtobufType';
export async function encodeProtobufToBase64(
source: ProtoSource,
type: string,
data: any,
) {
const array = encodeProtobuf(source, type, data);
return Buffer.from(array).toString('base64');
}
-4
View File
@@ -1,4 +0,0 @@
export * from './decodeProtobuf';
export * from './encodeProtobuf';
export * from './encodeProtobufToBase64';
export * from './lookupProtobufType';
@@ -1,12 +0,0 @@
import protobuf from 'protobufjs';
import average_definitions from '../../protos/average_definitions.proto';
import reviews from '../../protos/reviews.proto';
import tank_definitions from '../../protos/tank_definitions.proto';
export type ProtoSource = keyof typeof protos;
const protos = { reviews, average_definitions, tank_definitions };
export function lookupProtobufType(source: ProtoSource, type: string) {
return protobuf.parse(protos[source]).root.lookupType(type);
}
+1
View File
@@ -0,0 +1 @@
export * from './generated';
@@ -41,9 +41,9 @@ message TankDefinition {
}
enum TankPriceType {
TYPE_UNSPECIFIED = 0;
TYPE_CREDITS = 1;
TYPE_GOLD = 2;
TANK_PRICE_TYPE_UNSPECIFIED = 0;
TANK_PRICE_TYPE_CREDITS = 1;
TANK_PRICE_TYPE_GOLD = 2;
}
message TankPrice {
@@ -103,16 +103,32 @@ message GunDefinitionRegular {
GunDefinitionRegularProperties regular = 2;
}
message GunDefinitionRegularProperties {
float reload = 1;
}
message GunDefinitionAutoLoader {
GunDefinitionBase gun = 1;
GunDefinitionAutoLoaderProperties auto_loader = 2;
}
message GunDefinitionAutoLoaderProperties {
float clip_reload = 1;
float intra_clip = 2;
float shell_count = 3;
}
message GunDefinitionAutoReloader {
GunDefinitionBase gun = 1;
GunDefinitionAutoReloaderProperties auto_reloader = 2;
}
message GunDefinitionAutoReloaderProperties {
repeated float shell_reloads = 1;
float intra_clip = 2;
float shell_count = 3;
}
message GunDefinitionBase {
uint32 id = 1;
float rotation_speed = 2;
@@ -146,11 +162,11 @@ message ShellDefinition {
}
enum ShellType {
SHELL_UNSPECIFIED = 0;
SHELL_AP = 1;
SHELL_APCR = 2;
SHELL_HEAT = 3;
SHELL_HE = 4;
SHELL_TYPE_UNSPECIFIED = 0;
SHELL_TYPE_AP = 1;
SHELL_TYPE_APCR = 2;
SHELL_TYPE_HEAT = 3;
SHELL_TYPE_HE = 4;
}
message ShellPenetration {
@@ -170,20 +186,20 @@ message UnlockCost {
}
enum ModuleType {
MODULE_UNSPECIFIED = 0;
MODULE_VEHICLE = 1;
MODULE_ENGINE = 2;
MODULE_TRACKS = 3;
MODULE_TURRET = 4;
MODULE_GUN = 5;
MODULE_TYPE_UNSPECIFIED = 0;
MODULE_TYPE_VEHICLE = 1;
MODULE_TYPE_ENGINE = 2;
MODULE_TYPE_TRACKS = 3;
MODULE_TYPE_TURRET = 4;
MODULE_TYPE_GUN = 5;
}
enum TankClass {
CLASS_UNSPECIFIED = 0;
CLASS_LIGHT = 1;
CLASS_MEDIUM = 2;
CLASS_HEAVY = 3;
CLASS_TANK_DESTROYER = 4;
TANK_CLASS_UNSPECIFIED = 0;
TANK_CLASS_LIGHT = 1;
TANK_CLASS_MEDIUM = 2;
TANK_CLASS_HEAVY = 3;
TANK_CLASS_TANK_DESTROYER = 4;
}
enum Tier {
@@ -201,10 +217,10 @@ enum Tier {
}
enum TankType {
TYPE_UNSPECIFIED = 0;
TYPE_RESEARCHABLE = 1;
TYPE_PREMIUM = 2;
TYPE_COLLECTOR = 3;
TANK_TYPE_UNSPECIFIED = 0;
TANK_TYPE_RESEARCHABLE = 1;
TANK_TYPE_PREMIUM = 2;
TANK_TYPE_COLLECTOR = 3;
}
message Crew {
@@ -214,10 +230,10 @@ message Crew {
}
enum CrewType {
CREW_UNSPECIFIED = 0;
CREW_COMMANDER = 1;
CREW_RADIOMAN = 2;
CREW_GUNNER = 3;
CREW_DRIVER = 4;
CREW_LOADER = 5;
CREW_TYPE_UNSPECIFIED = 0;
CREW_TYPE_COMMANDER = 1;
CREW_TYPE_RADIOMAN = 2;
CREW_TYPE_GUNNER = 3;
CREW_TYPE_DRIVER = 4;
CREW_TYPE_LOADER = 5;
}
+33 -8
View File
@@ -1,16 +1,41 @@
import { $ } from 'bun';
import { readdir } from 'fs/promises';
import { exec as execSync } from 'child_process';
import { existsSync } from 'fs';
import { cp, mkdir, readdir, rm, writeFile } from 'fs/promises';
import { promisify } from 'util';
const ROOT = 'packages/core/protos';
const ROOT = 'packages/core/src/protos';
const exec = promisify(execSync);
let executableFileExtension: string;
if (existsSync('node_modules/.bin/protoc-gen-ts.exe')) {
executableFileExtension = '.exe';
} else {
executableFileExtension = '';
}
const files = await readdir(`${ROOT}/raw`);
const args = [
'--plugin="./node_modules/.bin/protoc-gen-ts"',
'--js_out="import_style=commonjs,binary:${OUT_DIR}"',
`--ts_out="${ROOT}/generated"`,
`--plugin="protoc-gen-ts=./node_modules/.bin/protoc-gen-ts${executableFileExtension}"`,
'--ts_opt=esModuleInterop=true',
`--js_out="import_style=commonjs,binary:./${ROOT}/generated"`,
`--ts_out="./${ROOT}/generated"`,
...files.map((file) => `${ROOT}/raw/${file}`),
];
console.log(`protoc ${args.join(' ')}`);
await rm(`${ROOT}/generated`, { recursive: true, force: true });
await mkdir(`${ROOT}/generated`, { recursive: true });
await exec(`protoc ${args.join(' ')}`);
await cp(`${ROOT}/generated/${ROOT}/raw`, `${ROOT}/generated`, {
recursive: true,
});
await rm(`${ROOT}/generated/packages`, { recursive: true, force: true });
console.log(await $`protoc ${args.join(' ')}`.text());
await writeFile(
`${ROOT}/generated/index.ts`,
files
.map((file) => file.replace('.proto', ''))
.map((file) => `export * from './${file}_pb';`)
.join('\n'),
);