mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +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",
|
"betakrieg",
|
||||||
"BINORMAL",
|
"BINORMAL",
|
||||||
"Binormals",
|
"Binormals",
|
||||||
|
"BKRL",
|
||||||
"bkwd",
|
"bkwd",
|
||||||
"blitzstars",
|
"blitzstars",
|
||||||
"Camo",
|
"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
|
# 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).
|
1. JSON compressed as CDON, written directly to disk (a direct 50% reduction).
|
||||||
2. CDON further compressed with LZ4 (a clean 90% reduction).
|
2. CDON further compressed with LZ4 (a clean 90% reduction).
|
||||||
3. The raw JSON file as fetched from a random data source.
|
3. The raw JSON file as fetched from a random data source.
|
||||||
@@ -19,7 +17,7 @@ primary CedillaObjectNotation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Header {
|
Header {
|
||||||
uint16 version;
|
uint16 version; // always 1
|
||||||
FSFormat fsFormat;
|
FSFormat fsFormat;
|
||||||
StringTable<fsFormat> stringTable;
|
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);
|
const magic = this.utf8(4);
|
||||||
|
|
||||||
if (magic !== 'CDON') {
|
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