This document tries to describe the design of KGame - the KDE multiplayer
library.
This document has been written by:
 Andreas Beckermann <b_mann@gmx.de>
 M. Heni <kde  at heni-online.de>
 Burkhard Lehner <Burkhard.Lehner@gmx.de>

This document is published under the terms of the GNU FDL

!!!
Note that this is the initial version of this document and has not yet been
approved by all core developers (and is far from being complete)
AB: please remove this comments as soon as all KGame hackers have read the
document
!!!

Please refer the API documentation of every KGame class if you want up tp date
information.


0. Contents
-----------

1. DEFINITIONS
1.1 Message Server
1.2 Client or Message Client
1.3 Master
1.4 Admin
1.5 Server
1.6 Player

2. Game Negotiation (M.Heni 20.05.2001)

AB: 3.x is obsolete!
3. Game Properties (Andreas Beckermann 28.07.2001) ( not yet completed )
3.1 Using KGameProperty
3.2 Custom Classes
3.3 Concepts

4. KGameIO (Andreas Beckermann 10.08.2001)

---------------------------------------------------------------------
1. DEFINITIONS
--------------

First we have to clear some words. The main expressions used in KGame which
need a definition are

1.1 Message Server
1.2 Client or Message Client
1.3 Master
1.4 Admin
1.5 Server
1.6 Player

The most important and confusing ones are Master, Admin and Server. We make
quite big differences between those inside KGame.

1.1 Message Server:
-------------------
A game has always exactly one object of this class, for local games as well as
for network games. For network games, this object can be on one of the users
processes (usually inside KGame), or it can also be on an independent computer,
that has no idea about what game is played on it.

A KMessageClient object can connect to it. Its main purpose is transmitting
messages between KMessageClient objects.

The Message Server is the main communication object. It is represented by the
class KMessageServer. Note that there is also a "Master" and a "Server" which
both differ heavily from the Message Server!

1.2 Client, Message Client:
---------------------------
Each process that wants to take part in the game must have a
KMessageClient object, that is connected to the Message Server. KGame creates
this object and connects it to the Messager Server, so that you usually don't
need to create these of your own. Even in a local game (no network) there
must be a message server and one message client connected to it. This is usually
done by the KGame object itself.

Each message client has a unique ID number (a positive integer value, not zero).
The KMessageClient object, which does the communication with the Message Server
is called "Message Client" and to simplify the use we call any KGame object (or
even the game process) that is connected to a game (i.e. even the Master) just
"Client".

The main purpose of a Client is to connect to a Master (i.e. to a game) and to
communicate with it. A client has always a KGame object.

1.3 Master:
-----------
The process that contains the Message Server is called "Master". In any local
game this is the game process. The Message Server is started by KGame using
KGame::setMaster(true) which is automatically done on startup. The Message
Server is deleted automatically as soon as you connect to another Master.
So in most cases there is exactly one KGame object / Client which is Master. But
in one case there can be no KGame object / Client that is Master - if the
Message Server is started as an own process. This "Message-Server-only" process
is called "Master" then, although there is no KGame object which is Master. See
also the definition of Admin!

1.4 Admin:
----------
One (and only one) of the Clients is the Admin. He can configure the Message
Server and the game in general in several ways. He can limit the maximum number
of connected message clients and can drop the connection to some other clients,
as well as he can configure game specific settings (like max/min players, start
money, ...). The Admin also initializes newly connected Clients. If the Admin
himself disconnects, another Client becomes Admin (The Admin can himself elect
some other Client to become Admin. He himself loses that Admin status then).
An Admin is *always* a KGame object. The Admin is usually the same as the Master,
but if the Master is an own process (i.e. the Message Server has been started
outside KGame) then Master and Admin differ. An Admin *must* be a KGame object
while the Master doesn't have to be.

