My first attempt was a server for a dungeon crawler that superficially looked like a rogue-like, but was actually 12 frames/sec realtime instead of turn based. It started out on Clojure, but I afterwards ported it to Go. In this server, the world was divided into 80x24 subgrids that did most of their processing in parallel. Processing would happen in two stages: 1) local data processing, where each entity got updated in a loop, sending out updates to clients and 2) collision resolution/movement. If I had to do it over again, I would relax the grid's invariant properties, and make each 80x24 subgrid completely independent, which would eliminate the collision resolution step.
In my current server, I'm basically sharding my space-game into star systems, with free travel between star systems though "Hyperspace." There is a farm of "worker processes" that is coordinated by a master server. Any instance of a star system can be idempotently spawned when a client is attached to it. < https://www.emergencevector.com >
I think Go is a good option for writing a game server. You'd have to be pretty profligate to make the GC pause overrun one 16.66 ms tick, and if you miss a tick here and there, who cares?
> In this server, the world was divided into 80x24 subgrids that did most of their processing in parallel.
Is there any reason why you do update() in parallel? There is certainly some interesting challenges to solve there but did you have a reason to make it parallel other than intellectual curiosity (e.g. better performance)?
Afaik a game loop's update() is not the intense part in the game loop (maybe that's different for games with lots of world information update, like roguelikes), but rather render() and IO() are so I am wondering what your design thoughts are.
Is there any reason why you do update() in parallel?
I wanted to come up with an architecture that could support an arbitrarily large world given enough resources. Up to a certain density (from 150 to 250 users per "subgrid") I was close to succeeding.
Afaik a game loop's update() is not the intense part in the game loop but rather render() and IO()
"Render" in the context of a server like this is the IO. One thing you should know, is that this game supported Conway's Life cellular automata at 12 frames/second, completely shared and multiplayer.
I've always enjoyed writing MUDs (similar to roguelikes), and I found Clojure's killer feature to be immutability, rather than some of the fancier concurrency features like STM. Operations that consume the most resources in a MUD tend to be very amenable to stale, but consistent snapshots, which immutability makes pretty easy to do. My goal was more about responsiveness than throughput though.
Clojure weenies on IRC. To be fair, the Go weenies aren't much better. If you like hanging out on IRC so that you can emotionally abuse newbies, ask yourself what you're doing with your life.