ondras / rot.js

ROguelike Toolkit in JavaScript. Cool dungeon-related stuff, interactive manual, documentation, tests!
https://ondras.github.io/rot.js/hp/
BSD 3-Clause "New" or "Revised" License
2.32k stars 254 forks source link

Best practices for running rot.js server-side? (and emitting the display to the client) #197

Closed scalemaildev closed 2 years ago

scalemaildev commented 2 years ago

I've been working on a NuxtJS app that will be hosting rot.js server-side. The basic flow of the app is this:

In the readme, it recommended using layout: "term" for node server-side games, but I don't want to run the game in the terminal. I'm just looking for a method of building a canvas-like image server-side which can be emitted back to the client. I'd prefer if the user didn't get any information about what's going on "under the hood" of the game; they should just get an image back (and some messages but I have that part covered).

I found this issue: https://github.com/ondras/rot.js/issues/168 describing someone's attempt to use node-canvas a few years back. Would you recommend using that module for this purpose? Or has a better method emerged since then? Are there any examples of this being done, such as an existing repo?

Thank you.

ondras commented 2 years ago

I am quite suprised by the proposed architecture. Rendering stuff server-side on every client update sounds very expensive with regard to the amount of image data transmitted server->client. I am not familiar with underlying decisions, but sending full raster updates on every keypress just does not fit into the typical client-server model/flow. You are essentially suggesting doing what VNC does - and to make stuff somewhat smooth, VNC needs to apply incredible tricks, mostly based on highly compressed partial updates.

So, before you try to dig deeper into unknown lands of server-side canvas rendering, I suggest you revisit the architecture and decide whether it really is absolutely necessary to push raster images from server to clients every time something updates.

scalemaildev commented 2 years ago

Ok will do. Thank you.

blinkdog commented 2 years ago

In the readme, it recommended using layout: "term" for node server-side games, but I don't want to run the game in the terminal. I'm just looking for a method of building a canvas-like image server-side which can be emitted back to the client. I'd prefer if the user didn't get any information about what's going on "under the hood" of the game; they should just get an image back (and some messages but I have that part covered).

I explored an architecture like this a few years ago.

If you're trying to update a full blown image, then it's as ondras said, like VNC, Screen Sharing, or streaming a game; see: Google Stadia

However, with a little code you can get away with a less intense architecture. If you use rot.js in the browser (rect or tile layout), then use something like socket.io to send user input to the server and draw commands back to the browser, you're in business. All your game logic is server side, and all your drawing is handled client side.

If I were going to do this, I'd probably create a new layout type remote that translated the draw calls into socket.io calls. That way your server code could use Display in the normal way. You could develop/debug with rect or tile, then in production use remote.

On the client side, you'd need to listen for socket.io events and translate those into the actual draw calls to the rect or tile running in the player's browser.

This is just a sketch, but I hope it helps.

scalemaildev commented 2 years ago

@blinkdog Thanks, I decided on a similar strategy already: passing draw commands back and forth instead of an actual image. There is a "dummy game" that exists client-side while the canonical gamestate runs on the server. The canonical gamestate runs the actual game logic and then just emits to the client what to draw and add to the messages. I will take a look at the remote idea after everything is up and running.

Do you have any suggestion for how to handle the draw for an entire map with a single emit?