Why is it necessary?

Extreme example: The game time is 59,9 seconds and the turn master orders the 
character to jump in oder to save him from the water which will increase in 0.1 
seconds.
It's important that the non turn master does not continue the game to the 60th 
game second, if it hasn't received the jump action yet. Otherwise the non turn 
master will see the character drown and no resurrection system can bring him 
back as the water has already risen.
How to detect that there are no further actions for the current physics frame?

If there had been actions in a physics frame wormux will send now one "echo" 
action at the end of the physics frame.
The non turn masters knows when receiving it that they can render all physics 
frames until that time.
---
 lib/wormux/include/WORMUX_action.h |    2 +-
 src/game/game.cpp                  |    1 +
 src/game/time.cpp                  |   35 +++++++++++++++++++++--------------
 src/game/time.h                    |    4 ++--
 src/include/action_handler.cpp     |   30 ++++++++++++++++++++++++++++--
 src/network/network.cpp            |   21 +++++++++++++++++----
 src/network/network.h              |   11 ++++++-----
 src/network/network_local.cpp      |    2 +-
 src/network/network_local.h        |    2 +-
 9 files changed, 78 insertions(+), 30 deletions(-)

diff --git a/lib/wormux/include/WORMUX_action.h 
b/lib/wormux/include/WORMUX_action.h
index 14238c9..4f9dc21 100644
--- a/lib/wormux/include/WORMUX_action.h
+++ b/lib/wormux/include/WORMUX_action.h
@@ -106,7 +106,7 @@ public:
     ACTION_NETWORK_RANDOM_INIT,
     ACTION_INFO_CLIENT_CONNECT,
     ACTION_INFO_CLIENT_DISCONNECT,
-
+    ACTION_ECHO,
     // ########################################################
   } Action_t;
 
diff --git a/src/game/game.cpp b/src/game/game.cpp
index d24bd99..70df1d8 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -552,6 +552,7 @@ void Game::MainLoop()
     }
   }
 #endif
+  Network::GetInstance()->SendEcho();
 
   delay = time_of_next_phy_frame - Time::GetInstance()->ReadRealTime();
   if (delay >= 0)
diff --git a/src/game/time.cpp b/src/game/time.cpp
index c345817..05ec829 100644
--- a/src/game/time.cpp
+++ b/src/game/time.cpp
@@ -19,7 +19,11 @@
  *  Handle the game time. The game can be paused.
  *****************************************************************************/
 
+#include "game/game.h"
 #include "game/time.h"
+#include "network/network.h"
+#include "team/team.h"
+#include "team/teams_list.h"
 #include <SDL.h>
 #include <sstream>
 #include <iomanip>
@@ -34,7 +38,7 @@ Time::Time()
   is_game_paused = false;
   delta_t = 20;
   current_time = 0;
-  //max_time = 0;
+  max_time_plus_one = 0;
   real_time_game_start = 0;
   real_time_pause_dt = 0;
 }
