From 0ebe3486b6a526242caaccb269d55920b46b62ab Mon Sep 17 00:00:00 2001 From: Ykkrosh Date: Fri, 13 Aug 2010 16:42:53 +0000 Subject: [PATCH] Add setTurnLength() function for hacky fixing of network lag. This was SVN commit r7936. --- source/network/NetClient.cpp | 2 +- source/network/NetServer.cpp | 6 ++++++ source/network/NetServer.h | 6 ++++++ source/network/NetTurnManager.cpp | 33 ++++++++++++++++++++----------- source/network/NetTurnManager.h | 10 +++++++++- source/scripting/ScriptGlue.cpp | 13 ++++++++++++ 6 files changed, 56 insertions(+), 14 deletions(-) diff --git a/source/network/NetClient.cpp b/source/network/NetClient.cpp index d88d991a92..eec42d2612 100644 --- a/source/network/NetClient.cpp +++ b/source/network/NetClient.cpp @@ -405,7 +405,7 @@ bool CNetClient::OnInGame(void *context, CFsmEvent* event) else if (message->GetType() == NMT_END_COMMAND_BATCH) { CEndCommandBatchMessage* endMessage = static_cast (message); - client->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn); + client->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn, endMessage->m_TurnLength); } } diff --git a/source/network/NetServer.cpp b/source/network/NetServer.cpp index fd0c81f9f4..c288195f6e 100644 --- a/source/network/NetServer.cpp +++ b/source/network/NetServer.cpp @@ -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); diff --git a/source/network/NetServer.h b/source/network/NetServer.h index 0ef73aee09..1a2cc81847 100644 --- a/source/network/NetServer.h +++ b/source/network/NetServer.h @@ -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() { } diff --git a/source/network/NetTurnManager.cpp b/source/network/NetTurnManager.cpp index 75be939969..5065c10409 100644 --- a/source/network/NetTurnManager.cpp +++ b/source/network/NetTurnManager.cpp @@ -35,7 +35,7 @@ #include #include -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; +} diff --git a/source/network/NetTurnManager.h b/source/network/NetTurnManager.h index 1a7b11b360..1b9e14d46b 100644 --- a/source/network/NetTurnManager.h +++ b/source/network/NetTurnManager.h @@ -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 > > 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 > m_ClientStateHashes; + // Current turn length + u32 m_TurnLength; + CNetServer& m_NetServer; }; diff --git a/source/scripting/ScriptGlue.cpp b/source/scripting/ScriptGlue.cpp index 32694b6714..85b0438198 100644 --- a/source/scripting/ScriptGlue.cpp +++ b/source/scripting/ScriptGlue.cpp @@ -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(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)