Scripts:BF2Admin

From BF2 Technical Information Wiki
Jump to navigation Jump to search

Template:Wip

This script so far, should read a file for a list of administrators listed by their profileID. This administrator can then use chat commands to kick and ban players.

Last Update: 16:01, 10 Jul 2005 (CST)

Documentation

Can be found in the BF2Admin Docs Page

Changes

  • Added sa_add_admin <player> <permissions> which will write new admins to the users.cfg,
  • Added pub_id <player> which print the profileID of a player to the requesters console,
  • Corrected the playername matching function to ignore case, e.g. "sa_kick dan bad guy" will kick a player with the name like FSR|Danni
  • Added sa_rcon <rconcmd> <args> to allow rcon commands to be executed, the results are not reported back.
  • Made the permissions work
  • Added configuration system
  • Added squad/ping kicker
  • Added immunity perm

To Do

  • Reserved Slot for administrators,
  • Rewrite the autobalancer to prioritze team switches,
  • Administrator immunity from TKPunish
  • Documentation (yeah right =P)

Requests?

  • Using key hash instead of player name as auth method. --Wizzler 19:50, 7 Jul 2005 (MDT)

Actually, this method is nicer, as it ties the user back to their GameSpy ID and not to a certain install of BF2.

Bugs?

  • ...
  • ...
  • ...

Files

File: bf2admin.py

# Ingame Administration System (BF2Admin)
#
# Author: Danni ([email protected])
# Clan: Fallen Soldiers Reborn
#
# http://www.fsrgaming.com
# http://www.animelab.com
#
#
# 100% Copyleft. Use at will but...
# If you reuse or modify this code you must credit me and
# the clan FSR. OR ELSE! >:D
#
# WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
#
# THIS MODULE IS NOT YET APPROVED FOR USE ON RANKED SERVERS!
# WE ARE NOT RESPONSIBLE FOR YOUR SERVER BEING DELISTED!
# PLEASE CHECK WITH EA FIRST BEFORE USING THIS MODULE ON A RANKED SERVER!
#
# WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
#
#
#       Special thanks        why?
#     _________________________________________________________________
#
#    Greeze            Inspiration from SayKick.py
#    DICE            tk_punish.py and other BF2 python sources
#    (unknown)        gui_log.pyw a VERY helpfull tool!
#    Everyone at BF2TIW    http://bf2.fun-o-matic.org/index.php/Main_Page
#


import string
import re
import bf2
import bf2.PlayerManager
import bf2.Timer
import host
from bf2 import g_debug
import bf2admincmd
import bf2adminkickers

# Dictionaries. Duh!
pdict = { }
rcmd = { }
pcmd = { }
pinfo = { }
rinfo = { }
config = { }
log = None

# Logging Levels
L_NONE         = 0
L_INFO         = 1
L_WARNING     = 2
L_ERROR     = 3
L_DEBUG        = 4



class AdminData:
    def __init__(self):
        self.admin = 0
        self.perms = ""


class PlayerData:
    def __init__(self):
        self.lastupdate = 0
        self.lastupdate = 0


### PlayerObject Extensions.

def getPlayerPerms(self):
    return self.adminData.perms

def isAdmin(self):
    return self.adminData.admin

def sendMessage(self, message):
    host.sgl_sendTextMessage(self.index, 12, 1, message, 0)


bf2.PlayerManager.Player.isAdmin = isAdmin
bf2.PlayerManager.Player.getPerms = getPlayerPerms
bf2.PlayerManager.Player.sendMessage = sendMessage







def addChatCommand(command, function, perm, usage):
    rcmd[command] = function
    rinfo[command] = (perm, usage)

def addPublicChatCommand(command, function, usage):
    pcmd[command] = function
    pinfo[command] = usage

def setConfig(var, val):
    config[var] = val

def getConfig(var):
    if config.has_key(var):
        return config[var]
    else:
        return False

def out(level, string):
    global log
    LOGLEVEL = ('[NONE]', '[INFO]', '[WARN]', '[ERROR]', '[DEBUG]')
    if not config.has_key('logging'):
        config['logging'] = 2
    if not config.has_key('loglevel'):
        config['loglevel'] = 3

    string = LOGLEVEL[level] + ' ' + string
    if level <= config['loglevel']:
        if config['logging'] >= 1:
            print string
        if config['logging'] >= 2:
            sendAdminMessage(string)
        if config['logging'] >= 3:
            log.write(string + "\n")


