endel / ecs

(NOT READY TO USE) Experimenting with @colyseus/schema + ECSY
MIT License
17 stars 4 forks source link

Client entity instantiated as schema #2

Closed will-hart closed 4 years ago

will-hart commented 4 years ago

I have a monorepo which doesn't do a whole lot yet. However when an entity is instantiated client side, the following error appears:

index.js:120 Uncaught TypeError: Cannot read property 'push' of undefined
    at MapSchema.entity.components.onAdd (index.js:120)
    at eval (Schema.js:804)
    at Map.forEach (<anonymous>)
    at _.Schema._triggerChanges (Schema.js:794)
    at _.Schema.decode (Schema.js:370)
    at SchemaSerializer.setState (SchemaSerializer.js:9)
    at Room.setState (Room.js:196)
    at Room.onMessageCallback (Room.js:178)
    at Connection.onMessageCallback (index.js:14)

Looking at the source code location, the following line is causing the exception:

entity['_ComponentTypes'].push(ComponentType)

It looks like the entity doesn't have any of the expected "reflection" types such as _ComponentTypes. Looking further into the schema decoding, the type identified for the entity is f _() on the client, and when the type is instantiated using this.createTypeInstance only the Schema constructor is called.

own_repo

When I do the same debugging in the @colyseus/ecs example, the client correctly identifies the entity as of type class Entity and calls the Entity constructor:

demo_cropped

Platform

Win 10
Node 12.16.1 and 14.5.0

"@colyseus/ecs": "^0.4.0-alpha.3"
"colyseus": "^0.14.0-alpha.11"
"@colyseus/schema": "^1.0.0-alpha.39"
"colyseus.js": "^0.14.0-alpha.4"

It is possibly something to do with ES2020 in the client's tsconfig, although I've played around with targets etc on the server/client/game packages without any luck.

{
  "compilerOptions": {
    "target": "ES2019",
    "module": "ES2020",
    "lib": ["es2020", "dom", "dom.iterable", "scripthost"],
...

P.S. I'm happy to do more to debug / fix but at this point I'm a bit stumped and don't know where to look next.

Elyx0 commented 4 years ago

I have a few guesses but first. 1) Can you run the examples from this repo correctly? 2) Did it ever work before or never?

Please recheck the examples (specifically the client) as it uses the enableAutoDecode magic, you're supposed to share components between the server and the client so the auto decoding works. (cortesy of https://github.com/endel/ecs/blob/master/src/index.ts#L120-L130)

Just a new World and registering the components in the SAME order than the server I hope this can help

will-hart commented 4 years ago

Thanks for the suggestions.

1) yes, examples in this repo (including with updated colyseus versions / TS version / tsconfig targets) run. I've struggled to make a small replication repo!! 2) In my monorepo the components are in a shared package and used in both client and server. The code for building the ECS uses the same function on both client and server.

If I understand it correctly, the issue is occurring before the component.onAdd handler in enableAutoDecode is run. Auto decode only works if the Entity constructor has been called so the _ComponentTypes etc are defined on the entity. As the schema decodes entities as plain Schema objects, the Entity constructor is never run.

Some possible differences to the demo:

will-hart commented 4 years ago

I wonder if this is related https://github.com/colyseus/schema/issues/74, as I'm importing the schema from another package within the monorepo

Elyx0 commented 4 years ago

I tried a version of the example using tsconfig paths and it still worked out fine, so you might try that see: https://github.com/endel/ecs/compare/master...Elyx0:tsconfig?expand=1 for the changes

Try to get Schema from the same place client and server yes, I've had very weird issues otherwise

Elyx0 commented 4 years ago

Normally @ecs replicates all the logic as if it was from an ecsy constructor: https://github.com/MozillaReality/ecsy/blob/dev/src/Entity.js#L6-L28

endel commented 4 years ago

Hi @will-hart, I've created a pull-request for you here https://github.com/will-hart/pixatore/pull/26

It is necessary to provide the "concrete" state class when joining the room, to make sure the right structures are going to be instantiated. If they're not provided, Colyseus will create them automatically based on the handshake data (all schema structures are created as class _ {})

Please let me know if you find any other issues like this!

will-hart commented 4 years ago

Ah you are a legend, thanks @endel !!

On the plus side I learned a lot about the internals of colyseus and I think was getting closer to the right answer, but on the minus side it might have taken me a while to realise that's where things were going wrong 😁