feat: initialize sunrise with 100-player shared rooms

This commit is contained in:
2026-10-30 16:36:35 +09:00
commit 31d6eac4c2
257 changed files with 66063 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { createRainGearState } from '../src/controls/rainGear.ts';
import { createEmoteState } from '../src/controls/emotes.ts';
import { createSheep } from '../src/scene/sheep.ts';
test('rain equipment is independent of emotes, remains in snow, and clears in dry weather', () => {
const gear = createRainGearState();
const emote = createEmoteState();
assert.equal(gear.toggle('umbrella'), false);
gear.updateWeather(1, 0);
assert.equal(gear.toggle('hood'), false, 'hood requires the raincoat');
assert.ok(gear.toggle('umbrella'));
assert.ok(gear.toggle('raincoat'));
assert.ok(gear.toggle('hood'));
assert.ok(gear.hood);
emote.start('wave', false); emote.update(4, true, false);
assert.equal(emote.current, 'idle');
assert.ok(gear.umbrella && gear.raincoat);
emote.start('pray', true);
gear.updateWeather(0, .3);
assert.ok(gear.umbrella && gear.raincoat);
gear.toggle('umbrella');
assert.ok(!gear.umbrella && gear.raincoat);
gear.toggle('raincoat');
assert.equal(gear.hood, false);
gear.updateWeather(0, 0);
assert.ok(!gear.available && !gear.umbrella && !gear.raincoat);
});
async function asset(name: string) {
const bytes = await readFile(new URL(`../public/characters/${name}.glb`, import.meta.url));
return (await new GLTFLoader().parseAsync(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength), '')).scene;
}
test('Blender gear follows the sheep joints and keeps the umbrella grip through walking, waving and prayer', async () => {
const [model, umbrella, raincoat] = await Promise.all(['red-sheep', 'umbrella', 'raincoat'].map(asset));
const sheep = createSheep(model, { umbrella, raincoat });
const right = model.getObjectByName('ArmRight')!;
const left = model.getObjectByName('ArmLeft')!;
const sleeve = model.getObjectByName('CoatArmRight')!;
const hood = model.getObjectByName('CoatHood')!;
const folded = model.getObjectByName('CoatFoldedHood')!;
assert.equal(hood.parent, model.getObjectByName('Head'));
assert.equal(sleeve.parent, right);
assert.equal(umbrella.visible, false);
sheep.setEquipment(true, true);
assert.ok(!hood.visible && folded.visible);
sheep.setEquipment(true, true, true);
assert.ok(hood.visible && !folded.visible);
sheep.pose('idle', 0, true, 1);
const grip = right.quaternion.clone();
const leftWalking = left.quaternion.clone();
sheep.pose('wave', .2, false, 1);
assert.ok(right.quaternion.angleTo(grip) < 1e-6);
assert.ok(left.quaternion.angleTo(leftWalking) > .5);
sheep.pose('pray', .2, false, 1);
assert.ok(right.quaternion.angleTo(grip) < 1e-6);
assert.ok(umbrella.visible && raincoat.visible && sleeve.visible);
sheep.setEquipment(false, false);
assert.ok(!umbrella.visible && !raincoat.visible && !sleeve.visible);
assert.equal(hood.visible, false);
sheep.dispose();
});