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)
{
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;
}
void CNetServer::SetTurnLength(u32 msecs)
{
if (m_ServerTurnManager)
m_ServerTurnManager->SetTurnLength(msecs);
}
bool CNetServer::OnClientHandshake(void* context, CFsmEvent* event)
{
debug_assert(event->GetType() == (uint)NMT_CLIENT_HANDSHAKE);

View File

@ -165,6 +165,12 @@ public:
*/
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:
/// Callback for autostart; called when a player has finished connecting
virtual void OnAddPlayer() { }

View File

@ -35,7 +35,7 @@
#include <fstream>
#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;
@ -51,7 +51,7 @@ static std::string Hexify(const std::string& s)
}
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)
{
// 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.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
NETTURN_LOG(L"Running %d cmds\n", commands.size());
#endif
m_Simulation2.Update(TURN_LENGTH, commands);
m_Simulation2.Update(m_TurnLength, commands);
NotifyFinishedUpdate(m_CurrentTurn);
// Set the time for the next turn update
m_DeltaTime -= TURN_LENGTH / 1000.f;
m_DeltaTime -= m_TurnLength / 1000.f;
return true;
}
@ -156,7 +156,10 @@ void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash)
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);
}
@ -178,14 +181,15 @@ void CNetTurnManager::AddCommand(int client, int player, CScriptValRooted data,
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
NETTURN_LOG(L"FinishedAllCommands(%d)\n", turn);
NETTURN_LOG(L"FinishedAllCommands(%d, %d)\n", turn, turnLength);
#endif
debug_assert(turn == m_ReadyTurn + 1);
m_ReadyTurn = turn;
m_TurnLength = turnLength;
}
void CNetClientTurnManager::PostCommand(CScriptValRooted data)
@ -211,7 +215,7 @@ void CNetClientTurnManager::NotifyFinishedOwnCommands(u32 turn)
// Send message to the server
CEndCommandBatchMessage msg;
msg.m_TurnLength = TURN_LENGTH;
msg.m_TurnLength = DEFAULT_TURN_LENGTH; // TODO: why do we send this?
msg.m_Turn = turn;
m_NetClient.SendMessage(&msg);
}
@ -255,7 +259,7 @@ void CNetLocalTurnManager::PostCommand(CScriptValRooted data)
void CNetLocalTurnManager::NotifyFinishedOwnCommands(u32 turn)
{
FinishedAllCommands(turn);
FinishedAllCommands(turn, DEFAULT_TURN_LENGTH);
}
void CNetLocalTurnManager::NotifyFinishedUpdate(u32 UNUSED(turn))
@ -271,7 +275,7 @@ void CNetLocalTurnManager::OnSimulationMessage(CSimulationMessage* UNUSED(msg))
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
CEndCommandBatchMessage msg;
msg.m_TurnLength = TURN_LENGTH;
msg.m_TurnLength = m_TurnLength;
msg.m_Turn = turn;
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?
}
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.
* This allows Update to progress to that turn.
*/
void FinishedAllCommands(u32 turn);
void FinishedAllCommands(u32 turn, u32 turnLength);
protected:
/**
@ -123,6 +123,9 @@ protected:
/// The latest turn for which we have received all commands from all clients
u32 m_ReadyTurn;
// Current turn length
u32 m_TurnLength;
/// Commands queued at each turn (index 0 is for m_CurrentTurn+1)
std::deque<std::map<u32, std::vector<SimulationCommand> > > m_QueuedCommands;
@ -199,6 +202,8 @@ public:
void InitialiseClient(int client);
void SetTurnLength(u32 msecs);
protected:
/// The latest turn for which we have received all commands from all clients
u32 m_ReadyTurn;
@ -213,6 +218,9 @@ protected:
// Map of turn -> {Client ID -> state hash}; old indexes <= min(m_ClientsSimulated) are deleted
std::map<u32, std::map<int, std::string> > m_ClientStateHashes;
// Current turn length
u32 m_TurnLength;
CNetServer& m_NetServer;
};

View File

@ -121,6 +121,18 @@ JSBool SetSimRate(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval
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)
// and stop timing with StopJsTimer(num). The results will be printed to stdout
// when the game exits.
@ -616,6 +628,7 @@ JSFunctionSpec ScriptFunctionTable[] =
// Timer
JS_FUNC("setSimRate", SetSimRate, 1)
JS_FUNC("setTurnLength", SetTurnLength, 1)
// Profiling
JS_FUNC("startXTimer", StartJsTimer, 1)