1
0
forked from 0ad/0ad
0ad/source/simulation/TurnManager.h
Matei 207d1367ec # A number of network synchronization fixes.
- The server will no longer send a new turn until the previous one has
been "acknowledged". (TODO: this may create lag between turns in its
current form; investigate and possibly allow executing two turns while
the third is being negotiated).
- Mutexes are now being used in NetServer and NetClient to ensure
commands go into the right batches.
- Commented out some orders in the GUI code that should not be there and
are not 100% working anyway (they were part of the follow/formation
system).
- Units that spawn or are created by scripts now have net-safe position
and orientation.
- Added a debug flag that can be turned on to print details about when
commands are received and executed (DEBUG_SYNCHRONIZATION). This is
especially useful if you diff the stdouts of two running games. There
should be no differences if everything is in synch.

This was SVN commit r5463.
2007-11-18 09:09:06 +00:00

129 lines
3.4 KiB
C++

#ifndef INCLUDED_TURNMANAGER
#define INCLUDED_TURNMANAGER
//#include "Network/NetMessage.h"
//#include "Network/Network.h"
#include <vector>
class CGameRecord;
class CNetMessage;
class IMessagePipeEnd;
class CTurnManager
{
public:
// Default turn length
static const uint DEFAULT_TURN_LENGTH = 150;
// Used with IterateBatch() to iterate a command batch and set the sync mask
// for each message. If the iterating function doesn't wish to change the
// mask, it should return oldMask unchanged.
typedef uint (BatchIteratorFunc)(CNetMessage *pMsg, uint oldMask, void *userdata);
// FIXME Should be in CNetServer instead
struct SClientTimingData
{
// The maximum latency observed from this client
uint m_MaxLatency;
// Approximate current round-trip time in milliseconds
uint m_Latency;
// Frames per Second - won't be used unless 1000/m_FPS > m_Latency (i.e.
// framerate is too slow to handle [m_Latency] as the turn length)
uint m_FPS;
};
private:
struct SMessageSyncEntry
{
// A bitmask telling which clients to sync this message to
uint m_ClientMask;
// The message pointer
CNetMessage *m_pMessage;
inline SMessageSyncEntry(CNetMessage *pMsg):
m_ClientMask(0),
m_pMessage(pMsg)
{}
};
struct SBatch
{
std::vector <SMessageSyncEntry> m_Messages;
uint m_TurnLength;
void Swap(SBatch &other);
};
struct SClient
{
// FIXME Move to CNetServer
SClientTimingData m_TimingData;
IMessagePipeEnd *m_Pipe;
};
std::vector <SClient> m_Clients;
SBatch m_Batches[3];
CGameRecord *m_pRecord;
protected:
// Rotate the three batches: {0, 1, 2} => {1, 2, 0}
void RotateBatches();
// Go through each message in the specified batch and send the message to
// each of the clients whose bit in the message's mask is set
void SendBatch(uint batch);
void ClearBatch(uint batch);
void SetClientPipe(uint client, IMessagePipeEnd *pipe);
// FIXME Should be in CNetServer instead [and implemented]
// void UpdateTimingData(uint client, uint fps, uint currentLatency);
void SetTurnLength(uint batch, uint turnLength);
void SendMessage(CNetMessage *pMsg, uint clientMask);
// Add the message to the specified batch. The message is assumed to be
// validated before passed here, and will be blindly trusted.
void QueueMessage(uint batch, CNetMessage *pMsg);
// Send the specified batch to CGameRecord for recording
void RecordBatch(uint batch);
static BatchIteratorFunc RecordIterator;
public:
CTurnManager();
virtual ~CTurnManager() { }
void Initialize(size_t numClients);
// Return the millisecond delay between the last frame and the next.
// CSimulation will use this to determine when to perform the deterministic
// update and call NewTurn()
uint GetTurnLength();
// Called by CSimulation when the current turn time has passed.
virtual void NewTurn()=0;
// Used by CSimulation to ask whether it can call NewTurn.
virtual bool NewTurnReady() { return true; }
// Apply a function to all messages in a given batch.
void IterateBatch(uint batch, BatchIteratorFunc *func, void *userdata);
// Queue a command originating from the local player.
virtual void QueueLocalCommand(CNetMessage *pMsg)=0;
};
class CSinglePlayerTurnManager: public CTurnManager
{
public:
CSinglePlayerTurnManager();
virtual void NewTurn();
virtual void QueueLocalCommand(CNetMessage *pMsg);
};
extern CSinglePlayerTurnManager *g_SinglePlayerTurnManager;
#endif