1. Fetching many resources simultaneously, 162 resources just for terrain data, a couple hundred more for meshes. I am currently serving with Express, so the solution here was to put Cloudflare in front of it as a reverse proxy with a short cache TTL. Cloudflare then serves them with HTTP/3. Also, requesting all of these simultaneously rather than sequentially. The header overhead isn't a problem with HTTP/3 since that uses a hash or something rather than re-sending all the same headers in each request.
2. Resource byte size. Cloudflare does Brotli but from my testing, I would need to combine terrain zones into a single binary blob for this to reduce byte size by half. (Compressing things that are a few hundred bytes achieves very little.) But combining these would mean that any change to the data of one zone would require re-compressing all zones. (Mesh compression with Draco[1] helped though.)
3. ROUNDTRIP. Especially with connection latency. This is where Server Push comes in. I actually experimented with it. But it basically only saves one roundtrip (~50-500ms depending on connection); the server establishes a connection then can push. Without server push, the server establishes a connection, then waits for the client to request resources.
The client requesting resources has a few advantages. 1) Server doesn't need to figure out what data the client needs, the client can do those calculations, and the server can simply verify (which is a lighter SQL query than discovery). 2) Client can not-request resources which it already has (in cache or storage)! 3) Resources can be cached by Cloudflare at the edge.
0: earth.suncapped.com
1: github.com/google/draco