Multiplayer Games Chapter 6 Network Topologies.ppt
MoissFreitas13
14 views
34 slides
Oct 17, 2024
Slide 1 of 34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
About This Presentation
Multiplayer Games Programming Network Topologies
Size: 159.92 KB
Language: en
Added: Oct 17, 2024
Slides: 34 pages
Slide Content
Multiplayer Game Programming
Chapter 6
Network Topologies
Chapter 6
Objectives
Network Topologies
–How should different computers be connected to each other,
in the game, and what are the tradeoffs?
Implementing Client-Server
–What are the specific challenges of implementing the client-
server topology?
Implementing Peer-to-Peer
–How to guarantee synchronization between peers in a
deterministic lockstep simulation?
Network Topologies
Which hosts send data to which other hosts
Impacts total bandwidth used by game
Impacts latency players experience
Impacts method used to share consistent game world
Impacts what game can do
Impacts how players can and cannot cheat
Impacts how player hardware affects other players
Impacts cost to operate game
Client-Server
???INSERT FIGURE 6.1 PLEASE
Client-Server Properties
All clients connect to only one server
–O(2n) connections total
•Server: O(n) connections
•Client:1 connection
–Asymmetric requirements
•Server needs better hardware and much more
upstream bandwidth than clients
•Server needs scale as client count increases
•Client needs remain relatively constant
Server Authority
“The Server Is The Man” –Tim Sweeney
The game server’s simulation of the game is
considered correct – if a client disagrees, the server
wins the argument
This may increase the lag or latency for commands,
since they must always be validated by the server
The round trip time (RTT) between clients is
increased, since it must go through the server
–Between Clients A and B, the worst-case latency is
½ Client A’s RTT + server processing time + ½
Client B’s RTT
Types of Servers
A dedicated server is only a server process, and can
run on a completely separate machine than any clients
–Many bigger games run their own servers
A listen server involves a server that is also an active
participant in the game
–Saves developers money
–May give the player who is on the listen server an
advantage in terms of latency
–May need a complex setup to support host
migration – changing from one player hosting to
another
Peer-to-Peer
???INSERT FIGURE 6.2 PLEASE
Peer-to-Peer Properties
Each computer connects to every other computer
–O(n
2
) connections total
•Each peer: O(n – 1) connections
–Symmetric bandwidth requirements
•The more players in the game, the more
bandwidth required
•Each peer requires the same amount of
bandwidth
–Better latency than client-server:
•Worst-case is ½ RTT
Input Sharing
Concept of authority is much more nebulous in peer-
to-peer
Most peer-to-peer games implement some sort of
input sharing – all actions are shared across all peers
Recall that Age of Empires used such a model
(deterministic lockstep)
Caveat
For now, the implementation of both the client-server
and peer-to-peer games will assume there is no
latency nor packet loss
This is not a realistic assumption for a real game
How to handle latency and packet loss is discussed in
Chapter 7 and 8
Separating Server and Client
Code
For a particular game object:
–Some code is specific to the server
–Some code is specific to the client
–Some code is shared between the server and the
client
One solution: use inheritance!
–Have a base class for the shared code
–A separate derived class for the server, and a
separate one for the client
Separating Server and Client
Code
???INSERT FIGURE 6.4 PLEASE
Network Manager
The NetworkManager does much of the heavy-lifting
of interacting with the network
Responsbilities are split up between subclasses, so:
–The base NetworkManager contains shared
functionality, such as basic UDP packet processing
–Server/client code is split up into
NetworkManagerServer and
NetworkManagerClient
Welcoming New Clients
1.Client sends the server a “hello” packet
2.Server assigns the new client a player ID, and sends
the client a “welcome” packet
3.When the client receives the welcome packet, it saves
its player ID
4.At some point in the future, the server spawns objects
for the new client, and starts sending object updates to
the new and existing clients
Client Sending and Receiving
Packets
void NetworkManagerClient ::SendOutgoingPackets()
{
switch(mState)
{
case NCS_SayingHello:
UpdateSayingHello();
break;
case NCS_Welcomed:
UpdateSendingInputPacket();
break;
}
}
Client Reading Welcome Packets
void NetworkManagerClient ::HandleWelcomePacket(
InputMemoryBitStream& inInputStream)
{
if (mState == NCS_SayingHello)
{
//if we received a player id, we've been welcomed!
int playerId;
inInputStream.Read(playerId);
mPlayerId = playerId;
mState = NCS_Welcomed;
LOG("'%s' was welcomed on client as player %d" ,
mName.c_str(), mPlayerId);
}
}
Server Tracking Clients
Server contains an address-to-client map
When data is received from an address, the server can
determine which client sent the packet
If the client is unknown, the only packets that are
considered are “hello” packets, and only if the game is
in a state where hello packets are valid
Input Sharing and Client Proxies
The client shouldn’t send replication data to the server,
since the server is the authority
Instead, the client’s (abstracted) input is sent to the
server for processing and validation
The server uses a client proxy for its representation
of each client in the game
As input data comes in, it is associated with the
corresponding proxy, and then all proxies are updated
every frame
Welcoming New Peers
In peer-to-peer, adding new players is a bit more complex
There is a master peer that coordinates adding a new
player, to ensure there are no race conditions
When a hello packet is received by a peer, there are three
possible responses:
–Welcome – Only the master peer will send this out,
signifying the player is welcomed to the game
–Not joinable – The game cannot be currently joined
–Not master peer – The hello packet was received by a
different peer, who informs the sender who the master
peer is
Peer-to-peer Addresses
One major issue in peer-to-peer is that not all peers
may be reachable to every other peer
This is especially an issue when some peers are on a
local network, whereas others have a global IP
address
One solution to this is a rendezvous server, that
insures all players are registered with their global IP
address
Rendezvous Server
In (a) Peer C cannot connect to Peer B, but this is solved
by the rendezvous server in (b)
???INSERT FIGURE 6.6 PLEASE
Command Sharing
As in Age of Empires, send commands rather than
object replication updates
RoboCat RTS uses 100ms turn durations
Commands issued by a peer on turn x are not
executed until turn x + 2, giving time for network
transmission
At the end of a turn, a turn packet is sent to each peer
Sending Turn Data to Peers
void NetworkManager::UpdateSendTurnPacket()
{
mSubTurnNumber++;
if (mSubTurnNumber == kSubTurnsPerTurn)
{
//create our turn data
TurnData data(mPlayerId,
RandGen::sInstance->GetRandomUInt32(0, UINT32_MAX),
ComputeGlobalCRC(),
InputManager::sInstance->GetCommandList());
//we need to send a turn packet to all of our peers
OutputMemoryBitStream packet;
packet.Write(kTurnCC);
//we're sending data for 2 turns from now
packet.Write(mTurnNumber + 2);
packet.Write(mPlayerId);
data.Write(packet);
for (auto &iter: mPlayerToSocketMap)
{
SendPacket(packet, iter.second);
}
//continued on next slide...
Sending Turn Data to Peers
//save our turn data for turn + 2
mTurnData[mTurnNumber + 2].emplace(mPlayerId, data);
InputManager::sInstance->ClearCommandList();
if (mTurnNumber >= 0)
{
TryAdvanceTurn();
}
else
{
//a negative turn means there's no possible commands yet
mTurnNumber++;
mSubTurnNumber = 0;
}
}
}
Advancing the Turn
TryAdvanceTurn will only advance to the next turn if all
the command data for that turn has been received
from all peers
Otherwise, go into a delay state and wait for the
missing data
This is to ensure the peers never desynchronize
Synchronizing PRNGs
Pseudo-random number generators (PRNGs) rely on a
seed value to generate the sequences
PRNGs can be synchronized across peers:
–Each PRNG starts with the same seed
–Each peer will always make the same number of
PRNG calls per frame
–Each call will occur in the same exact locations in
the code
–Each call will occur in the same order for each peer
Can’t use Standard C rand because the PRNG
algorithm is implementation-defined
C++11 Random Numbers
C++11 has several tightly specified PRNG algorithms
in the <random> header
A popular choice for games is the 32-bit Mersenne
Twister algorithm (MT19937)
The Mersenne Twister sequence has a period of 2
19937
,
which means it realistically will not repeat during the
course of a game – and even if it does, it would be
difficult for the player to exploit
Implementing a RandGen Class
void RandGen::StaticInit()
{
sInstance = std::make_unique< RandGen>();
//just use a default random seed, we'll reseed later
std::random_device rd;
sInstance->mGenerator.seed(rd());
}
Verifying Game Synchronization
Much how packets are validated, use a checksum to
determine whether peers remain synchronized
Every frame, perform a 32-bit CRC calculation over all
relevant data for each game object
Include this checksum in each turn packet
Before advancing to the next turn, verify all the
checksums are consistent – if they aren’t, the game
has desynchronized