@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
88 lines (72 loc) • 3.14 kB
JavaScript
import { quat_decode_from_uint32 } from "../../../core/geom/3d/quaternion/quat_decode_from_uint32.js";
import { quat_encode_to_uint32 } from "../../../core/geom/3d/quaternion/quat_encode_to_uint32.js";
import { v3_binary_equality_decode } from "../../../core/geom/vec3/serialization/v3_binary_equality_decode.js";
import { v3_binary_equality_encode } from "../../../core/geom/vec3/serialization/v3_binary_equality_encode.js";
import { BinaryClassSerializationAdapter } from "../../ecs/storage/binary/BinaryClassSerializationAdapter.js";
import { Transform } from "../../ecs/transform/Transform.js";
/**
* Decode scratch for {@link TransformReplicationAdapter#deserialize}. Decoders
* write into indexed slots; we then publish the final value to each field
* via `.set(...)` so the `onChanged` signal fires once with the assembled
* value rather than not at all (direct-write) or partially per intermediate.
* @type {Float32Array}
*/
const decode_scratch = new Float32Array(4);
/**
* Network-replication adapter for {@link Transform}. Mirrors
* {@link TransformSerializationAdapter} but uses Float32 for position instead
* of Float64, halving the per-component cost (12 B vs 24 B) for a precision
* loss that is below visible threshold for typical action-game scales.
*
* Wire layout (typical 17 B, 13 B if scale is identity):
* - position: 3 × Float32 = 12 bytes
* - rotation: smallest-three uint32 = 4 bytes
* - scale: `v3_binary_equality_encode` = 1 byte (identity) or 13 bytes (full)
*
* Total: 17 bytes typical, 29 bytes max.
*
* Distinct from {@link TransformSerializationAdapter} so save-game files keep
* Float64 position precision while wire packets stay tight.
*
* @author Alex Goldring
* @copyright Company Named Limited (c) 2025
*/
export class TransformReplicationAdapter extends BinaryClassSerializationAdapter {
klass = Transform;
version = 1;
/**
* @param {BinaryBuffer} buffer
* @param {Transform} value
*/
serialize(buffer, value) {
const position = value.position;
const rotation = value.rotation;
const scale = value.scale;
buffer.writeFloat32(position.x);
buffer.writeFloat32(position.y);
buffer.writeFloat32(position.z);
buffer.writeUint32(quat_encode_to_uint32(
rotation.x,
rotation.y,
rotation.z,
rotation.w
));
v3_binary_equality_encode(buffer, scale.x, scale.y, scale.z);
}
/**
* @param {BinaryBuffer} buffer
* @param {Transform} value
*/
deserialize(buffer, value) {
const positionX = buffer.readFloat32();
const positionY = buffer.readFloat32();
const positionZ = buffer.readFloat32();
const encoded_rotation = buffer.readUint32();
const s = decode_scratch;
v3_binary_equality_decode(buffer, s, 0);
value.scale.set(s[0], s[1], s[2]);
quat_decode_from_uint32(s, 0, encoded_rotation);
value.rotation.set(s[0], s[1], s[2], s[3]);
value.position.set(positionX, positionY, positionZ);
}
}