Day's progress so far, and some thinking out loud:
Continuing work on Umpire client-server architecture. I realized the naive port I was attempting was going to be unnecessarily ugly---while it would have let me replace every method call with an RPC call, it did so at the cost of turning everything
async, and likely introducing latency into things that really shouldn't have latency (steps in a unit movement animation, say).
So the new approach: each client maintains a cached copy of the player's (or players') view of the game state. (This can be incomplete and even stale due to the fog of war mechanic.) The protocol then focuses on high-level player commands, with the server replying with low-level updates to the player's view, for example, unit A observed tile x,y as having state S in turn T. That's a lot of placeholder variables, but whatever.
Some of this is already how the game-UI interface works, but not enough---lots of the code as written assumes that the game state will always be instantly accessible at essentially zero cost, something we can no longer guarantee. Thus the addition of a simple caching layer.
This may allow simplification of the game engine as well, which has had the task of tracking each player's observations separately. I expect this can be delegated entirely to the clients.
tarpc vs tonic
Along the way I thought I might need a bidirectional RPC mechanism, allowing the server to send messages to the client as well as the reverse. Since I couldn't at first find an example of how to do this using
tarpc, I spent a while exploring
tonic as an alternative.
tonic distinguishes itself by relying on Protocol Buffers to generate the RPC code (while
tarpc defines this all in Rust) and by focusing on HTTP/2 as a transport, rather than the more agnostic system
tarpc uses. I hadn't worked much with Protocol Buffers since a prototype serialization layer for Analytics data I did at Adobe, but things haven't changed much, if at all.
In the end, though, I did find an example of bidirectional RPC using
tarpc. Since it really would be far cleaner at this point to use my existing types defined in Rust rather than externalizing those to the protobuf compiler, I gave up on
tonic for this use case and am moving forward with
The conceptual shift, summed up for my own benefit: the clients will be "thicker" than they were, taking charge of tracking player observations, and the protocol will be "thinner" than it was, focusing on mutations to each player's cached observations.
That's it for now. Good night and good luck.
Current listening: Revolution-Etude, Chopin; followed by HALOHEAD, by Kunzite.
Pictured: roadmap excerpt