def loadConfig():
    fn = 'admin/bf2admin.cfg'

    try:
        cfg = open(fn, 'r')
        lineNo = 0

        p = re.compile('(.*?):\s(.*?)', re.IGNORECASE)

        for line in cfg:
            lineNo += 1
            if line.strip() != '' and line.strip() != '\n':
                m = p.match(line)
                if m:
                    config[m.group(1)] = m.group(2)

    except IOError, detail:
        out (L_WARNING, 'couldn\'t read "%s": %s' % (fn, detail))


   

def saveConfig():
    fn = 'admin/bf2admin.cfg'

    try:
        cfg = open(fn, 'w')
        lineNo = 0

        keys = config.keys()
        keys.sort()
        for key in keys:
            cfg.write(str(key) + ': ' + str(config[key]) + '\n')

    except IOError, detail:
        out(L_WARNING, 'couldn\'t write "%s": %s' % (fn, detail))




def sendAdminMessage(message):
    for tp in bf2.playerManager.getPlayers():
        if tp.adminData.admin:
            host.sgl_sendTextMessage(playerId, 12, 1, message, 0)




def findPlayerFromString(playpart):
    for tp in bf2.playerManager.getPlayers():
        name = tp.getName()
        playpart = playpart.lower()
        name = name.lower()
        if name.find(playpart) != -1:
            return tp
    return

def findPlayerNameFromString(playpart):
    for tp in bf2.playerManager.getPlayers():
        name = tp.getName()
        playpart = playpart.lower()
        name = name.lower()
        if name.find(playpart) != -1:
            return tp.getName()
    return


def init():
    global log
    out(L_INFO, 'initializing BF2Admin script')
    loadConfig()
    parseUsers()
    host.registerHandler('PlayerConnect', onPlayerConnect, 1)
    host.registerHandler('PlayerDisconnect', onPlayerDisconnect, 1)
    host.registerHandler('ChatMessage', onChatMessage, 1)


    fn = 'admin/logs/bf2admin.log'
    try:
        log = open(fn, 'a')
   
    except IOError, detail:
        out(L_WARNING, 'couldn\'t open "%s": %s' % (fn, detail))

    bf2admincmd.init()
    bf2adminkickers.init()

def stripmessage(text):
    text = text.replace("HUD_TEXT_CHAT_TEAM", "")
    text = text.replace("HUD_TEXT_CHAT_SQUAD", "")
    text = text.replace("HUD_CHAT_DEADPREFIX", "")
    return text

def onChatMessage(playerid, text, channel, flags):
    player = bf2.playerManager.getPlayerByIndex(playerid)
    text = stripmessage(text)
    cmdList = text.split(' ')

    if len(cmdList) > 1 and playerid != -1:
        cmd = cmdList[0]
        cmdList[0:1] = []
        args = string.join(cmdList,' ')
        try:
            if player.adminData.admin and rinfo[cmd]:
                if player.adminData.perms.find(rinfo[cmd][0]) == -1:
                    player.sendMessage(player.index, 'BF2Admin:  You have no access to that command')
                else:
                    rcmd[cmd](player, args)
        except Exception, detail:
            out(L_DEBUG, 'Run-time error:' + detail)

        try:
            if pcmd[cmd] and pinfo[cmd]:
                pcmd[cmd](player, args)
        except Exception, detail:
            out(L_DEBUG, 'Run-time error:' + detail)



def onPlayerConnect(player):
    player.adminData = AdminData()
    if pdict[str(player.getProfileId())]:
        player.adminData.admin = 1
        player.adminData.perms = str(pdict[str(player.getProfileId())])



# This is just in case a playerslot is reused and not initalized correctly.
# and yes I have seen it happen in other games =P

def onPlayerDisconnect(player):
    player.adminData = AdminData()


# Parses the config file, if it's there
def parseUsers():
    def boolFromString (str):
        if str in ['True', 'true', '1']:
            return True
        elif value in ['False', 'false', '0']:
            return False
        else:
            raise ValueError

    fn = 'admin/users.cfg'
    try:

    # users.cfg format
    # Note: playername is purly so the maintainer can tell who a line is for
    #
    #
    # profileID    "playername"    "permissions"    "reserved"    "reserved" // Comment
    #

        cfg = open(fn, 'r')
        lineNo = 0

        # and now for some of that RegEx magic. ^_^

        #            profileid    name     perms      resv     resv
        p = re.compile('\s*?([0-9]*?)\s\"(.*?)\"\s"(.*?)\"\s"(.*?)\"\s"(.*?)\"', re.IGNORECASE)

        for line in cfg:
            lineNo += 1
            if line.strip() != '' and line.strip() != '\n':
                m = p.match(line)
                if m:
                    pdict[m.group(1)] = m.group(3)
                   


    except IOError, detail:
        out(L_WARNING, 'couldn\'t read "%s": %s' % (fn, detail))

