Among Cafu's most prominent and important features are the
networking
code and, closely related to that, the
client
prediction feature. These two together implement a client-server
network model that allows fast multi-player games over the internet, where the
prediction makes sure that network lag is compensated for so that the game
feels fast and responsive for all participating players.
Building on this basis, Cafu also implements some complementing features that
further improve the client experience: Automatic
interpolation
is available so that also the movement, colors and other attributes of
"non-player" entities get smoothly updated with the client framerate, even if
they actually receive updates over the network with the much lower server
framerate. And there is a broad spectrum of
client effects
that create a great visual experience that is entirely independent from the
server: model animations are played, particles effects rendered, and so on.
I've written more about client effects in my news post
Server state
and client effects in online games.
However, recently it was time for a revision: When the player was riding
a lift as implemented in our new
Mover component, the movement
of the lift and/or the (relative) movement of player itself (being pushed by
the lift) was not yet ideal. Lifts are run and operated on the server, which
makes them difficult to integrate with the client prediction of a riding
player.
It quickly turned out that
reconciliation, a
sub-feature of client prediction that "smoothly" fixes mismatches of the
prediction results against the server, was still missing and that riding lifts
would become a perfect experience as a side effect of adding the more general
reconciliation (sub-)feature.
Other minor issues with the old code included that our interpolation feature
(and the temporary world state related to it) must not accidentally interfere
with the client prediction, and that while our own local human player is fully
covered by prediction, other (3rd person) human player entities should be
covered by interpolation instead.
At that opportunity, but independent from the above, I wanted to achieve a
better (generic, powerful and simple) means for implementing "pure" client
effects, so that game and map designers could easily add features like these
(some long existing, some still missing):
- 1st person (the local human player):
- head swaying (in state
FrozenSpectator
,
currently still implemented in ComponentHumanPlayerT
via sync'ed m_HeadSway
member),
- head bopping when walking / running,
- smooth stepping on staircases.
- 3rd person (monsters, other human players, game objects, etc.):
- properly advanced model animations,
- light sources that pulsate, swing, move, ...
- items that rotate, bop, circle, ...
Last but not least, also largely independent from the above, I wanted to
clean up the client's source code. These client feature are complex, and I
wanted to have them as clearly and comprehensibly implemented as possible,
providing a good code design for C++ developers.
In summary, these are the existing and new features that I wanted to cover:
- server updates (authoritative frame updates as received over the
network from the server),
- prediction (handles the instant processing of input for the local human
player), with sub-features:
- reprediction,
- reconciliation;
- interpolation (updates monsters, 3rd person players and other game
objects smoothly with the client's framerate),
- client effects (generic server-independent effects as outlined above).
It had taken me a while to implement all this, but the work has turned out
to be very worthwhile and successful, and has been committed already (merge
commit is
eea2f04 of 2015-06-18).
I would also like to summarize the main technical ideas behind the new client's
code structure, but considering the length of this post, I'll rather postpone
them to a future news post, coming soon.