@@ -42,6 +46,7 @@ Time::Time()
 void Time::Reset()
 {
   current_time = 0;
+  max_time_plus_one = 0;
   is_game_paused = false;
   real_time_game_start = SDL_GetTicks();
   real_time_pause_dt = 0;
@@ -55,19 +60,21 @@ uint Time::ReadRealTime() const
 
 void Time::Refresh()
 {
-  /*
-  TODO : Activate this condition later.
-  Refresh time condition :
-  - active team is Local
-  - current node is server and game loop is not in Playing state
-  - game don't use network
-  if((ActiveTeam().IsLocal() || ActiveTeam().IsLocalAI()) ||
-     (Network::GetInstance()->IsServer() && Game::GetInstance()->ReadState() 
!= Game::PLAYING) ||
-     (!Network::GetInstance()->IsServer() && 
!Network::GetInstance()->IsClient()) ||
-     current_time < max_time)
-  */
-  current_time += delta_t;
-  //RefreshMaxTime(current_time);
+  uint newValue = current_time + delta_t;
+  bool activeTeamLocal = ActiveTeam().IsLocal() || ActiveTeam().IsLocalAI();
+  bool serverButNotPlaying = Network::GetInstance()->IsServer() && 
Game::GetInstance()->ReadState() != Game::PLAYING;
+  bool noNetworkGame = !Network::GetInstance()->IsServer() && 
!Network::GetInstance()->IsClient();
+  bool ignoreMaxTime = activeTeamLocal || serverButNotPlaying || noNetworkGame;
+  if (ignoreMaxTime || (newValue < max_time_plus_one))
+    current_time = newValue;
+  else
+    real_time_pause_dt += delta_t;
+}
+
+void Time::RefreshMaxTimePlusOne(uint updated_max_time_plus_one)
+{
+  if (updated_max_time_plus_one >= max_time_plus_one)
+    max_time_plus_one = updated_max_time_plus_one;
 }
 
 void Time::TogglePause()
diff --git a/src/game/time.h b/src/game/time.h
index 193c8e9..edb9109 100644
--- a/src/game/time.h
+++ b/src/game/time.h
@@ -31,7 +31,7 @@ class Time : public Singleton<Time>
 {
 private:
   uint        current_time;
-  //uint        max_time;
+  uint        max_time_plus_one;
   uint        delta_t;
   bool        is_game_paused;
 
@@ -59,7 +59,7 @@ public:
   uint ReadMin() const { return ReadSec() / 60; };
   void Refresh();
   uint GetDelta() const { return delta_t; };
-  //void RefreshMaxTime(uint updated_max_time);
+  void RefreshMaxTimePlusOne(uint updated_max_time_plus_one);
 
   // Read the clock time
   uint ClockSec() const { return ReadSec() % 60; };
diff --git a/src/include/action_handler.cpp b/src/include/action_handler.cpp
index df17a05..f22348d 100644
--- a/src/include/action_handler.cpp
+++ b/src/include/action_handler.cpp
@@ -825,6 +825,11 @@ static void Action_Network_Ping(Action */*a*/)
 {
 }
 
+// Nothing to do here. The action handler will use the timestamp to set the 
maximal time.
+static void Action_Echo(Action */*a*/)
+{
+}
+
 // ########################################################
 
 static void _Info_ConnectHost(const std::string& hostname, const std::string& 
nicknames)
@@ -1084,7 +1089,7 @@ void Action_Handler_Init()
   ActionHandler::GetInstance()->Register (Action::ACTION_NETWORK_RANDOM_INIT, 
"NETWORK_random_init", &Action_Network_RandomInit);
   ActionHandler::GetInstance()->Register 
(Action::ACTION_INFO_CLIENT_DISCONNECT, "INFO_client_disconnect", 
&Action_Info_ClientDisconnect);
   ActionHandler::GetInstance()->Register (Action::ACTION_INFO_CLIENT_CONNECT, 
"INFO_client_connect", &Action_Info_ClientConnect);
-
+  ActionHandler::GetInstance()->Register (Action::ACTION_ECHO, "ACTION_echo", 
&Action_Echo);
   // ########################################################
   ActionHandler::GetInstance()->UnLock();
 }
@@ -1106,11 +1111,32 @@ void ActionHandler::ExecActions()
 {
   Action * a;
   std::list<Action*>::iterator it;
+  Time * time = Time::GetInstance();
+
+  // The game can continue until the point at which all actions are known.
+  // If for example a non turn master receives:
+  // 5s game time: jump
+  // 6s game time: jump
+  // then the game can continue until the game time is (6s - smallest time 
unit).
+  // The physics frame for the 6th game second must not be calculated
+  // as more actions for the 6th game second might be received in future.
+  for (it = queue.begin(); it != queue.end() ;it++)
+  {
+    Lock();
+    a = (*it);
+    // The action echo gets send at the end of a physics frame:
+    // No more physic related actions are expected for the current frame.
+    if (a->GetType() == Action::ACTION_ECHO)
+      time->RefreshMaxTimePlusOne(a->GetTimestamp() + 1);
+    else
+      time->RefreshMaxTimePlusOne(a->GetTimestamp());
+    UnLock();
+  }
+
   for (it = queue.begin(); it != queue.end() ;)
   {
     Lock();
     a = (*it);
-    //Time::GetInstance()->RefreshMaxTime((*it)->GetTimestamp());
     // If action is in the future, wait for next refresh
     if (a->GetTimestamp() > Time::GetInstance()->Read()) {
       UnLock();
diff --git a/src/network/network.cpp b/src/network/network.cpp
index da56cab..5652b5c 100644
--- a/src/network/network.cpp
+++ b/src/network/network.cpp
@@ -340,7 +340,7 @@ void Network::DisconnectNetwork()
 //-----------------------------------------------------------------------------
 
 // Send Messages
-void Network::SendActionToAll(const Action& a) const
+void Network::SendActionToAll(const Action& a)
 {
   MSG_DEBUG("network.traffic","Send action %s to all remote computers",
             ActionHandler::GetInstance()->GetActionName(a.GetType()).c_str());
@@ -348,7 +348,7 @@ void Network::SendActionToAll(const Action& a) const
   SendAction(a, NULL, false);
 }
 
-void Network::SendActionToOne(const Action& a, DistantComputer* client) const
+void Network::SendActionToOne(const Action& a, DistantComputer* client)
 {
   MSG_DEBUG("network.traffic","Send action %s to %s (%s)",
             ActionHandler::GetInstance()->GetActionName(a.GetType()).c_str(),
@@ -357,7 +357,7 @@ void Network::SendActionToOne(const Action& a, 
DistantComputer* client) const
   SendAction(a, client, true);
 }
 
-void Network::SendActionToAllExceptOne(const Action& a, DistantComputer* 
client) const
+void Network::SendActionToAllExceptOne(const Action& a, DistantComputer* 
client)
 {
   MSG_DEBUG("network.traffic","Send action %s to all EXCEPT %s",
             ActionHandler::GetInstance()->GetActionName(a.GetType()).c_str(),
@@ -369,11 +369,13 @@ void Network::SendActionToAllExceptOne(const Action& a, 
DistantComputer* client)
 // if (client == NULL) sending to every clients
 // if (clt_as_rcver) sending only to client 'client'
 // if (!clt_as_rcver) sending to all EXCEPT client 'client'
-void Network::SendAction(const Action& a, DistantComputer* client, bool 
clt_as_rcver) const
+void Network::SendAction(const Action& a, DistantComputer* client, bool 
clt_as_rcver)
 {
   char* packet;
   int size;
 
+  echo_outstanding = true;
+
   a.WriteToPacket(packet, size);
   ASSERT(packet != NULL);
 
@@ -405,6 +407,17 @@ void Network::SendAction(const Action& a, DistantComputer* 
client, bool clt_as_r
   free(packet);
 }
 
+void Network::SendEcho() {
+  if (echo_outstanding)
+  {
+    Action a(Action::ACTION_ECHO);
+    SendActionToAll(a);
+
+    // this must be set after SendActionToAll as SendActionToAll would set it 
to true otherwise.
+    echo_outstanding = false;
+  }
+}
+
 //-----------------------------------------------------------------------------
 
 // Static method
diff --git a/src/network/network.h b/src/network/network.h
index 1a1964b..a9bd1c2 100644
--- a/src/network/network.h
+++ b/src/network/network.h
@@ -85,7 +85,7 @@ private:
 
   Player player;
   bool turn_master_player;
-
+  bool echo_outstanding;
 protected:
   bool game_master_player;
   WNet::net_game_state_t state;
@@ -99,7 +99,7 @@ protected:
   int fin;
 #endif
 
-  virtual void SendAction(const Action& a, DistantComputer* client, bool 
clt_as_rcver) const;
+  virtual void SendAction(const Action& a, DistantComputer* client, bool 
clt_as_rcver);
 
   void DisconnectNetwork();
 
@@ -150,9 +150,10 @@ public:
   virtual void CloseConnection(std::list<DistantComputer*>::iterator closed) = 
0;
 
   // Action handling
-  void SendActionToAll(const Action& action) const;
-  void SendActionToOne(const Action& action, DistantComputer* client) const;
-  void SendActionToAllExceptOne(const Action& action, DistantComputer* client) 
const;
+  void SendActionToAll(const Action& action);
+  void SendActionToOne(const Action& action, DistantComputer* client);
+  void SendActionToAllExceptOne(const Action& action, DistantComputer* client);
+  void SendEcho();
 
   // Manage network state
   void SetState(WNet::net_game_state_t state);
diff --git a/src/network/network_local.cpp b/src/network/network_local.cpp
index 48c70e6..3e6cc14 100644
--- a/src/network/network_local.cpp
+++ b/src/network/network_local.cpp
@@ -25,7 +25,7 @@ NetworkLocal::NetworkLocal() : Network("-", "") {}
 
 NetworkLocal::~NetworkLocal() {}
 
-void NetworkLocal::SendAction(const Action& /*a*/, DistantComputer* 
/*client*/, bool /*clt_as_rcver*/) const {}
+void NetworkLocal::SendAction(const Action& /*a*/, DistantComputer* 
/*client*/, bool /*clt_as_rcver*/) {}
 
 void NetworkLocal::CloseConnection(std::list<DistantComputer*>::iterator 
/*closed*/)
 {
diff --git a/src/network/network_local.h b/src/network/network_local.h
index 6d29dbc..727a577 100644
--- a/src/network/network_local.h
+++ b/src/network/network_local.h
@@ -30,7 +30,7 @@ class NetworkLocal : public Network
 protected:
   virtual void HandleAction(Action* /*a*/, DistantComputer* /*sender*/) { 
ASSERT(false) };
   virtual void WaitActionSleep() { ASSERT(false) };
-  virtual void SendAction(const Action& a, DistantComputer* client, bool 
clt_as_rcver) const;
+  virtual void SendAction(const Action& a, DistantComputer* client, bool 
clt_as_rcver);
 
 public:
   NetworkLocal();
-- 
1.6.0.4


_______________________________________________
Wormux-dev mailing list
Wormux-dev@gna.org
https://mail.gna.org/listinfo/wormux-dev

Répondre à