mirror of
https://github.com/Terncode/pixel.horse.git
synced 2026-09-24 13:55:04 +02:00
154 lines
3.7 KiB
TypeScript
154 lines
3.7 KiB
TypeScript
import {
|
|
BinaryWriter, BinaryReader, writeInt16, readInt16, createBinaryReader, readUint16, readLength,
|
|
readUint32, readUint8, readObject, readUint8Array
|
|
} from 'ag-sockets/dist/browser';
|
|
import { DecodedUpdate, DecodedRegionUpdate, TileUpdate, UpdateFlags } from '../interfaces';
|
|
import { tileWidth, tileHeight, MAX_VELOCITY } from '../constants';
|
|
import { decodeStringFromUint8Array } from '../binaryUtils';
|
|
|
|
export function writeVelocity(writer: BinaryWriter, value: number) {
|
|
if (value >= MAX_VELOCITY || value <= -MAX_VELOCITY) {
|
|
throw new Error(`Exceeded max velocity (${value})`);
|
|
}
|
|
|
|
writeInt16(writer, (value * 0x8000) / MAX_VELOCITY);
|
|
}
|
|
|
|
export function readVelocity(reader: BinaryReader) {
|
|
return (readInt16(reader) * MAX_VELOCITY) / 0x8000;
|
|
}
|
|
|
|
export function writeCoordX(writer: BinaryWriter, value: number) {
|
|
writeInt16(writer, (value * tileWidth) | 0);
|
|
}
|
|
|
|
export function writeCoordY(writer: BinaryWriter, value: number) {
|
|
writeInt16(writer, (value * tileHeight) | 0);
|
|
}
|
|
|
|
export function readCoordX(reader: BinaryReader) {
|
|
return readInt16(reader) / tileWidth;
|
|
}
|
|
|
|
export function readCoordY(reader: BinaryReader) {
|
|
return readInt16(reader) / tileHeight;
|
|
}
|
|
|
|
export function emptyUpdate(id: number): DecodedUpdate {
|
|
return {
|
|
id,
|
|
x: undefined,
|
|
y: undefined,
|
|
vx: 0,
|
|
vy: 0,
|
|
state: undefined,
|
|
expression: undefined,
|
|
type: undefined,
|
|
options: undefined,
|
|
crc: undefined,
|
|
name: undefined,
|
|
filterName: false,
|
|
info: undefined,
|
|
action: undefined,
|
|
switchRegion: false,
|
|
playerState: undefined,
|
|
};
|
|
}
|
|
|
|
export function decodeUpdate(data: Uint8Array): DecodedRegionUpdate {
|
|
const reader = createBinaryReader(data);
|
|
const x = readUint16(reader);
|
|
const y = readUint16(reader);
|
|
const updates: DecodedUpdate[] = [];
|
|
let update: DecodedUpdate | undefined;
|
|
|
|
while (update = readOneUpdate(reader)) {
|
|
updates.push(update);
|
|
}
|
|
|
|
const removesLength = readLength(reader);
|
|
const removes: number[] = [];
|
|
|
|
for (let i = 0; i < removesLength; i++) {
|
|
removes.push(readUint32(reader));
|
|
}
|
|
|
|
const tilesLength = readLength(reader);
|
|
const tiles: TileUpdate[] = [];
|
|
|
|
for (let i = 0; i < tilesLength; i++) {
|
|
tiles.push({
|
|
x: readUint8(reader),
|
|
y: readUint8(reader),
|
|
type: readUint8(reader),
|
|
});
|
|
}
|
|
|
|
const tileData = readUint8Array(reader);
|
|
|
|
return { x, y, updates, removes, tiles, tileData };
|
|
}
|
|
|
|
export function readOneUpdate(reader: BinaryReader): DecodedUpdate | undefined {
|
|
if (reader.offset >= reader.view.byteLength) {
|
|
return undefined;
|
|
}
|
|
|
|
const flags = readUint16(reader);
|
|
|
|
if (flags === 0) {
|
|
return undefined;
|
|
}
|
|
|
|
const id = readUint32(reader);
|
|
const update = emptyUpdate(id);
|
|
|
|
update.switchRegion = (flags & UpdateFlags.SwitchRegion) !== 0;
|
|
|
|
if ((flags & UpdateFlags.Position) !== 0) {
|
|
update.x = readCoordX(reader);
|
|
update.y = readCoordY(reader);
|
|
}
|
|
|
|
if ((flags & UpdateFlags.Velocity) !== 0) {
|
|
update.vx = readVelocity(reader);
|
|
update.vy = readVelocity(reader);
|
|
}
|
|
|
|
if ((flags & UpdateFlags.State) !== 0) {
|
|
update.state = readUint8(reader);
|
|
}
|
|
|
|
if ((flags & UpdateFlags.Expression) !== 0) {
|
|
update.expression = readUint32(reader);
|
|
}
|
|
|
|
if ((flags & UpdateFlags.Type) !== 0) {
|
|
update.type = readUint16(reader);
|
|
}
|
|
|
|
if ((flags & UpdateFlags.Options) !== 0) {
|
|
update.options = readObject(reader);
|
|
}
|
|
|
|
if ((flags & UpdateFlags.Info) !== 0) {
|
|
update.crc = readUint16(reader);
|
|
update.info = readUint8Array(reader)!;
|
|
}
|
|
|
|
if ((flags & UpdateFlags.Action) !== 0) {
|
|
update.action = readUint8(reader);
|
|
}
|
|
|
|
if ((flags & UpdateFlags.Name) !== 0) {
|
|
update.name = decodeStringFromUint8Array(readUint8Array(reader)) || undefined;
|
|
update.filterName = (flags & UpdateFlags.NameBad) !== 0;
|
|
}
|
|
|
|
if ((flags & UpdateFlags.PlayerState) !== 0) {
|
|
update.playerState = readUint8(reader);
|
|
}
|
|
|
|
return update;
|
|
}
|