File: bf2admincmd.py

# Ingame Administration System (BF2Admin)
#
# Author: Danni ([email protected])
# Clan: Fallen Soldiers Reborn
#
# http://www.fsrgaming.com
# http://www.animelab.com
#
#
# 100% Copyleft. Use at will but...
# If you reuse or modify this code you must credit me and
# the clan FSR. OR ELSE! >:D
#
# WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
#
# THIS MODULE IS NOT YET APPROVED FOR USE ON RANKED SERVERS!
# WE ARE NOT RESPONSIBLE FOR YOUR SERVER BEING DELISTED!
# PLEASE CHECK WITH EA FIRST BEFORE USING THIS MODULE ON A RANKED SERVER!
#
# WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
#
#
#       Special thanks        why?
#     _________________________________________________________________
#
#    Greeze            Inspiration from SayKick.py
#    DICE            tk_punish.py and other BF2 python sources
#    (unknown)        gui_log.pyw a VERY helpfull tool!
#    Everyone at BF2TIW    http://bf2.fun-o-matic.org/index.php/Main_Page
#


import string
import re
import bf2
import host
import bf2.PlayerManager
import bf2admin
from bf2 import g_debug
# Logging Levels
L_NONE         = 0
L_INFO         = 1
L_WARNING     = 2
L_ERROR     = 3
L_DEBUG        = 4

def init():
    bf2admin.out(L_INFO, 'initializing BF2AdminCmd script')
    bf2admin.addChatCommand('sa_kick',    sa_kick,    'k',    'sa_kick <player> <reason>   -   Kick a player')
    bf2admin.addChatCommand('sa_ban',    sa_ban,        'b',    'sa_ban <player> <length> <reason>   -   Ban a player')
    bf2admin.addChatCommand('sa_bankey',    sa_bankey,    'b',    'sa_bankey <player> <length> <reason>   -   Ban a player by CD-Key')
    bf2admin.addChatCommand('sa_rcon',    sa_rcon,    'r',    'sa_rcon <command> <args> ...   -   Send and rcon command')
    bf2admin.addChatCommand('sa_add_admin',    sa_add_admin,    'f',    'sa_add_admin <player> <permissions> ...   -   Add an administrator')
    bf2admin.addChatCommand('sa_save',    sa_save,    'f',    'sa_save <config>   -   Save the configuration')
    bf2admin.addChatCommand('sa_set',    sa_set,        'f',    'sa_set <key> <value>  -   Change a configuration option')
    bf2admin.addChatCommand('sa_get',    sa_get,        'f',    'sa_get <key>  -   Print a configuration option')


    bf2admin.addPublicChatCommand('pub_id',     pub_id,     'pub_id <player>   -   Retreave a players ProfileId')



def sa_kick(issuer, args):
    argv = args.split(' ')
    playername = bf2admin.findPlayerNameFromString(argv[0])
    player = bf2admin.findPlayerFromString(argv[0])
    argv[0:1] = []
    reason = string.join(argv, ' ')
    if playername:
        if player.getPerms().find('i') != -1:
            issuer.sendMessage('BF2Admin: ' + playername + ' is immune from that command')
        else:
            host.rcon_invoke('game.sayAll "BF2Admin: ' + playername + ' was kicked: ' + reason + '"')
            host.rcon_invoke('admin.kickPlayer "' + playername + '"')


def sa_ban(issuer, args):
    argv = args.split(' ')
    if not argv[2]:
        issuer.sendMessage("usage: sa_ban <player> <length> <reason>")
        return
    playername = bf2admin.findPlayerFromString(argv[0])
    player = bf2admin.findPlayerFromString(argv[0])
    length = int(argv[1])
    argv[0:2] = []
    reason = string.join(argv, ' ')
    if playername:
        if player.getPerms().find('i') != -1:
            issuer.sendMessage('BF2Admin: ' + playername + ' is immune from that command')
        else:
            host.rcon_invoke('game.sayAll "BF2Admin: ' + playername + ' was banned: ' + reason + '"')
            host.rcon_invoke('admin.banPlayer ' + player.index + ' ' + length)



