Add setTurnLength() function for hacky fixing of network lag.

This was SVN commit r7936.
This commit is contained in:
Ykkrosh 2010-08-13 16:42:53 +00:00
parent c8f90ce5a2
commit 0ebe3486b6
6 changed files with 56 additions and 14 deletions

View File

@ -405,7 +405,7 @@ bool CNetClient::OnInGame(void *context, CFsmEvent* event)
else if (message->GetType() == NMT_END_COMMAND_BATCH) else if (message->GetType() == NMT_END_COMMAND_BATCH)
{ {
CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (message); CEndCommandBatchMessage* endMessage = static_cast<CEndCommandBatchMessage*> (message);
client->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn); client->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn, endMessage->m_TurnLength);
} }
} }

View File

@ -371,6 +371,12 @@ ScriptInterface& CNetServer::GetScriptInterface()
return *m_ScriptInterface; return *m_ScriptInterface;
} }
void CNetServer::SetTurnLength(u32 msecs)
{
if (m_ServerTurnManager)
m_ServerTurnManager->SetTurnLength(msecs);
}
bool CNetServer::OnClientHandshake(void* context, CFsmEvent* event) bool CNetServer::OnClientHandshake(void* context, CFsmEvent* event)
{ {
debug_assert(event->GetType() == (uint)NMT_CLIENT_HANDSHAKE); debug_assert(event->GetType() == (uint)NMT_CLIENT_HANDSHAKE);

View File

@ -165,6 +165,12 @@ public:
*/ */
ScriptInterface& GetScriptInterface(); ScriptInterface& GetScriptInterface();
/**
* Set the turn length to a fixed value.
* TODO: we should replace this with some adapative lag-dependent computation.
*/
void SetTurnLength(u32 msecs);
protected: protected:
/// Callback for autostart; called when a player has finished connecting /// Callback for autostart; called when a player has finished connecting
virtual void OnAddPlayer() { } virtual void OnAddPlayer() { }

View File

@ -35,7 +35,7 @@
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
static const int TURN_LENGTH = 200; // TODO: this should be a variable controlled by the server depending on latency static const int DEFAULT_TURN_LENGTH = 200;
static const int COMMAND_DELAY = 2; static const int COMMAND_DELAY = 2;
@ -51,7 +51,7 @@ static std::string Hexify(const std::string& s)
} }
CNetTurnManager::CNetTurnManager(CSimulation2& simulation, int clientId, IReplayLogger& replay) : CNetTurnManager::CNetTurnManager(CSimulation2& simulation, int clientId, IReplayLogger& replay) :
m_Simulation2(simulation), m_CurrentTurn(0), m_ReadyTurn(1), m_DeltaTime(0), m_Simulation2(simulation), m_CurrentTurn(0), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH), m_DeltaTime(0),
m_PlayerId(-1), m_ClientId(clientId), m_HasSyncError(false), m_Replay(replay) m_PlayerId(-1), m_ClientId(clientId), m_HasSyncError(false), m_Replay(replay)
{ {
// When we are on turn n, we schedule new commands for n+2. // When we are on turn n, we schedule new commands for n+2.
@ -96,18 +96,18 @@ bool CNetTurnManager::Update(float frameLength)
m_QueuedCommands.pop_front(); m_QueuedCommands.pop_front();
m_QueuedCommands.resize(m_QueuedCommands.size() + 1); m_QueuedCommands.resize(m_QueuedCommands.size() + 1);
m_Replay.Turn(m_CurrentTurn-1, TURN_LENGTH, commands); m_Replay.Turn(m_CurrentTurn-1, m_TurnLength, commands);
#ifdef NETTURN_LOG #ifdef NETTURN_LOG
NETTURN_LOG(L"Running %d cmds\n", commands.size()); NETTURN_LOG(L"Running %d cmds\n", commands.size());
#endif #endif
m_Simulation2.Update(TURN_LENGTH, commands); m_Simulation2.Update(m_TurnLength, commands);
NotifyFinishedUpdate(m_CurrentTurn); NotifyFinishedUpdate(m_CurrentTurn);
// Set the time for the next turn update // Set the time for the next turn update
m_DeltaTime -= TURN_LENGTH / 1000.f; m_DeltaTime -= m_TurnLength / 1000.f;
return true; return true;
} }
@ -156,7 +156,10 @@ void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash)
void CNetTurnManager::Interpolate(float frameLength) void CNetTurnManager::Interpolate(float frameLength)
{ {
float offset = clamp(m_DeltaTime / (TURN_LENGTH / 1000.f) + 1.0, 0.0, 1.0); // TODO: using m_TurnLength might be a bit dodgy when length changes - maybe
// we need to save the previous turn length?
float offset = clamp(m_DeltaTime / (m_TurnLength / 1000.f) + 1.0, 0.0, 1.0);
m_Simulation2.Interpolate(frameLength, offset); m_Simulation2.Interpolate(frameLength, offset);
} }
@ -178,14 +181,15 @@ void CNetTurnManager::AddCommand(int client, int player, CScriptValRooted data,
m_QueuedCommands[turn - (m_CurrentTurn+1)][client].push_back(cmd); m_QueuedCommands[turn - (m_CurrentTurn+1)][client].push_back(cmd);
} }
void CNetTurnManager::FinishedAllCommands(u32 turn) void CNetTurnManager::FinishedAllCommands(u32 turn, u32 turnLength)
{ {
#ifdef NETTURN_LOG #ifdef NETTURN_LOG
NETTURN_LOG(L"FinishedAllCommands(%d)\n", turn); NETTURN_LOG(L"FinishedAllCommands(%d, %d)\n", turn, turnLength);
#endif #endif
debug_assert(turn == m_ReadyTurn + 1); debug_assert(turn == m_ReadyTurn + 1);
m_ReadyTurn = turn; m_ReadyTurn = turn;
m_TurnLength = turnLength;
} }
void CNetClientTurnManager::PostCommand(CScriptValRooted data) void CNetClientTurnManager::PostCommand(CScriptValRooted data)
@ -211,7 +215,7 @@ void CNetClientTurnManager::NotifyFinishedOwnCommands(u32 turn)
// Send message to the server // Send message to the server
CEndCommandBatchMessage msg; CEndCommandBatchMessage msg;
msg.m_TurnLength = TURN_LENGTH; msg.m_TurnLength = DEFAULT_TURN_LENGTH; // TODO: why do we send this?
msg.m_Turn = turn; msg.m_Turn = turn;
m_NetClient.SendMessage(&msg); m_NetClient.SendMessage(&msg);
} }
@ -255,7 +259,7 @@ void CNetLocalTurnManager::PostCommand(CScriptValRooted data)
void CNetLocalTurnManager::NotifyFinishedOwnCommands(u32 turn) void CNetLocalTurnManager::NotifyFinishedOwnCommands(u32 turn)
{ {
FinishedAllCommands(turn); FinishedAllCommands(turn, DEFAULT_TURN_LENGTH);
} }
void CNetLocalTurnManager::NotifyFinishedUpdate(u32 UNUSED(turn)) void CNetLocalTurnManager::NotifyFinishedUpdate(u32 UNUSED(turn))
@ -271,7 +275,7 @@ void CNetLocalTurnManager::OnSimulationMessage(CSimulationMessage* UNUSED(msg))
CNetServerTurnManager::CNetServerTurnManager(CNetServer& server) : CNetServerTurnManager::CNetServerTurnManager(CNetServer& server) :
m_NetServer(server), m_ReadyTurn(1) m_NetServer(server), m_ReadyTurn(1), m_TurnLength(DEFAULT_TURN_LENGTH)
{ {
} }
@ -300,7 +304,7 @@ void CNetServerTurnManager::NotifyFinishedClientCommands(int client, u32 turn)
// Tell all clients that the next turn is ready // Tell all clients that the next turn is ready
CEndCommandBatchMessage msg; CEndCommandBatchMessage msg;
msg.m_TurnLength = TURN_LENGTH; msg.m_TurnLength = m_TurnLength;
msg.m_Turn = turn; msg.m_Turn = turn;
m_NetServer.Broadcast(&msg); m_NetServer.Broadcast(&msg);
@ -364,3 +368,8 @@ void CNetServerTurnManager::InitialiseClient(int client)
// TODO: do we need some kind of UninitialiseClient in case they leave? // TODO: do we need some kind of UninitialiseClient in case they leave?
} }
void CNetServerTurnManager::SetTurnLength(u32 msecs)
{
m_TurnLength = msecs;
}

