Scripts:IdleKick

From BF2 Technical Information Wiki
Jump to navigation Jump to search
 # ------------------------------------------------------------------------
 # Module: IdleKick.py
 # Authors: xlr8or, www.xlr8or.com
 # Version 2.02
 # Description:
 #   This script kicks players who are idle, based on the configuration settings below.
 # Requirements:
 #   None.
 # Installation:
 #   Save this script as 'IdleKick.py' in your <bf2>/admin/standard_admin directory,
 #   and add the lines 'import IdleKick' and 'IdleKick.init()' to the file
 #   '<bf2>/admin/standard_admin/__init__.py'.
 # Credit:
 #   This script is based on the pingkick script from the guys at bf2.no
 #   Format is mainly the same as what they did, and where I could use their
 #   code I have shamelessly done so.
 #   Credit therefor goes to Kybber and Panic, Battlefield.no
 # History:
 #   Autobalancing is a nice feature, but not when a large part of your team
 #   is doing something else, while staying ingame to not lose their slot.
 #   BF2 does not have a spectator ability, so if you're not participating,
 #   you're letting your team down!
 # Version 1.00 to 2.00:
 #   Cleaned some code up, added the ability to exclude clanmembers.
 # Version 2.00 to 2.01:
 #   Cleaned and corrected some global def's.
 # Version 2.01 to 2.02:
 #   Fixed the clantag protection.
 # ------------------------------------------------------------------------
 
 
 # ------------------------------------------------------------------------
 #                     C O N F I G U R A T I O N
 # ------------------------------------------------------------------------
 # Settings for auto-kicking:
 autokick    = 1      # Enables/disables autokicking
 warnings    = 10     # The number of checks/warns a player has to fail/get before being kicked
 interval    = 30     # The interval between idle checks
 minplayers  = 5      # The minimum ammount of players online before checking idle players.
 announceme  = 0      # Announce the module at roundstart?
 warnme      = 1      # Warn the idle player 3 intervals before the maximum nr of warnings is reached?
 
 clantags = ["[XLR]","[xlr]","xlr8or"] # Clantags to protect from being kicked
 
 # ------------------------------------------------------------------------
 #                        I M P O R T
 # ------------------------------------------------------------------------
 
 import host
 import bf2
 from bf2 import g_debug
 
 # ------------------------------------------------------------------------
 #                       V A R I A B L E S
 # ------------------------------------------------------------------------
 
 # Let's set up our debug flag:
 xlr_debug = False
 
 # The timers:
 IkCheckTimer    = None  # Timer firing off the idle checker. Depends on the 'interval' variable.
 KickTimer       = None  # Timer that delays kicking after the final warning has been issued.
 AnnounceTimer   = None  # Timer that delays the "activated" message after entering bf2.GameStatus.Playing
 
 # List of people to kick for high idle. Will contain touples of p.index and p.getProfileId():
 kicklist = []
 
 # For keeping track of the game status:
 gamestatus = None
 
 
 # ------------------------------------------------------------------------
 #                       F U N C T I O N S
 # ------------------------------------------------------------------------
 
 # ------------------------------------------------------------------------
 # The init function is run by the standard_admin/__init__ functions:
 # ------------------------------------------------------------------------
 def init():
 
    if g_debug or xlr_debug: print 'IDLEKICK: initializing IdleKick script'
    # Force at least 20 seconds between idle checks:
    if interval < 10: interval = 10
    # Print debug message if autokick is disabled:
    if autokick != 1:
       if g_debug or xlr_debug: print 'IDLEKICK: Idle autokick not enabled'
   
    # Autokick is enabled, so hook it up:
    else:
       if g_debug or xlr_debug: print 'IDLEKICK: Enabling kick for being idle. Max. checkfails = %s.' % (warnings)
 
       # Register 'PlayerConnect' callback:
       host.registerHandler('PlayerConnect', onPlayerConnect, 1)
       host.registerHandler('PlayerSpawn', onPlayerSpawn, 1)
       host.registerGameStatusHandler(onGameStatusChanged)
 # ------------------------------------------------------------------------
 
 
 # ------------------------------------------------------------------------
 # Callback function for the "PlayerConnect" event:
 # ------------------------------------------------------------------------
 def onPlayerConnect(p):
    #Resets the idle warning counter for the player
    resetPlayer(p)
 # ------------------------------------------------------------------------
 
 
 # ------------------------------------------------------------------------
 # Callback function for the "PlayerSpawn" event:
 # ------------------------------------------------------------------------
 def onPlayerSpawn(p,s):
    # Sets the 'actuallyPlaying' flag for the player
    p.actuallyPlaying = True
    # We can reset the warnings, since the player has actually spawned.
    p.idleWarnings = 0
 # ------------------------------------------------------------------------
 
 
 # ------------------------------------------------------------------------
 # Callback function for the "PreGame" game status event:
 # ------------------------------------------------------------------------
 def onGameStatusChanged(status):
    # Enables the idle check timer
    # Import variables, and update the game status:
    global gamestatus, kicklist, AnnounceTimer
   
    gamestatus = status
    if gamestatus == bf2.GameStatus.Playing:
       if announceme ==1:
          if g_debug or xlr_debug: print "IDLEKICK: Round Started. Setting AnnounceTimer"
          AnnounceTimer = bf2.Timer(onAnnounceTimer,10,1)
       if g_debug or xlr_debug: print "IDLEKICK: Round Started. (Re-)enabling check-timer"
       # Enable the idle check timer:
       enableCheckTimer()
    elif gamestatus == bf2.GameStatus.PreGame:
       if g_debug or xlr_debug: print "IDLEKICK: Game status changed to PreGame. Killing check-timer"
       # Kill the check-timer
       disableCheckTimer()
    elif gamestatus == bf2.GameStatus.Paused:
       if g_debug or xlr_debug: print "IDLEKICK: Game status changed to Paused. Killing check-timer"
       # Kill the check-timer
       disableCheckTimer()
    elif gamestatus == bf2.GameStatus.EndGame:
       if g_debug or xlr_debug: print "IDLEKICK: Game status changed to EndGame. Reset Players, Kicklist and killing check-timer"
       # Kill the check-timer
       disableCheckTimer()
       # Reset the kicklist
       kicklist = []
       # Reset players:
       resetPlayers()
 # ------------------------------------------------------------------------
 
 
 
 # ------------------------------------------------------------------------
 # Reset the idlescript variables placed in the player object:
 # ------------------------------------------------------------------------
 def resetPlayers():
    # Reset Warnings and stuff:
    if g_debug or xlr_debug: print "IDLEKICK: Resetting Players"
    for p in bf2.playerManager.getPlayers():
       resetPlayer(p)
 # ------------------------------------------------------------------------
 
 
 # ------------------------------------------------------------------------
 # Reset the idlescript variables placed in the player object:
 # ------------------------------------------------------------------------
 def resetPlayer(p):
    # Reset Warnings and stuff:
    p.idleWarnings = 0
    p.actuallyPlaying = False
 # ------------------------------------------------------------------------
 
 
 # ------------------------------------------------------------------------
 # Callback function for timer, that delays a message at round start:
 # ------------------------------------------------------------------------
 def onAnnounceTimer(data):
    global AnnounceTimer
   
    if g_debug or xlr_debug: print "IDLEKICK: Entering onAnnounceTimer... Sending the Activated announcement"
    msg = "Activated! Kicking after " + str(warnings) + " checks."
    sendMsg(msg)
    AnnounceTimer.destroy()
    AnnounceTimer = None
 # ------------------------------------------------------------------------
 
 
 # ------------------------------------------------------------------------
 # Send text messages to the server, using rcon game.sayAll:
 # ------------------------------------------------------------------------
 def sendMsg(msg):
    # Sure you can edit this. But hey, why not give us the credit? ;-)
    host.rcon_invoke("game.sayAll \"[XLR]No-Idle: " + str(msg) + "\"")
 # ------------------------------------------------------------------------
 
 
 # ------------------------------------------------------------------------
 # Enable the KickTimer:
 # ------------------------------------------------------------------------
 def enableKickTimer():
    # Enables the timer that runs the 'kickPlayers' functions
    global KickTimer
   
    if g_debug or xlr_debug: print "IDLEKICK: Enabling the kicktimer..."
    KickTimer = bf2.Timer(kickPlayers, 5, 1)
 # ------------------------------------------------------------------------
 
 
 # ------------------------------------------------------------------------
 # Enable the IkCheckTimer:
 # ------------------------------------------------------------------------
 def enableCheckTimer():
    # Enables the timer that runs the 'checkidle' function
    global IkCheckTimer
   
    if IkCheckTimer:
       if g_debug or xlr_debug: print "IDLEKICK: IkCheckTimer (already) running: Next check @ %s" % (IkCheckTimer.getTime())
       return True
    else:
       # Create the timer:
       if g_debug or xlr_debug: print "IDLEKICK: Timer not enabled. Enabling..."
       IkCheckTimer = bf2.Timer(checkidle, interval, 1)
       IkCheckTimer.setRecurring(interval)
       # Print debug message telling the status of the timer:
       if IkCheckTimer:
          if g_debug or xlr_debug: print "IDLEKICK: First check @ %s" % (IkCheckTimer.getTime())
          return True
       else:
          if g_debug or xlr_debug: print "IDLEKICK: ERROR: IkCheckimer Not enabled in def enableCheckTimer()"
          return False
 # ------------------------------------------------------------------------
 
 
 # ------------------------------------------------------------------------
 # Disable the IkCheckTimer:
 # ------------------------------------------------------------------------
 def disableCheckTimer():
    global IkCheckTimer
   
    IkCheckTimer.destroy()
    IkCheckTimer = None
 
 # ------------------------------------------------------------------------
 
 # ------------------------------------------------------------------------
 # Loop all players, checking their idle, kick high-idleer:
 # ------------------------------------------------------------------------
 def checkidle(data):
    # Checks idle of all players, and kicks idlers
    global kicklist, gamestatus
 
    # We only want to check idle during rounds:
    if gamestatus != bf2.GameStatus.Playing: return
   
    # Make sure our timer is enabled:
    if not enableCheckTimer(): return
   
    if bf2.playerManager.getNumberOfPlayers() < minplayers:
       if g_debug or xlr_debug: print "IDLEKICK: Not enough players to check for idlers..."
       return
 
    if g_debug or xlr_debug: print "IDLEKICK: Running checkidle"
 
    # Loop all players
    for p in bf2.playerManager.getPlayers():
       # Do not check players that haven't completed their "connect" yet:
       if not p.isConnected():
         if g_debug or xlr_debug: print "IDLEKICK: Player not yet connected, continuing..."
         continue
       if p.isAlive():
         if g_debug or xlr_debug: print "IDLEKICK: Player is already playing, continuing..."
         continue
       if p.isManDown():
         if g_debug or xlr_debug: print "IDLEKICK: Player in ManDown state, continuing..."
         continue
       # Get the player name. We'll use it often:
       name = str(p.getName())
 
       # Prevent Clanmembers from being kicked
       skip = 0
       for clantag in clantags:
         if name.find(clantag)>-1:
           skip = 1
           break
       if skip == 1: continue
 
       # If we have a valid idle, check it, and issue a warning if the idle exceeds the limit:
       p.idleWarnings += 1
       if g_debug or xlr_debug: print "IDLEKICK: Player " + name + " has been detected as idle " + str(p.idleWarnings) + " time(s)"
       if warnme == 1 and p.idleWarnings == (warnings - 3):
         #tmp = p.idleWarnings * interval / 60
         sendMsg("WARNING: " + name + " has not returned to duty for quite some time now. Move in fast, you're about to be court marshalled!")
       # Issue a warning if a player has reached the maximum number of warnings. Will be kicked next time 'checkidle' is run:
       if warnings <= p.idleWarnings:
         #tmp = p.idleWarnings * intervals / 60
         sendMsg("Desertion Violation: " + name + " is being removed for not returning to duty in time! (aka idling)")
         # Add the player to the kicklist:
         kicklist.append((p.index,p.getProfileId()))
 
    # Check of we shall enable the kicktimer:
    if len(kicklist):
       enableKickTimer()
 # ------------------------------------------------------------------------
 
 
 # ------------------------------------------------------------------------
 # Function run by the kicktimer:
 # ------------------------------------------------------------------------
 def kickPlayers(data):
    # Loops through 'kicklist', and kicks players accordingly.
    #print "IDLEKICK: kickPlayers..."
    global kicklist, KickTimer
   
    for i in kicklist:
       p = bf2.playerManager.getPlayerByIndex(i[0])
       # Make sure we're not kicking a player that has gotten an already disconnected "violater's" index:
       if not p.getProfileId() == i[1]: continue
       # Check if this player indeed has reached the limit for maximum warnings
       if warnings <= p.idleWarnings:
          # Kick if limit is reached:
          if g_debug or xlr_debug: print "IDLEKICK: Kicking player " + p.getName() + " for being idle."
          result = host.rcon_invoke("admin.kickPlayer " + str(p.index))
    kicklist = []
    KickTimer.destroy()
    KickTimer = None
 # ------------------------------------------------------------------------