Skip to content

Commit

Permalink
Merge pull request #5536 from mozilla/bitecs-experiment
Browse files Browse the repository at this point in the history
New Entity Framework
  • Loading branch information
netpro2k authored Jul 19, 2022
2 parents 778e02c + ecd712d commit ed12a5a
Show file tree
Hide file tree
Showing 88 changed files with 3,721 additions and 2,550 deletions.
6 changes: 3 additions & 3 deletions admin/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"ammo-debug-drawer": "github:infinitelee/ammo-debug-drawer",
"ammo.js": "github:mozillareality/ammo.js#hubs/master",
"animejs": "github:mozillareality/anime#hubs/master",
"bitecs": "^0.3.38",
"buffered-interpolation": "github:Infinitelee/buffered-interpolation",
"classnames": "^2.2.5",
"color": "^3.1.2",
Expand Down
76 changes: 75 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
import Store from "./storage/store";
import * as bitecs from "bitecs";
import { addEntity, createWorld } from "bitecs";
import "./aframe-to-bit-components";
import { AEntity, Networked, Object3DTag, Owned } from "./bit-components";
import MediaSearchStore from "./storage/media-search-store";
import Store from "./storage/store";
import qsTruthy from "./utils/qs_truthy";

window.$B = bitecs;

const timeSystem = world => {
const { time } = world;
const now = performance.now();
const delta = now - time.then;
time.delta = delta;
time.elapsed += delta;
time.then = now;
time.tick++;
return world;
};

