mirror of
https://github.com/demostf/demo.js
synced 2026-06-04 00:54:14 +02:00
handle string table compression
This commit is contained in:
parent
a771702307
commit
31440704d6
5 changed files with 31 additions and 7 deletions
|
|
@ -7,6 +7,7 @@ export interface StringTable {
|
||||||
fixedUserDataSize?: number;
|
fixedUserDataSize?: number;
|
||||||
fixedUserDataSizeBits?: number;
|
fixedUserDataSizeBits?: number;
|
||||||
clientEntries?: StringTableEntry[];
|
clientEntries?: StringTableEntry[];
|
||||||
|
compressed: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StringTableEntry {
|
export interface StringTableEntry {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ export const StringTableHandler: MessageHandler<StringTablesMessage> = {
|
||||||
entries,
|
entries,
|
||||||
name: tableName,
|
name: tableName,
|
||||||
maxEntries: entryCount,
|
maxEntries: entryCount,
|
||||||
clientEntries: []
|
clientEntries: [],
|
||||||
|
compressed: false
|
||||||
};
|
};
|
||||||
|
|
||||||
if (messageStream.readBoolean()) {
|
if (messageStream.readBoolean()) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import {CreateStringTablePacket} from '../../Data/Packet';
|
||||||
import {logBase2} from '../../Math';
|
import {logBase2} from '../../Math';
|
||||||
import {readVarInt, writeVarInt} from '../readBitVar';
|
import {readVarInt, writeVarInt} from '../readBitVar';
|
||||||
|
|
||||||
import {uncompress} from 'snappyjs';
|
import {uncompress, compress} from 'snappyjs';
|
||||||
import {StringTable} from '../../Data/StringTable';
|
import {StringTable} from '../../Data/StringTable';
|
||||||
import {encodeStringTableEntries, guessStringTableEntryLength, parseStringTableEntries} from '../StringTableParser';
|
import {encodeStringTableEntries, guessStringTableEntryLength, parseStringTableEntries} from '../StringTableParser';
|
||||||
|
|
||||||
|
|
@ -53,7 +53,8 @@ export function ParseCreateStringTable(stream: BitStream): CreateStringTablePack
|
||||||
entries: [],
|
entries: [],
|
||||||
maxEntries,
|
maxEntries,
|
||||||
fixedUserDataSize: userDataSize,
|
fixedUserDataSize: userDataSize,
|
||||||
fixedUserDataSizeBits: userDataSizeBits
|
fixedUserDataSizeBits: userDataSizeBits,
|
||||||
|
compressed: isCompressed
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log(`${tableName} ${entityCount} ${bitCount}`);
|
// console.log(`${tableName} ${entityCount} ${bitCount}`);
|
||||||
|
|
@ -72,9 +73,20 @@ export function EncodeCreateStringTable(packet: CreateStringTablePacket, stream:
|
||||||
const numEntries = packet.table.entries.filter((entry) => entry).length;
|
const numEntries = packet.table.entries.filter((entry) => entry).length;
|
||||||
stream.writeBits(numEntries, encodeBits + 1);
|
stream.writeBits(numEntries, encodeBits + 1);
|
||||||
|
|
||||||
const entryData = new BitStream(new ArrayBuffer(guessStringTableEntryLength(packet.table, packet.table.entries)));
|
let entryData = new BitStream(new ArrayBuffer(guessStringTableEntryLength(packet.table, packet.table.entries)));
|
||||||
encodeStringTableEntries(entryData, packet.table, packet.table.entries);
|
encodeStringTableEntries(entryData, packet.table, packet.table.entries);
|
||||||
|
|
||||||
|
if (packet.table.compressed) {
|
||||||
|
const decompressedByteLength = Math.ceil(entryData.length / 8);
|
||||||
|
entryData.index = 0;
|
||||||
|
const compressedData = compress(entryData.readArrayBuffer(decompressedByteLength));
|
||||||
|
entryData = new BitStream(new ArrayBuffer(decompressedByteLength));
|
||||||
|
entryData.writeUint32(decompressedByteLength);
|
||||||
|
entryData.writeUint32(compressedData.byteLength + 4); // 4 magic bytes
|
||||||
|
entryData.writeASCIIString('SNAP', 4);
|
||||||
|
let typeForce: any = compressedData.buffer;
|
||||||
|
entryData.writeArrayBuffer(typeForce as BitStream);
|
||||||
|
}
|
||||||
const entryLength = entryData.index;
|
const entryLength = entryData.index;
|
||||||
entryData.index = 0;
|
entryData.index = 0;
|
||||||
|
|
||||||
|
|
@ -88,8 +100,7 @@ export function EncodeCreateStringTable(packet: CreateStringTablePacket, stream:
|
||||||
stream.writeBoolean(false);
|
stream.writeBoolean(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we never compress table data
|
stream.writeBoolean(packet.table.compressed);
|
||||||
stream.writeBoolean(false);
|
|
||||||
|
|
||||||
if (entryLength) {
|
if (entryLength) {
|
||||||
stream.writeBitStream(entryData, entryLength);
|
stream.writeBitStream(entryData, entryLength);
|
||||||
|
|
|
||||||
BIN
src/tests/data/packetMessageFirst.bin
Normal file
BIN
src/tests/data/packetMessageFirst.bin
Normal file
Binary file not shown.
|
|
@ -3,9 +3,10 @@ import {readFileSync} from 'fs';
|
||||||
import {PacketTypeId} from '../../../../Data/Packet';
|
import {PacketTypeId} from '../../../../Data/Packet';
|
||||||
import {ParserState} from '../../../../Data/ParserState';
|
import {ParserState} from '../../../../Data/ParserState';
|
||||||
import {PacketMessageHandler} from '../../../../Parser/Message/Packet';
|
import {PacketMessageHandler} from '../../../../Parser/Message/Packet';
|
||||||
import {assertEncoder, assertParser, getStream} from '../Packet/PacketTest';
|
import {assertEncoder, assertParser, assertReEncode, getStream} from '../Packet/PacketTest';
|
||||||
|
|
||||||
const data = Object.values(JSON.parse(readFileSync(__dirname + '/../../../data/packetMessageData.json', 'utf8')));
|
const data = Object.values(JSON.parse(readFileSync(__dirname + '/../../../data/packetMessageData.json', 'utf8')));
|
||||||
|
const firstPacketData = readFileSync(__dirname + '/../../../data/packetMessageFirst.bin');
|
||||||
const expected = JSON.parse(readFileSync(__dirname + '/../../../data/packetMessageResult.json', 'utf8'));
|
const expected = JSON.parse(readFileSync(__dirname + '/../../../data/packetMessageResult.json', 'utf8'));
|
||||||
|
|
||||||
const getParserState = (fastMode) => {
|
const getParserState = (fastMode) => {
|
||||||
|
|
@ -40,4 +41,14 @@ suite('Packet', () => {
|
||||||
// shorted since empty entity list encoded, instead of skipping over entities
|
// shorted since empty entity list encoded, instead of skipping over entities
|
||||||
assertEncoder(parser, encoder, expected, 920, '');
|
assertEncoder(parser, encoder, expected, 920, '');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Encode first packet message', () => {
|
||||||
|
const expected = parser(new BitStream(firstPacketData));
|
||||||
|
assertEncoder(parser, encoder, expected, 1512600, '');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Re-encode packet message', () => {
|
||||||
|
// shorted since empty entity list encoded, instead of skipping over entities
|
||||||
|
assertReEncode(parser, encoder, new BitStream(firstPacketData));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue