LCOV - code coverage report
Current view: top level - source/simulation2/system - TurnManager.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 0 3 0.0 %
Date: 2023-01-19 00:18:29 Functions: 0 4 0.0 %

          Line data    Source code
       1             : /* Copyright (C) 2021 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #ifndef INCLUDED_TURNMANAGER
      19             : #define INCLUDED_TURNMANAGER
      20             : 
      21             : #include "ps/CStr.h"
      22             : #include "simulation2/helpers/SimulationCommand.h"
      23             : 
      24             : #include <list>
      25             : #include <map>
      26             : #include <vector>
      27             : #include <deque>
      28             : 
      29             : class CSimulationMessage;
      30             : class CSimulation2;
      31             : class IReplayLogger;
      32             : 
      33             : /**
      34             :  * This file defines the base class of the turn managers for clients, local games and replays.
      35             :  * The basic idea of our turn managing system across a network is as in this article:
      36             :  * http://www.gamasutra.com/view/feature/3094/1500_archers_on_a_288_network_.php?print=1
      37             :  *
      38             :  * Each player performs the simulation for turn N.
      39             :  * User input is translated into commands scheduled for execution in turn N+2 which are
      40             :  * distributed to all other clients.
      41             :  * After a while, a client wants to perform the simulation for turn N+1,
      42             :  * which first requires that it has all the other clients' commands for turn N+1.
      43             :  * In that case, it does the simulation and tells all the other clients (via the server)
      44             :  * it has finished sending commands for turn N+2, and it starts sending commands for turn N+3.
      45             :  *
      46             :  * Commands are redistributed immediately by the server.
      47             :  * To ensure a consistent execution of commands, they are each associated with a
      48             :  * client session ID (which is globally unique and consistent), which is used to sort them.
      49             :  */
      50             : 
      51             : /**
      52             :  * Default turn length in SP & MP.
      53             :  * This value should be as low as possible, while not introducing un-necessary lag.
      54             :  */
      55             : inline constexpr u32 DEFAULT_TURN_LENGTH = 200;
      56             : 
      57             : /**
      58             :  * In single-player, commands are directly scheduled for the next turn.
      59             :  */
      60             : inline constexpr u32 COMMAND_DELAY_SP = 1;
      61             : 
      62             : /**
      63             :  * In multi-player, clients can only compute turn N if all clients have finished sending commands for it,
      64             :  * i.e. N < CurrentTurn + COMMAND_DELAY for all clients.
      65             :  * Commands are sent from client to server to client, and both client and network can lag.
      66             :  * If a client reaches turn CURRENT_TURN + COMMAND_DELAY - 1, it'll freeze while waiting for commands.
      67             :  * To avoid that, we increase the command-delay to make sure that in general players will have received all commands
      68             :  * by the time they reach a given turn. Keep in mind the minimum delay is one turn.
      69             :  * This value should be as low as possible while avoiding 'freezing' in general usage.
      70             :  * TODO:
      71             :  *  - this command-delay could vary based on server-client pings
      72             :  *  - it ought be possible to send commands in a P2P fashion (with server verification), which would lower the ping.
      73             :  */
      74             : inline constexpr u32 COMMAND_DELAY_MP = 4;
      75             : 
      76             : /**
      77             :  * Common turn system (used by clients and offline games).
      78             :  */
      79             : class CTurnManager
      80             : {
      81             :     NONCOPYABLE(CTurnManager);
      82             : public:
      83             :     /**
      84             :      * Construct for a given network session ID.
      85             :      */
      86             :     CTurnManager(CSimulation2& simulation, u32 defaultTurnLength, u32 commandDelay, int clientId, IReplayLogger& replay);
      87             : 
      88           0 :     virtual ~CTurnManager() { }
      89             : 
      90             :     void ResetState(u32 newCurrentTurn, u32 newReadyTurn);
      91             : 
      92             :     /**
      93             :      * Set the current user's player ID, which will be added into command messages.
      94             :      */
      95             :     void SetPlayerID(int playerId);
      96             : 
      97             :     /**
      98             :      * Advance the simulation by a certain time. If this brings us past the current
      99             :      * turn length, the next turns are processed and the function returns true.
     100             :      * Otherwise, nothing happens and it returns false.
     101             :      *
     102             :      * @param simFrameLength Length of the previous frame, in simulation seconds
     103             :      * @param maxTurns Maximum number of turns to simulate at once
     104             :      */
     105             :     bool Update(float simFrameLength, size_t maxTurns);
     106             : 
     107             :     /**
     108             :      * Advance the simulation by as much as possible. Intended for catching up
     109             :      * over a small number of turns when rejoining a multiplayer match.
     110             :      * Returns true if it advanced by at least one turn.
     111             :      */
     112             :     bool UpdateFastForward();
     113             : 
     114             :     /**
     115             :      * Advance the graphics by a certain time.
     116             :      * @param simFrameLength Length of the previous frame, in simulation seconds
     117             :      * @param realFrameLength Length of the previous frame, in real time seconds
     118             :      */
     119             :     void Interpolate(float simFrameLength, float realFrameLength);
     120             : 
     121             :     /**
     122             :      * Called by networking code when a simulation message is received.
     123             :      */
     124             :     virtual void OnSimulationMessage(CSimulationMessage* msg) = 0;
     125             : 
     126             :     /**
     127             :      * Called by simulation code, to add a new command to be distributed to all clients and executed soon.
     128             :      */
     129             :     virtual void PostCommand(JS::HandleValue data) = 0;
     130             : 
     131             :     /**
     132             :      * Called when all commands for a given turn have been received.
     133             :      * This allows Update to progress to that turn.
     134             :      */
     135             :     void FinishedAllCommands(u32 turn, u32 turnLength);
     136             : 
     137             :     /**
     138             :      * Enables the recording of state snapshots every @p numTurns,
     139             :      * which can be jumped back to via RewindTimeWarp().
     140             :      * If @p numTurns is 0 then recording is disabled.
     141             :      */
     142             :     void EnableTimeWarpRecording(size_t numTurns);
     143             : 
     144             :     /**
     145             :      * Jumps back to the latest recorded state snapshot (if any).
     146             :      */
     147             :     void RewindTimeWarp();
     148             : 
     149             :     void QuickSave(JS::HandleValue GUIMetadata);
     150             :     void QuickLoad();
     151             : 
     152           0 :     u32 GetCurrentTurn() const { return m_CurrentTurn; }
     153             : 
     154             :     /**
     155             :      * @return how many turns are ready to be computed.
     156             :      * (used to detect players/observers that fall behind the live game.
     157             :      */
     158           0 :     u32 GetPendingTurns() const { return m_ReadyTurn - m_CurrentTurn; }
     159             : 
     160             : protected:
     161             :     /**
     162             :      * Store a command to be executed at a given turn.
     163             :      */
     164             :     void AddCommand(int client, int player, JS::HandleValue data, u32 turn);
     165             : 
     166             :     /**
     167             :      * Called when this client has finished sending all its commands scheduled for the given turn.
     168             :      */
     169             :     virtual void NotifyFinishedOwnCommands(u32 turn) = 0;
     170             : 
     171             :     /**
     172             :      * Called when this client has finished a simulation update.
     173             :      */
     174             :     virtual void NotifyFinishedUpdate(u32 turn) = 0;
     175             : 
     176             :     /**
     177             :      * Returns whether we should compute a complete state hash for the given turn,
     178             :      * instead of a quick less-complete hash.
     179             :      */
     180             :     bool TurnNeedsFullHash(u32 turn) const;
     181             : 
     182             :     CSimulation2& m_Simulation2;
     183             : 
     184             :     /// The turn that we have most recently executed
     185             :     u32 m_CurrentTurn;
     186             : 
     187             :     // Current command delay (commands are scheduled for m_CurrentTurn + m_CommandDelay)
     188             :     u32 m_CommandDelay;
     189             : 
     190             :     /// The latest turn for which we have received all commands from all clients
     191             :     u32 m_ReadyTurn;
     192             : 
     193             :     // Current turn length
     194             :     u32 m_TurnLength;
     195             : 
     196             :     /// Commands queued at each turn (index 0 is for m_CurrentTurn+1)
     197             :     std::deque<std::map<u32, std::vector<SimulationCommand>>> m_QueuedCommands;
     198             : 
     199             :     int m_PlayerId;
     200             :     uint m_ClientId;
     201             : 
     202             :     /// Simulation time remaining until we ought to execute the next turn (as a negative value to
     203             :     /// add elapsed time increments to until we reach 0).
     204             :     float m_DeltaSimTime;
     205             : 
     206             :     IReplayLogger& m_Replay;
     207             : 
     208             :     // The number of the last turn that is allowed to be executed (used for replays)
     209             :     u32 m_FinalTurn;
     210             : 
     211             : private:
     212             :     static const CStr EventNameSavegameLoaded;
     213             : 
     214             :     size_t m_TimeWarpNumTurns; // 0 if disabled
     215             :     std::list<std::string> m_TimeWarpStates;
     216             :     std::string m_QuickSaveState; // TODO: should implement a proper disk-based quicksave system
     217             :     JS::PersistentRootedValue m_QuickSaveMetadata;
     218             : };
     219             : 
     220             : #endif // INCLUDED_TURNMANAGER

Generated by: LCOV version 1.13