Live data from Hacker News

Reflect – Multiplayer web app framework with game-style synchronization

rocicorp.dev

81–90 of 159 posts

Re: Reflect – Multiplayer web app framework with game-style synchronization

#81

I worked extensively on this (also implemented it on JS) about 15 years ago, to escape boredom while on my grandma's place. I wish I had open sourced something, but back then I was a young boy with no ulterior motivations :^). Anyway, I want to comment on this: >For example, any kind of arithmetic just works: Of course, it is extremely trivial to set those up as idempotent operations. >List operations just work: Nope…

Hi! Thanks for the thoughtful question. >List operations just work: Fair point. Will change. What I really meant here was "(Many) list operations just work" (just like above I said "all kinds of things just work". > All updates reach the server at the same time. What is the solution to that? Timestamps? Fallback to LLW? There are a number of issues you might be pointing out, and I'm not sure which one you mean. In ge…

>nothing can fix this

Exactly.

>For these problems, undo and presence indicators go a long way to avoid these problems through human/social mechanisms.

x1,000 to this. This guy builds. That's exactly my takeaway as well from years working on this; provide a solid (by that I mean clearly defined) deterministic algo, and solve the rest w/ UX.

Re: Reflect – Multiplayer web app framework with game-style synchronization

#83

I worked extensively on this (also implemented it on JS) about 15 years ago, to escape boredom while on my grandma's place. I wish I had open sourced something, but back then I was a young boy with no ulterior motivations :^). Anyway, I want to comment on this: >For example, any kind of arithmetic just works: Of course, it is extremely trivial to set those up as idempotent operations. >List operations just work: Nope…

You don’t even need to involve deletes; if all of these happen “simultaneously”: - client A appends “a” to list L - client B appends “b” to list L - client C appends “c” to list L the server will arbitrarily apply the appends in some order, and then send the result back to the clients. But, each of the clients has applied its append locally and is showing those results until it gets different information from the ser…

We have the "game-winning" scenario on the reflect.net homepage right now: https://reflect.net/. It's a puzzle and when the last piece is placed, it shows a celebration and the puzzle resets moments later. But we only want that logic to run once. We can't do this client-side because there are many people and we'd end up having to choose a leader or something. This is the same exact situation as wanting to show in the UI who won (who placed the last piece) and only wanting to do that once.

Reflect has first-class support for this kind of situation by allowing mutators to run special code server-side. I talk about this a bit here:

https://rocicorp.dev/blog/ready-player-two#server-authority

You can use the same mechanism to have a branch in the code that places the piece that only runs server-side and chooses the winner.

Re: Reflect – Multiplayer web app framework with game-style synchronization

#85

Earlier quoted context omitted.

By your example, 5 was marked as deleted, so it would just be [1, ]. Most likely this would be implemented with a single mutator for each element. But if you implemented a "range delete", then it would depend on what the order of arrival was. Notably, the server has to sequence actions somehow, so there isn't going to be an issue of "all actions arriving at the same time". If C arrived last in that case, the new elem…

Whoops, you're right, Is the solution to that, a) [1] or b) [1, ] ? >Notably, the server has to sequence actions somehow [...] Yes, that's my whole point, you have to fallback to something like LLW, and then it's over for the transactional model :P. Edit: Btw, I'm not trying to be the snarky, pessimistic dude. This kind of models are really interesting and I love working with them. I am just trying to illustrate how…

No, the server is going to process the actions in a single queue. So again, it's whatever action arrives first.

Re: Reflect – Multiplayer web app framework with game-style synchronization

#86

For reference, this strategy is called "deterministic lockstep" in the gamedev world, and is used especially often in games which have many entities which need their state synced. The canonical example is rtses, which pretty much all use it.

Hey wheybags, this is not deterministic lockstep.

That is an algorithm for peer-to-peer games, where each peer waits for the input from all other players before advancing the game simulation. The deterministic part is because players share inputs (not simulation results) AND the simulation is deterministic for the same inputs. The lockstep part is because all clients advance at a coordinated pace. The Age of Empires series use this approach, and that’s why units don’t move immediately when you click. Starcraft uses this too, but it has some tricks to smooth the gameplay experience. Both are peer-to-peer with no single “server”.

In the case of Reflect, we have a server-authorative simulation (not peer-to-peer). Clients send their inputs to the server, but they do not wait for the result, they instead predict the result locally without confirmation from the server. The server also rolls back time and then replays inputs to compensate for individual client latency. And the client corrects/reconciles their local simulation once the server sends a simulation result that included one of their inputs.

The keywords for this algorithm are:

- Server-authoritative

- Predicted

- Lag compensated (simulation rollback / server rewind / input replay)

- Prediction reconciliation (local simulation rollback / local input replay / misprediction smoothing)

I’m not sure if Reflect has it, but client-side interpolation is also a common feature in FPS games, where upon receiving a world update, the client will tween entities to their new positions/rotations over a fixed interval (such as 0.1s). This allows you to send updates to clients at only 10Hz but have entities move smoothly (without needing the client to locally simulate the physics of every entity).

There is only one authority, the server, so determinism isn’t super important. However, it is nice to have for client predictions to reduce the occurrences of mispredictions. Mispredictions occur when the server state did not advance the way the client predicted. These can happen when:

(1) Another client’s input changed the world state in an important way,

(2) The simulation is not deterministic (e.g. the random number generation is not synced).

In FPS games, (1) is impossible to eliminate. These mispredictions are often smoothed using interpolation. (2) should be minimised, but may actually be desirable. For example, Counter Strike does not sync the RNG for bullet spread randomness, to prevent “nospread” cheat programs from predicting where each bullet will go and instantly adjusting the player’s aim so the bullet lines up perfectly.

https://www.gabrielgambetta.com/client-side-prediction-live-...

https://developer.valvesoftware.com/wiki/Latency_Compensatin...

https://developer.valvesoftware.com/wiki/Source_Multiplayer_...

Re: Reflect – Multiplayer web app framework with game-style synchronization

#87
post #82

What’s the transport for this? Websockets? I have a hard time imagining 120 messages for 100 clients over websocket in a CF Durable Object, but maybe I’m just completely misimagining.

It's websockets, and yes we do make use of Durable Objects. But we do extensive batching and buffering on top of the raw platform. You can't literally send 120 messages / second to and from 100 concurrent clients. Actually the math tops out at about 8 :).

