This commit is contained in:
33333-33333 2026-09-29 23:45:12 +09:00
commit f5fc9b76ce
73 changed files with 32628 additions and 376 deletions

View file

@ -1,6 +1,7 @@
import {World,DT} from './engine.js?v=41';
import {roleCode} from './ecology/feeding.js';
const seedBuffer=new Uint32Array(1);crypto.getRandomValues(seedBuffer);const world=new World(seedBuffer[0]);let speed=1,statMode=false,last=performance.now(),debt=0,lastSend=0,lastMeasure=last,steps=0,actual=0,selected=null,limited=false,lastFieldEpoch=-1,lastSummary=0,forceSnapshot=true,lastHistoryTime=-1,lastEvent=null,awaitingAck=false,waterDirty=true,rocksDirty=true,moistureDirty=true;
import {World,DT} from './engine.js?v=45';
import {roleCode} from './ecology/feeding.js?v=45';
import {NORMAL_PLAYBACK_DAYS_PER_SECOND} from './time.js?v=45';
const seedBuffer=new Uint32Array(1);crypto.getRandomValues(seedBuffer);const world=new World(seedBuffer[0]);let speed=1,statMode=false,last=performance.now(),debt=0,lastSend=0,lastMeasure=last,steps=0,actual=0,selected=null,limited=false,lastSummary=0,forceSnapshot=true,lastHistoryTime=-1,lastEvent=null,awaitingAck=false,waterDirty=true,rocksDirty=true,moistureDirty=true,lastFieldSend=0;
onmessage=({data:d})=>{
if(d.type==='ack'){awaitingAck=false;return}
@ -13,9 +14,9 @@ onmessage=({data:d})=>{
function send(){
if(awaitingAck)return;const now=performance.now(),summary=forceSnapshot||now-lastSummary>850,field=!statMode&&(forceSnapshot||Math.floor(world.tick/20)!==lastFieldEpoch),a=world.animals.find(a=>a.id===selected&&!a.dead);const packet={type:'state',actual,limited,statMode};const alive=statMode?[]:world.animals.filter(a=>!a.dead),data=new Float32Array(alive.length*7),ids=new Uint32Array(alive.length),sids=new Uint32Array(alive.length);
if(awaitingAck)return;const now=performance.now(),summary=forceSnapshot||now-lastSummary>650,field=!statMode&&(forceSnapshot||waterDirty||rocksDirty||moistureDirty||now-lastFieldSend>750),a=world.animals.find(a=>a.id===selected&&!a.dead);const packet={type:'state',actual,limited,statMode};const alive=statMode?[]:world.animals.filter(a=>!a.dead),data=new Float32Array(alive.length*7),ids=new Uint32Array(alive.length),sids=new Uint32Array(alive.length);
for(let i=0;i<alive.length;i++){const a=alive[i],j=i*7;ids[i]=a.id;sids[i]=a.sid;data[j]=a.x;data[j+1]=a.y;data[j+2]=world.radius(a);data[j+3]=a.vx;data[j+4]=a.vy;data[j+5]=roleCode(world.species[a.sid]?.trophicRole);data[j+6]=a.g.waterAffinity}packet.animalData=data;packet.animalIds=ids;packet.animalSids=sids;
if(summary){packet.stats=world.stats();const newest=world.history.at(-1)?.time;if(forceSnapshot||newest!==lastHistoryTime){packet.history=world.history;lastHistoryTime=newest}if(forceSnapshot||world.events[0]!==lastEvent){packet.events=world.events;lastEvent=world.events[0]}packet.selected=a?{id:a.id,sid:a.sid,g:a.g,age:a.age,energy:a.energy,stamina:a.stamina,maxStamina:world.staminaCapacity(a),concealment:world.concealmentAt(a.x,a.y),action:a.action,parents:a.parents,generation:a.generation,mass:world.biomass(a),maxEnergy:world.maxEnergy(a)}:null;lastSummary=now}
if(field){packet.carcasses=world.carcasses;if(waterDirty){packet.water=world.water;waterDirty=false}if(rocksDirty){packet.rocks=world.rocks;rocksDirty=false}packet.trees=world.trees.map(({x,y,r,trunk,leaves,maxLeaves,variant})=>({x,y,r,trunk,leaves,maxLeaves,variant}));packet.fallen=world.fallen;packet.plants=world.plants;if(moistureDirty){packet.moisture=world.moisture;moistureDirty=false}lastFieldEpoch=Math.floor(world.tick/20)}if(statMode)packet.carcasses=[];awaitingAck=true;postMessage(packet,[data.buffer,ids.buffer,sids.buffer]);forceSnapshot=false;lastSend=now;
if(field){packet.carcasses=world.carcasses;if(waterDirty){packet.water=world.water;waterDirty=false}if(rocksDirty){packet.rocks=world.rocks;rocksDirty=false}packet.trees=world.trees.map(({x,y,r,trunk,leaves,maxLeaves,variant})=>({x,y,r,trunk,leaves,maxLeaves,variant}));packet.fallen=world.fallen;packet.plants=world.plants;if(moistureDirty){packet.moisture=world.moisture;moistureDirty=false}lastFieldSend=now}if(statMode)packet.carcasses=[];awaitingAck=true;postMessage(packet,[data.buffer,ids.buffer,sids.buffer]);forceSnapshot=false;lastSend=now;
}
function loop(){const now=performance.now(),elapsed=Math.min(.2,(now-last)/1000);last=now;if(speed){debt=Math.min(debt+elapsed*speed,DT*300);const start=performance.now();while(debt>=DT&&performance.now()-start<22){world.step();debt-=DT;steps++;if(world.animals.length>18000){speed=0;limited=true;world.log('計算保護:18,000個体を超えたため一時停止');break}}}if(now-lastMeasure>1000){actual=steps*DT/((now-lastMeasure)/1000);steps=0;lastMeasure=now}if(now-lastSend>(statMode?900:120))send();setTimeout(loop,4)}send();loop();
function loop(){const now=performance.now(),elapsed=Math.min(.2,(now-last)/1000);last=now;if(speed){debt=Math.min(debt+elapsed*speed*NORMAL_PLAYBACK_DAYS_PER_SECOND,DT*300);const start=performance.now();while(debt>=DT&&performance.now()-start<22){world.step();debt-=DT;steps++;if(world.animals.length>18000){speed=0;limited=true;world.log('計算保護:18,000個体を超えたため一時停止');break}}}if(now-lastMeasure>1000){actual=steps*DT/((now-lastMeasure)/1000);steps=0;lastMeasure=now}const sendInterval=statMode?900:speed>=100?250:speed>=20?160:100;if(now-lastSend>sendInterval)send();setTimeout(loop,4)}send();loop();