Skip to content
34 changes: 29 additions & 5 deletions src/components/body-helper.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { addComponent, removeComponent } from "bitecs";
import { CONSTANTS } from "three-ammo";
import { Rigidbody } from "../bit-components";
import { updateBodyParams } from "../inflators/rigid-body";
import { validatePhysicsParams } from "../utils/validatePhysicsParams";

const ACTIVATION_STATE = CONSTANTS.ACTIVATION_STATE,
TYPE = CONSTANTS.TYPE;

Expand Down Expand Up @@ -30,24 +31,46 @@ AFRAME.registerComponent("body-helper", {
type: { default: "dynamic", oneOf: [TYPE.STATIC, TYPE.DYNAMIC, TYPE.KINEMATIC] },
emitCollisionEvents: { default: false },
disableCollision: { default: false },
collisionFilterGroup: { default: 1 }, //32-bit mask,
collisionFilterMask: { default: 1 }, //32-bit mask
collisionFilterGroup: { default: 1 },
collisionFilterMask: { default: 1 },
scaleAutoUpdate: { default: true }
},

validateConfig(data) {
if (typeof data.mass !== "number" || isNaN(data.mass)) {
console.warn(`[body-helper] Invalid mass: ${data.mass}. Defaulting to 1.`);
data.mass = 1;
}

const validTypes = [TYPE.STATIC, TYPE.DYNAMIC, TYPE.KINEMATIC];
if (!validTypes.includes(data.type)) {
console.warn(`[body-helper] Invalid type: ${data.type}. Defaulting to dynamic.`);
data.type = TYPE.DYNAMIC;
}

if (!data.gravity || typeof data.gravity !== "object") {
console.warn("[body-helper] Invalid gravity vector. Using default gravity.");
data.gravity = { x: 0, y: -9.8, z: 0 };
}
},

init: function () {
this.validateConfig(this.data);

this.system = this.el.sceneEl.systems["hubs-systems"].physicsSystem;
this.alive = true;
this.el.object3D.updateMatrices();
this.uuid = this.system.addBody(this.el.object3D, this.data);
this.data = validatePhysicsParams(this.data);

const eid = this.el.object3D.eid;
addComponent(APP.world, Rigidbody, eid);
updateBodyParams(eid, this.data);
Rigidbody.bodyId[eid] = this.uuid; //uuid is a lie, it's actually an int
Rigidbody.bodyId[eid] = this.uuid;
},

update: function (prevData) {
if (prevData) {
this.validateConfig(this.data);
const eid = this.el.object3D.eid;
this.system.updateRigidBody(eid, this.data);
}
Expand All @@ -60,3 +83,4 @@ AFRAME.registerComponent("body-helper", {
this.alive = false;
}
});

26 changes: 26 additions & 0 deletions src/components/camera.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
AFRAME.registerComponent("stabilize-camera", {
init: function () {
this.el.addEventListener("grab-start", (evt) => {
if (!NAF.utils.isMine(this.el)) {
console.warn("Cannot interact: you do not own this camera.");
evt.stopImmediatePropagation();
evt.preventDefault();
}
});

this.el.addEventListener("grab-move", (evt) => {
if (!NAF.utils.isMine(this.el)) {
evt.stopImmediatePropagation();
evt.preventDefault();
}
});

this.el.addEventListener("grab-end", (evt) => {
if (!NAF.utils.isMine(this.el)) {
evt.stopImmediatePropagation();
evt.preventDefault();
}
});
}
});

13 changes: 8 additions & 5 deletions src/components/gltf-model-plus.js
Original file line number Diff line number Diff line change
Expand Up @@ -596,14 +596,17 @@ class GLTFHubsComponentsExtension {
if (shouldUseNewLoader()) {
if (Object.prototype.hasOwnProperty.call(ext, "link")) {
if (["image", "video", "model"].includes(componentName)) {
ext["media-link"] = {
src: ext.link.href
};
delete ext.link;
if (!ext.link || !ext.link.href) {
console.warn("Warning: Attempted to load a link but the href is missing! Component : ${componentName}", ext);
} else {
ext["media-link"] = {
src: ext.link.href
};
delete ext.link;
}
}
}
}

const value = props[propName];
const type = value?.__mhc_link_type;
if (type && value.index !== undefined) {
Expand Down
34 changes: 34 additions & 0 deletions src/utils/validatePhysicsParams.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { CONSTANTS } from "three-ammo";

const { TYPE, ACTIVATION_STATE } = CONSTANTS;

export function validatePhysicsParams(data) {
const validated = { ...data };

// Mass must be a valid number
if (typeof validated.mass !== "number" || isNaN(validated.mass)) {
console.warn("[body-helper] Invalid mass:", validated.mass, "→ defaulting to 1");
validated.mass = 1;
}

// Type must be one of the constants
const validTypes = [TYPE.DYNAMIC, TYPE.STATIC, TYPE.KINEMATIC];
if (!validTypes.includes(validated.type)) {
console.warn("[body-helper] Invalid type:", validated.type, "→ defaulting to dynamic");
validated.type = TYPE.DYNAMIC;
}

// Gravity must be a vec3
if (
!validated.gravity ||
typeof validated.gravity.x !== "number" ||
typeof validated.gravity.y !== "number" ||
typeof validated.gravity.z !== "number"
) {
console.warn("[body-helper] Invalid gravity vector → defaulting to (0, -9.8, 0)");
validated.gravity = { x: 0, y: -9.8, z: 0 };
}

return validated;
}

15 changes: 5 additions & 10 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,6 @@ module.exports = async (env, argv) => {
// .replaceAll("connect-src", "connect-src https://example.com");
}

const addonsConfigFilePath = "./addons.json";
const addonsConfig = JSON.parse(fs.readFileSync(addonsConfigFilePath, "utf-8"));

const internalHostname = process.env.INTERNAL_HOSTNAME || "hubs.local";
return {
cache: {
Expand All @@ -306,9 +303,7 @@ module.exports = async (env, argv) => {
"three/examples/js/libs/basis/basis_transcoder.js": basisTranscoderPath,
"three/examples/js/libs/draco/gltf/draco_wasm_wrapper.js": dracoWasmWrapperPath,
"three/examples/js/libs/basis/basis_transcoder.wasm": basisWasmPath,
"three/examples/js/libs/draco/gltf/draco_decoder.wasm": dracoWasmPath,

hubs$: path.resolve(__dirname, "./src/hubs.js")
"three/examples/js/libs/draco/gltf/draco_decoder.wasm": dracoWasmPath
},
// Allows using symlinks in node_modules
symlinks: false,
Expand All @@ -325,7 +320,7 @@ module.exports = async (env, argv) => {
entry: {
support: path.join(__dirname, "src", "support.js"),
index: path.join(__dirname, "src", "index.js"),
hub: [path.join(__dirname, "src", "hub.js"), ...addonsConfig.addons],
hub: path.join(__dirname, "src", "hub.js"),
scene: path.join(__dirname, "src", "scene.js"),
avatar: path.join(__dirname, "src", "avatar.js"),
link: path.join(__dirname, "src", "link.js"),
Expand All @@ -341,9 +336,6 @@ module.exports = async (env, argv) => {
filename: "assets/js/[name]-[chunkhash].js",
publicPath: process.env.BASE_ASSETS_PATH || ""
},
optimization: {
minimize: argv.mode === "production" ? true : false
},
target: ["web", "es5"], // use es5 for webpack runtime to maximize compatibility
devtool: argv.mode === "production" ? "source-map" : "inline-source-map",
devServer: {
Expand Down Expand Up @@ -633,6 +625,9 @@ module.exports = async (env, argv) => {
priority: 10
}
}
},
runtimeChunk: {
name: "runtime"
}
},
plugins: [
Expand Down