This commit is contained in:
33333-33333 2026-06-24 21:20:53 +09:00
commit 2741b93dea
31 changed files with 751 additions and 546 deletions

View file

@ -12,25 +12,17 @@
Object.defineProperties(World.prototype, Object.getOwnPropertyDescriptors({
performanceLevel() {
if (window.TarinaiPerformance) return window.TarinaiPerformance.quality?.(this)?.level || window.TarinaiPerformance.level || 0;
const fps = typeof window !== "undefined" ? Number(window.__tarinaiFps || 0) : 60;
if (!fps || !Number.isFinite(fps)) return 0;
if (fps < 22) return 3;
if (fps < 34) return 2;
if (fps < 48) return 1;
return 0;
},
performanceQuality() {
return window.TarinaiPerformance?.quality?.(this) || { level: this.performanceLevel(), antStride: 1, effectLimit: CONFIG.effectLimit ?? 96 };
return { level: 0, pressure: 0, effectDensity: 1, antStride: 2, effectLimit: CONFIG.effectLimit ?? 96, itemScanLimit: 16, socialScanLimit: 8, collisionInterval: 1.8, bedConflictInterval: 3.2, statsInterval: 1.2, maxDpr: 2 };
},
beginFramePerformanceBudgets(quality = this.performanceQuality?.()) {
const pressure = clamp(Number(quality?.pressure || 0) || 0, 0, 1);
const density = clamp(Number(quality?.effectDensity || (1 - pressure)) || 0, 0.12, 1);
beginFramePerformanceBudgets() {
this.workBudget = {
ai: Math.max(4, Math.round(4 + density * 24)),
env: Math.max(3, Math.round(3 + density * 15)),
ai: Math.max(1, Math.ceil(((this.tarinai || []).length || 1) / 2)),
env: Math.max(1, Math.ceil(((this.tarinai || []).length || 1) / 3)),
aiUsed: 0,
envUsed: 0,
};
@ -106,11 +98,11 @@
},
performance: {
liveTarinai,
fps: window.TarinaiPerformance?.fps || window.__tarinaiFps || 0,
pressure: this.performanceQuality?.().pressure || 0,
level: this.performanceLevel?.() || 0,
fps: window.__tarinaiFps || window.TarinaiPerformance?.fps || 0,
pressure: 0,
level: 0,
dpr: (typeof uiCache !== "undefined" ? uiCache?.canvasDpr : window.uiCache?.canvasDpr) || 0,
quality: this.performanceQuality?.() || null,
quality: null,
},
work: {
budget: this.workBudget || null,
@ -121,10 +113,9 @@
grassLoadLevel() {
const grass = this.itemCounts?.grass || 0;
const perf = this.performanceLevel();
if (perf >= 3 || grass >= 180) return 3;
if (perf >= 2 || grass >= 120) return 2;
if (perf >= 1 || grass >= 72) return 1;
if (grass >= 180) return 3;
if (grass >= 120) return 2;
if (grass >= 72) return 1;
return 0;
},
@ -132,6 +123,29 @@
return [1.0, 1.35, 1.85, 2.45][this.grassLoadLevel()] || 1.0;
},
grassLimit() {
const limit = Number(CONFIG.grassLimit ?? 360);
return Number.isFinite(limit) && limit >= 0 ? Math.floor(limit) : Infinity;
},
isGrassLimitExempt(item) {
return Boolean(item && item.type === "grass" && (item.grassLimitExempt || item.manualGrass || item.placedByPlayer));
},
liveGrassCount() {
let total = 0;
for (const it of this.items || []) {
if (it && !it.dead && it.type === "grass" && !this.isGrassLimitExempt?.(it)) total += 1;
}
return total;
},
canAddGrass(extra = 1) {
const limit = this.grassLimit ? this.grassLimit() : (CONFIG.grassLimit ?? 360);
if (!Number.isFinite(limit)) return true;
return (this.liveGrassCount ? this.liveGrassCount() : 0) + Math.max(0, Number(extra) || 0) <= limit;
},
sortedDrawList() {
if (!this.drawList) this.drawList = [];
const antCount = liveCount(this.ants);
@ -149,6 +163,10 @@
ensureSpatial(reason = "read") {
if (!this.spatial) return false;
if (!this.spatialDirty && (this.spatialVersion || 0) > 0) return false;
// Rebuild at most once per frame. Queries after movement may use the previous
// frame's grid until the next update-start; this is acceptable for this game
// and avoids repeated full-grid rebuilds under dense scenes.
if ((this.spatialRebuildsThisFrame || 0) > 0 && (this.spatialVersion || 0) > 0) return false;
return this.rebuildSpatial(true, reason);
},
@ -213,6 +231,9 @@
addItem(item, reason = "add-item", opts = {}) {
if (!item) return null;
const ignoreGrassLimit = Boolean(opts.ignoreGrassLimit || opts.manualGrass || item.grassLimitExempt || item.manualGrass || item.placedByPlayer);
if (item.type === "grass" && !ignoreGrassLimit && !this.canAddGrass?.(1)) return null;
if (item.type === "grass" && ignoreGrassLimit) item.grassLimitExempt = true;
this.items.push(item);
this.markItemBucketsDirty?.(reason);
this.markSpatialDirty?.(reason);
@ -273,7 +294,6 @@
},
compactItems() {
this.enforceItemBudget();
const before = this.items.length;
let write = 0;
for (let read = 0; read < this.items.length; read++) {
@ -291,48 +311,8 @@
return changed;
},
enforceItemBudget() {
const pruneOldest = (type, limit) => {
if (!Number.isFinite(limit) || limit < 0) return;
const live = this.liveItemsOfType?.(type) || (this.items || []).filter(it => it && it.type === type && !it.dead);
const count = live.length;
if (count <= limit) return;
const victims = live
.slice()
.sort((a, b) => (b.age || 0) - (a.age || 0))
.slice(0, count - limit);
for (const it of victims) it.amount = 0;
};
pruneOldest("zunchi", CONFIG.zunchiLimit ?? 56);
pruneOldest("trace", CONFIG.traceLimit ?? 64);
pruneOldest("splat", CONFIG.splatLimit ?? 48);
pruneOldest("grass", this.grassLimit ? this.grassLimit() : (CONFIG.grassLimit ?? 96));
const fenceLimit = this.fenceLimit ? this.fenceLimit() : (CONFIG.fenceLimit ?? 72);
const liveFences = this.liveFenceCount ? this.liveFenceCount() : 0;
if (liveFences > fenceLimit) {
const victims = (this.items || [])
.filter(it => it && this.isFenceType?.(it.type) && !it.dead)
.sort((a, b) => (b.age || 0) - (a.age || 0))
.slice(0, liveFences - fenceLimit);
for (const it of victims) it.amount = 0;
}
const limit = CONFIG.itemLimit ?? Infinity;
if (!Number.isFinite(limit) || this.items.length <= limit) return;
const priority = { trace: 1, splat: 2, zunchi: 3, water: 4, grass: 5, sweet: 6, firecracker: 7, fence_v: 8, fence_h: 8 };
const removable = (this.items || [])
.filter(it => it && !it.dead && (priority[it.type] || 99) < 99)
.sort((a, b) => (priority[a.type] || 99) - (priority[b.type] || 99) || (b.age || 0) - (a.age || 0));
let extra = this.items.length - limit;
for (const it of removable) {
if (extra <= 0) break;
it.amount = 0;
extra -= 1;
}
},
compactEffects() {
const limit = this.performanceQuality?.().effectLimit ?? CONFIG.effectLimit ?? 96;
const limit = CONFIG.effectLimit ?? 96;
if (Number.isFinite(limit) && this.effects.length > limit) {
this.effects.sort((a, b) => (a.life / Math.max(a.maxLife || 1, 0.001)) - (b.life / Math.max(b.maxLife || 1, 0.001)));
const remove = this.effects.length - limit;