export class App {
constructor() {
this.scene = null;
Expand All @@ -23,6 +40,50 @@ export class App {
this.clippingState = new Set();
this.mutedState = new Set();
this.isAudioPaused = new Set();

this.world = createWorld();

// TODO: Create accessor / update methods for these maps / set
this.world.eid2obj = new Map(); // eid -> Object3D

this.world.nid2eid = new Map();
this.world.deletedNids = new Set();
this.world.ignoredNids = new Set();

this.str2sid = new Map([[null, 0]]);
this.sid2str = new Map([[0, null]]);
this.nextSid = 1;

window.$o = eid => {
this.world.eid2obj.get(eid);
};

// reserve entity 0 to avoid needing to check for undefined everywhere eid is checked for existance
addEntity(this.world);

// used in aframe and networked aframe to avoid imports
this.world.nameToComponent = {
object3d: Object3DTag,
networked: Networked,
owned: Owned,
AEntity
};
}

// TODO nothing ever cleans these up
getSid(str) {
if (!this.str2sid.has(str)) {
const sid = this.nextSid;
this.nextSid = this.nextSid + 1;
this.str2sid.set(str, sid);
this.sid2str.set(sid, str);
return sid;
}
return this.str2sid.get(str);
}

getString(sid) {
return this.sid2str.get(sid);
}

// This gets called by a-scene to setup the renderer, camera, and audio listener
Expand Down Expand Up @@ -66,13 +127,24 @@ export class App {
const camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 0.05, 10000);

const audioListener = new THREE.AudioListener();
APP.audioListener = audioListener;
camera.add(audioListener);

const renderClock = new THREE.Clock();

// TODO NAF currently depends on this, it should not
sceneEl.clock = renderClock;

// TODO we should have 1 source of truth for time
APP.world.time = {
delta: 0,
elapsed: 0,
then: performance.now(),
tick: 0
};

APP.world.scene = sceneEl.object3D;

// Main RAF loop
function mainTick(_rafTime, xrFrame) {
// TODO we should probably be using time from the raf loop itself
Expand All @@ -82,6 +154,8 @@ export class App {
// TODO pass this into systems that care about it (like input) once they are moved into this loop
sceneEl.frame = xrFrame;

timeSystem(APP.world);

// Tick AFrame systems and components
if (sceneEl.isPlaying) {
sceneEl.tick(time, delta);
Expand Down
31 changes: 31 additions & 0 deletions src/aframe-to-bit-components.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { addComponent, removeComponent } from "bitecs";
import {
RemoteRight,
RemoteLeft,
HandRight,
HandLeft,
RemoteHoverTarget,
NotRemoteHoverTarget,
RemoveNetworkedEntityButton,
DestroyAtExtremeDistance
} from "./bit-components";

[
["remote-right", RemoteRight],
["remote-left", RemoteLeft],
["hand-right", HandRight],
["hand-left", HandLeft],
["is-remote-hover-target", RemoteHoverTarget],
["is-not-remote-hover-target", NotRemoteHoverTarget],
["remove-networked-object-button", RemoveNetworkedEntityButton],
["destroy-at-extreme-distances", DestroyAtExtremeDistance]
].forEach(([aframeComponentName, bitecsComponent]) => {
AFRAME.registerComponent(aframeComponentName, {
init: function() {
addComponent(APP.world, bitecsComponent, this.el.object3D.eid);
},
remove: function() {
removeComponent(APP.world, bitecsComponent, this.el.object3D.eid);
}
});
});
121 changes: 121 additions & 0 deletions src/bit-components.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { defineComponent, setDefaultSize, Types } from "bitecs";

// TODO this has to happen before all components are defined. Is there a better spot to be doing this?
setDefaultSize(10000);

export const $isStringType = Symbol("isStringType");

export const Networked = defineComponent({
id: Types.ui32,
creator: Types.ui32,
owner: Types.ui32,

lastOwnerTime: Types.ui32
});
Networked.id[$isStringType] = true;
Networked.creator[$isStringType] = true;
Networked.owner[$isStringType] = true;

export const Owned = defineComponent();
export const NetworkedMediaFrame = defineComponent({
capturedNid: Types.ui32,
scale: [Types.f32, 3]
});
NetworkedMediaFrame.capturedNid[$isStringType] = true;

export const MediaFrame = defineComponent({
capturedNid: Types.ui32,
scale: [Types.f32, 3],
mediaType: Types.ui8,
bounds: [Types.f32, 3],
preview: Types.eid,
previewingNid: Types.eid
});
export const Text = defineComponent();
export const Slice9 = defineComponent({
insets: [Types.ui32, 4],
size: [Types.f32, 2]
});

export const NetworkedTransform = defineComponent({
position: [Types.f32, 3],
rotation: [Types.f32, 4],
scale: [Types.f32, 3]
});

export const AEntity = defineComponent();
export const Object3DTag = defineComponent();
export const GLTFModel = defineComponent();
export const CursorRaycastable = defineComponent();
export const RemoteHoverTarget = defineComponent();
export const NotRemoteHoverTarget = defineComponent();
export const Holdable = defineComponent();
export const RemoveNetworkedEntityButton = defineComponent();
export const Interacted = defineComponent();

export const HandRight = defineComponent();
export const HandLeft = defineComponent();
export const RemoteRight = defineComponent();
export const RemoteLeft = defineComponent();
export const HoveredHandRight = defineComponent();
export const HoveredHandLeft = defineComponent();
export const HoveredRemoteRight = defineComponent();
export const HoveredRemoteLeft = defineComponent();
export const HeldHandRight = defineComponent();
export const HeldHandLeft = defineComponent();
export const HeldRemoteRight = defineComponent();
export const HeldRemoteLeft = defineComponent();
export const Held = defineComponent();
export const OffersRemoteConstraint = defineComponent();
export const HandCollisionTarget = defineComponent();
export const OffersHandConstraint = defineComponent();
export const TogglesHoveredActionSet = defineComponent();

export const HoverButton = defineComponent({ type: Types.ui8 });
export const TextButton = defineComponent({ labelRef: Types.eid });
export const HoldableButton = defineComponent();
export const SingleActionButton = defineComponent();

export const Pen = defineComponent();
export const HoverMenuChild = defineComponent();
export const Static = defineComponent();
export const Inspectable = defineComponent();
export const PreventAudioBoost = defineComponent();
export const IgnoreSpaceBubble = defineComponent();
export const Rigidbody = defineComponent({
bodyId: Types.ui16,
collisionGroup: Types.ui32,
collisionMask: Types.ui32,
flags: Types.ui8,
gravity: Types.f32
});
export const PhysicsShape = defineComponent({ bodyId: Types.ui16, shapeId: Types.ui16, halfExtents: [Types.f32, 3] });
export const Pinnable = defineComponent();
export const Pinned = defineComponent();
export const DestroyAtExtremeDistance = defineComponent();

export const MediaLoading = defineComponent();

export const FloatyObject = defineComponent({ flags: Types.ui8, releaseGravity: Types.f32 });
export const MakeKinematicOnRelease = defineComponent();

export const CameraTool = defineComponent({
snapTime: Types.f32,
state: Types.ui8,
captureDurIdx: Types.ui8,
trackTarget: Types.eid,

snapMenuRef: Types.eid,
button_next: Types.eid,
button_prev: Types.eid,
snapRef: Types.eid,
cancelRef: Types.eid,
recVideoRef: Types.eid,
screenRef: Types.eid,
selfieScreenRef: Types.eid,
cameraRef: Types.eid,
countdownLblRef: Types.eid,
captureDurLblRef: Types.eid,
sndToggleRef: Types.eid
});
export const MyCameraTool = defineComponent();
Loading

0 comments on commit ed12a5a

Please sign in to comment.