Scripts:BF2Admin

From BF2 Technical Information Wiki
Jump to: navigation, search
Wiki letter w.png WARNING: This page is a work in progress
The information here is not quite correct or complete yet, but it's being worked on, and should be finished "soon"! If you have insights into the matters discussed, please feel free to contribute to the page.

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)

Contents

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 (webmaster@animelab.com) 
# 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 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):
	return config.get(var, False)

def out(level, string):
	global log
	LOGLEVEL = ('[NONE]', '[INFO]', '[WARN]', '[ERROR]', '[DEBUG]')
	if 'logging' not in config:
		config['logging'] = 2
	if 'loglevel' not in config:
		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 = ' '.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 (webmaster@animelab.com) 
# 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 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 = ' '.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 = ' '.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 = ' '.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 = ' '.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 (webmaster@animelab.com) 
# 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 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
Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox