Birch-san / box2d-wasm

Box2D physics engine compiled to WebAssembly. Supports TypeScript and ES modules.
263 stars 21 forks source link

Node.js #8

Closed gpeles closed 3 years ago

gpeles commented 3 years ago

Hello, thank you very much for porting the newer version of Box2d and supporting TypeScript. Is it possible to make the package work also server-side on Node.js?

Birch-san commented 3 years ago

Sure; I'd originally removed server-side support (to save a bit of filesize) since I didn't think there was a use-case for it.

I've added Node.js support back in for box2d-wasm v1.3.0.

I've made a few backend demos to demonstrate how to install it into your application.

Can I ask what it is you're doing with Box2D server-side? Is it a multiplayer game or something?

gpeles commented 3 years ago

Awesome, thank you so much for that!

Yes, I'm working on a multiplayer game and currently checking some potential physics engines. Box2D seems a really good fit to what I need although I just realised that it doesn't support resizing shapes (for example, growing and shrinking circles) which might actually be a problem for my project.

gpeles commented 3 years ago

Followed the instructions for Modern + Typescript and got this after npm start:

> node --loader ts-node/esm --experimental-specifier-resolution=node --harmony -r source-map-support/register src/index.ts

(node:75115) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
TypeError [ERR_INVALID_RETURN_PROPERTY_VALUE]: Expected string to be returned for the "format" from the "loader getFormat" function but got type object.
    at Loader.getFormat (internal/modules/esm/loader.js:110:13)
    at Loader.getModuleJob (internal/modules/esm/loader.js:230:20)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:53:21)
    at async Promise.all (index 0)
    at link (internal/modules/esm/module_job.js:58:9)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! box2d-wasm-demo-backend-modern-ts@1.0.0 start: `node --loader ts-node/esm --experimental-specifier-resolution=node --harmony -r source-map-support/register src/index.ts`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the box2d-wasm-demo-backend-modern-ts@1.0.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:

And got this after npm run build:

> tsc

node_modules/@types/emscripten/index.d.ts:53:33 - error TS2304: Cannot find name 'WebGLRenderingContext'.

53     preinitializedWebGLContext: WebGLRenderingContext;
                                   ~~~~~~~~~~~~~~~~~~~~~

node_modules/@types/emscripten/index.d.ts:67:28 - error TS2304: Cannot find name 'MessageEvent'.

67     onCustomMessage(event: MessageEvent): void;
                              ~~~~~~~~~~~~

node_modules/box2d-wasm/Box2DModule.d.ts:7:3 - error TS2309: An export assignment cannot be used in a module with other exported elements.

7   export = Box2DFactory;
    ~~~~~~~~~~~~~~~~~~~~~~

node_modules/box2d-wasm/Box2DModuleAugmentations.d.ts:21:19 - error TS2694: Namespace 'Box2D' has no exported member 'b2PointState'.

21     state1: Box2D.b2PointState | number, state2: Box2D.b2PointState | number,
                     ~~~~~~~~~~~~

node_modules/box2d-wasm/Box2DModuleAugmentations.d.ts:21:56 - error TS2694: Namespace 'Box2D' has no exported member 'b2PointState'.

21     state1: Box2D.b2PointState | number, state2: Box2D.b2PointState | number,
                                                          ~~~~~~~~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:59:18 - error TS2416: Property '__class__' in type 'b2World' is not assignable to the same property in base type 'WrapperObject'.
  Type 'typeof b2World' is not assignable to type 'typeof WrapperObject'.
    Types of construct signatures are incompatible.
      Type 'new (gravity: number | b2Vec2) => b2World' is not assignable to type 'new () => WrapperObject'.

59         readonly __class__: typeof b2World;
                    ~~~~~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:199:18 - error TS2416: Property '__class__' in type 'b2Transform' is not assignable to the same property in base type 'WrapperObject'.
  Type 'typeof b2Transform' is not assignable to type 'typeof WrapperObject'.
    Types of construct signatures are incompatible.
      Type 'new (position: number | b2Vec2, rotation: number | b2Rot) => b2Transform' is not assignable to type 'new () => WrapperObject'.

199         readonly __class__: typeof b2Transform;
                     ~~~~~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:265:18 - error TS2416: Property '__class__' in type 'b2Vec2' is not assignable to the same property in base type 'WrapperObject'.
  Type 'typeof b2Vec2' is not assignable to type 'typeof WrapperObject'.
    Types of construct signatures are incompatible.
      Type 'new (x: number, y: number) => b2Vec2' is not assignable to type 'new () => WrapperObject'.

265         readonly __class__: typeof b2Vec2;
                     ~~~~~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:290:18 - error TS2416: Property '__class__' in type 'b2Vec3' is not assignable to the same property in base type 'WrapperObject'.
  Type 'typeof b2Vec3' is not assignable to type 'typeof WrapperObject'.
    Types of construct signatures are incompatible.
      Type 'new (x: number, y: number, z: number) => b2Vec3' is not assignable to type 'new () => WrapperObject'.

290         readonly __class__: typeof b2Vec3;
                     ~~~~~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:442:21 - error TS2304: Cannot find name 'short'.

442         groupIndex: short;
                        ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:443:27 - error TS2304: Cannot find name 'short'.

443         get_groupIndex(): short;
                              ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:444:36 - error TS2304: Cannot find name 'short'.

