by zombie@computer on Mon Oct 04, 2010 5:21 pm
The Source code is divided up in client and server.dll
A 'game' in source consists of a server (server.dll) and any number of clients (up to 128 iirc) connected to it. Note that for singleplayer this means a server and one client are running on the same computer!
So, in essence, the server has all the code that 'applies to all clients', while the client contains the code that applies to 'just that client'. Simpler said the server does the game mechanics, the client does the rendering and the interface.
A short list of examples: (may not be 100% accurate)
client:
-rendering (closed source)
-hud
-controls (via keybindings)
-clientside physics (eg prop_physics_multiplayer)
server:
game mechanics (game rules, eg checking if client x can fire weapon y)
Interactions (eg bullets, explosions, calculation of health)
entity i/o's
physics
AI
Client and server interact with each other. This interaction goes really fast when both are running on the same computer, but can be a lot slower when your client is connected to a server on the internet.
They interact using data packets. Basically, the server summarises some variables of entities and sends them to the client (about 20 times per second). These variables need to be selected by the programmers. The client uses these packets to synchronize its local variables. This is best explained using an example.
For starters, a class is needed to contain these variables. (usually called C_someclass clientside, CSomeclass serverside) These classes are usually entities themselves (meaning, derived from cbaseentity and c_baseentity). We call these networked entities. You can have up to 2048 of these, each entity can have 1024 variables synchronised between server and client.
In programming, you select the variables (serverside these are templated using CNetworkVar) and put them in a NETWORK_TABLE. This groups all variables to be sent (using SendPropInt serverside, RecvPropInt clientside). The server then synchronises these variables to all the clients.
Pure serverside logic has no need for clientside classes. Logics like a logic_trigger has no place in a client, as the server executes the logic, then only needs to tell the clients what the outcomes are. Since physics are calculated serverside, you'd think physic entities (eg prop_physics) are serverside only as well, but this is wrong. The clients need to know what the state of the prop is (eg rotation, location) to render it correctly. That is why the prop_physics is a shared class. The clientside can then be used for rendering and other clientstuff.
Pure clientside logic are those of keybindings, and the HUD.
For optimization purposes, clients do a bit more of calculation than mentioned above. The client for example is more than capable of determining if a player's move is blocked by another entity. These exceptions are rare though, and mostly you never going to see them.
For starters, take a look at the following classes:
pure client
hud_*.cpp
pure server
logicrelay.cpp
shared
most weapons (note: some are just 'stubbed' clientside, as their clientside code is limited mostly to showing and animating the weapon model)
player:
CHL2_player.cpp
C_HL2_player.cpp
To make the code a bit less easy to read, theres quite a number of classes derived from other classes, like the player class mentioned above. (which is derived from cbaseplayer, which is derived from cbasecombatcharacter, which is derived from cbaseanimating (iirc), which is derived from... which is derived from cbaseentity. Some classes for client and server are coded in the same files (xxx_shared.cpp) in which clientside and serverside code is divided using preprocessor commands. Note that usually a #define cmyclass c_myclass line divides the server and client class names.
umm, was that at all understandable?
When you are up to your neck in shit, keep your head up high