This commit is contained in:
33333-33333 2026-07-18 13:06:02 +09:00
commit f657b6a4a4
94 changed files with 3970 additions and 1241 deletions

View file

@ -8,6 +8,7 @@
const updatePolicy = global.TarinaiCreatureUpdatePolicy;
function inc(map, key, n = 1) {
if (!map) return;
const k = String(key || "none");
map[k] = (map[k] || 0) + n;
}
@ -105,6 +106,7 @@
const pressureActive = Boolean(pressure?.active);
const visibleFullBudget = pressureActive ? Math.max(1, profileNumber("pressureCreatureFullBudget", 24)) : 1000000000;
const visibleMotionBudget = pressureActive ? Math.max(1, profileNumber("pressureCreatureMotionBudget", 36)) : 1000000000;
const collectDiagnostics = global.TarinaiPerf?.diagnosticsEnabled?.() === true;
const stats = {
total: 0,
full: 0,
@ -116,10 +118,10 @@
visible: 0,
near: 0,
far: 0,
lanes: {},
states: {},
smoothStates: {},
skippedStates: {},
lanes: collectDiagnostics ? {} : null,
states: collectDiagnostics ? {} : null,
smoothStates: collectDiagnostics ? {} : null,
skippedStates: collectDiagnostics ? {} : null,
sleepPhysical: 0,
passivePhysical: 0,
fullBudget: backgroundFullBudgetFor(worldRef),
@ -147,7 +149,25 @@
// after all visible bodies have been advanced.
worldRef.deferSpatialRebuildMode = "mobile";
try {
for (const t of worldRef.tarinai) {
const creatureList = worldRef.tarinai || [];
const creatureCount = creatureList.length;
const perfProfile = global.TarinaiPerf?.performanceProfile?.() || {};
// High-population AI/environment budgets are consumed in a rotating order.
// Every creature is still visited each frame, but the first candidates for
// expensive scheduled work change without a queue, sort, or per-frame hash.
const rotateScheduledWork = perfProfile.simulationThrottled !== false && creatureCount >= 80;
let creatureIndex = rotateScheduledWork
? (Math.max(0, Math.floor(worldRef._creatureScheduledWorkCursor || 0)) % Math.max(1, creatureCount))
: 0;
if (rotateScheduledWork) {
const cursorStep = Math.max(1, Math.min(creatureCount, Math.floor(Number(perfProfile.aiBudget || 10)) || 10));
worldRef._creatureScheduledWorkCursor = (creatureIndex + cursorStep) % creatureCount;
} else {
worldRef._creatureScheduledWorkCursor = 0;
}
for (let creatureVisited = 0; creatureVisited < creatureCount; creatureVisited += 1) {
if (creatureIndex >= creatureCount) creatureIndex = 0;
const t = creatureList[creatureIndex++];
if (!t || t.dead) continue;
stats.total += 1;
const behaviorId = updatePolicy.behaviorId(t);
@ -229,7 +249,7 @@
stats.mechanicalDetailedContacts = pressure?.detailedContacts || 0;
stats.mechanicalDegradedContacts = pressure?.degradedContacts || 0;
stats.mechanicalSkippedContacts = pressure?.skippedContacts || 0;
worldRef._creatureUpdateStats = stats;
worldRef._creatureUpdateStats = collectDiagnostics ? stats : null;
if (end) end();
}
const bedConflictInterval = 3.2;
@ -241,12 +261,19 @@
worldRef.workStats && (worldRef.workStats.bedConflictSkips = (worldRef.workStats.bedConflictSkips || 0) + 1);
}
const endSpatial = global.TarinaiPerf.begin("update.tarinai.spatial") || null;
const tarinaiMoved = h.markSpatialDirtyIfMoved(worldRef, worldRef.tarinai, "tarinai-moved", 0.25);
if (tarinaiMoved || worldRef.spatialDirty) {
// Maintain the Tarinai grid incrementally. The same O(N) pass that used to
// detect movement now moves only entities that crossed a cell boundary,
// avoiding a second O(N) clear-and-rebuild pass every active frame.
const tarinaiCellChanges = worldRef.spatial?.syncTarinai?.(worldRef.tarinai || []) || 0;
if (tarinaiCellChanges > 0) worldRef.spatialVersion = (worldRef.spatialVersion || 0) + 1;
if (worldRef.spatialDirty && (worldRef.spatialStaticItemsDirty || worldRef.spatialDynamicItemsDirty || worldRef.spatialAntDirty)) {
if (worldRef.rebuildSpatial) worldRef.rebuildSpatial(true, worldRef.deferredSpatialDirtyReason || "post-tarinai-update");
else worldRef.ensureSpatial?.("post-tarinai-update");
worldRef.deferredSpatialDirtyReason = "";
} else if (worldRef.spatialTarinaiDirty) {
worldRef.spatialTarinaiDirty = false;
worldRef.spatialDirty = Boolean(worldRef.spatialStaticItemsDirty || worldRef.spatialDynamicItemsDirty || worldRef.spatialAntDirty);
}
worldRef.deferredSpatialDirtyReason = "";
if (endSpatial) endSpatial();
const endBallInteractions = global.TarinaiPerf.begin("update.ballInteractions") || null;
worldRef.limitBallChasers();