This book is a work in progress, comments are welcome to: johno(at)johno(dot)se

Back to index...

MVC/E - multiplayer enabled MVC architecture


Building on GC2 experience, uses a write proxy (similar to IGame) to control access to Model.

This is called EventTarget. The main difference from IPlayer/IGame is that EventTarget is the only abstract "event interface". The idea is that all events of interest are "system-wide", i.e. not pertaining specifically to the client or server side.

EventTarget servers many purposes:

basic architecture

Controller can write to application state (Model) via EventTarget

Model implements EventTarget to change state and optionally (per method) propagate the call to its EventTarget reference/pointer. In this way Controller also gets a change to react to individual events (if desired)

Controller can directly inspect Model state (constant access, includes public members and const methods)

As View also has a direct constant reference to Model, it may well expose very high level / application specific methods, such as: void View::drawWorld(); This is implemented by directly accessing Model's state and visualising it in somw way

Note that Controller is in charge of actually issuing calls to the various View methods

In addition to actually performing visualisation, View acts as the natural repository of any assets required for thie visualisation. This often takes the form of in-memory art and audio assets like meshes, textures and waveforms. Note that while these assets technically constitute "state", they are most often of the form of resource handles to assets already pre-committed to system hardware, i.e. vertex/index buffers, texture handles, sound buffers. While these things are conceptually stateful "caches", they are of the type "things that CAN be used for visualisation", as opposed to classic Retained Mode "specific instances of visulisation". This is a key concept, and much more aligned with the way modern graphics hardware actually functions (as compared to RM systems).

network aspects


As implied, other implementations of EventTarget can be used. Specifically, Client acts as a proxy to a remote Model, as well as a natural place to put any local prediction and simulation.

Client encodes EventTarget method calls and propagates them across the network to a remote Mode. For incoming network traffic, Client decodes state updates and applies them to local Model.

As mentioned, this also includes any prediction, interpolation, or other local simulation. As Client has a (non-const) reference to Model, it can run the exact same code that is run remotely (on the server) in order to simulate game logic locally.

Besides directly manipulating the local Model, Client also derives EventTarget "events" based on differences between consecutive State updates from the remote Model. By not requiring EventTarget callbacks to be sent explicitly, we can get away with a pure state transfer from server to client (i.e. Quake 3 Arena scheme, including delta compression).


On the server side, things are even simpler.

Server is completely external to the Model, and exists to handle RemoteClient connections as well as the timely propagation of state to these clients (using delta compression).

In this deployment (dedicated server), Model has no reference to an EventTarget for propagation of EventTarget method calls. Instead, as mentioned, the corresponding "events" are derived by the Client on the receiving end by comparing consecutive state updates, differences in which imply that EventTarget "events" have occured.


old stuff to be integrated into the above...
Model / View / Controller / IEventTarget

Building on the experience gained from the Ground Control II architecture, a new architecture has emerged that aims to do away with the redundancies inherent to both the Message based and IPlayer / IGame architectures. Consider the below:

This is a variant of the classic Model / View / Controller architecture. In this architecture, the existence of the network implementation is still hidden, but logical concepts and data only appear in a single form (Model). The IPlayer / IGame interfaces have been merged into the IEventTarget interface, which can be seen as the unified, system-wide event protocol. The tenet is that "reads are free" (i.e. the View or Controller(s) polling state in the Model), while "writes are formalized" (via the IEventTarget interface).

Controllers (conceptually clients) connect to a central Model (conceptually the server), which encapsulates the centralized logic typical of a server module.

Due to the unified event protocol, security issues may arise, with malicious remote clients (Controllers) calling IEventTarget methods on the Model that they aren't meant to be able to call. This can be handled elegantly in this architecture due to the fact that Client is allowed to override Model implementations of all IEventTarget methods as it sees fit. Note that there is not necessarily a one-to-one mapping of all IEventTarget methods to the internal network protocol, and it is therefore not possible to propagate IEventTarget calls to a remote Model if the network protocol does not allow it. Again, all such details are part of the Client implementation, and are nicely hidden from the rest of the application.

In the IPlayer / IGame architecture, all communication between remote nodes in a multiplayer game was required to go via the IPlayer / IGame interfaces. With Model / View, this is no longer a requirement, due to the fact that the Model proxy acts as both an interface proxy AND a state proxy. Consider the need to constantly synchronize the positions and orientations of units in an RTS game; this was expressed in Ground Control II's IPlayer / IGame interfaces as IPlayer::UnitFrame(). With MVC/E, this is not at all necessary in the local case, as Controller(s) and View always operate directly upon the state of its constant Model reference, which is this case is the only Model in the system. In the remote case, such synchronization is required, due to the fact that the authoritative Model resides in a different address space. This can however be done as part of the Client implementation, and can from a network protocol point of view be seen as out-of-band network traffic (state synchronization), totally seperated from the overrides of the IEventTarget methods. From a View's point of view (pun intended), the Model is simply always synchronized and up to date; how this is achieved is simply not relevant.

In Ground Control II, we wanted to save network bandwidth by not constantly synchronizing projectiles across the network. This was done by creating Player versions of the Game projectiles and simulating these locally in the same way as they were simulated in the remote Game (using shared movement code). This type of optimization is still possible, but there is fortunately no need to created multiple versions of the projectile objects anymore. Consider the following:

//model implementation
void Model::update()
   //update unit logic

   //update projectile logic

//remote model override
void Client::simulate()
   //just update projectile logic
Back to index...