444         set_groupIndex(groupIndex: short): void;
                                       ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:632:18 - error TS2416: Property '__class__' in type 'b2Color' is not assignable to the same property in base type 'WrapperObject'.
  Type 'typeof b2Color' is not assignable to type 'typeof WrapperObject'.
    Types of construct signatures are incompatible.
      Type 'new (r: number, g: number, b: number) => b2Color' is not assignable to type 'new () => WrapperObject'.

632         readonly __class__: typeof b2Color;
                     ~~~~~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:677:17 - error TS2304: Cannot find name 'octet'.

677         indexA: octet;
                    ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:678:23 - error TS2304: Cannot find name 'octet'.

678         get_indexA(): octet;
                          ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:679:28 - error TS2304: Cannot find name 'octet'.

679         set_indexA(indexA: octet): void;
                               ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:680:17 - error TS2304: Cannot find name 'octet'.

680         indexB: octet;
                    ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:681:23 - error TS2304: Cannot find name 'octet'.

681         get_indexB(): octet;
                          ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:682:28 - error TS2304: Cannot find name 'octet'.

682         set_indexB(indexB: octet): void;
                               ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:683:16 - error TS2304: Cannot find name 'octet'.

683         typeA: octet;
                   ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:684:22 - error TS2304: Cannot find name 'octet'.

684         get_typeA(): octet;
                         ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:685:26 - error TS2304: Cannot find name 'octet'.

685         set_typeA(typeA: octet): void;
                             ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:686:16 - error TS2304: Cannot find name 'octet'.

686         typeB: octet;
                   ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:687:22 - error TS2304: Cannot find name 'octet'.

687         get_typeB(): octet;
                         ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:688:26 - error TS2304: Cannot find name 'octet'.

688         set_typeB(typeB: octet): void;
                             ~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:994:18 - error TS2416: Property '__class__' in type 'b2Mat22' is not assignable to the same property in base type 'WrapperObject'.
  Type 'typeof b2Mat22' is not assignable to type 'typeof WrapperObject'.

994         readonly __class__: typeof b2Mat22;
                     ~~~~~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:1015:18 - error TS2416: Property '__class__' in type 'b2Mat33' is not assignable to the same property in base type 'WrapperObject'.
  Type 'typeof b2Mat33' is not assignable to type 'typeof WrapperObject'.
    Types of construct signatures are incompatible.
      Type 'new (c1: number | b2Vec3, c2: number | b2Vec3, c3: number | b2Vec3) => b2Mat33' is not assignable to type 'new () => WrapperObject'.

1015         readonly __class__: typeof b2Mat33;
                      ~~~~~~~~~

node_modules/box2d-wasm/build/Box2D.d.ts:1324:18 - error TS2416: Property '__class__' in type 'b2Rot' is not assignable to the same property in base type 'WrapperObject'.
  Type 'typeof b2Rot' is not assignable to type 'typeof WrapperObject'.
    Types of construct signatures are incompatible.
      Type 'new (angle: number) => b2Rot' is not assignable to type 'new () => WrapperObject'.

1324         readonly __class__: typeof b2Rot;
                      ~~~~~~~~~

Found 28 errors.

npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! box2d-wasm-demo-backend-modern-ts@1.0.0 build: `tsc`
npm ERR! Exit status 2
npm ERR! 
npm ERR! Failed at the box2d-wasm-demo-backend-modern-ts@1.0.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/gonipeles/.npm/_logs/2020-11-26T19_11_07_832Z-debug.log
gpeles commented 3 years ago

But classic and modern do work 👍

Birch-san commented 3 years ago

@gpeles thanks for trying it out.

npm start:

TypeError [ERR_INVALID_RETURN_PROPERTY_VALUE]: Expected string to be returned for the "format" from the "loader getFormat" function but got type object.
    at Loader.getFormat (internal/modules/esm/loader.js:110:13)

I think that's a ts-node 9.0.0 problem with Node.js v14.13.1 (whereas I've been testing against v14.13.0).

Sounds like they've fixed it; try upgrading to ts-node 9.1.0.

npm run build - DOM types

This one looks like you're missing DOM types from your tsconfig.json:

node_modules/@types/emscripten/index.d.ts:53:33 - error TS2304: Cannot find name 'WebGLRenderingContext'.

53     preinitializedWebGLContext: WebGLRenderingContext;
                                   ~~~~~~~~~~~~~~~~~~~~~

node_modules/@types/emscripten/index.d.ts:67:28 - error TS2304: Cannot find name 'MessageEvent'.

67     onCustomMessage(event: MessageEvent): void;

This is a weird situation — the Emscripten types include web-specific typings that you won't be using.

You have two options (both can be configured in your tsconfig.json).

Option 1: skipLibCheck

This will tell TS not to bother performing type-checking upon .d.ts files:

{
  "compilerOptions": {
    "skipLibCheck": true
  }
}

Option 2: reference DOM libraries

Add "dom" to your lib array:

{
  "compilerOptions": {
    "lib": ["DOM"]
  }
}

This will give you the types that Emscripten is trying to reference, but it's a bit disingenuous — those types aren't actually available in the runtime environment you're targeting (NodeJS). But doesn't matter since you're not actually trying to use those particular Emscripten functions.

npm run build - the other errors

I've fixed these as of version 2.0.1 🙂

The type Box2DEmscriptenModule from the examples no longer exists, the new invocation is:

import Box2DFactory from 'box2d-wasm';
const { b2Vec2, b2World }: typeof Box2D & EmscriptenModule = await Box2DFactory();

const gravity = new b2Vec2(0, 10);
const world = new b2World(gravity);
gpeles commented 3 years ago

Yes, I can confirm that it works now! Thanks a lot!

Birch-san commented 3 years ago

no problem 🙂 hope it works out for multiplayer!