"use strict"; // Layer: simulation/system-maintenance // Owns low-frequency cleanup and cache maintenance. Heavy sweeps are deliberately // staggered so they do not all land on the same animation frame. (function (global) { function initializeSchedule(worldRef) { if (worldRef._maintenanceScheduleReady) return; const now = Number(worldRef.time || 0) || 0; worldRef._maintenanceScheduleReady = true; worldRef._nextStructureDependencyCheckAt = now + 0.85; worldRef._nextItemCompactAt = now + 1.65; worldRef._nextAntCompactAt = now + 3.35; worldRef._nextEffectCountRefreshAt = now + 2.15; worldRef._nextFamilyPruneAt = now + 9.1; if (!Number.isFinite(worldRef.nextGrassLimitCheckAt) || worldRef.nextGrassLimitCheckAt <= now) worldRef.nextGrassLimitCheckAt = now + 1.25; if (!Number.isFinite(worldRef.nextFireCompactAt) || worldRef.nextFireCompactAt <= now) worldRef.nextFireCompactAt = now + 0.45; if (!Number.isFinite(worldRef.nextGrassBedExpiryCheckAt) || worldRef.nextGrassBedExpiryCheckAt <= now) worldRef.nextGrassBedExpiryCheckAt = now + 2.85; if (!Number.isFinite(worldRef.outOfBoundsCheckAt)) worldRef.outOfBoundsCheckAt = now - 1.55; } function runMaintenance(worldRef, dt, itemCountBefore) { initializeSchedule(worldRef); const now = Number(worldRef.time || 0) || 0; let itemsCompacted = false; // Link/plushie reconciliation is a safety net. Deletions already reconcile // dependencies immediately, so a periodic pass is sufficient during normal play. if (now >= (worldRef._nextStructureDependencyCheckAt || 0)) { worldRef._nextStructureDependencyCheckAt = now + 0.85; const relevantCount = (worldRef.itemCounts?.plushie || 0) + (worldRef.itemCounts?.rope || 0) + (worldRef.itemCounts?.rod || 0) + (worldRef.itemCounts?.spring || 0) + (worldRef.itemCounts?.wire || 0) + (worldRef.itemCounts?.insulated_wire || 0); if (relevantCount > 0 || worldRef.itemBucketsDirty) global.TarinaiStructureLifecycle?.maintainDependencies?.(worldRef); } // Keep the existing creature cleanup cadence separate; item/ant sweeps are // offset so large arrays are not compacted on the same frame. worldRef.compactTimer += dt; if (worldRef.compactTimer >= 2.5) { worldRef.compactTarinai(); worldRef.compactTimer = 0; } if (now >= (worldRef._nextItemCompactAt || 0)) { worldRef._nextItemCompactAt = now + 3.7; itemsCompacted = worldRef.compactItems(); } if (now >= (worldRef._nextAntCompactAt || 0)) { worldRef._nextAntCompactAt = now + 4.3; worldRef.compactAnts?.(); } if (worldRef.familyPrunePending && now >= (worldRef._nextFamilyPruneAt || 0)) { worldRef._nextFamilyPruneAt = now + 8.0; worldRef.familyPrunePending = false; worldRef.pruneExtinctFamilies?.(); } const itemCountChanged = worldRef.items.length !== itemCountBefore || worldRef.items.length !== (worldRef._lastMaintenanceItemCount ?? worldRef.items.length); const effectCountChanged = worldRef.effects.length !== (worldRef._lastMaintenanceEffectCount ?? worldRef.effects.length); if (itemsCompacted || itemCountChanged || worldRef.itemBucketsDirty) { worldRef.updateItemCounts(); worldRef._lastMaintenanceItemCount = worldRef.items.length; } if (effectCountChanged || now >= (worldRef._nextEffectCountRefreshAt || 0)) { worldRef._nextEffectCountRefreshAt = now + 4.6; worldRef.updateEffectCounts(); worldRef._lastMaintenanceEffectCount = worldRef.effects.length; } if (now >= (worldRef.nextGrassLimitCheckAt || 0)) { worldRef.nextGrassLimitCheckAt = now + 3.0; const removedGrass = worldRef.enforceGrassLimit?.("periodic-grass-limit") || 0; if (removedGrass > 0) { worldRef.compactItems(); worldRef.updateItemCounts(); } } if (now >= (worldRef.nextFireCompactAt || 0)) { worldRef.nextFireCompactAt = now + 0.8; const compactedFires = global.TarinaiItemDynamicToolSystem?.compactWorldFires?.(worldRef) || 0; if (compactedFires > 0) worldRef.updateItemCounts(); } if (now >= (worldRef.nextGrassBedExpiryCheckAt || 0)) { worldRef.nextGrassBedExpiryCheckAt = now + 5.0; const lifespan = Math.max(1, CONFIG.dayLength || 120); let removedBeds = 0; const grassBeds = typeof worldRef.itemsOfType === "function" ? worldRef.itemsOfType("grass_bed") : (worldRef.items || []); for (const it of grassBeds || []) { if (!it || it.dead || it.type !== "grass_bed") continue; if (!Number.isFinite(Number(it.createdAt))) it.createdAt = now; if (now - Number(it.createdAt || 0) < lifespan) continue; const removed = global.TarinaiStructureLifecycle?.deleteItem?.(worldRef, it, { reason: "grass-bed-expired", userReason: "\u304b\u3093\u305f\u3093\u30d9\u30c3\u30c9\u304c\u53e4\u304f\u306a\u3063\u3066\u6d88\u3048\u305f", wake: false, panicOwner: false, }); if (removed) removedBeds += 1; } if (removedBeds > 0) { worldRef.compactItems(); worldRef.updateItemCounts(); worldRef.markSpatialDirty?.("grass-bed-expired"); } } if ((worldRef.outOfBoundsCheckAt || -999) + 5.0 <= now) { worldRef.outOfBoundsCheckAt = now; worldRef.sanitizeOutOfBounds(); } worldRef.drawSortTimer = 0; } global.TarinaiMaintenanceSimulationSystem = Object.freeze({ phases: Object.freeze({ runMaintenance }), }); })(typeof window !== "undefined" ? window : globalThis);