Ticket #2400: playerTimeout_v1.patch

File playerTimeout_v1.patch, 6.6 KB (added by Michael, 10 years ago)

Automatic timeout of players which have left a multi-player game. For testing the timeout is just 15 seconds long!

  • binaries/data/mods/public/gui/session/messages.js

     
    207207        {
    208208            if (! message.hosts[host])
    209209            {
     210                // cache values
     211                var removedPlayerID = g_PlayerAssignments[host].player;
     212                var removedPlayerName = g_PlayerAssignments[host].name;
     213                var removedPlayerState = g_Players[removedPlayerID].state;
    210214                // Tell the user about the disconnection
    211215                addChatMessage({ "type": "disconnect", "guid": host });
    212216
    213217                // Update the cached player data, so we can display the disconnection status
    214218                updatePlayerDataRemove(g_Players, host);
     219
     220                if (!g_IsController || removedPlayerState != "active")
     221                    return;
     222                // start timer and show timeout message
     223                Engine.PostNetworkCommand({
     224                    "type": "start-player-timeout",
     225                    "playerID": removedPlayerID,
     226                    "playerName": removedPlayerName,
     227                    "rejoinTimeLimit": REJOIN_TIME_LIMIT
     228                });
    215229            }
    216230        }
    217231
     
    225239
    226240                // Tell the user about the connection
    227241                addChatMessage({ "type": "connect", "guid": host }, message.hosts);
     242           
     243                if (!g_IsController || g_Players[message.hosts[host].player].state != "active") // TODO: check, if g_Players is getting updated.
     244                    return;
     245                // stop timer and show timeout message
     246                Engine.PostNetworkCommand({
     247                    "type": "stop-player-timeout",
     248                    "playerID": message.hosts[host].player,
     249                });
    228250            }
    229251        }
    230252
  • binaries/data/mods/public/gui/session/session.js

     
     1const REJOIN_TIME_LIMIT = 15; // rejoin time limit in seconds
     2
    13// Network Mode
    24var g_IsNetworked = false;
    35
  • binaries/data/mods/public/simulation/components/EndGameManager.js

     
    1919    // Allied victory means allied players can win if victory conditions are met for each of them
    2020    // Would be false for a "last man standing" game (when diplomacy is fully implemented)
    2121    this.alliedVictory = true;
     22   
     23    // is used to store IDs of timer for auto timeout in multiplayer game
     24    // uses as indices the playerID of the player, which times out.
     25    this.autoPlayerTimeout = [];
    2226};
    2327
    2428EndGameManager.prototype.SetGameType = function(newGameType)
     
    3236    return this.gameType == type;
    3337};
    3438
     39/**
     40 * starts the timeout counter, if a player leaves a multiplayer game
     41 * playerID: ID of the player which left
     42 * playerName: name of the player which left
     43 * timeout: time in ms until the is timed out
     44 */
     45EndGameManager.prototype.startPlayerTimeout = function(playerID, playerName, timeout)
     46{
     47    // check, if the player is active
     48    var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
     49    var playerEntityId = cmpPlayerManager.GetPlayerByID(playerID);
     50    var cmpPlayer =  Engine.QueryInterface(playerEntityId, IID_Player);
     51
     52    if (!cmpPlayer || cmpPlayer.GetState() != "active")
     53        return;
     54    // query some stuff
     55    var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     56    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     57    if (!cmpGuiInterface || !cmpTimer || !cmpPlayerManager)
     58        return;
     59       
     60    // get players to send the message
     61    var players = [];
     62    for (var i = 1; i < cmpPlayerManager.GetNumPlayers(); i++)
     63            players.push(i);   
     64
     65    // add timers
     66    var textTimerID = cmpGuiInterface.AddTimeNotification({
     67        "message": playerName + " will be auto-resigned in %T",
     68        "players": players,
     69        "time": timeout
     70    });     
     71    var timerID = cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_EndGameManager, "MarkPlayerAsAutoResigned", timeout, playerID);
     72    // save timer IDs
     73    this.autoPlayerTimeout[playerID] = [textTimerID, timerID];
     74};
     75
     76/**
     77 * stops the timeout of a player, if he rejoins
     78 * playerID: ID of the player which rejoined
     79 */
     80EndGameManager.prototype.stopPlayerTimeout = function(playerID)
     81{
     82    if (!this.autoPlayerTimeout[playerID]) // no timeout for player running
     83        return;
     84    var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     85    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     86    if (!cmpGuiInterface || !cmpTimer)
     87        return;
     88   
     89    // delete the timers
     90    var timerIDs = this.autoPlayerTimeout[playerID];
     91    cmpGuiInterface.DeleteTimeNotification(timerIDs[0]);
     92    cmpTimer.CancelTimer(timerIDs[1]);
     93    delete this.autoPlayerTimeout[playerID];
     94};
     95
     96
     97/**
     98 * marks an player as auto resigned after an timeout. (is called by startPlayerTimeout normally)
     99 * playerID: player ID of the player to mark as auto resigned
     100 */
     101EndGameManager.prototype.MarkPlayerAsAutoResigned = function(playerID)
     102{
     103    var cmpPlayerMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
     104    if (!cmpPlayerMan)
     105        return;
     106
     107    var playerEnt = cmpPlayerMan.GetPlayerByID(playerID);
     108    if (playerEnt == INVALID_ENTITY)
     109        return;
     110
     111    // send OnPlayerDefeated message
     112    Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": playerID } );
     113};
     114
    35115EndGameManager.prototype.MarkPlayerAsWon = function(playerID)
    36116{
    37117    var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
  • binaries/data/mods/public/simulation/helpers/Commands.js

     
    321321        Engine.PostMessage(playerEnt, MT_PlayerDefeated, { "playerId": player } );
    322322        break;
    323323
     324    case "start-player-timeout":
     325        var cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager);
     326        if (!cmpEndGameManager)
     327            return;
     328        cmpEndGameManager.startPlayerTimeout(cmd.playerID, cmd.playerName, cmd.rejoinTimeLimit * 1000);
     329        break;
     330       
     331    case "stop-player-timeout":
     332        var cmpEndGameManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_EndGameManager);
     333        if (!cmpEndGameManager)
     334            return;
     335        cmpEndGameManager.stopPlayerTimeout(cmd.playerID);
     336        break;
     337       
    324338    case "garrison":
    325339        // Verify that the building can be controlled by the player or is mutualAlly
    326340        if (CanControlUnitOrIsAlly(cmd.target, player, controlAllUnits))