1.5 Server:
-----------
The definition of Server differs quite much from the definition of Master.
A Master just accepts connections and forwards messages. The Server on the other
side checks these messages, calculates results and sends the results to the
Clients. That means the Server does all game calculations and doesn't directly
forward the messages from one Clients to all other Clients.
KGamer makes it possible to write multiplayer games even without a Server. All
Clients just send their moves to the Master which forwards them to all Clients.
Now all Clients calculate the result.
E.g. in a poker game a player selects two of five cards to be exchanges and
clicks on "draw" then the client sends the message "Exchange Card-1 and Card-2"
to the Master. A no-Server solution forwards this to all Clients, and these
Clients exchange the cards of the player. Note that in a no-Server solution
(you can also see it as a "every-Client-is-a-Server solution") all Clients must
have the same random seed and must be of the same version, i.e. the result must
be the same on all Clients.
In a Server-Solution on the other hand the Master forwards the Message
("Exchange Card-1 and Card-2") to the Server only. This Server now calculates
the result, and sends the new cards back to the Client.
Both concepts have advantages and disadvantages. It is on you - the game
developer - to decide which way is better for you.
E.g. the Server-Solution makes it easier for you to write games. The version
must not necessarily be the same, you have one central computer which does the
calculations. The No-Server-Solution on the other hand decreases network
traffic as the Clients just send their moves and all Clients can calculate the
reactions. I'm sure there are a lot of advantages/disadvantages more for both
concepts.

1.6 Player:
-----------
A KPlayer object is always connected to a KGame object and represents a
player that participates the game. In a network game, every KPlayer object is
duplicated on every other KGame object connected to the message server with
virtual KPlayer objects. So at every time in the game, every KGame object has
the same number of KPlayer objects.


2. Game negotiation
-------------------
Upon connection  of a client the admin and the client try to negotiate
the game setup. Basically this means the game of the admin is transferred
(saved) on the client. However, the client's players are added to the game
as far as possible. If the addition of the client's players would add more
players than allowed some players are inactivated. Which players are
inactivated depends on their networkPriority(). This procedure allows
easy replacement of players in a constant number game (e.g. chess). If
this feature is of no interest simply keep the priorities equal (all 0)
and the client will only add only players if the number of players is
less or equal the maximum player number.

The following is the negotiation procedure as started by the connection
of a client. It is initiated in the negotiateNetworkGame() virtual function
of KGame:

admin:                client:
------------          ------------
IdSetupGame
  QINT16 Library
         Version
  QINT32 Application
         cookie
                      IdSetupGameContinue;
                        QValueList<int> player id's
                        QValueList<int> network priority's

IdGameLoad
  all game data

IdGameReactivate
  QValueList<int> id's

IdSyncRandom
  int randomseed


3. Game Properties
------------------
A very hard task in a network game is consistency. You have to achieve that all
properties of the game and of all players have the same value on all clients
every time. This is because 
a) the user might be confused if he sees "Player has $0" on client A but 
"Player has $10" on client B and 
b) Often game handling depends on those values, e.g. if the example above
happens the computer might quit the game for the Player on client A because
he/she doesn't have enough money. But the game continues on client B. 
Another not that easy task is the network protocol itself. You have to write
several send() and receive() functions which apply changed values of properties
to the local property. 

KGameProperty is designed to do all of this for you. KGameProperty is
implemented as a template so you can use it theoretically for every type of data
- even for your self defined classes. 


3.1 Using KGameProperty
-----------------------
It is basically very easy to use a KGameProperty. You first create your own
class containing the property, e.g:
class MyGame : public KGame
{
[...]
protected:
	KGamePropertyInt money;
	KGamePropertyQString name;
	KGameProperty<AntotherClass> myProperty;
};
KGamePropertyInt is just a typedef for KGameProperty<int> - just like
KGamePropertyQString. Now you need to register the properties in the constructor
of the class to the KGamePropertyHandler:
MyGame::MyGame() : KGame(myCookie)
{
 money.registerData(KGamePropertyBase::IdUser+1, dataHandler(), "Money");
 name.registerData(KGamePropertyBase::IdUser+2, this, "Name");
 myProperty.registerData(KGamePropertyBase::IdUser+3, dataHandler(), "MyProperty");
}
-> You need to specify a *unique* ID. This ID must be greater than
KGamePropertyBase::IdUser. IDs below this are reserved for KGame. Probably this
will be changed so that you cannot use IDs below IdUser in the future. Then you
have to specify the dataHandler(). You can also use a KGame or KPlayer pointer.
This will automatically use KGame::dataHandler() or KPlayer::dataHandler().
Finally you *can* provide a name for the property.
Note that if you use pointers to create the properties dynamically they are
*not* deleted automatically! You MUST delete them yourself!
Now you can use the KGameProperty like every variable else. See also Section 
"3.3 Concepts" for restrictions in use.