View File

@ -97,7 +97,7 @@ public:
* Called when all commands for a given turn have been received. * Called when all commands for a given turn have been received.
* This allows Update to progress to that turn. * This allows Update to progress to that turn.
*/ */
void FinishedAllCommands(u32 turn); void FinishedAllCommands(u32 turn, u32 turnLength);
protected: protected:
/** /**
@ -123,6 +123,9 @@ protected:
/// The latest turn for which we have received all commands from all clients /// The latest turn for which we have received all commands from all clients
u32 m_ReadyTurn; u32 m_ReadyTurn;
// Current turn length
u32 m_TurnLength;
/// Commands queued at each turn (index 0 is for m_CurrentTurn+1) /// Commands queued at each turn (index 0 is for m_CurrentTurn+1)
std::deque<std::map<u32, std::vector<SimulationCommand> > > m_QueuedCommands; std::deque<std::map<u32, std::vector<SimulationCommand> > > m_QueuedCommands;
@ -199,6 +202,8 @@ public:
void InitialiseClient(int client); void InitialiseClient(int client);
void SetTurnLength(u32 msecs);
protected: protected:
/// The latest turn for which we have received all commands from all clients /// The latest turn for which we have received all commands from all clients
u32 m_ReadyTurn; u32 m_ReadyTurn;
@ -213,6 +218,9 @@ protected:
// Map of turn -> {Client ID -> state hash}; old indexes <= min(m_ClientsSimulated) are deleted // Map of turn -> {Client ID -> state hash}; old indexes <= min(m_ClientsSimulated) are deleted
std::map<u32, std::map<int, std::string> > m_ClientStateHashes; std::map<u32, std::map<int, std::string> > m_ClientStateHashes;
// Current turn length
u32 m_TurnLength;
CNetServer& m_NetServer; CNetServer& m_NetServer;
}; };

View File

@ -121,6 +121,18 @@ JSBool SetSimRate(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval
return JS_TRUE; return JS_TRUE;
} }
JSBool SetTurnLength(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval)
{
JSU_REQUIRE_PARAMS(1);
if (g_NetServer)
g_NetServer->SetTurnLength(ToPrimitive<unsigned int>(argv[0]));
else
LOGERROR(L"Only network host can change turn length");
return JS_TRUE;
}
// Script profiling functions: Begin timing a piece of code with StartJsTimer(num) // Script profiling functions: Begin timing a piece of code with StartJsTimer(num)
// and stop timing with StopJsTimer(num). The results will be printed to stdout // and stop timing with StopJsTimer(num). The results will be printed to stdout
// when the game exits. // when the game exits.
@ -616,6 +628,7 @@ JSFunctionSpec ScriptFunctionTable[] =
// Timer // Timer
JS_FUNC("setSimRate", SetSimRate, 1) JS_FUNC("setSimRate", SetSimRate, 1)
JS_FUNC("setTurnLength", SetTurnLength, 1)
// Profiling // Profiling
JS_FUNC("startXTimer", StartJsTimer, 1) JS_FUNC("startXTimer", StartJsTimer, 1)