Lusito / box2d.ts

Full blown Box2D Ecosystem for the web, written in TypeScript
https://lusito.github.io/box2d.ts
60 stars 6 forks source link

box2d-core on the server side #39

Closed 8Observer8 closed 2 months ago

8Observer8 commented 1 year ago

Solution:

This problem was solved in the Node.js 16. I have moved my example on the Glitch hosting: https://glitch.com/edit/#!/box2d-core-on-the-server-side-js

import { b2World } from "@box2d/core";

const world = b2World.Create({ x: 0, y: -9.8 });

const gravity = world.GetGravity();
console.log(`gravity = (${gravity.x}, ${gravity.y})`);

You can see an output result of the program if you press "LOGS" at the bottom:

image

I have add the required Node.js version to package.json:

{
  "name": "box2d-core-on-the-server-side-js",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "engines": {
    "node": ">=16.0.0"
  },
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server/app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@box2d/core": "^0.10.0"
  }

Question:

I tried running box2d-core on the server side using Node.js:

app.js

import { b2World } from "@box2d/core";

const world = b2World.Create({ x: 0, y: -9.8 });

console.log("ok");

Error:

` E:_Projects\Physics\box2d-core\server-side-box2dcore-webgl-js>nodemon src/server/app.js [nodemon] 2.0.20 [nodemon] to restart at any time, enter rs [nodemon] watching path(s): . [nodemon] watching extensions: js,mjs,json [nodemon] starting node src/server/app.js E:_Projects\node_modules\@box2d\core\dist\common\b2_timer.js:27 this.m_start = performance.now(); ^

ReferenceError: performance is not defined at new b2Timer (E:_Projects\node_modules\@box2d\core\dist\common\b2_timer.js:27:24) at Object. (E:_Projects\node_modules\@box2d\core\dist\collision\b2_time_of_impact.js:230:32) at Module._compile (internal/modules/cjs/loader.js:1072:14) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10) at Module.load (internal/modules/cjs/loader.js:937:32) at Function.Module._load (internal/modules/cjs/loader.js:778:12) at Module.require (internal/modules/cjs/loader.js:961:19) at require (internal/modules/cjs/helpers.js:92:18) at Object. (E:_Projects\node_modules\@box2d\core\dist\index.js:46:14) at Module._compile (internal/modules/cjs/loader.js:1072:14) [nodemon] app crashed - waiting for file changes before starting... `

Lusito commented 1 year ago

You can check how the CLI benchmark does it: https://github.com/Lusito/box2d.ts/blob/master/packages/benchmark/src/cli/index.ts

import { performance } from "perf_hooks";

global.performance = performance as any;
8Observer8 commented 1 year ago

Sorry, I don't understand what should I change to fix it. I use JavaScript instead of TypeScript.

Lusito commented 1 year ago

Somewhere in your server-side code, add the import and the global.performance assignment. Just make sure, the assignment happens before you work with box2d.

JavaScript version:

import { performance } from "perf_hooks";

global.performance = performance;
8Observer8 commented 1 year ago
import { performance } from "perf_hooks";
global.performance = performance;
import { b2World } from "@box2d/core";

const world = b2World.Create({ x: 0, y: -9.8 });
console.log("ok");
E:\_Projects\Physics\box2d-core\server-side-box2dcore-webgl-js>node src/server/app.js
E:\_Projects\node_modules\@box2d\core\dist\common\b2_timer.js:27
        this.m_start = performance.now();
                       ^

ReferenceError: performance is not defined
    at new b2Timer (E:\_Projects\node_modules\@box2d\core\dist\common\b2_timer.js:27:24)
    at Object.<anonymous> (E:\_Projects\node_modules\@box2d\core\dist\collision\b2_time_of_impact.js:230:32)
    at Module._compile (internal/modules/cjs/loader.js:1072:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1101:10)
    at Module.load (internal/modules/cjs/loader.js:937:32)
    at Function.Module._load (internal/modules/cjs/loader.js:778:12)
    at Module.require (internal/modules/cjs/loader.js:961:19)
    at require (internal/modules/cjs/helpers.js:92:18)
    at Object.<anonymous> (E:\_Projects\node_modules\@box2d\core\dist\index.js:46:14)
    at Module._compile (internal/modules/cjs/loader.js:1072:14)
Lusito commented 1 year ago

Ah, I'm sorry. I forgot, that one timer gets created on top-level. Try this instead:

Create a file "fixPerformance.js" (name it whatever you like) with the 2 code lines above, then import that file before you import @box2d/core.

8Observer8 commented 1 year ago

Thank you very much!

fix-performance.js

import { performance } from "perf_hooks";
global.performance = performance;

app.js

import "./fix-performance.js";
import { b2World } from "@box2d/core";

const world = b2World.Create({ x: 0, y: -9.8 });
console.log(`gravity = ${world.GetGravity().y}`);

Output: gravity = -9.8

8Observer8 commented 4 months ago

I have reopened this issue because I think the solution above should be added to the NPM package.

Lusito commented 2 months ago

Hi @8Observer8, sorry for the delay, life kept me busy.

What exactly do you mean by adding it to the NPM package?

  1. perf_hooks is a node API and box2d.ts should be usable from the browser, so I can't just add it by default, as it will then fail in the browser.
  2. I guess I could make something like a submodule import. For example: import '@box2d/core/global-performance', is that what you'd want?
  3. Alternatively, I've just read about the browser field in package.json, which might be usable for this, but I'd have to do a little more research, if this is actually supported by all major bundlers: https://github.com/defunctzombie/package-browser-field-spec

Solution 2 will work for everyone, but it still requires a manual import by you. Solution 3 is more convenient, but also might break in some bundling scenarios.

8Observer8 commented 2 months ago

I see that it is impossible. I just wanted to make it more user friendly. I mean user installs npm i @box2d/core and just uses it on the server side. I thought I can be solved. Thank you for your time to explain this clearly.

Lusito commented 2 months ago

Maybe I wrote this a bit confusing.. Only the first of the 3 approaches above is impossible. The other two are possible, but each have their downsides. I was hoping you would tell me your opinion on the last 2 approaches.

8Observer8 commented 2 months ago

I don't understand 3) but 2) is better than now. I think it must be in the documentation here: https://lusito.github.io/box2d.ts/docs/guide/ on the left side panel, for example, the Server section after Particels and Controller sections.

Lusito commented 2 months ago

I just noticed, that I don't get the error anymore and checked: performance.now is globally available since Node 16, so it's no longer needed to have this fix. I wrote the fix when I was still using Node 12.

Are you sure you still need this fix? I think we can drop support for Node 12 by now.

8Observer8 commented 2 months ago

It works! I have moved my example on the Glitch hosting: https://glitch.com/edit/#!/box2d-core-on-the-server-side-js

import { b2World } from "@box2d/core";

const world = b2World.Create({ x: 0, y: -9.8 });

const gravity = world.GetGravity();
console.log(`gravity = (${gravity.x}, ${gravity.y})`);

You can see an output result of the program if you press "LOGS" at the bottom:

image

I have add the required Node.js (>=16) version to package.json:

{
  "name": "box2d-core-on-the-server-side-js",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "engines": {
    "node": ">=16.0.0"
  },
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server/app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@box2d/core": "^0.10.0"
  }