3.2 Custom Classes
------------------
To make custom classes possible you have to implement several operators for your
them: you need at least << and >> for QDataStream as well as "==" for your own
class. To overload the "<<" you would e.g. do something like this:
QDataStream& operator<<(QDataStream& stream, MyData& data)
{
 int type = data.type;
 QString name = data.name;
 stream << type << name;
 return stream;
}
So you basically just have to split your class to several basic types and stream
them.

3.3 Concepts
------------
You can use KGameProperty basically in two completely different ways. You can
also use a mixture of both but this is not recommended. The default behaviour
and therefore also the recommended is the "clean" way: 
a) Always Consistent. This means that a KGameProperty has always the same value
on *every* client. This is achieved by using KGameProperty::send() whenever you
want to change the value using "=". You can still use changeValue() or
setLocal() but send() will be the default. If you use send() then the value of
the property does *NOT* change immediately. It is just sent to the
KMessageServer which forwards the value to all clients. As soon as the new value
is received from the message server the KGamePropertyHandler (a collection class
for KGameProperty) calls KGameProperty::load() and changes the value of the
property. So the game first has to go into the event loop, where the message is
received. This means to you that you cannot do this:
myIntProperty = 10;
int value = myIntProperty;
As myIntPoperty still has the old value when "value = myIntProperty" is called.
This might seem to be quite complex, but 
KGamePropertyHandler::signalPropertyChanged() is emitted whenever a new value is
assigned so you can connect to this and work immediately with the new value.
You gain the certainty that the value is the same on every client every time.
That will safe you a lot of time debugging!
Another way is the "dirty" way:
b) Not Always Consistent. Sometimes you really *want* to do something like
myIntProperty = 10;
int value = myIntProperty;
but this is not possible with the default behaviour. If you call
KGameProperty::setAlwaysConsistent(false) in the constructor (right after
registerData()) you get another behaviour. "=" means changeValue() now.
changeValue() also uses send() to change the value but additionally calls
setLocal() to create a local copy of the property. This copy now has the value
you supplied with "=" and is deleted again as soon as any value from the network
is received. 

4. KGameIO
----------
The class KGameIO is used to let the players communicate with the server. You
can plug as many KGameIO objects into a player as you want, e.g. you can plug a
KGameMouseIO and a KGameKeyIO into a player so that you can control the player
with the mouse and the keyboard - e.g. in a breakout game. 
You can probably see the advantage: as most of the control stuff is common in a
lot of games you can use the same IO class in many different games with very
small adjustments. 
You could also put all the IO stuff directly into your KPlayer object, like
sendBet(int money) for a poker game. But there is a major disadvantage and I'm
very sure you don't want to use a KPlayer object for your IO stuff as soon as
you know which disadvantage:
KGameIO is designed to be able to switch between different IOs "on the fly". So
you might have a KGamePlayerIO, derived from KGameIO, for your game. But now
this player (who "owns"/uses the KGamePlayerIO) leaves the game (e.g. because he
was a remote player). So now the game would be over for every player as one
player is now out of order. But with KGameIO you can just let any of the
remaining clients create a KGameComputerIO and plug this into the player. So the
player now is controlled by the computer and the game can continue. 

Think about it! You don't have to care about removing players when a player
leaves as you can just replace it! The same works the other way round: imagine a
game with 10 player (e.g. 5 human and 5 computer players) that has already
started. You cannot add any further players without restarting. So if there are
any additional player you can just call KPlayer::removeGameIO() which removes
the IO of a computer player and then call KPlayer::addGameIO() for the same
player which adds a GameIO for new human player. That's all!

To achieve this you just have to make sure that you make *all* of your IO
operations through a KGameIO! So instead of using MyPlayer::sendBet(int money)
you should use something like MyIO::sendBet(). The amount of money would
probably be calculated by the game IO itself.



