Portals!
This commit is contained in:
parent
4d59654eef
commit
16ed2a012e
|
@ -1,8 +1,8 @@
|
||||||
|
*.js.map
|
||||||
/dummykey.crt
|
/dummykey.crt
|
||||||
/dummykey.key
|
/dummykey.key
|
||||||
/dummykey.pem
|
/dummykey.pem
|
||||||
/index.js
|
/index.js
|
||||||
/index.js.map
|
|
||||||
/lib
|
/lib
|
||||||
/node_modules
|
/node_modules
|
||||||
/src.ts/
|
/src.ts/
|
||||||
|
|
|
@ -6,5 +6,7 @@ PortalDestination =
|
||||||
/ @remote <remote <ws @url string> @sturdyref sturdy.SturdyRef>
|
/ @remote <remote <ws @url string> @sturdyref sturdy.SturdyRef>
|
||||||
.
|
.
|
||||||
|
|
||||||
|
Gravity = <gravity @direction shapes.Vector3> .
|
||||||
|
|
||||||
; Message
|
; Message
|
||||||
Touch = <touch @subject string @object string> .
|
Touch = <touch @subject string @object string> .
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<Scene "lobby" $config>
|
||||||
|
<Room "other">
|
||||||
|
|
||||||
|
? <Room ?name> [
|
||||||
|
let ?scene = dataspace
|
||||||
|
<Scene $name $scene>
|
||||||
|
]
|
|
@ -0,0 +1,9 @@
|
||||||
|
? <Scene ?name ?scene> [
|
||||||
|
$scene [
|
||||||
|
? <Exit ?spriteName ?roomName> [
|
||||||
|
$config ? <Scene $roomName ?ds> [
|
||||||
|
$scene <portal $spriteName $ds>
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
|
@ -0,0 +1,65 @@
|
||||||
|
? <Scene "lobby" ?scene> $scene [
|
||||||
|
<sprite "light" <hemispheric-light <v 0.1 1.0 0.0>>>
|
||||||
|
<gravity <v 0.0 -9.81 0.0>>
|
||||||
|
|
||||||
|
<sprite "ground"
|
||||||
|
<texture ["textures/grass-256x256.jpg"
|
||||||
|
<v 0.01 0.01>
|
||||||
|
<v 0.0 0.0>]
|
||||||
|
<floor <ground <v 300.0 300.0>>>>>
|
||||||
|
|
||||||
|
<sprite "box"
|
||||||
|
<move <v -6.0 1.0 8.0>
|
||||||
|
<scale <v 10.0 0.1 10.0>
|
||||||
|
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
|
||||||
|
<v 0.1 0.1>
|
||||||
|
<v 0.0 0.0>
|
||||||
|
0.75]
|
||||||
|
<floor <box>>>>>>
|
||||||
|
|
||||||
|
<sprite "box2"
|
||||||
|
<move <v -500.0 0.5 3.0>
|
||||||
|
<floor
|
||||||
|
<color 0.0 0.0 1.0 1.0
|
||||||
|
<scale <v 1000.0 1.0 1.0> <box>>>>>>
|
||||||
|
|
||||||
|
<sprite "steps"
|
||||||
|
<color 0.0 0.5 0.0
|
||||||
|
<move <v 0.0 0.0 3.5>
|
||||||
|
<scale <v 1.0 1.0 3.0>
|
||||||
|
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"]
|
||||||
|
[
|
||||||
|
<move <v 0.0 0.25 0.0> <box>>
|
||||||
|
<move <v 1.0 0.0 0.0> <box>>
|
||||||
|
<move <v 2.0 -0.25 0.0> <box>>
|
||||||
|
]>>>>>
|
||||||
|
|
||||||
|
<Exit "ball" "other">
|
||||||
|
<sprite "ball"
|
||||||
|
<move <v 0.0 1.5 2.0>
|
||||||
|
<scale <v 1.0 1.0 1.0>
|
||||||
|
<color 0.0 1.0 0.0
|
||||||
|
<floor
|
||||||
|
<touchable
|
||||||
|
<sphere>>>>>>>
|
||||||
|
|
||||||
|
<sprite "plans"
|
||||||
|
<texture ["plans/signal-2022-12-27-125451_002.jpeg"]
|
||||||
|
<move <v 0.0 1.0 -10.0>
|
||||||
|
<rotate <v 0.5 0.0 0.0>
|
||||||
|
<scale <v 2.0 2.0 0.1>
|
||||||
|
<box>>>>>>
|
||||||
|
|
||||||
|
<sprite "tower"
|
||||||
|
<rotate <v 0.6 0.0 0.0>
|
||||||
|
<move <v -10.0 50.0 13.0>
|
||||||
|
<scale <v 3.0 100.0 3.0>
|
||||||
|
<floor
|
||||||
|
<color 0.5 0.5 0.0
|
||||||
|
<box>>>>>>>
|
||||||
|
|
||||||
|
<sprite "house"
|
||||||
|
<scale <v 10.0 4.0 15.0>
|
||||||
|
<floor
|
||||||
|
<move <v 1.5 0.5 -0.5> <box>>>>>
|
||||||
|
]
|
|
@ -0,0 +1,12 @@
|
||||||
|
? <Scene "other" ?scene> $scene [
|
||||||
|
<sprite "light" <hemispheric-light <v 0.1 1.0 0.0>>>
|
||||||
|
|
||||||
|
<sprite "ground2"
|
||||||
|
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
|
||||||
|
<v 0.01 0.01>
|
||||||
|
<v 0.0 0.0>]
|
||||||
|
<floor <ground <v 300.0 300.0>>>>>
|
||||||
|
|
||||||
|
<Exit "home" "lobby">
|
||||||
|
<sprite "home" <move <v 0.0 1.5 -5.0> <color 0.0 1.0 0.0 <touchable <sphere>>>>>
|
||||||
|
]
|
|
@ -1,66 +0,0 @@
|
||||||
<sprite "light" <hemispheric-light <v 0.1 1.0 0.0>>>
|
|
||||||
|
|
||||||
<sprite "ground"
|
|
||||||
<texture ["textures/grass-256x256.jpg"
|
|
||||||
<v 0.01 0.01>
|
|
||||||
<v 0.0 0.0>]
|
|
||||||
<floor <ground <v 300.0 300.0>>>>>
|
|
||||||
|
|
||||||
<sprite "box"
|
|
||||||
<move <v -6.0 1.0 8.0>
|
|
||||||
<scale <v 10.0 0.1 10.0>
|
|
||||||
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"
|
|
||||||
<v 0.1 0.1>
|
|
||||||
<v 0.0 0.0>
|
|
||||||
0.75]
|
|
||||||
<floor <box>>>>>>
|
|
||||||
|
|
||||||
<sprite "box2"
|
|
||||||
<move <v -500.0 0.5 3.0>
|
|
||||||
<floor
|
|
||||||
<color 0.0 0.0 1.0 1.0
|
|
||||||
<scale <v 1000.0 1.0 1.0> <box>>>>>>
|
|
||||||
|
|
||||||
<sprite "steps"
|
|
||||||
<color 0.0 0.5 0.0
|
|
||||||
<move <v 0.0 0.0 3.5>
|
|
||||||
<scale <v 1.0 1.0 3.0>
|
|
||||||
<texture ["textures/oak-herringbone-5e80fb40b00c9-1200.jpg"]
|
|
||||||
[
|
|
||||||
<move <v 0.0 0.25 0.0> <box>>
|
|
||||||
<move <v 1.0 0.0 0.0> <box>>
|
|
||||||
<move <v 2.0 -0.25 0.0> <box>>
|
|
||||||
]>>>>>
|
|
||||||
|
|
||||||
let ?ballDs = dataspace
|
|
||||||
<portal "ball" $ballDs>
|
|
||||||
|
|
||||||
<sprite "ball"
|
|
||||||
<move <v 0.0 1.5 2.0>
|
|
||||||
<scale <v 1.0 1.0 1.0>
|
|
||||||
<color 0.0 1.0 0.0
|
|
||||||
<floor
|
|
||||||
<touchable
|
|
||||||
<sphere>>>>>>>
|
|
||||||
|
|
||||||
<sprite "plans"
|
|
||||||
<texture ["plans/signal-2022-12-27-125451_002.jpeg"]
|
|
||||||
<move <v 0.0 1.0 -10.0>
|
|
||||||
<rotate <v 0.5 0.0 0.0>
|
|
||||||
<scale <v 2.0 2.0 0.1>
|
|
||||||
<box>>>>>>
|
|
||||||
|
|
||||||
<sprite "tower"
|
|
||||||
<rotate <v 0.6 0.0 0.0>
|
|
||||||
<move <v -10.0 50.0 13.0>
|
|
||||||
<scale <v 3.0 100.0 3.0>
|
|
||||||
<floor
|
|
||||||
<color 0.5 0.5 0.0
|
|
||||||
<box>>>>>>>
|
|
||||||
|
|
||||||
<sprite "house"
|
|
||||||
<scale <v 10.0 4.0 15.0>
|
|
||||||
<floor
|
|
||||||
<move <v 1.5 0.5 -0.5> <box>>>>>
|
|
||||||
|
|
||||||
[]
|
|
|
@ -45,9 +45,7 @@ if ((navigator as any).oscpu?.startsWith('Linux')) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CreateScene = (engine: Engine) => Promise<CreatedScene>;
|
export type Interactivity = {
|
||||||
export type CreatedScene = {
|
|
||||||
scene: Scene,
|
|
||||||
floorMeshes: () => Mesh[],
|
floorMeshes: () => Mesh[],
|
||||||
touchableMeshes: () => Mesh[],
|
touchableMeshes: () => Mesh[],
|
||||||
};
|
};
|
||||||
|
@ -87,9 +85,9 @@ export class GamepadState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RunningEngine {
|
export class RunningEngine {
|
||||||
camera: FreeCamera;
|
camera!: FreeCamera;
|
||||||
xrSessionManager: WebXRSessionManager | null;
|
xrSessionManager: WebXRSessionManager | null = null;
|
||||||
gamepadInput: FreeCameraGamepadInput;
|
gamepadInput!: FreeCameraGamepadInput;
|
||||||
|
|
||||||
leanBase: { position: Vector3 } | null = null;
|
leanBase: { position: Vector3 } | null = null;
|
||||||
recenterBase: { rotation: Quaternion } | null = null;
|
recenterBase: { rotation: Quaternion } | null = null;
|
||||||
|
@ -97,7 +95,7 @@ export class RunningEngine {
|
||||||
padStates: Map<Gamepad, GamepadState> = new Map();
|
padStates: Map<Gamepad, GamepadState> = new Map();
|
||||||
|
|
||||||
static async start(
|
static async start(
|
||||||
createScene: CreateScene,
|
interactivity: Interactivity,
|
||||||
options0: Partial<EngineOptions> = {},
|
options0: Partial<EngineOptions> = {},
|
||||||
): Promise<RunningEngine> {
|
): Promise<RunningEngine> {
|
||||||
const options = Object.assign({
|
const options = Object.assign({
|
||||||
|
@ -106,15 +104,16 @@ export class RunningEngine {
|
||||||
canvas: document.getElementById("renderCanvas") as HTMLCanvasElement,
|
canvas: document.getElementById("renderCanvas") as HTMLCanvasElement,
|
||||||
}, options0);
|
}, options0);
|
||||||
const engine = new Engine(options.canvas, true);
|
const engine = new Engine(options.canvas, true);
|
||||||
const createdScene = await createScene(engine);
|
const scene = new Scene(engine);
|
||||||
const xr = await createdScene.scene.createDefaultXRExperienceAsync({});
|
const xr = await scene.createDefaultXRExperienceAsync({});
|
||||||
return new RunningEngine(options, engine, createdScene, xr);
|
return new RunningEngine(options, engine, interactivity, scene, xr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private constructor (
|
private constructor (
|
||||||
public options: EngineOptions,
|
public options: EngineOptions,
|
||||||
public engine: Engine,
|
public engine: Engine,
|
||||||
public createdScene: CreatedScene,
|
public interactivity: Interactivity,
|
||||||
|
public scene: Scene,
|
||||||
public xr: WebXRDefaultExperience,
|
public xr: WebXRDefaultExperience,
|
||||||
) {
|
) {
|
||||||
this.xrSessionManager = this.xr.baseExperience?.sessionManager ?? null;
|
this.xrSessionManager = this.xr.baseExperience?.sessionManager ?? null;
|
||||||
|
@ -124,7 +123,7 @@ export class RunningEngine {
|
||||||
} else {
|
} else {
|
||||||
this.camera = new FreeCamera("camera",
|
this.camera = new FreeCamera("camera",
|
||||||
this.options.initialPos,
|
this.options.initialPos,
|
||||||
this.createdScene.scene);
|
this.scene);
|
||||||
this.camera.rotation = this.options.initialRotation;
|
this.camera.rotation = this.options.initialRotation;
|
||||||
this.camera.minZ = 0.1;
|
this.camera.minZ = 0.1;
|
||||||
this.camera.inertia = 0.75;
|
this.camera.inertia = 0.75;
|
||||||
|
@ -138,12 +137,13 @@ export class RunningEngine {
|
||||||
this.camera.inputs.add(this.gamepadInput);
|
this.camera.inputs.add(this.gamepadInput);
|
||||||
this.gamepadInput.attachControl();
|
this.gamepadInput.attachControl();
|
||||||
|
|
||||||
this.createdScene.scene.gravity = new Vector3(0, -9.81 / 90, 0);
|
this.scene.gravity = new Vector3(0, -9.81 / 90, 0);
|
||||||
this.createdScene.scene.collisionsEnabled = true;
|
this.scene.collisionsEnabled = true;
|
||||||
|
|
||||||
this.camera.checkCollisions = true;
|
this.camera.checkCollisions = true;
|
||||||
this.camera.applyGravity = true;
|
this.camera.applyGravity = false;
|
||||||
this.camera.ellipsoid = new Vector3(0.25, 0.8, 0.25);
|
(this.camera as any)._needMoveForGravity = true;
|
||||||
|
this.camera.ellipsoid = new Vector3(0.25, this.options.initialPos.y / 2, 0.25);
|
||||||
|
|
||||||
if (this.options.canvas) {
|
if (this.options.canvas) {
|
||||||
const canvas = this.options.canvas;
|
const canvas = this.options.canvas;
|
||||||
|
@ -158,8 +158,9 @@ export class RunningEngine {
|
||||||
Array.from(navigator.getGamepads()).forEach(gp => {
|
Array.from(navigator.getGamepads()).forEach(gp => {
|
||||||
if (gp !== null) this.checkGamepadInput(gp);
|
if (gp !== null) this.checkGamepadInput(gp);
|
||||||
});
|
});
|
||||||
this.createdScene.scene.render();
|
this.scene.render();
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener("resize", () => this.engine.resize());
|
window.addEventListener("resize", () => this.engine.resize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,8 +227,8 @@ export class RunningEngine {
|
||||||
|
|
||||||
xrTouch() {
|
xrTouch() {
|
||||||
const ray = this.xr.baseExperience.camera.getForwardRay();
|
const ray = this.xr.baseExperience.camera.getForwardRay();
|
||||||
const meshes = this.createdScene.touchableMeshes();
|
const meshes = this.interactivity.touchableMeshes();
|
||||||
const hit = this.createdScene.scene.pickWithRay(ray, m => meshes.indexOf(m as any) !== -1);
|
const hit = this.scene.pickWithRay(ray, m => meshes.indexOf(m as any) !== -1);
|
||||||
|
|
||||||
if (hit === null) return;
|
if (hit === null) return;
|
||||||
if (meshes.indexOf(hit.pickedMesh as any) === -1) return;
|
if (meshes.indexOf(hit.pickedMesh as any) === -1) return;
|
||||||
|
@ -239,8 +240,8 @@ export class RunningEngine {
|
||||||
if (!this.xrSessionManager) return;
|
if (!this.xrSessionManager) return;
|
||||||
|
|
||||||
const ray = this.xr.baseExperience.camera.getForwardRay();
|
const ray = this.xr.baseExperience.camera.getForwardRay();
|
||||||
const meshes = this.createdScene.floorMeshes();
|
const meshes = this.interactivity.floorMeshes();
|
||||||
const hit = this.createdScene.scene.pickWithRay(ray, m => meshes.indexOf(m as any) !== -1);
|
const hit = this.scene.pickWithRay(ray, m => meshes.indexOf(m as any) !== -1);
|
||||||
|
|
||||||
if (hit === null) return;
|
if (hit === null) return;
|
||||||
if (meshes.indexOf(hit.pickedMesh as any) === -1) return;
|
if (meshes.indexOf(hit.pickedMesh as any) === -1) return;
|
||||||
|
|
249
src/index.ts
249
src/index.ts
|
@ -1,4 +1,4 @@
|
||||||
import { is, Dataspace, Embedded, Reader, Ref, Schemas, Sturdy, Turn } from "@syndicate-lang/core";
|
import { is, embed, stringify, Dataflow, Dataspace, Embedded, Reader, Ref, Schemas, Sturdy, Turn, Value } from "@syndicate-lang/core";
|
||||||
import * as html from "@syndicate-lang/html";
|
import * as html from "@syndicate-lang/html";
|
||||||
import * as timer from "@syndicate-lang/timer";
|
import * as timer from "@syndicate-lang/timer";
|
||||||
import * as wsRelay from "@syndicate-lang/ws-relay";
|
import * as wsRelay from "@syndicate-lang/ws-relay";
|
||||||
|
@ -14,16 +14,17 @@ import {
|
||||||
Mesh,
|
Mesh,
|
||||||
Scene,
|
Scene,
|
||||||
TargetCamera,
|
TargetCamera,
|
||||||
|
Vector3,
|
||||||
WebXRCamera,
|
WebXRCamera,
|
||||||
} from '@babylonjs/core/Legacy/legacy';
|
} from '@babylonjs/core/Legacy/legacy';
|
||||||
|
|
||||||
import { activeFloorMeshes, activeTouchableMeshes, ShapeTree, builder as B } from './shapes.js';
|
import { activeFloorMeshes, activeTouchableMeshes, ShapeTree, builder as B } from './shapes.js';
|
||||||
import { RunningEngine, CreatedScene } from './engine.js';
|
import { RunningEngine } from './engine.js';
|
||||||
import { uuid } from './uuid.js';
|
import { uuid } from './uuid.js';
|
||||||
|
|
||||||
assertion type SceneHandle(ds: Embedded<Ref>);
|
assertion type SceneHandle(ds: Embedded<Ref>);
|
||||||
|
|
||||||
function interpretScene(myId: string, scene: Scene, sceneDs: Ref) {
|
function interpretScene(myId: string, scene: Scene, rootMesh: Mesh, sceneDs: Ref) {
|
||||||
at sceneDs {
|
at sceneDs {
|
||||||
during Shapes.Sprite({ "name": $name: string }) => spawn named `sprite:${name}` {
|
during Shapes.Sprite({ "name": $name: string }) => spawn named `sprite:${name}` {
|
||||||
if (name === myId) {
|
if (name === myId) {
|
||||||
|
@ -31,22 +32,153 @@ function interpretScene(myId: string, scene: Scene, sceneDs: Ref) {
|
||||||
} else {
|
} else {
|
||||||
console.log('+shape', name);
|
console.log('+shape', name);
|
||||||
on stop console.log('-shape', name);
|
on stop console.log('-shape', name);
|
||||||
spriteMain(name, scene, sceneDs);
|
spriteMain(name, scene, rootMesh, sceneDs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function spriteMain(spriteName: string, scene: Scene, sceneDs: Ref) {
|
function spriteMain(spriteName: string, scene: Scene, rootMesh: Mesh, sceneDs: Ref) {
|
||||||
at sceneDs {
|
at sceneDs {
|
||||||
let currentShape = ShapeTree.empty(spriteName, scene);
|
let currentShape = ShapeTree.empty(spriteName, scene);
|
||||||
|
currentShape.node.parent = rootMesh;
|
||||||
on stop currentShape.remove();
|
on stop currentShape.remove();
|
||||||
during Shapes.Sprite({ "name": spriteName, "shape": $shape: Shapes.Shape }) => {
|
during Shapes.Sprite({ "name": spriteName, "shape": $shape: Shapes.Shape }) => {
|
||||||
currentShape = currentShape.reconcile(spriteName, spriteName, shape);
|
currentShape = currentShape.reconcile(spriteName, spriteName, shape);
|
||||||
|
currentShape.node.parent = rootMesh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function enterScene(
|
||||||
|
id: string,
|
||||||
|
runningEngine: RunningEngine,
|
||||||
|
ds: Ref,
|
||||||
|
sceneDs: Ref,
|
||||||
|
email: Dataflow.Field<string>,
|
||||||
|
) {
|
||||||
|
const currentSceneFacet = Turn.activeFacet;
|
||||||
|
|
||||||
|
console.log('enterScene', sceneDs);
|
||||||
|
|
||||||
|
const rootMesh = new Mesh('--root-' + (+new Date()), runningEngine.scene);
|
||||||
|
interpretScene(id, runningEngine.scene, rootMesh, sceneDs);
|
||||||
|
|
||||||
|
const camera = runningEngine.camera;
|
||||||
|
camera.applyGravity = false;
|
||||||
|
camera.position = runningEngine.options.initialPos;
|
||||||
|
|
||||||
|
let lastTouchTime = 0;
|
||||||
|
let lastTouchSpriteName = "";
|
||||||
|
camera.onCollide = (other: AbstractMesh) => {
|
||||||
|
if (other.metadata?.touchable) {
|
||||||
|
const now = +new Date();
|
||||||
|
const touched = other.metadata?.spriteName ?? "";
|
||||||
|
if ((now - lastTouchTime > 500) || (lastTouchSpriteName !== touched)) {
|
||||||
|
currentSceneFacet.turn(() => {
|
||||||
|
at sceneDs {
|
||||||
|
send message SceneProtocol.Touch({
|
||||||
|
subject: id,
|
||||||
|
object: touched,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
lastTouchTime = now;
|
||||||
|
lastTouchSpriteName = touched;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentPosition = () => Shapes.Vector3(camera.position);
|
||||||
|
const currentRotation = () => Shapes.Vector3(
|
||||||
|
camera instanceof WebXRCamera
|
||||||
|
? camera.rotationQuaternion.toEulerAngles()
|
||||||
|
: camera.rotation);
|
||||||
|
|
||||||
|
field position: Shapes.Vector3 = currentPosition();
|
||||||
|
field rotation: Shapes.Vector3 = currentRotation();
|
||||||
|
|
||||||
|
const refreshPeriod = Math.floor(1000 / 10);
|
||||||
|
at ds {
|
||||||
|
on message timer.PeriodicTick(refreshPeriod) => {
|
||||||
|
const newPosition = currentPosition();
|
||||||
|
const newRotation = currentRotation();
|
||||||
|
if (!is(Shapes.fromVector3(position.value), Shapes.fromVector3(newPosition))) {
|
||||||
|
position.value = newPosition;
|
||||||
|
}
|
||||||
|
if (!is(Shapes.fromVector3(rotation.value), Shapes.fromVector3(newRotation))) {
|
||||||
|
rotation.value = newRotation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
at sceneDs {
|
||||||
|
during SceneProtocol.Gravity($direction: Shapes.Vector3) => {
|
||||||
|
camera.applyGravity = true;
|
||||||
|
on stop camera.applyGravity = false;
|
||||||
|
const frameRate = 60;
|
||||||
|
runningEngine.scene.gravity = new Vector3(direction.x / frameRate,
|
||||||
|
direction.y / frameRate,
|
||||||
|
direction.z / frameRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
on message SceneProtocol.Touch({ "subject": id, "object": $o }) => {
|
||||||
|
console.log('touched', o);
|
||||||
|
react {
|
||||||
|
let needStop = true;
|
||||||
|
on asserted SceneProtocol.Portal({
|
||||||
|
"name": o,
|
||||||
|
"destination": $dest: SceneProtocol.PortalDestination
|
||||||
|
}) => {
|
||||||
|
needStop = false;
|
||||||
|
switch (dest._variant) {
|
||||||
|
case "local":
|
||||||
|
runningEngine.scene.removeMesh(rootMesh, true);
|
||||||
|
Turn.active.stop(currentSceneFacet, () => {
|
||||||
|
react {
|
||||||
|
enterScene(id, runningEngine, ds, dest.value, email);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const checkFacet = Turn.activeFacet;
|
||||||
|
Turn.active.sync(sceneDs).then(() => checkFacet.turn(() => {
|
||||||
|
if (needStop) {
|
||||||
|
stop {}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert Shapes.Sprite({
|
||||||
|
name: id,
|
||||||
|
shape: B.nonphysical(
|
||||||
|
B.move(position.value, B.many([
|
||||||
|
B.move({ x: 0, y: -0.9, z: 0 },
|
||||||
|
B.rotate({ x: 0, y: rotation.value.y, z: 0 },
|
||||||
|
B.scale({ x: 0.4, y: 1.4, z: 0.1 }, B.box()))),
|
||||||
|
B.rotate(rotation.value,
|
||||||
|
B.scale({ x: 0.15, y: 0.23, z: 0.18 }, B.many([
|
||||||
|
B.box(),
|
||||||
|
B.move({ x: 0, y: 0, z: 0.501 },
|
||||||
|
B.texture(
|
||||||
|
Shapes.TextureSpec.uvAlpha({
|
||||||
|
path: `https://www.gravatar.com/avatar/${md5(new TextEncoder().encode(email.value.trim()))}?s=256&d=wavatar`,
|
||||||
|
scale: Shapes.Vector2({ x:1, y:1 }),
|
||||||
|
offset: Shapes.Vector2({ x:0, y:0 }),
|
||||||
|
alpha: 1
|
||||||
|
}),
|
||||||
|
B.rotate({ x: 0, y: Math.PI, z: 0 },
|
||||||
|
B.plane()))),
|
||||||
|
]))),
|
||||||
|
]))),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function wsurl(): string {
|
function wsurl(): string {
|
||||||
const scheme = (document.location.protocol.toLowerCase() === 'https:') ? 'wss' : 'ws';
|
const scheme = (document.location.protocol.toLowerCase() === 'https:') ? 'wss' : 'ws';
|
||||||
return `${scheme}://${document.location.host}/ws`;
|
return `${scheme}://${document.location.host}/ws`;
|
||||||
|
@ -82,99 +214,12 @@ function bootApp(ds: Ref, runningEngine: RunningEngine) {
|
||||||
send message wsRelay.ForceRelayDisconnect(relayAddr);
|
send message wsRelay.ForceRelayDisconnect(relayAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
at remoteDs {
|
react {
|
||||||
during SceneHandle($sceneDs_e: Embedded) => {
|
at remoteDs {
|
||||||
const thisFacet = Turn.activeFacet;
|
stop on asserted SceneHandle($sceneDs_e: Embedded) => {
|
||||||
const sceneDs = sceneDs_e.embeddedValue;
|
react {
|
||||||
interpretScene(id, runningEngine.createdScene.scene, sceneDs);
|
enterScene(id, runningEngine, ds, sceneDs_e.embeddedValue, email);
|
||||||
|
|
||||||
const camera = runningEngine.camera;
|
|
||||||
camera.onCollide = (other: AbstractMesh) => {
|
|
||||||
if (other.metadata?.touchable) {
|
|
||||||
thisFacet.turn(() => {
|
|
||||||
at sceneDs {
|
|
||||||
send message SceneProtocol.Touch({
|
|
||||||
subject: id,
|
|
||||||
object: other.metadata?.spriteName,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
field position: Shapes.Vector3 = Shapes.Vector3({ x:0, y:0, z:0 });
|
|
||||||
field rotation: Shapes.Vector3 = Shapes.Vector3({ x:0, y:0, z:0 });
|
|
||||||
|
|
||||||
at ds {
|
|
||||||
const refreshPeriod = Math.floor(1000 / 10);
|
|
||||||
on message timer.PeriodicTick(refreshPeriod) => {
|
|
||||||
if (camera instanceof TargetCamera) {
|
|
||||||
const newPosition = Shapes.Vector3(camera.position);
|
|
||||||
const newRotation = Shapes.Vector3(camera instanceof WebXRCamera
|
|
||||||
? camera.rotationQuaternion.toEulerAngles()
|
|
||||||
: camera.rotation);
|
|
||||||
if (!is(Shapes.fromVector3(position.value), Shapes.fromVector3(newPosition))) {
|
|
||||||
position.value = newPosition;
|
|
||||||
}
|
|
||||||
if (!is(Shapes.fromVector3(rotation.value), Shapes.fromVector3(newRotation))) {
|
|
||||||
rotation.value = newRotation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
at sceneDs {
|
|
||||||
on message SceneProtocol.Touch({ "subject": id, "object": $o }) => {
|
|
||||||
console.log('touch!', o);
|
|
||||||
react {
|
|
||||||
on stop console.log('portal check ending', o);
|
|
||||||
stop on asserted SceneProtocol.Portal({
|
|
||||||
"name": o,
|
|
||||||
"destination": $dest: SceneProtocol.PortalDestination
|
|
||||||
}) => react {
|
|
||||||
console.log('portal!', dest);
|
|
||||||
switch (dest._variant) {
|
|
||||||
case "local":
|
|
||||||
at dest.value {
|
|
||||||
assert 909909909;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const checkFacet = Turn.activeFacet;
|
|
||||||
Turn.active.sync(sceneDs).then(() => checkFacet.turn(() => {
|
|
||||||
console.log('synced');
|
|
||||||
stop {}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert Shapes.Sprite({
|
|
||||||
name: id,
|
|
||||||
shape: B.nonphysical(
|
|
||||||
B.move(position.value, B.many([
|
|
||||||
B.move({ x: 0, y: -0.9, z: 0 },
|
|
||||||
B.rotate({ x: 0, y: rotation.value.y, z: 0 },
|
|
||||||
B.scale({ x: 0.4, y: 1.4, z: 0.1 },
|
|
||||||
B.box()))),
|
|
||||||
B.rotate(rotation.value,
|
|
||||||
B.scale({ x: 0.15, y: 0.23, z: 0.18 }, B.many([
|
|
||||||
B.box(),
|
|
||||||
B.move({ x: 0, y: 0, z: 0.501 },
|
|
||||||
B.texture(
|
|
||||||
Shapes.TextureSpec.uvAlpha({
|
|
||||||
path: `https://www.gravatar.com/avatar/${md5(new TextEncoder().encode(email.value.trim()))}?s=256&d=wavatar`,
|
|
||||||
scale: Shapes.Vector2({ x:1, y:1 }),
|
|
||||||
offset: Shapes.Vector2({ x:0, y:0 }),
|
|
||||||
alpha: 1
|
|
||||||
}),
|
|
||||||
B.rotate({ x: 0, y: Math.PI, z: 0 },
|
|
||||||
B.plane()))),
|
|
||||||
]))),
|
|
||||||
]))),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,12 +229,10 @@ function bootApp(ds: Ref, runningEngine: RunningEngine) {
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('load', async () => {
|
window.addEventListener('load', async () => {
|
||||||
const runningEngine = await RunningEngine.start(
|
const runningEngine = await RunningEngine.start({
|
||||||
async (engine: Engine): Promise<CreatedScene> => ({
|
floorMeshes: () => activeFloorMeshes,
|
||||||
scene: new Scene(engine),
|
touchableMeshes: () => activeTouchableMeshes,
|
||||||
floorMeshes: () => activeFloorMeshes,
|
});
|
||||||
touchableMeshes: () => activeTouchableMeshes,
|
|
||||||
}));
|
|
||||||
Dataspace.boot(ds => {
|
Dataspace.boot(ds => {
|
||||||
html.boot(ds);
|
html.boot(ds);
|
||||||
timer.boot(ds);
|
timer.boot(ds);
|
||||||
|
|
Loading…
Reference in New Issue