mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 02:37:05 +02:00
feat: ratings leaderboard disk format
This commit is contained in:
1 parent
c8edd16eb3
commit
1c03701e17
5 files changed
+210
-4
No files matched your search
Vendored
+1
@@ -16,6 +16,7 @@
|
||||
"betakrieg",
|
||||
"BINORMAL",
|
||||
"Binormals",
|
||||
"BKRL",
|
||||
"bkwd",
|
||||
"blitzstars",
|
||||
"Camo",
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
# Blitzkrieg Ratings Leaderboard
|
||||
|
||||
A straightforward way of storing the entire World of Tanks Blitz ratings leaderboard to disk.
|
||||
|
||||
```cpp
|
||||
primary BlitzkriegRatingsLeaderboard {
|
||||
utf8"BKRL" magic;
|
||||
Header header;
|
||||
primary Body<header> body;
|
||||
}
|
||||
|
||||
Header {
|
||||
uint16 version; // always 1
|
||||
Format format;
|
||||
uint32 count;
|
||||
}
|
||||
|
||||
Format enum<uint8> {
|
||||
Minimal,
|
||||
Comprehensive1,
|
||||
}
|
||||
|
||||
Body<Header header> match<header.format> {
|
||||
Minimal {
|
||||
primary {
|
||||
uint32 id;
|
||||
uint16 score;
|
||||
}[header.count] entries;
|
||||
};
|
||||
|
||||
Comprehensive1 {
|
||||
primary {
|
||||
uint32 id;
|
||||
uint16 score;
|
||||
|
||||
uint32 battles;
|
||||
uint32 wins;
|
||||
uint32 survived;
|
||||
|
||||
uint32 damageDealt;
|
||||
uint32 damageReceived;
|
||||
|
||||
uint32 shots;
|
||||
uint32 hits;
|
||||
|
||||
uint32 kills;
|
||||
}[header.count] entries;
|
||||
};
|
||||
}
|
||||
```
|
||||
+1
-3
@@ -1,7 +1,5 @@
|
||||
# Cedilla Object Notation
|
||||
|
||||
This documentation uses an experimental binary notation syntax called "Buffer Up".
|
||||
|
||||
1. JSON compressed as CDON, written directly to disk (a direct 50% reduction).
|
||||
2. CDON further compressed with LZ4 (a clean 90% reduction).
|
||||
3. The raw JSON file as fetched from a random data source.
|
||||
@@ -19,7 +17,7 @@ primary CedillaObjectNotation {
|
||||
}
|
||||
|
||||
Header {
|
||||
uint16 version;
|
||||
uint16 version; // always 1
|
||||
FSFormat fsFormat;
|
||||
StringTable<fsFormat> stringTable;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
import { times } from 'lodash';
|
||||
import { ReadStream, WriteStream } from './buffer';
|
||||
|
||||
enum Format {
|
||||
Minimal,
|
||||
Comprehensive1,
|
||||
}
|
||||
|
||||
interface BkrlMinimalEntry {
|
||||
id: number;
|
||||
score: number;
|
||||
}
|
||||
|
||||
interface BkrlComprehensive1Entry {
|
||||
id: number;
|
||||
score: number;
|
||||
|
||||
battles: number;
|
||||
wins: number;
|
||||
survived: number;
|
||||
|
||||
damageDealt: number;
|
||||
damageReceived: number;
|
||||
|
||||
shots: number;
|
||||
hits: number;
|
||||
|
||||
kills: number;
|
||||
}
|
||||
|
||||
type DiscriminatedEntries =
|
||||
| {
|
||||
format: Format.Minimal;
|
||||
entries: BkrlMinimalEntry[];
|
||||
}
|
||||
| {
|
||||
format: Format.Comprehensive1;
|
||||
entries: BkrlComprehensive1Entry[];
|
||||
};
|
||||
|
||||
export class BkrlReadStream extends ReadStream {
|
||||
bkrl() {
|
||||
this.magic();
|
||||
const header = this.header();
|
||||
return this.body(header);
|
||||
}
|
||||
|
||||
body(header: ReturnType<typeof this.header>): DiscriminatedEntries {
|
||||
switch (header.format) {
|
||||
case Format.Minimal: {
|
||||
return {
|
||||
format: Format.Minimal,
|
||||
entries: times(
|
||||
header.count,
|
||||
() =>
|
||||
({
|
||||
id: this.uint32(),
|
||||
score: this.uint16(),
|
||||
}) satisfies BkrlMinimalEntry,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
case Format.Comprehensive1: {
|
||||
return {
|
||||
format: Format.Comprehensive1,
|
||||
entries: times(
|
||||
header.count,
|
||||
() =>
|
||||
({
|
||||
id: this.uint32(),
|
||||
score: this.uint16(),
|
||||
|
||||
battles: this.uint32(),
|
||||
wins: this.uint32(),
|
||||
survived: this.uint32(),
|
||||
|
||||
damageDealt: this.uint32(),
|
||||
damageReceived: this.uint32(),
|
||||
|
||||
shots: this.uint32(),
|
||||
hits: this.uint32(),
|
||||
|
||||
kills: this.uint32(),
|
||||
}) satisfies BkrlComprehensive1Entry,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header() {
|
||||
return {
|
||||
version: this.uint16(),
|
||||
format: this.uint8() as Format,
|
||||
count: this.uint32(),
|
||||
};
|
||||
}
|
||||
|
||||
magic() {
|
||||
const magic = this.utf8(4);
|
||||
|
||||
if (magic !== 'BKRL') {
|
||||
throw new Error(`Invalid BKRL magic number: "${magic}"`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class BkrlWriteStream extends WriteStream {
|
||||
bkrl(discriminatedEntries: DiscriminatedEntries) {
|
||||
this.magic();
|
||||
this.header(discriminatedEntries);
|
||||
this.body(discriminatedEntries);
|
||||
}
|
||||
|
||||
body(discriminatedEntries: DiscriminatedEntries) {
|
||||
switch (discriminatedEntries.format) {
|
||||
case Format.Minimal: {
|
||||
discriminatedEntries.entries.forEach((entry) => {
|
||||
this.uint32(entry.id);
|
||||
this.uint16(entry.score);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case Format.Comprehensive1: {
|
||||
discriminatedEntries.entries.forEach((entry) => {
|
||||
this.uint32(entry.id);
|
||||
this.uint16(entry.score);
|
||||
|
||||
this.uint32(entry.battles);
|
||||
this.uint32(entry.wins);
|
||||
this.uint32(entry.survived);
|
||||
|
||||
this.uint32(entry.damageDealt);
|
||||
this.uint32(entry.damageReceived);
|
||||
|
||||
this.uint32(entry.shots);
|
||||
this.uint32(entry.hits);
|
||||
|
||||
this.uint32(entry.kills);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header(discriminatedEntries: DiscriminatedEntries) {
|
||||
this.uint16(1);
|
||||
this.uint8(discriminatedEntries.format);
|
||||
this.uint32(discriminatedEntries.entries.length);
|
||||
}
|
||||
|
||||
magic() {
|
||||
this.utf8('BKRL');
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ export class CdonReadStream extends ReadStream {
|
||||
const magic = this.utf8(4);
|
||||
|
||||
if (magic !== 'CDON') {
|
||||
throw new Error(`Invalid Cdon magic number: "${magic}"`);
|
||||
throw new Error(`Invalid CDON magic number: "${magic}"`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user