def sa_bankey(issuer, args):
    argv = args.split(' ')
    if not argv[2]:
        issuer.sendMessage("usage: sa_bankey <player> <length> <reason>")
        return
    playername = bf2admin.findPlayerFromString(argv[0])
    player = bf2admin.findPlayerFromString(argv[0])
    length = int(argv[1])
    argv[0:2] = []
    reason = string.join(argv, ' ')
    if playername:
        if player.getPerms().find('i') != -1:
            issuer.sendMessage('BF2Admin: ' + playername + ' is immune from that command')
        else:
            host.rcon_invoke('game.sayAll "BF2Admin: ' + playername + '\'s CD-KEY was banned: ' + reason + '"')
            host.rcon_invoke('admin.banPlayerKey ' + player.index + ' ' + length)


def sa_save(issuer, args):
    bf2admin.saveConfig()
    issuer.sendMessage('BF2Admin: Configuration Saved')

def sa_set(issuer, args):
    argv = args.split(' ')
    bf2admin.setConfig(argv[0], argv[1])

def sa_get(issuer, args):
    issuer.sendMessage('BF2Admin: ' + str(args) + ': ' + str(bf2admin.getConfig(args)))
   

def sa_add_admin(issuer, args):
    # sa_add_admin playerName permissions
    argv = args.split(' ')
    playername = bf2admin.findPlayerNameFromString(argv[0])
    player = bf2admin.findPlayerFromString(argv[0])
    profileId = player.getProfileId()
    if player.getPerms():
        issuer.sendMessage('BF2Admin: ' + playername + ' is already an administrator. Please edit the users.cfg file manualy to change permissions')
    else:
        file = open('admin/users.cfg', 'a')
        file.write('    ' + str(profileId) + '    "' + playername + '"    "' + argv[1] +'"    ""    ""\n')
        file.close()
        issuer.sendMessage('BF2Admin: ' + playername + ' added as an administrator.')



def sa_rcon(issuer, args):
    argv = args.split(' ')
    argv[0:1] = []
    reason = string.join(argv, ' ')
    res = host.rcon_invoke(args)
    issuer.sendMessage('BF2Admin: rcon command issued')   
    for line in res.split('\n'):
        issuer.sendMessage(line)   
   


def pub_id(issuer, args):
    argv = args.split(' ')
    tp = bf2admin.findPlayerFromString(argv[0])   
    if tp:
        issuer.sendMessage('BF2Admin: Name: ' + str(tp.getName()) + '        ProfileId: ' + str(tp.getProfileId()))
    else:
        issuer.sendMessage('BF2Admin: Error: Could not find a player with that name')


def pub_help(issuer, args):
    argv = args.split(' ')
    tp = bf2admin.findPlayerFromString(argv[0])   
    if tp:
        issuer.sendMessage('BF2Admin: Name: ' + str(tp.getName()) + '        ProfileId: ' + str(tp.getProfileId()))
    else:
        issuer.sendMessage('BF2Admin: Error: Could not find a player with that name')

File: bf2adminkickers.py

# Ingame Administration System (BF2Admin)
#
# Author: Danni ([email protected])
# Clan: Fallen Soldiers Reborn
#
# http://www.fsrgaming.com
# http://www.animelab.com
#
#
# 100% Copyleft. Use at will but...
# If you reuse or modify this code you must credit me and
# the clan FSR. OR ELSE! >:D
#
# WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
#
# THIS MODULE IS NOT YET APPROVED FOR USE ON RANKED SERVERS!
# WE ARE NOT RESPONSIBLE FOR YOUR SERVER BEING DELISTED!
# PLEASE CHECK WITH EA FIRST BEFORE USING THIS MODULE ON A RANKED SERVER!
#
# WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
#
#
#       Special thanks        why?
#     _________________________________________________________________
#
#    Greeze            Inspiration from SayKick.py
#    DICE            tk_punish.py and other BF2 python sources
#    (unknown)        gui_log.pyw a VERY helpfull tool!
#    Everyone at BF2TIW    http://bf2.fun-o-matic.org/index.php/Main_Page
#


import string
import re
import bf2
import bf2.PlayerManager
import bf2.Timer
import host
from bf2 import g_debug
import bf2admin


gamestatus = None
ten_secs = None
sixty_secs = None

bf2.PlayerManager.Player.pingWarnings = 0
bf2.PlayerManager.Player.squadWarnings = 0
bf2.PlayerManager.Player.detectedPing = []
bf2.PlayerManager.Player.pingSamples = 0
bf2.PlayerManager.Player.actuallyPlaying = False

