1
0
Fork 0
mirror of https://github.com/demostf/demo.js synced 2026-06-04 00:54:14 +02:00

add encoder for sendprops

This commit is contained in:
Robin Appelman 2017-09-01 19:49:40 +02:00
commit ca2083c64a
7 changed files with 336 additions and 58 deletions

View file

@ -1,43 +1,8 @@
import {BitStream} from 'bit-buffer';
import {BSPDecalPacket} from '../../Data/Packet';
import {Vector} from '../../Data/Vector';
export function getCoord(stream: BitStream): number {
const hasInt = stream.readBoolean();
const hasFract = stream.readBoolean();
let value = 0;
if (hasInt || hasFract) {
const sign = stream.readBoolean();
if (hasInt) {
value += stream.readBits(14) + 1;
}
if (hasFract) {
value += stream.readBits(5) * (1 / 32);
}
if (sign) {
value = -value;
}
}
return value;
}
export function encodeCoord(value: number, stream: BitStream) {
const abs = Math.abs(value);
const intPart = Math.floor(abs);
const fractPart = abs % 1;
stream.writeBoolean(intPart !== 0);
stream.writeBoolean(fractPart !== 0);
if (intPart || fractPart) {
stream.writeBoolean(value < 0);
if (intPart) {
stream.writeBits(intPart - 1, 14);
}
if (fractPart) {
stream.writeBits(fractPart * 32, 5);
}
}
}
import {SendPropParser} from '../SendPropParser';
import {SendPropEncoder} from '../SendPropEncoder';
export function getVecCoord(stream: BitStream): Vector {
const hasX = stream.readBoolean();
@ -45,9 +10,9 @@ export function getVecCoord(stream: BitStream): Vector {
const hasZ = stream.readBoolean();
return {
x: hasX ? getCoord(stream) : 0,
y: hasY ? getCoord(stream) : 0,
z: hasZ ? getCoord(stream) : 0,
x: hasX ? SendPropParser.readBitCoord(stream) : 0,
y: hasY ? SendPropParser.readBitCoord(stream) : 0,
z: hasZ ? SendPropParser.readBitCoord(stream) : 0,
};
}
@ -57,13 +22,13 @@ export function encodeVecCoord(vector: Vector, stream: BitStream) {
stream.writeBoolean(vector.z !== 0);
if (vector.x !== 0) {
encodeCoord(vector.x, stream);
SendPropEncoder.writeBitCoord(vector.x, stream);
}
if (vector.y !== 0) {
encodeCoord(vector.y, stream);
SendPropEncoder.writeBitCoord(vector.y, stream);
}
if (vector.z !== 0) {
encodeCoord(vector.z, stream);
SendPropEncoder.writeBitCoord(vector.z, stream);
}
}

View file

@ -0,0 +1,163 @@
import {BitStream} from 'bit-buffer';
import {SendPropArrayValue, SendPropValue} from '../Data/SendProp';
import {SendPropDefinition, SendPropFlag, SendPropType} from '../Data/SendPropDefinition';
import {Vector} from '../Data/Vector';
import {logBase2} from '../Math';
import {makeUnsigned, writeVarInt} from './readBitVar';
import {bitNormalFactor} from './SendPropParser';
export class SendPropEncoder {
public static encode(value: SendPropValue, propDefinition: SendPropDefinition, stream: BitStream) {
switch (propDefinition.type) {
case SendPropType.DPT_Int:
if (typeof value !== 'number') {
throw new Error('Invalid value for DPT_Int');
}
return SendPropEncoder.writeInt(value, propDefinition, stream);
case SendPropType.DPT_Vector:
if (!(value instanceof Vector)) {
throw new Error('Invalid value for DPT_Vector');
}
return SendPropEncoder.writeVector(value, propDefinition, stream);
case SendPropType.DPT_VectorXY:
if (!(value instanceof Vector)) {
throw new Error('Invalid value for DPT_Vector');
}
return SendPropEncoder.writeVectorXY(value, propDefinition, stream);
case SendPropType.DPT_Float:
if (typeof value !== 'number') {
throw new Error('Invalid value for DPT_Int');
}
return SendPropEncoder.writeFloat(value, propDefinition, stream);
case SendPropType.DPT_String:
if (typeof value !== 'string') {
throw new Error('Invalid value for DPT_Int');
}
return SendPropEncoder.writeString(value, stream);
case SendPropType.DPT_Array:
if (!Array.isArray(value)) {
throw new Error('Invalid value for DPT_Int');
}
return SendPropEncoder.writeArray(value, propDefinition, stream);
}
throw new Error('Unknown property type');
}
public static writeInt(value: number, propDefinition: SendPropDefinition, stream: BitStream) {
if (propDefinition.hasFlag(SendPropFlag.SPROP_VARINT)) {
return writeVarInt(value, stream, !propDefinition.hasFlag(SendPropFlag.SPROP_UNSIGNED));
} else {
if (propDefinition.hasFlag(SendPropFlag.SPROP_UNSIGNED)) {
return stream.writeBits(value, propDefinition.bitCount);
} else {
return stream.writeBits(makeUnsigned(value), propDefinition.bitCount);
}
}
}
public static writeArray(value: SendPropArrayValue[], propDefinition: SendPropDefinition, stream: BitStream) {
const numBits = logBase2(propDefinition.numElements) + 1;
stream.writeBits(value.length, numBits);
if (!propDefinition.arrayProperty) {
throw new Error('Array of undefined type');
}
for (const arrayValue of value) {
SendPropEncoder.encode(arrayValue, propDefinition.arrayProperty, stream);
}
}
public static writeString(value: string, stream: BitStream) {
// +1 for null
stream.writeBits(value.length + 1, 9);
stream.writeASCIIString(value);
}
public static writeVector(value: Vector, propDefinition: SendPropDefinition, stream: BitStream) {
SendPropEncoder.writeFloat(value.x, propDefinition, stream);
SendPropEncoder.writeFloat(value.y, propDefinition, stream);
SendPropEncoder.writeFloat(value.z, propDefinition, stream);
}
public static writeVectorXY(value: Vector, propDefinition: SendPropDefinition, stream: BitStream) {
SendPropEncoder.writeFloat(value.x, propDefinition, stream);
SendPropEncoder.writeFloat(value.y, propDefinition, stream);
}
public static writeFloat(value: number, propDefinition: SendPropDefinition, stream: BitStream) {
if (propDefinition.hasFlag(SendPropFlag.SPROP_COORD)) {
return SendPropEncoder.writeBitCoord(value, stream);
} else if (propDefinition.hasFlag(SendPropFlag.SPROP_COORD_MP)) {
return SendPropEncoder.writeBitCoordMP(value, stream, false, false);
} else if (propDefinition.hasFlag(SendPropFlag.SPROP_COORD_MP_LOWPRECISION)) {
return SendPropEncoder.writeBitCoordMP(value, stream, false, true);
} else if (propDefinition.hasFlag(SendPropFlag.SPROP_COORD_MP_INTEGRAL)) {
return SendPropEncoder.writeBitCoordMP(value, stream, true, false);
} else if (propDefinition.hasFlag(SendPropFlag.SPROP_NOSCALE)) {
return stream.writeFloat32(value);
} else if (propDefinition.hasFlag(SendPropFlag.SPROP_NORMAL)) {
return SendPropEncoder.writeBitNormal(value, stream);
} else {
const percentage = (value - propDefinition.lowValue) / (propDefinition.highValue - propDefinition.lowValue);
const raw = Math.round(percentage * ((1 << propDefinition.bitCount) - 1));
stream.writeBits(raw, propDefinition.bitCount);
}
}
public static writeBitNormal(value: number, stream: BitStream) {
stream.writeBoolean(value < 0);
const abs = Math.abs(value);
const fractPart = abs % 1;
const fractVal = Math.round(fractPart / bitNormalFactor);
stream.writeBits(fractVal, 11);
}
public static writeBitCoord(value: number, stream: BitStream) {
const abs = Math.abs(value);
const intPart = Math.floor(abs);
const fractPart = abs % 1;
stream.writeBoolean(intPart !== 0);
stream.writeBoolean(fractPart !== 0);
if (intPart || fractPart) {
stream.writeBoolean(value < 0);
if (intPart) {
stream.writeBits(intPart - 1, 14);
}
if (fractPart) {
stream.writeBits(fractPart * 32, 5);
}
}
}
public static writeBitCoordMP(value: number, stream: BitStream, isIntegral: boolean, isLowPrecision: boolean) {
const abs = Math.abs(value);
const intPart = Math.floor(abs);
const fractPart = abs % 1;
const inBounds = intPart < Math.pow(2, 11);
stream.writeBoolean(inBounds);
stream.writeBoolean(intPart > 0);
if (isIntegral) {
if (intPart) {
stream.writeBoolean(value < 0);
if (inBounds) {
stream.writeBits(intPart - 1, 11);
} else {
stream.writeBits(intPart - 1, 14);
}
}
} else {
stream.writeBoolean(value < 0);
if (intPart) {
if (inBounds) {
stream.writeBits(intPart - 1, 11);
} else {
stream.writeBits(intPart - 1, 14);
}
}
const fractVal = Math.round(fractPart / (1 / (1 << (isLowPrecision ? 3 : 5))));
stream.writeBits(fractVal, isLowPrecision ? 3 : 5);
}
}
}

View file

@ -5,6 +5,8 @@ import {Vector} from '../Data/Vector';
import {logBase2} from '../Math';
import {readVarInt} from './readBitVar';
export const bitNormalFactor = (1 / ((1 << 11) - 1));
export class SendPropParser {
public static decode(propDefinition: SendPropDefinition, stream: BitStream): SendPropValue {
switch (propDefinition.type) {
@ -72,11 +74,11 @@ export class SendPropParser {
if (propDefinition.hasFlag(SendPropFlag.SPROP_COORD)) {
return SendPropParser.readBitCoord(stream);
} else if (propDefinition.hasFlag(SendPropFlag.SPROP_COORD_MP)) {
return SendPropParser.readBitCoordMP(propDefinition, stream, false, false);
return SendPropParser.readBitCoordMP(stream, false, false);
} else if (propDefinition.hasFlag(SendPropFlag.SPROP_COORD_MP_LOWPRECISION)) {
return SendPropParser.readBitCoordMP(propDefinition, stream, false, true);
return SendPropParser.readBitCoordMP(stream, false, true);
} else if (propDefinition.hasFlag(SendPropFlag.SPROP_COORD_MP_INTEGRAL)) {
return SendPropParser.readBitCoordMP(propDefinition, stream, true, false);
return SendPropParser.readBitCoordMP(stream, true, false);
} else if (propDefinition.hasFlag(SendPropFlag.SPROP_NOSCALE)) {
return stream.readFloat32();
} else if (propDefinition.hasFlag(SendPropFlag.SPROP_NORMAL)) {
@ -91,7 +93,7 @@ export class SendPropParser {
public static readBitNormal(stream: BitStream) {
const isNegative = stream.readBoolean();
const fractVal = stream.readBits(11);
const value = fractVal * (1 / ((1 << 11) - 1));
const value = fractVal * bitNormalFactor;
return (isNegative) ? -value : value;
}
@ -103,14 +105,14 @@ export class SendPropParser {
const isNegative = stream.readBoolean();
const intVal = (hasIntVal) ? stream.readBits(14) + 1 : 0;
const fractVal = (hasFractVal) ? stream.readBits(5) : 0;
const value = intVal + fractVal * (1 / (1 << 5));
const value = intVal + fractVal * (1 / 32);
return (isNegative) ? -value : value;
}
return 0;
}
public static readBitCoordMP(propDefinition: SendPropDefinition, stream: BitStream, isIntegral: boolean, isLowPrecision: boolean): number {
public static readBitCoordMP(stream: BitStream, isIntegral: boolean, isLowPrecision: boolean): number {
let value = 0;
let isNegative = false;
const inBounds = stream.readBoolean();

View file

@ -1,7 +1,7 @@
import {BitStream} from 'bit-buffer';
import {logBase2} from '../Math';
function makeUnsigned(value: number, signed?: boolean) {
export function makeUnsigned(value: number, signed?: boolean) {
if (signed) {
const signBit = value < 0 ? 1 : 0;
return ((value ^ -signBit) << 1) + signBit;