forked from 0ad/0ad
Add setTurnLength() function for hacky fixing of network lag.
This was SVN commit r7936.
This commit is contained in:
parent
c8f90ce5a2
commit
0ebe3486b6
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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() { }
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user