try:
    def resetPlayer(p):
        p.pingWarnings = 0
        p.squadWarnings = 0
        p.detectedPing = []
        p.pingSamples = 0
        p.actuallyPlaying = False
 


    def init():
        # defaults
        if not bf2admin.getConfig('pk_enabled'):
            bf2admin.setConfig('pk_enabled', 1)
        if not bf2admin.getConfig('sk_enabled'):
            bf2admin.setConfig('sk_enabled', 1)
   
        if not bf2admin.getConfig('pk_samples'):
            bf2admin.setConfig('pk_samples', 12) # two minuites of samples
        if not bf2admin.getConfig('pk_warnings'):
            bf2admin.setConfig('pk_warnings', 3)
        if not bf2admin.getConfig('pk_maxping'):
            bf2admin.setConfig('pk_maxping', 1)
        if not bf2admin.getConfig('sk_warnings'):
            bf2admin.setConfig('sk_warnings', 3)
   
   
        host.registerHandler('PlayerConnect', onPlayerConnect)
        host.registerHandler('PlayerDisconnect', onPlayerDisconnect)
        host.registerHandler('PlayerSpawn', onPlayerSpawn)
        host.registerHandler('PlayerDeath', onPlayerSpawn)
        host.registerGameStatusHandler(onGameStatusChanged)
        enableTimers()



    def enableTimers():
        global ten_secs
        global sixty_secs

        if not ten_secs:
            ten_secs = bf2.Timer(ten_seconds, 10, 1)
        ten_secs.setRecurring(10)
        if not sixty_secs:
            sixty_secs = bf2.Timer(sixty_seconds, 60, 1)
        sixty_secs.setRecurring(60)
           
    def ten_seconds(data):
        # ping kick
        enableTimers()
   
           
           
   
    def sixty_seconds(data):
        enableTimers()
        for tp in bf2.playerManager.getPlayers():
            if bf2admin.getConfig('pk_enabled') and tp.actuallyPlaying:
                if tp.getPing() > bf2admin.getConfig('pk_maxping'):
                    if tp.pingWarnings < bf2admin.getConfig('pk_warnings'):
                        tp.pingWarnings += 1
                        tp.sendMessage('BF2Admin: WARNING ' + str(tp.pingWarnings) + '/' + str(bf2admin.getConfig('pk_warnings')) +'! YOUR PING IS TOO HIGH! YOU WILL BE REMOVED IF IT DOES NOT FALL BELOW ' + str(bf2admin.getConfig('pk_maxping')) + '!')
                    else:
                        host.rcon_invoke('game.sayAll "BF2Admin: ' + tp.getName() + ' was kicked due to high ping!')
                        host.rcon_invoke('admin.kickPlayer "' + tp.getName() + '"')
                else:
                    tp.pingWarnings = 0
   
            if bf2admin.getConfig('sk_enabled') and tp.actuallyPlaying:       
                if not tp.isCommander() and tp.getSquadId() == 0:
                    if tp.squadWarnings < bf2admin.getConfig('sk_warnings'):
                        tp.squadWarnings += 1
                        tp.sendMessage('BF2Admin: WARNING ' + str(tp.squadWarnings) + '/' + str(bf2admin.getConfig('sk_warnings')) +'! JOIN OR CREATE A SQUAD OR YOU WILL BE KICKED!')
                    else:
                        host.rcon_invoke('game.sayAll "BF2Admin: ' + tp.getName() + ' was kicked for not joining a squad!')
                        host.rcon_invoke('admin.kickPlayer "' + tp.getName() + '"')   
           
    def onPlayerSpawn(p, vehicle):
        enableTimers()
        p.actuallyPlaying = 1
   
    def onPlayerDeath(p, vehicle):
        p.actuallyPlaying = 1
           
    def onPlayerConnect(player):
        enableTimers()
        resetPlayer(player)
   
    def onPlayerDisconnect(player):
        enableTimers()
        resetPlayer(player)


    def onGameStatusChanged(status):
        gamestatus = status
       
        if gamestatus == bf2.GameStatus.EndGame:
            for tp in bf2.playerManager.getPlayers():
                tp.actuallyPlaying = 0
               

except Exception, detail:
    print 'Error! ' + detail

File: users.cfg

This file should be placed in the ./admin/ directory in the main BF2 directory.

# users.cfg # Administrator configuration file  # users.cfg format # Note: playername is purly so the maintainer can tell who a line is for # # profileID	"playername"	"permissions"	"reserved"	"reserved" // Comment   	44773626	"FSR|Danni"	"abcdefghijklmnopqrstuvwxyz1234567890" "" "" // Main Admin