Warning, /games/libkdegames/src/private/kgame/DESIGN is written in an unsupported language. File is not indexed.

0001 This document tries to describe the design of KGame - the KDE multiplayer
0002 library.
0003 This document has been written by:
0004  Andreas Beckermann <b_mann@gmx.de>
0005  M. Heni <kde  at heni-online.de>
0006  Burkhard Lehner <Burkhard.Lehner@gmx.de>
0007 
0008 This document is published under the terms of the GNU FDL
0009 
0010 !!!
0011 Note that this is the initial version of this document and has not yet been
0012 approved by all core developers (and is far from being complete)
0013 AB: please remove this comments as soon as all KGame hackers have read the
0014 document
0015 !!!
0016 
0017 Please refer the API documentation of every KGame class if you want up tp date
0018 information.
0019 
0020 
0021 0. Contents
0022 -----------
0023 
0024 1. DEFINITIONS
0025 1.1 Message Server
0026 1.2 Client or Message Client
0027 1.3 Master
0028 1.4 Admin
0029 1.5 Server
0030 1.6 Player
0031 
0032 2. Game Negotiation (M.Heni 20.05.2001)
0033 
0034 AB: 3.x is obsolete!
0035 3. Game Properties (Andreas Beckermann 28.07.2001) ( not yet completed )
0036 3.1 Using KGameProperty
0037 3.2 Custom Classes
0038 3.3 Concepts
0039 
0040 4. KGameIO (Andreas Beckermann 10.08.2001)
0041 
0042 ---------------------------------------------------------------------
0043 1. DEFINITIONS
0044 --------------
0045 
0046 First we have to clear some words. The main expressions used in KGame which
0047 need a definition are
0048 
0049 1.1 Message Server
0050 1.2 Client or Message Client
0051 1.3 Master
0052 1.4 Admin
0053 1.5 Server
0054 1.6 Player
0055 
0056 The most important and confusing ones are Master, Admin and Server. We make
0057 quite big differences between those inside KGame.
0058 
0059 1.1 Message Server:
0060 -------------------
0061 A game has always exactly one object of this class, for local games as well as
0062 for network games. For network games, this object can be on one of the users
0063 processes (usually inside KGame), or it can also be on an independent computer,
0064 that has no idea about what game is played on it.
0065 
0066 A KMessageClient object can connect to it. Its main purpose is transmitting
0067 messages between KMessageClient objects.
0068 
0069 The Message Server is the main communication object. It is represented by the
0070 class KMessageServer. Note that there is also a "Master" and a "Server" which
0071 both differ heavily from the Message Server!
0072 
0073 1.2 Client, Message Client:
0074 ---------------------------
0075 Each process that wants to take part in the game must have a
0076 KMessageClient object, that is connected to the Message Server. KGame creates
0077 this object and connects it to the Messager Server, so that you usually don't
0078 need to create these of your own. Even in a local game (no network) there
0079 must be a message server and one message client connected to it. This is usually
0080 done by the KGame object itself.
0081 
0082 Each message client has a unique ID number (a positive integer value, not zero).
0083 The KMessageClient object, which does the communication with the Message Server
0084 is called "Message Client" and to simplify the use we call any KGame object (or
0085 even the game process) that is connected to a game (i.e. even the Master) just
0086 "Client".
0087 
0088 The main purpose of a Client is to connect to a Master (i.e. to a game) and to
0089 communicate with it. A client has always a KGame object.
0090 
0091 1.3 Master:
0092 -----------
0093 The process that contains the Message Server is called "Master". In any local
0094 game this is the game process. The Message Server is started by KGame using
0095 KGame::setMaster(true) which is automatically done on startup. The Message
0096 Server is deleted automatically as soon as you connect to another Master.
0097 So in most cases there is exactly one KGame object / Client which is Master. But
0098 in one case there can be no KGame object / Client that is Master - if the
0099 Message Server is started as an own process. This "Message-Server-only" process
0100 is called "Master" then, although there is no KGame object which is Master. See
0101 also the definition of Admin!
0102 
0103 1.4 Admin:
0104 ----------
0105 One (and only one) of the Clients is the Admin. He can configure the Message
0106 Server and the game in general in several ways. He can limit the maximum number
0107 of connected message clients and can drop the connection to some other clients,
0108 as well as he can configure game specific settings (like max/min players, start
0109 money, ...). The Admin also initializes newly connected Clients. If the Admin
0110 himself disconnects, another Client becomes Admin (The Admin can himself elect
0111 some other Client to become Admin. He himself loses that Admin status then).
0112 An Admin is *always* a KGame object. The Admin is usually the same as the Master,
0113 but if the Master is an own process (i.e. the Message Server has been started
0114 outside KGame) then Master and Admin differ. An Admin *must* be a KGame object
0115 while the Master doesn't have to be.
0116 
0117 1.5 Server:
0118 -----------
0119 The definition of Server differs quite much from the definition of Master.
0120 A Master just accepts connections and forwards messages. The Server on the other
0121 side checks these messages, calculates results and sends the results to the
0122 Clients. That means the Server does all game calculations and doesn't directly
0123 forward the messages from one Clients to all other Clients.
0124 KGamer makes it possible to write multiplayer games even without a Server. All
0125 Clients just send their moves to the Master which forwards them to all Clients.
0126 Now all Clients calculate the result.
0127 E.g. in a poker game a player selects two of five cards to be exchanges and
0128 clicks on "draw" then the client sends the message "Exchange Card-1 and Card-2"
0129 to the Master. A no-Server solution forwards this to all Clients, and these
0130 Clients exchange the cards of the player. Note that in a no-Server solution
0131 (you can also see it as a "every-Client-is-a-Server solution") all Clients must
0132 have the same random seed and must be of the same version, i.e. the result must
0133 be the same on all Clients.
0134 In a Server-Solution on the other hand the Master forwards the Message
0135 ("Exchange Card-1 and Card-2") to the Server only. This Server now calculates
0136 the result, and sends the new cards back to the Client.
0137 Both concepts have advantages and disadvantages. It is on you - the game
0138 developer - to decide which way is better for you.
0139 E.g. the Server-Solution makes it easier for you to write games. The version
0140 must not necessarily be the same, you have one central computer which does the
0141 calculations. The No-Server-Solution on the other hand decreases network
0142 traffic as the Clients just send their moves and all Clients can calculate the
0143 reactions. I'm sure there are a lot of advantages/disadvantages more for both
0144 concepts.
0145 
0146 1.6 Player:
0147 -----------
0148 A KPlayer object is always connected to a KGame object and represents a
0149 player that participates the game. In a network game, every KPlayer object is
0150 duplicated on every other KGame object connected to the message server with
0151 virtual KPlayer objects. So at every time in the game, every KGame object has
0152 the same number of KPlayer objects.
0153 
0154 
0155 2. Game negotiation
0156 -------------------
0157 Upon connection  of a client the admin and the client try to negotiate
0158 the game setup. Basically this means the game of the admin is transferred
0159 (saved) on the client. However, the client's players are added to the game
0160 as far as possible. If the addition of the client's players would add more
0161 players than allowed some players are inactivated. Which players are
0162 inactivated depends on their networkPriority(). This procedure allows
0163 easy replacement of players in a constant number game (e.g. chess). If
0164 this feature is of no interest simply keep the priorities equal (all 0)
0165 and the client will only add only players if the number of players is
0166 less or equal the maximum player number.
0167 
0168 The following is the negotiation procedure as started by the connection
0169 of a client. It is initiated in the negotiateNetworkGame() virtual function
0170 of KGame:
0171 
0172 admin:                client:
0173 ------------          ------------
0174 IdSetupGame
0175   QINT16 Library
0176          Version
0177   QINT32 Application
0178          cookie
0179                       IdSetupGameContinue;
0180                         QValueList<int> player id's
0181                         QValueList<int> network priority's
0182 
0183 IdGameLoad
0184   all game data
0185 
0186 IdGameReactivate
0187   QValueList<int> id's
0188 
0189 IdSyncRandom
0190   int randomseed
0191 
0192 
0193 3. Game Properties
0194 ------------------
0195 A very hard task in a network game is consistency. You have to achieve that all
0196 properties of the game and of all players have the same value on all clients
0197 every time. This is because 
0198 a) the user might be confused if he sees "Player has $0" on client A but 
0199 "Player has $10" on client B and 
0200 b) Often game handling depends on those values, e.g. if the example above
0201 happens the computer might quit the game for the Player on client A because
0202 he/she doesn't have enough money. But the game continues on client B. 
0203 Another not that easy task is the network protocol itself. You have to write
0204 several send() and receive() functions which apply changed values of properties
0205 to the local property. 
0206 
0207 KGameProperty is designed to do all of this for you. KGameProperty is
0208 implemented as a template so you can use it theoretically for every type of data
0209 - even for your self defined classes. 
0210 
0211 
0212 3.1 Using KGameProperty
0213 -----------------------
0214 It is basically very easy to use a KGameProperty. You first create your own
0215 class containing the property, e.g:
0216 class MyGame : public KGame
0217 {
0218 [...]
0219 protected:
0220         KGamePropertyInt money;
0221         KGamePropertyQString name;
0222         KGameProperty<AntotherClass> myProperty;
0223 };
0224 KGamePropertyInt is just a typedef for KGameProperty<int> - just like
0225 KGamePropertyQString. Now you need to register the properties in the constructor
0226 of the class to the KGamePropertyHandler:
0227 MyGame::MyGame() : KGame(myCookie)
0228 {
0229  money.registerData(KGamePropertyBase::IdUser+1, dataHandler(), "Money");
0230  name.registerData(KGamePropertyBase::IdUser+2, this, "Name");
0231  myProperty.registerData(KGamePropertyBase::IdUser+3, dataHandler(), "MyProperty");
0232 }
0233 -> You need to specify a *unique* ID. This ID must be greater than
0234 KGamePropertyBase::IdUser. IDs below this are reserved for KGame. Probably this
0235 will be changed so that you cannot use IDs below IdUser in the future. Then you
0236 have to specify the dataHandler(). You can also use a KGame or KPlayer pointer.
0237 This will automatically use KGame::dataHandler() or KPlayer::dataHandler().
0238 Finally you *can* provide a name for the property.
0239 Note that if you use pointers to create the properties dynamically they are
0240 *not* deleted automatically! You MUST delete them yourself!
0241 Now you can use the KGameProperty like every variable else. See also Section 
0242 "3.3 Concepts" for restrictions in use.
0243 
0244 3.2 Custom Classes
0245 ------------------
0246 To make custom classes possible you have to implement several operators for your
0247 them: you need at least << and >> for QDataStream as well as "==" for your own
0248 class. To overload the "<<" you would e.g. do something like this:
0249 QDataStream& operator<<(QDataStream& stream, MyData& data)
0250 {
0251  int type = data.type;
0252  QString name = data.name;
0253  stream << type << name;
0254  return stream;
0255 }
0256 So you basically just have to split your class to several basic types and stream
0257 them.
0258 
0259 3.3 Concepts
0260 ------------
0261 You can use KGameProperty basically in two completely different ways. You can
0262 also use a mixture of both but this is not recommended. The default behaviour
0263 and therefore also the recommended is the "clean" way: 
0264 a) Always Consistent. This means that a KGameProperty has always the same value
0265 on *every* client. This is achieved by using KGameProperty::send() whenever you
0266 want to change the value using "=". You can still use changeValue() or
0267 setLocal() but send() will be the default. If you use send() then the value of
0268 the property does *NOT* change immediately. It is just sent to the
0269 KMessageServer which forwards the value to all clients. As soon as the new value
0270 is received from the message server the KGamePropertyHandler (a collection class
0271 for KGameProperty) calls KGameProperty::load() and changes the value of the
0272 property. So the game first has to go into the event loop, where the message is
0273 received. This means to you that you cannot do this:
0274 myIntProperty = 10;
0275 int value = myIntProperty;
0276 As myIntPoperty still has the old value when "value = myIntProperty" is called.
0277 This might seem to be quite complex, but 
0278 KGamePropertyHandler::signalPropertyChanged() is emitted whenever a new value is
0279 assigned so you can connect to this and work immediately with the new value.
0280 You gain the certainty that the value is the same on every client every time.
0281 That will safe you a lot of time debugging!
0282 Another way is the "dirty" way:
0283 b) Not Always Consistent. Sometimes you really *want* to do something like
0284 myIntProperty = 10;
0285 int value = myIntProperty;
0286 but this is not possible with the default behaviour. If you call
0287 KGameProperty::setAlwaysConsistent(false) in the constructor (right after
0288 registerData()) you get another behaviour. "=" means changeValue() now.
0289 changeValue() also uses send() to change the value but additionally calls
0290 setLocal() to create a local copy of the property. This copy now has the value
0291 you supplied with "=" and is deleted again as soon as any value from the network
0292 is received. 
0293 
0294 4. KGameIO
0295 ----------
0296 The class KGameIO is used to let the players communicate with the server. You
0297 can plug as many KGameIO objects into a player as you want, e.g. you can plug a
0298 KGameMouseIO and a KGameKeyIO into a player so that you can control the player
0299 with the mouse and the keyboard - e.g. in a breakout game. 
0300 You can probably see the advantage: as most of the control stuff is common in a
0301 lot of games you can use the same IO class in many different games with very
0302 small adjustments. 
0303 You could also put all the IO stuff directly into your KPlayer object, like
0304 sendBet(int money) for a poker game. But there is a major disadvantage and I'm
0305 very sure you don't want to use a KPlayer object for your IO stuff as soon as
0306 you know which disadvantage:
0307 KGameIO is designed to be able to switch between different IOs "on the fly". So
0308 you might have a KGamePlayerIO, derived from KGameIO, for your game. But now
0309 this player (who "owns"/uses the KGamePlayerIO) leaves the game (e.g. because he
0310 was a remote player). So now the game would be over for every player as one
0311 player is now out of order. But with KGameIO you can just let any of the
0312 remaining clients create a KGameComputerIO and plug this into the player. So the
0313 player now is controlled by the computer and the game can continue. 
0314 
0315 Think about it! You don't have to care about removing players when a player
0316 leaves as you can just replace it! The same works the other way round: imagine a
0317 game with 10 player (e.g. 5 human and 5 computer players) that has already
0318 started. You cannot add any further players without restarting. So if there are
0319 any additional player you can just call KPlayer::removeGameIO() which removes
0320 the IO of a computer player and then call KPlayer::addGameIO() for the same
0321 player which adds a GameIO for new human player. That's all!
0322 
0323 To achieve this you just have to make sure that you make *all* of your IO
0324 operations through a KGameIO! So instead of using MyPlayer::sendBet(int money)
0325 you should use something like MyIO::sendBet(). The amount of money would
0326 probably be calculated by the game IO itself.
0327 
0328 
0329