stable
This commit is contained in:
parent
0f1cb2fe6c
commit
129c07183a
51 changed files with 5711 additions and 1122 deletions
|
|
@ -7,36 +7,99 @@
|
|||
const helpers = () => global.TarinaiSimulationRuntime?.helpers || {};
|
||||
const updatePolicy = () => global.TarinaiCreatureUpdatePolicy || {};
|
||||
|
||||
function inc(map, key, n = 1) {
|
||||
const k = String(key || "none");
|
||||
map[k] = (map[k] || 0) + n;
|
||||
}
|
||||
|
||||
function updateCreatures(worldRef, dt) {
|
||||
const h = helpers();
|
||||
const end = global.TarinaiPerf?.begin?.("update.tarinai") || null;
|
||||
const end = global.TarinaiPerf?.begin?.("update.tarinai.individual") || null;
|
||||
const visibleRect = h.updateVisibleWorldRect?.(worldRef, 160) || { left: -Infinity, top: -Infinity, right: Infinity, bottom: Infinity };
|
||||
const now = worldRef.time || 0;
|
||||
const stats = {
|
||||
total: 0,
|
||||
full: 0,
|
||||
realtime: 0,
|
||||
smooth: 0,
|
||||
skipped: 0,
|
||||
selected: 0,
|
||||
urgent: 0,
|
||||
visible: 0,
|
||||
near: 0,
|
||||
far: 0,
|
||||
lanes: {},
|
||||
states: {},
|
||||
smoothStates: {},
|
||||
skippedStates: {},
|
||||
sleepPhysical: 0,
|
||||
passivePhysical: 0,
|
||||
};
|
||||
const prevSpatialDeferMode = worldRef.deferSpatialRebuildMode || "";
|
||||
worldRef.deferSpatialRebuildDepth = (worldRef.deferSpatialRebuildDepth || 0) + 1;
|
||||
// Smooth-motion Tarinai pass may read obstacle/item grids after Tarinai and
|
||||
// constraint movement have dirtied mobile buckets. Use the last coherent
|
||||
// grid during this phase and collapse mobile invalidations into one rebuild
|
||||
// after all visible bodies have been advanced.
|
||||
worldRef.deferSpatialRebuildMode = "mobile";
|
||||
try {
|
||||
for (const t of worldRef.tarinai) {
|
||||
if (!t || t.dead) continue;
|
||||
const interval = updatePolicy().updateInterval?.(worldRef, t, visibleRect) ?? 0;
|
||||
stats.total += 1;
|
||||
const behaviorId = updatePolicy().behaviorId?.(t) || t.state || "none";
|
||||
inc(stats.states, behaviorId);
|
||||
const cadence = updatePolicy().updateCadence?.(worldRef, t, visibleRect) || { interval: 0, lane: "legacy", smoothMotion: false, visible: true, urgent: false };
|
||||
const interval = Number.isFinite(cadence.interval) ? cadence.interval : Infinity;
|
||||
inc(stats.lanes, cadence.lane || "unknown");
|
||||
if (worldRef.selected === t) stats.selected += 1;
|
||||
if (cadence.urgent) stats.urgent += 1;
|
||||
if (cadence.sleepPhysical) stats.sleepPhysical += 1;
|
||||
if (cadence.passivePhysicsNeed) stats.passivePhysical += 1;
|
||||
if (cadence.visible) stats.visible += 1;
|
||||
else if (interval < 0.75) stats.near += 1;
|
||||
else stats.far += 1;
|
||||
if (!Number.isFinite(interval)) continue;
|
||||
|
||||
const context = { cadence, motionDt: dt };
|
||||
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);
|
||||
stats.full += 1;
|
||||
stats.realtime += 1;
|
||||
if (global.TarinaiCreatureRuntime?.updateOne) global.TarinaiCreatureRuntime.updateOne(t, runDt, { context });
|
||||
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) {
|
||||
if (!Number.isFinite(t._nextLowFreqUpdateAt)) {
|
||||
const jitter = typeof stableUnit === "function" ? stableUnit(t.id || t.familyKey || Math.random(), "creature-cadence") : Math.random();
|
||||
t._nextLowFreqUpdateAt = now + interval * (0.65 + jitter * 0.70);
|
||||
}
|
||||
if (now >= t._nextLowFreqUpdateAt) {
|
||||
const runDt = Math.max(dt, t._updateAccum || dt);
|
||||
const jitter = typeof stableUnit === "function" ? stableUnit(t.id || t.familyKey || Math.random(), `creature-cadence:${Math.floor(now * 2)}`) : Math.random();
|
||||
t._updateAccum = 0;
|
||||
t._nextLowFreqUpdateAt = (worldRef.time || 0) + interval;
|
||||
if (global.TarinaiCreatureRuntime?.updateOne) global.TarinaiCreatureRuntime.updateOne(t, runDt);
|
||||
t._nextLowFreqUpdateAt = now + interval * (0.92 + jitter * 0.22);
|
||||
stats.full += 1;
|
||||
if (global.TarinaiCreatureRuntime?.updateOne) global.TarinaiCreatureRuntime.updateOne(t, runDt, { context });
|
||||
else t.update(runDt);
|
||||
} else if (cadence.smoothMotion && global.TarinaiCreatureRuntime?.updateMotionOnly) {
|
||||
if (global.TarinaiCreatureRuntime.updateMotionOnly(t, dt, { context })) {
|
||||
stats.smooth += 1;
|
||||
inc(stats.smoothStates, behaviorId);
|
||||
}
|
||||
} else {
|
||||
stats.skipped += 1;
|
||||
inc(stats.skippedStates, behaviorId);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
worldRef.deferSpatialRebuildDepth = Math.max(0, (worldRef.deferSpatialRebuildDepth || 1) - 1);
|
||||
worldRef.deferSpatialRebuildMode = prevSpatialDeferMode;
|
||||
worldRef._creatureUpdateStats = stats;
|
||||
if (end) end();
|
||||
}
|
||||
const now = worldRef.time || 0;
|
||||
const bedConflictInterval = 3.2;
|
||||
if (now >= (worldRef.nextBedConflictCheckAt || 0)) {
|
||||
worldRef.nextBedConflictCheckAt = now + bedConflictInterval;
|
||||
|
|
@ -45,15 +108,29 @@
|
|||
} 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");
|
||||
const endSpatial = global.TarinaiPerf?.begin?.("update.tarinai.spatial") || null;
|
||||
const tarinaiMoved = h.markSpatialDirtyIfMoved?.(worldRef, worldRef.tarinai, "tarinai-moved", 0.25) || false;
|
||||
if (tarinaiMoved || worldRef.spatialDirty) {
|
||||
if (worldRef.rebuildSpatial) worldRef.rebuildSpatial(true, worldRef.deferredSpatialDirtyReason || "post-tarinai-update");
|
||||
else worldRef.ensureSpatial?.("post-tarinai-update");
|
||||
worldRef.deferredSpatialDirtyReason = "";
|
||||
}
|
||||
if (endSpatial) endSpatial();
|
||||
const endBallInteractions = global.TarinaiPerf?.begin?.("update.ballInteractions") || null;
|
||||
worldRef.limitBallChasers();
|
||||
worldRef.resolveBallInteractions(dt);
|
||||
const collisionInterval = 1.8;
|
||||
if (now >= (worldRef.nextTarinaiCollisionCheckAt || 0)) {
|
||||
if (endBallInteractions) endBallInteractions();
|
||||
const hasFastTarinai = (worldRef.tarinai || []).some(t => {
|
||||
if (!t || t.dead || worldRef.isTarinaiHiddenInNestBox?.(t)) return false;
|
||||
return Math.hypot(t.vx || 0, t.vy || 0) >= 150;
|
||||
});
|
||||
const collisionInterval = hasFastTarinai ? 0 : 0.55;
|
||||
if (hasFastTarinai || now >= (worldRef.nextTarinaiCollisionCheckAt || 0)) {
|
||||
worldRef.nextTarinaiCollisionCheckAt = now + collisionInterval;
|
||||
worldRef.workStats && (worldRef.workStats.collisionRuns = (worldRef.workStats.collisionRuns || 0) + 1);
|
||||
worldRef.resolveTarinaiHighSpeedCollisions(dt);
|
||||
const endCollision = global.TarinaiPerf?.begin?.("update.tarinai.collisions") || null;
|
||||
try { worldRef.resolveTarinaiHighSpeedCollisions(dt); }
|
||||
finally { if (endCollision) endCollision(); }
|
||||
} else {
|
||||
worldRef.workStats && (worldRef.workStats.collisionSkips = (worldRef.workStats.collisionSkips || 0) + 1);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue