feat: start of proto only

This commit is contained in:
TrèsAbhi committed 2024-09-28 21:07:00 -05:00
1 parent d90a3cc010
commit 45dc99e1ce
19 files changed
+365 -891

No files matched your search

@@ -1,7 +0,0 @@
import { superDecompress } from './superDecompress';
export async function fetchCdonLz4<Type>(url: string) {
return await fetch(url, { cache: 'no-store' })
.then((response) => response.arrayBuffer())
.then((buffer) => superDecompress<Type>(buffer));
}
-3
View File
@@ -13,7 +13,6 @@ export * from './degressiveStat';
// export * from './emblemURL';
export * from './equipmentDefinitions';
export * from './eventManager';
// export * from './fetchCdonLz4';
// export * from './flagUserActivity';
export * from './gameDefinitions';
// export * from './getArchivedLatestSeasonNumber';
@@ -36,8 +35,6 @@ export * from './resolvePenetrationCoefficient';
export * from './reviews';
export * from './skillDefinitions';
export * from './sum';
export * from './superCompress';
export * from './superDecompress';
export * from './tankDefinitions';
export * from './tankIcon';
export * from './tankNames';
@@ -1,8 +0,0 @@
import { compress } from 'lz4js';
import { CdonWriteStream } from '../streams';
export function superCompress(object: any) {
const write = new CdonWriteStream().cdon(object);
const compressed = compress(write.uint8Array);
return Buffer.from(compressed).toString('base64');
}
@@ -1,8 +0,0 @@
import { decompress } from 'lz4js';
import { CdonReadStream } from '../streams';
export function superDecompress<Type>(buffer: ArrayBuffer) {
const decompressed = decompress(new Uint8Array(buffer)).buffer as ArrayBuffer;
const read = new CdonReadStream(decompressed);
return read.cdon() as Type;
}
@@ -1,10 +1,10 @@
import {
CrewMember,
CrewType,
GunDefinition,
ShellType,
TankClass,
TankType,
Tier,
TreeType,
} from '.';
export const SHELL_NAMES: Record<ShellType, string> = {
@@ -13,7 +13,7 @@ export const SHELL_NAMES: Record<ShellType, string> = {
hc: 'HEAT',
he: 'HE',
};
export const CREW_MEMBER_NAMES: Record<CrewMember, string> = {
export const CREW_MEMBER_NAMES: Record<CrewType, string> = {
commander: 'Commander',
radioman: 'Radioman',
gunner: 'Gunner',
@@ -77,7 +77,7 @@ export const flags: Record<string, string> = {
european: '🇪🇺',
other: '<:other:1218421572243558482>',
};
export const TREE_TYPE_ICONS: Record<TreeType, Record<TankClass, string>> = {
export const TREE_TYPE_ICONS: Record<TankType, Record<TankClass, string>> = {
researchable: TANK_ICONS,
premium: TANK_ICONS_PREMIUM,
collector: TANK_ICONS_COLLECTOR,
@@ -1,27 +1,48 @@
import { Vector2Tuple } from 'three';
import { TANK_CLASSES, TREE_TYPES } from '../../blitz/constants';
import { asset } from '../asset';
import { fetchCdonLz4 } from '../fetchCdonLz4';
import { TIERS } from './constants';
export type TankClass = (typeof TANK_CLASSES)[number];
export type TreeType = (typeof TREE_TYPES)[number];
export enum TankClass {
Unspecified,
Light,
Medium,
Heavy,
TankDestroyer,
}
export enum TankType {
Unspecified,
Researchable,
Premium,
Collector,
}
export enum ShellType {
AP = 'ap',
APCR = 'ap_cr',
HEAT = 'hc',
HE = 'he',
Unspecified,
AP,
APCR,
HEAT,
HE,
}
export enum CrewType {
Unspecified,
Commander,
Radioman,
Gunner,
Driver,
Loader,
}
export type CrewMember =
| 'commander'
| 'radioman'
| 'gunner'
| 'driver'
| 'loader';
export type TankDefinitions = Record<number, TankDefinition>;
export type ModuleType = 'vehicle' | 'engine' | 'chassis' | 'turret' | 'gun';
export enum ModuleType {
Unspecified,
Vehicle,
Engine,
Tracks,
Turret,
Gun,
}
export interface Unlock {
type: ModuleType;
id: number;
@@ -32,9 +53,9 @@ export interface Unlock {
};
}
export interface Crew {
type: CrewMember;
type: CrewType;
count?: number;
substitute?: CrewMember[];
substitute?: CrewType[];
}
export type ModuleDefinition =
| TrackDefinition
@@ -45,18 +66,18 @@ export interface TankDefinition {
id: number;
roles: Record<number, number>;
description?: string;
fixedCamouflage?: boolean;
camouflages?: number[];
ancestors?: number[];
successors?: number[];
fixed_camouflage: boolean;
camouflages: number[];
ancestors: number[];
successors: number[];
crew: Crew[];
health: number;
nation: string;
name: string;
nameFull?: string;
treeType: TreeType;
consumables: number;
provisions: number;
type: TankType;
max_consumables: number;
max_provisions: number;
tier: Tier;
class: TankClass;
testing: boolean;
@@ -66,16 +87,12 @@ export interface TankDefinition {
tracks: TrackDefinition[];
price: TankPrice;
xp?: number;
speed: {
forwards: number;
backwards: number;
};
camouflage: {
still: number;
moving: number;
onFire: number;
};
equipment: string;
speed_forwards: number;
speed_backwards: number;
camouflage_still: number;
camouflage_moving: number;
camouflage_onFire: number;
equipment_preset: string;
weight: number;
}
export interface TrackDefinition {
@@ -83,17 +100,13 @@ export interface TrackDefinition {
tier: Tier;
name: string;
weight: number;
traverseSpeed: number;
traverse_speed: number;
xp?: number;
dispersion: {
move: number;
traverse: number;
};
resistance: {
hard: number;
medium: number;
soft: number;
};
dispersion_move: number;
dispersion_traverse: number;
resistance_hard: number;
resistance_medium: number;
resistance_soft: number;
unlocks?: Unlock[];
}
export interface EngineDefinition {
@@ -101,18 +114,24 @@ export interface EngineDefinition {
name: string;
xp?: number;
tier: Tier;
fireChance: number;
fire_chance: number;
power: number;
weight: number;
unlocks?: Unlock[];
}
export type TankPrice =
| { type: 'credits'; value: number }
| { type: 'gold'; value: number };
export type TankPrice = {
type: TankPriceType;
value: number;
};
enum TankPriceType {
Unspecified,
Credits,
Gold,
}
export interface TurretDefinition {
health: number;
viewRange: number;
traverseSpeed: number;
view_range: number;
traverse_speed: number;
xp?: number;
id: number;
name: string;
@@ -126,52 +145,60 @@ export type GunDefinition =
| GunDefinitionAutoLoader
| GunDefinitionAutoReloader;
interface GunDefinitionBase {
rotationSpeed: number;
rotation_speed: number;
xp?: number;
weight: number;
id: number;
name: string;
tier: Tier;
shells: ShellDefinition[];
camouflageLoss: number;
aimTime: number;
dispersion: {
base: number;
traverse: number;
shot: number;
damaged: number;
};
camouflage_loss: number;
aim_time: number;
dispersion_base: number;
dispersion_traverse: number;
dispersion_shot: number;
dispersion_damaged: number;
unlocks?: Unlock[];
}
interface GunDefinitionRegular extends GunDefinitionBase {
type: 'regular';
interface GunDefinitionRegular {
gun: GunDefinitionBase;
regular: GunDefinitionRegularProperties;
}
interface GunDefinitionRegularProperties {
reload: number;
}
interface GunDefinitionAutoLoader extends GunDefinitionBase {
type: 'autoLoader';
interface GunDefinitionAutoLoader {
gun: GunDefinitionBase;
auto_loader: GunDefinitionAutoLoaderProperties;
}
interface GunDefinitionAutoLoaderProperties {
reload: number;
intraClip: number;
intra_clip: number;
count: number;
}
interface GunDefinitionAutoReloader extends GunDefinitionBase {
type: 'autoReloader';
interface GunDefinitionAutoReloader {
gun: GunDefinitionBase;
auto_reloader: GunDefinitionAutoReloaderProperties;
}
interface GunDefinitionAutoReloaderProperties {
reload: number[];
intraClip: number;
count: number;
}
export type ShellDefinition = {
export interface ShellDefinition {
id: number;
name: string;
speed: number;
damage: { armor: number; module: number };
velocity: number;
armor_damage: number;
module_damage: number;
caliber: number;
icon: string;
penetration: number | Vector2Tuple;
type: ShellType;
normalization?: number;
ricochet?: number;
explosionRadius?: number;
};
explosion_radius?: number;
}
export const tankDefinitions = fetchCdonLz4<TankDefinitions>(
asset('definitions/tanks.cdon.lz4'),
@@ -180,6 +207,18 @@ export const tankDefinitions = fetchCdonLz4<TankDefinitions>(
export const tankDefinitionsArray = tankDefinitions.then((tanks) =>
Object.values(tanks),
);
export type Tier = (typeof TIERS)[number];
export enum Tier {
Unspecified,
I,
II,
III,
IV,
V,
VI,
VII,
VIII,
IX,
X,
}
export * from './constants';
@@ -1,10 +1,11 @@
import protobuf from 'protobufjs';
import average_definitions from '../../protos/average_definitions.proto?raw';
import reviews from '../../protos/reviews.proto?raw';
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 };
const protos = { reviews, average_definitions, tank_definitions };
export function lookupProtobufType(source: ProtoSource, type: string) {
return protobuf.parse(protos[source]).root.lookupType(type);
-375
View File
@@ -1,375 +0,0 @@
import { times } from 'lodash-es';
import { ReadStream, WriteStream } from './buffer';
enum ValueType {
Null,
Boolean,
Uint8,
Uint16,
Uint32,
Uint64,
Int8,
Int16,
Int32,
Int64,
Float32,
Float64,
String,
FastString,
Array,
Object,
}
enum FastStringFormat {
Format8,
Format16,
Format32,
}
export type CdonValue =
| undefined
| null
| boolean
| number
| bigint
| string
| CdonValue[]
| { [key: string]: CdonValue };
export class CdonReadStream extends ReadStream {
cdon() {
this.magic();
const header = this.header();
const body = this.body(header.fastStringFormat, header.stringTable);
return body;
}
magic() {
const magic = this.utf8(4);
if (magic !== 'CDON') {
throw new Error(`Invalid CDON magic number: "${magic}"`);
}
}
header() {
const version = this.uint16();
const fastStringFormat = this.uint8() as FastStringFormat;
return {
version,
fastStringFormat,
stringTable: this.stringTable(fastStringFormat),
};
}
body(
fastStringFormat: FastStringFormat,
stringTable: Record<number, string>,
) {
return this.value(fastStringFormat, stringTable);
}
stringTable(fastStringFormat: FastStringFormat) {
let count: number;
switch (fastStringFormat) {
case FastStringFormat.Format8:
count = this.uint8();
break;
case FastStringFormat.Format16:
count = this.uint16();
break;
case FastStringFormat.Format32:
count = this.uint32();
break;
}
const strings: string[] = [];
for (let index = 0; index < count; index++) {
strings.push(this.string());
}
const table: Record<number, string> = {};
times(count, (index) => (table[index] = strings[index]));
return table;
}
string() {
const length = this.uint32();
const string = this.utf8(length);
return string;
}
value(
fastStringFormat: FastStringFormat,
stringTable: Record<number, string>,
): CdonValue {
const type = this.uint8() as ValueType;
switch (type) {
case ValueType.Null:
return null;
case ValueType.Boolean:
return this.boolean();
case ValueType.Uint8:
return this.uint8();
case ValueType.Uint16:
return this.uint16();
case ValueType.Uint32:
return this.uint32();
case ValueType.Uint64:
return this.uint64();
case ValueType.Int8:
return this.int8();
case ValueType.Int16:
return this.int16();
case ValueType.Int32:
return this.int32();
case ValueType.Int64:
return this.int64();
case ValueType.Float32:
return this.float32();
case ValueType.Float64:
return this.float64();
case ValueType.String:
return this.string();
case ValueType.FastString: {
switch (fastStringFormat) {
case FastStringFormat.Format8:
return stringTable[this.uint8()];
case FastStringFormat.Format16:
return stringTable[this.uint16()];
case FastStringFormat.Format32:
return stringTable[this.uint32()];
}
}
case ValueType.Array:
return times(this.uint32(), () =>
this.value(fastStringFormat, stringTable),
);
case ValueType.Object: {
const count = this.uint32();
const keys = times(
count,
() => this.value(fastStringFormat, stringTable) as string,
);
const values = times(count, () =>
this.value(fastStringFormat, stringTable),
);
const object: Record<string, CdonValue> = {};
keys.forEach((string, index) => (object[string] = values[index]));
return object;
}
default:
throw new Error(`Invalid value type: ${type}`);
}
}
}
export class CdonWriteStream extends WriteStream {
cdon(object: CdonValue) {
this.magic();
const header = this.header(object);
this.body(header.fastStringFormat, object, header.stringTable);
return this;
}
body(
fastStringFormat: FastStringFormat,
object: CdonValue,
stringTable: Map<string, number>,
) {
this.value(fastStringFormat, object, stringTable);
return this;
}
value(
fastStringFormat: FastStringFormat,
object: CdonValue,
stringTable: Map<string, number>,
) {
if (object === null || object === undefined) {
this.uint8(ValueType.Null);
} else if (typeof object === 'boolean') {
this.uint8(ValueType.Boolean);
this.uint8(object ? 1 : 0);
} else if (typeof object === 'number') {
if (object % 1 === 0) {
if (object < 0) {
if (object < -0x80000000) {
this.uint8(ValueType.Int64);
this.int64(BigInt(object));
} else if (object < -0x8000) {
this.uint8(ValueType.Int32);
this.int32(object);
} else if (object < -0x80) {
this.uint8(ValueType.Int16);
this.int16(object);
} else {
this.uint8(ValueType.Int8);
this.int8(object);
}
} else {
if (object > 0x7fffffff) {
this.uint8(ValueType.Uint64);
this.uint64(BigInt(object));
} else if (object > 0x7fff) {
this.uint8(ValueType.Uint32);
this.uint32(object);
} else if (object > 0x7f) {
this.uint8(ValueType.Uint16);
this.uint16(object);
} else {
this.uint8(ValueType.Uint8);
this.uint8(object);
}
}
} else {
if (object < -0x80000000 || object > 0x7fffffff) {
this.uint8(ValueType.Float64);
this.float64(object);
} else {
this.uint8(ValueType.Float32);
this.float32(object);
}
}
} else if (typeof object === 'bigint') {
if (object < 0) {
this.int64(object);
} else {
this.uint64(object);
}
} else if (typeof object === 'string') {
if (stringTable.has(object)) {
this.uint8(ValueType.FastString);
const id = stringTable.get(object)!;
switch (fastStringFormat) {
case FastStringFormat.Format8:
this.uint8(id);
break;
case FastStringFormat.Format16:
this.uint16(id);
break;
case FastStringFormat.Format32:
this.uint32(id);
}
} else {
this.uint8(ValueType.String);
this.string(object);
}
} else if (Array.isArray(object)) {
this.uint8(ValueType.Array);
this.uint32(object.length);
object.forEach((value) =>
this.value(fastStringFormat, value, stringTable),
);
} else {
const entries = Object.entries(object).filter(
([, value]) => value !== undefined,
);
this.uint8(ValueType.Object);
this.uint32(entries.length);
entries.forEach(([key]) =>
this.value(fastStringFormat, key, stringTable),
);
entries.forEach(([, value]) =>
this.value(fastStringFormat, value, stringTable),
);
}
}
header(object: CdonValue) {
this.uint16(1);
return this.stringTable(object);
}
stringTable(object: CdonValue) {
const stringTable = this.buildStringTable(
this.collectStringCounts(object, new Map()),
);
let fastStringFormat: FastStringFormat;
if (stringTable.size <= 0xff) {
fastStringFormat = FastStringFormat.Format8;
this.uint8(FastStringFormat.Format8);
this.uint8(stringTable.size);
} else if (stringTable.size <= 0xffff) {
fastStringFormat = FastStringFormat.Format16;
this.uint8(FastStringFormat.Format16);
this.uint16(stringTable.size);
} else {
fastStringFormat = FastStringFormat.Format32;
this.uint8(FastStringFormat.Format32);
this.uint32(stringTable.size);
}
stringTable.forEach((_index, string) => this.string(string));
return { fastStringFormat, stringTable };
}
buildStringTable(stringCounts: Map<string, number>) {
const stringTable = new Map<string, number>();
stringCounts.forEach((count, string) => {
if (count > 1) stringTable.set(string, stringTable.size);
});
return stringTable;
}
collectStringCounts(object: CdonValue, stringCounts: Map<string, number>) {
if (typeof object === 'string') {
if (stringCounts.has(object)) {
stringCounts.set(object, stringCounts.get(object)! + 1);
} else {
stringCounts.set(object, 1);
}
} else if (object instanceof Array) {
object.forEach((value) => this.collectStringCounts(value, stringCounts));
} else if (object instanceof Object) {
Object.entries(object).forEach((strings) =>
this.collectStringCounts(strings, stringCounts),
);
}
return stringCounts;
}
string(value: string) {
this.uint32(Buffer.byteLength(value));
this.utf8(value);
}
magic() {
this.utf8('CDON');
}
}
-1
View File
@@ -1,6 +1,5 @@
export * from './bkrl';
export * from './buffer';
export * from './cdon';
export * from './dds';
export * from './dids';
export * from './pvr';