70 lines
3.3 KiB
JavaScript
70 lines
3.3 KiB
JavaScript
"use strict";
|
|
|
|
// Layer: simulation/system-creatures
|
|
// Owns Tarinai update cadence, Tarinai movement invalidation, and creature
|
|
// collision/interactions scheduled after individual updates.
|
|
(function (global) {
|
|
const helpers = () => global.TarinaiSimulationRuntime?.helpers || {};
|
|
const updatePolicy = () => global.TarinaiCreatureUpdatePolicy || {};
|
|
|
|
function updateCreatures(worldRef, dt) {
|
|
const h = helpers();
|
|
const end = global.TarinaiPerf?.begin?.("update.tarinai") || null;
|
|
const visibleRect = h.updateVisibleWorldRect?.(worldRef, 160) || { left: -Infinity, top: -Infinity, right: Infinity, bottom: Infinity };
|
|
try {
|
|
for (const t of worldRef.tarinai) {
|
|
if (!t || t.dead) continue;
|
|
const interval = updatePolicy().updateInterval?.(worldRef, t, visibleRect) ?? 0;
|
|
if (!Number.isFinite(interval)) continue;
|
|
if (interval <= 0) {
|
|
const runDt = Math.min(1.4, (t._updateAccum || 0) + dt);
|
|
t._updateAccum = 0;
|
|
if (global.TarinaiCreatureRuntime?.updateOne) global.TarinaiCreatureRuntime.updateOne(t, runDt);
|
|
else t.update(runDt);
|
|
continue;
|
|
}
|
|
t._updateAccum = Math.min(2.4, (t._updateAccum || 0) + dt);
|
|
t._nextLowFreqUpdateAt = Number.isFinite(t._nextLowFreqUpdateAt) ? t._nextLowFreqUpdateAt : (worldRef.time || 0) + interval * (0.65 + Math.random() * 0.7);
|
|
if ((worldRef.time || 0) >= t._nextLowFreqUpdateAt) {
|
|
const runDt = Math.max(dt, t._updateAccum || dt);
|
|
t._updateAccum = 0;
|
|
t._nextLowFreqUpdateAt = (worldRef.time || 0) + interval;
|
|
if (global.TarinaiCreatureRuntime?.updateOne) global.TarinaiCreatureRuntime.updateOne(t, runDt);
|
|
else t.update(runDt);
|
|
}
|
|
}
|
|
} finally {
|
|
if (end) end();
|
|
}
|
|
const now = worldRef.time || 0;
|
|
const bedConflictInterval = 3.2;
|
|
if (now >= (worldRef.nextBedConflictCheckAt || 0)) {
|
|
worldRef.nextBedConflictCheckAt = now + bedConflictInterval;
|
|
worldRef.workStats && (worldRef.workStats.bedConflictRuns = (worldRef.workStats.bedConflictRuns || 0) + 1);
|
|
worldRef.resolveOwnedBedSleepConflicts?.();
|
|
} else {
|
|
worldRef.workStats && (worldRef.workStats.bedConflictSkips = (worldRef.workStats.bedConflictSkips || 0) + 1);
|
|
}
|
|
h.markSpatialDirtyIfMoved?.(worldRef, worldRef.tarinai, "tarinai-moved", 0.25);
|
|
worldRef.ensureSpatial?.("post-tarinai-update");
|
|
worldRef.limitBallChasers();
|
|
worldRef.resolveBallInteractions(dt);
|
|
const collisionInterval = 1.8;
|
|
if (now >= (worldRef.nextTarinaiCollisionCheckAt || 0)) {
|
|
worldRef.nextTarinaiCollisionCheckAt = now + collisionInterval;
|
|
worldRef.workStats && (worldRef.workStats.collisionRuns = (worldRef.workStats.collisionRuns || 0) + 1);
|
|
worldRef.resolveTarinaiHighSpeedCollisions(dt);
|
|
} else {
|
|
worldRef.workStats && (worldRef.workStats.collisionSkips = (worldRef.workStats.collisionSkips || 0) + 1);
|
|
}
|
|
}
|
|
|
|
const phases = Object.freeze({ updateCreatures });
|
|
const helpersApi = Object.freeze({
|
|
updateInterval(worldRef, tarinai, visibleRect) {
|
|
return updatePolicy().updateInterval?.(worldRef, tarinai, visibleRect) ?? Infinity;
|
|
},
|
|
});
|
|
|
|
global.TarinaiCreatureSimulationSystem = Object.freeze({ phases, helpers: helpersApi });
|
|
})(typeof window !== "undefined" ? window : globalThis);
|