Re: Reflect – Multiplayer web app framework with game-style synchronization

#89

As someone who's casually been eyeing up CRDTs for two years I've wondered continually what the story for authorization is, and this article seems to suggest (in line with my own understanding) that a CRDT library on its own like Y.js can't really handle applications where mutations need to be checked for authorization because it lacks a central authority (i.e., the server) while Reflect assumes that a server will be…

"Can't" is a strong word. You can get auth with a CRDT with effort, for example you can put a server in the middle of everything and have the server reverse any changes it sees which are unauthorized.

This ends up being a lot of work to maintain and easy to break as the application gets bigger, and it also defeats some of the benefits of the CRDT in the first place (now the server has to mediate everything and you can't have peer-to-peer sync).

Also if there are side-effects of any actions which require auth which aren't undoable, then that gets more complicated.

If you already have a server in the middle, it's a lot simpler to just use a protocol that allows the server to reject messages in the first place.

Re: Reflect – Multiplayer web app framework with game-style synchronization

#90
This looks great! I'm curious what the recommended use cases are for something like this. Is it worth adding the additional complexity for complex crud-y saas? I know Linear is built on this local-first model but from seeing their presentations on the challenges they've had scaling it, I'm left wondering if it makes sense for something like a full-featured CRM with hundreds of tables. Is Reflect/Replicache suited for that kind of use case?
Post reply on HN