silphius/app/client/interpolator.js

120 lines
3.1 KiB
JavaScript
Raw Normal View History

2024-09-06 19:21:58 -05:00
let authoritative = [];
let duration = 0;
let last = performance.now();
let latest = null;
let location = 0;
let penultimate;
let tracking = [];
const interpolate = () => {
const now = performance.now();
const elapsed = (now - last) / 1000;
last = now;
if (authoritative.length > 0) {
for (const packet of authoritative) {
2024-09-05 01:41:45 -05:00
postMessage(packet);
2024-08-29 15:43:50 -05:00
}
2024-09-06 19:21:58 -05:00
authoritative = [];
2024-08-29 15:43:50 -05:00
}
2024-09-06 19:21:58 -05:00
if (tracking.length > 0) {
location += elapsed;
const fraction = location / duration;
const [from, to] = [penultimate.payload.ecs, latest.payload.ecs];
2024-08-29 15:43:50 -05:00
const interpolated = {};
2024-09-06 19:21:58 -05:00
for (const {entityId, componentName, properties} of tracking) {
2024-08-29 15:43:50 -05:00
if (!interpolated[entityId]) {
interpolated[entityId] = {};
}
if (!interpolated[entityId][componentName]) {
interpolated[entityId][componentName] = {};
}
for (const property of properties) {
if (
!(property in from[entityId][componentName])
|| !(property in to[entityId][componentName])
) {
continue;
}
interpolated[entityId][componentName][property] = (
from[entityId][componentName][property]
+ (
fraction
* (to[entityId][componentName][property] - from[entityId][componentName][property])
)
);
}
}
2024-09-06 19:21:58 -05:00
postMessage({
2024-08-29 15:43:50 -05:00
type: 'Tick',
payload: {
2024-09-06 19:21:58 -05:00
...penultimate.payload,
2024-08-29 15:43:50 -05:00
ecs: interpolated,
elapsed,
2024-09-06 19:21:58 -05:00
frame: penultimate.payload.frame + fraction,
2024-08-29 15:43:50 -05:00
},
2024-09-06 19:21:58 -05:00
});
2024-08-29 15:43:50 -05:00
}
2024-09-06 19:21:58 -05:00
requestAnimationFrame(interpolate);
2024-08-29 15:43:50 -05:00
}
2024-09-06 19:21:58 -05:00
requestAnimationFrame(interpolate);
2024-08-29 15:43:50 -05:00
onmessage = async (event) => {
2024-09-06 19:21:58 -05:00
const packet = event.data;
switch (packet.type) {
2024-09-06 13:33:13 -05:00
case 'EcsChange': {
2024-09-06 19:21:58 -05:00
authoritative = [];
latest = null;
tracking = [];
postMessage(packet);
2024-09-06 13:33:13 -05:00
break;
}
case 'Tick': {
2024-09-06 19:21:58 -05:00
penultimate = latest;
latest = packet;
if (penultimate) {
duration = penultimate.payload.elapsed;
location = 0;
tracking = [];
const [from, to] = [penultimate.payload.ecs, latest.payload.ecs];
for (const entityId in from) {
for (const componentName in from[entityId]) {
if (
['Camera', 'Position'].includes(componentName)
&& to[entityId]?.[componentName]
) {
tracking.push({
entityId,
componentName,
properties: ['x', 'y'],
});
}
2024-09-06 21:20:40 -05:00
if (
['Sprite'].includes(componentName)
&& to[entityId]?.[componentName]
) {
tracking.push({
entityId,
componentName,
properties: ['alpha', 'scaleX', 'scaleY'],
});
}
2024-09-06 19:21:58 -05:00
}
}
authoritative.push({
2024-09-06 13:33:13 -05:00
type: 'Tick',
payload: {
2024-09-06 19:21:58 -05:00
...penultimate.payload,
2024-09-06 13:33:13 -05:00
elapsed: last ? (performance.now() - last) / 1000 : 0,
},
});
2024-09-06 19:21:58 -05:00
last = performance.now();
2024-09-06 13:33:13 -05:00
}
break;
2024-08-29 15:43:50 -05:00
}
2024-09-06 19:21:58 -05:00
default: {
postMessage(packet);
break;
}
2024-08-29 15:43:50 -05:00
}
};