<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://bf2tech.uturista.pt/index.php?action=history&amp;feed=atom&amp;title=Scripts%3AModified_admin_script</id>
	<title>Scripts:Modified admin script - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://bf2tech.uturista.pt/index.php?action=history&amp;feed=atom&amp;title=Scripts%3AModified_admin_script"/>
	<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:Modified_admin_script&amp;action=history"/>
	<updated>2026-08-06T01:08:28Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.40.1</generator>
	<entry>
		<id>https://bf2tech.uturista.pt/index.php?title=Scripts:Modified_admin_script&amp;diff=132&amp;oldid=prev</id>
		<title>Pireax: Created page with &quot;__TOC__    == Introduction ==  When the BF2 server starts, it loads some code called an &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039;. The purpose of the default &#039;&#039;&#039;&#039;&#039;admin script&#039;&#039;&#039;&#039;&#039; provided by D...&quot;</title>
		<link rel="alternate" type="text/html" href="https://bf2tech.uturista.pt/index.php?title=Scripts:Modified_admin_script&amp;diff=132&amp;oldid=prev"/>
		<updated>2018-06-22T15:38:08Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;__TOC__    == Introduction ==  When the BF2 server starts, it loads some code called an &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;. The purpose of the default &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; provided by D...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
When the BF2 server starts, it loads some code called an &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;. The purpose of the default &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; provided by Dice, is to create and start an RCON service, letting both connected BF2 clients and standalone RCON clients run RCON commands on the server. The &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; is completely open to the server operator, and can be reprogrammed at will. It is located in the &amp;#039;&amp;#039;admin&amp;#039;&amp;#039; directory of the BF2 server, and the default &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; is called &amp;#039;&amp;#039;default.py&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
We at [http://www.battlefield.no/ Battlefield.no] have created a modified &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; that uses [http://www.multiplay.co.uk/ Steven Hartland&amp;#039;s] brilliant idea of making the &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; load a separate configuration file, called &amp;#039;&amp;#039;adminsettings.con&amp;#039;&amp;#039;, from the same directory that the server has loaded the map list. These settings are loaded into a Python &amp;#039;&amp;#039;dictionary&amp;#039;&amp;#039; called &amp;#039;&amp;#039;options&amp;#039;&amp;#039;, and made globally available via a reference in the &amp;#039;bf2&amp;#039; object, calles &amp;#039;&amp;#039;adminoptions&amp;#039;&amp;#039;. The script also enables logging to both file and UDP, which are both configured using the &amp;#039;&amp;#039;adminsettings.con&amp;#039;&amp;#039; file. The &amp;#039;&amp;#039;adminsettings.con&amp;#039;&amp;#039; file is also re-read on every &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;EndRound&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; server event, so for most settings (RCON port and password being an exception) you do not have to restart the server to see the effect of a changed setting.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
&lt;br /&gt;
No we&amp;#039;ll have a look at what you need to do, to get online with the modified &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;. Please note that this description is for doing the modification on Linux. For Windows you will need to make some minor ajustments. Please see the &amp;#039;&amp;#039;discussion&amp;#039;&amp;#039; page for details.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Modifying the Admin Script ===&lt;br /&gt;
&lt;br /&gt;
It is not a good idea to modify the original &amp;#039;&amp;#039;default.py&amp;#039;&amp;#039;. It is much better to copy it, and start editing the copy. To enable your copy as the &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;, simply open the &amp;#039;&amp;#039;serversettings.con&amp;#039;&amp;#039; file that you are using, and edit the server setting called &amp;#039;&amp;#039;sv.adminScript&amp;#039;&amp;#039;, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sv.adminScript = &amp;quot;&amp;lt;name of admin script&amp;gt;&amp;quot; &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We at [http://www.battlefield.no/ Battlefield.no] have called our &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; &amp;#039;&amp;#039;bfno.py&amp;#039;&amp;#039;, and hence, our &amp;#039;&amp;#039;serversettings.con&amp;#039;&amp;#039; file is modified to look like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;sv.adminScript = &amp;quot;bfno&amp;quot; &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the lack of the &amp;#039;&amp;#039;.py&amp;#039;&amp;#039; extension. You will need to change &amp;#039;bfno&amp;#039; to whatever you call your &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Creating the Admin Settings File ===&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;adminsettings.con&amp;#039;&amp;#039; file needs to reside in the same directory as your current &amp;#039;&amp;#039;maplist&amp;#039;&amp;#039;. So if you are starting your BF2 server without the &amp;#039;&amp;#039;+mapList&amp;#039;&amp;#039; option, you must place it in your &amp;#039;&amp;#039;mods/bf2/settings&amp;#039;&amp;#039; directory. When you have created it, you need to populate it with the following settings:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
admin.rconPort 4711&lt;br /&gt;
admin.rconPassword &amp;quot;yourRconPassword&amp;quot;&lt;br /&gt;
admin.debugLogEnabled 1&lt;br /&gt;
admin.debugLogFile &amp;quot;/path/to/debug.log&amp;quot;&lt;br /&gt;
admin.udpLogEnabled 1&lt;br /&gt;
admin.udpLogHost &amp;quot;localhost&amp;quot;&lt;br /&gt;
admin.udpLogPort 29500&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will of course need to change the ports, path and password to your own, and turn off logging to file and/or UDP if you don&amp;#039;t want that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== The Admin Script ==&lt;br /&gt;
&lt;br /&gt;
This is the modified &amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;admin script&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; as we use it at [http://www.battlefield.no/ Battlefield.no]. Feel free to copy it, and since this is a wiki, feel free to modify it. But we would be very gratefull of you appended a note in the &amp;#039;&amp;#039;updates&amp;#039;&amp;#039; section if you do.&lt;br /&gt;
&lt;br /&gt;
For your convenience, we&amp;#039;ve uploaded the script to our website as well. You can download it [http://www.battlefield.no/filer/pafiledb.php?action=file&amp;amp;id=190 here]. &lt;br /&gt;
&lt;br /&gt;
=== The Code ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Battlefield II -- default remote console module.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#&lt;br /&gt;
# This is a very simple, TCP based remote console which does simple MD5 digest&lt;br /&gt;
# password authentication. It can be configured via the admin/default.cfg file.&lt;br /&gt;
# Recognized options are &amp;#039;port&amp;#039; and &amp;#039;password&amp;#039;.&lt;br /&gt;
#&lt;br /&gt;
# Implementation guidelines for this file (and for your own rcon modules):&lt;br /&gt;
#&lt;br /&gt;
#  - All socket operations MUST be non-blocking. If your module blocks on a&lt;br /&gt;
#    socket the game server will hang.&lt;br /&gt;
#&lt;br /&gt;
#  - Do as little work as possible in update() as it runs in the server main&lt;br /&gt;
#    loop.&lt;br /&gt;
#&lt;br /&gt;
# Other notes:&lt;br /&gt;
#&lt;br /&gt;
#  - To get end-of-message markers (0x04 hex) after each reply, begin your&lt;br /&gt;
#    commands with an ascii 0x02 code. This module will then append the&lt;br /&gt;
#    end-of-message marker to all results. This is useful if you need to wait&lt;br /&gt;
#    for a complete response.&lt;br /&gt;
#&lt;br /&gt;
# Copyright (c)2004 Digital Illusions CE AB&lt;br /&gt;
# Author: Andreas `dep&amp;#039; Fredriksson&lt;br /&gt;
#&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#&lt;br /&gt;
# -----------------------------&lt;br /&gt;
# Changes made by the community&lt;br /&gt;
# -----------------------------&lt;br /&gt;
#&lt;br /&gt;
# If you make any modifications to this script that enhances its&lt;br /&gt;
# functionality, please post the changes to the ICCULUS mailing list.&lt;br /&gt;
#&lt;br /&gt;
# NB: Use &amp;quot;tab expansion&amp;quot;, and expand to 3 spaces!&lt;br /&gt;
#&lt;br /&gt;
# Maintained by Kybber and Panic, Battlefield.no.&lt;br /&gt;
#&lt;br /&gt;
# -----------&lt;br /&gt;
# Version 1.1&lt;br /&gt;
# -----------&lt;br /&gt;
#&lt;br /&gt;
# The script has been reorganized into the following sections:&lt;br /&gt;
# - Import&lt;br /&gt;
# - Variables&lt;br /&gt;
# - Classes&lt;br /&gt;
# - Functions&lt;br /&gt;
# - Program&lt;br /&gt;
#&lt;br /&gt;
# adminsettings.con:&lt;br /&gt;
# This version of the admin script uses this file for all admin&lt;br /&gt;
# settings. It is read and parsed by &amp;#039;parseConfig&amp;#039;. The file must&lt;br /&gt;
# be located in the same directory as the server is reading the&lt;br /&gt;
# maplist from.&lt;br /&gt;
#&lt;br /&gt;
# class writer:&lt;br /&gt;
# A heavily modified copy of the writer class has been added,&lt;br /&gt;
# facilitating logging to file and over udp.&lt;br /&gt;
#&lt;br /&gt;
# def parseConfig:&lt;br /&gt;
# The function parseConfig has been updated to load a file called&lt;br /&gt;
# adminsettings.con from the same directory as the maplist is being&lt;br /&gt;
# read. This emulates the old &amp;quot;+overlaypath&amp;quot; option. Thanks a lot to&lt;br /&gt;
# Steven Hartland at Multiplay.co.uk for this!&lt;br /&gt;
#&lt;br /&gt;
# def onGameStatusChanged:&lt;br /&gt;
# This function is built as a callback function to be registered with&lt;br /&gt;
# &amp;#039;host.registerGameStatusHandler(onGameStatusChanged)&amp;#039;. It&amp;#039;s intended&lt;br /&gt;
# use is to reload the adminsettings.con file.&lt;br /&gt;
#&lt;br /&gt;
# This version of the file also &amp;#039;globalizez&amp;#039; the &amp;#039;options&amp;#039; dictionary,&lt;br /&gt;
# by adding a reference called &amp;#039;adminoptions&amp;#039; to the &amp;#039;bf2&amp;#039; object.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                          I M P O R T&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
import socket&lt;br /&gt;
import errno&lt;br /&gt;
import host&lt;br /&gt;
import bf2&lt;br /&gt;
import types&lt;br /&gt;
import md5&lt;br /&gt;
import string&lt;br /&gt;
import random&lt;br /&gt;
import sys&lt;br /&gt;
import datetime&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                       V A R I A B L E S&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# File version&lt;br /&gt;
version = &amp;quot;1.1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Debug flags:&lt;br /&gt;
a_debug = 1 # Get debug info&lt;br /&gt;
a_info  = 1 # Get other runtime info&lt;br /&gt;
&lt;br /&gt;
# Admin options:&lt;br /&gt;
options = {&lt;br /&gt;
    &amp;#039;admin.rconPort&amp;#039;: &amp;#039;4711&amp;#039;,   # Overwritten by admin.rconPort in adminsettings.con&lt;br /&gt;
    &amp;#039;admin.rconPassword&amp;#039;: None, # Overwritten by admin.rconPassword in adminsettings.con&lt;br /&gt;
    # True if multiple commands should be processed in one update and&lt;br /&gt;
    # if as many responses as possible should be sent each update.&lt;br /&gt;
    &amp;#039;admin.allowBatching&amp;#039;: False,&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                         C L A S S E S&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# class writer: Get a hold of stdout and stderr!&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
class writer:&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Class for writing output to files and sockets&lt;br /&gt;
  &lt;br /&gt;
   Arguments&lt;br /&gt;
   The __init__ function takes no arguments.&lt;br /&gt;
&lt;br /&gt;
   Functions&lt;br /&gt;
   __init__(self) : Creating stream and socket objects to log to.&lt;br /&gt;
   __del__(self)  : Closes the streams and sockets created by __init__.&lt;br /&gt;
   write(self,str): Write data to the streams and sockets created by __init__.&lt;br /&gt;
&lt;br /&gt;
   Description&lt;br /&gt;
   The intended use of the class is to override sys.stdout and sys.stderr,&lt;br /&gt;
   like this: sys.stdout = sys.stderr = writer().&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
   # Constructor:&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
   def __init__(self):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Creates streams and sockets to log data to, using the write function.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
     &lt;br /&gt;
      # Class variables:&lt;br /&gt;
      self.debugLogEnabled = None&lt;br /&gt;
      self.debugLogFile = None&lt;br /&gt;
      self.udpLogEnabled = None&lt;br /&gt;
      self.udpLogHost = None&lt;br /&gt;
      self.udpLogPort = None&lt;br /&gt;
      self.stream = None&lt;br /&gt;
      self.sock = None&lt;br /&gt;
     &lt;br /&gt;
      # Try to get the debug log settings:&lt;br /&gt;
      try:&lt;br /&gt;
         if str(options[&amp;#039;admin.debugLogEnabled&amp;#039;]) in [&amp;#039;True&amp;#039;,&amp;#039;true&amp;#039;,&amp;#039;1&amp;#039;]: self.debugLogEnabled = True&lt;br /&gt;
         self.debugLogFile = options[&amp;#039;admin.debugLogFile&amp;#039;]&lt;br /&gt;
      except:&lt;br /&gt;
         pass&lt;br /&gt;
      # Try to get the udp log settings:&lt;br /&gt;
      try:&lt;br /&gt;
         if str(options[&amp;#039;admin.udpLogEnabled&amp;#039;]) in [&amp;#039;True&amp;#039;,&amp;#039;true&amp;#039;,&amp;#039;1&amp;#039;]: self.udpLogEnabled = True&lt;br /&gt;
         self.udpLogHost = str(options[&amp;#039;admin.udpLogHost&amp;#039;])&lt;br /&gt;
         self.udpLogPort = int(options[&amp;#039;admin.udpLogPort&amp;#039;])&lt;br /&gt;
      except:&lt;br /&gt;
         pass&lt;br /&gt;
     &lt;br /&gt;
      # Prepare for udp logging:&lt;br /&gt;
      if self.udpLogEnabled and self.udpLogHost and self.udpLogPort:&lt;br /&gt;
         self.sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)&lt;br /&gt;
     &lt;br /&gt;
      # Prepare for logging to file:&lt;br /&gt;
      if self.debugLogEnabled and self.debugLogFile:&lt;br /&gt;
         self.stream = open( self.debugLogFile, &amp;#039;a+&amp;#039; )&lt;br /&gt;
&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
  &lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
   # Deconstructor:&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
   def __del__(self):&lt;br /&gt;
      &amp;quot;&amp;quot;&amp;quot;Closes the streams and sockets created by __init__&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
      if self.stream: self.stream.close()&lt;br /&gt;
      if self.sock: self.sock.close()&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
   # Write data:&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Writes data to the streams and sockets defined in __init__&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   def write(self, str):&lt;br /&gt;
      if &amp;#039;\n&amp;#039; != str:&lt;br /&gt;
         if self.stream: self.stream.write(&amp;#039;[&amp;#039; + datetime.datetime.now().strftime(&amp;quot;%Y-%m-%d %H:%M:%S&amp;quot;)  + &amp;#039;] &amp;#039; + str)&lt;br /&gt;
         if self.sock: self.sock.sendto(str,(self.udpLogHost,self.udpLogPort))&lt;br /&gt;
      else:&lt;br /&gt;
         if self.stream:&lt;br /&gt;
            self.stream.write(str)&lt;br /&gt;
            self.stream.flush()&lt;br /&gt;
   # ---------------------------------------------------------------------&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# A stateful output buffer that knows how to enqueue data and ship it out&lt;br /&gt;
# without blocking.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
class OutputBuffer(object):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, sock):&lt;br /&gt;
        self.sock = sock&lt;br /&gt;
        self.data = []&lt;br /&gt;
        self.index = 0&lt;br /&gt;
&lt;br /&gt;
    def enqueue(self, str):&lt;br /&gt;
        self.data.append(str)&lt;br /&gt;
&lt;br /&gt;
    def update(self):&lt;br /&gt;
        allowBatching = options[&amp;#039;admin.allowBatching&amp;#039;]&lt;br /&gt;
        while len(self.data) &amp;gt; 0:&lt;br /&gt;
            try:&lt;br /&gt;
                item = self.data[0]&lt;br /&gt;
                scount = self.sock.send(item[self.index:])&lt;br /&gt;
                self.index += scount&lt;br /&gt;
                if self.index == len(item):&lt;br /&gt;
                    del self.data[0]&lt;br /&gt;
                    self.index = 0&lt;br /&gt;
            except socket.error, detail:&lt;br /&gt;
                if detail[0] != errno.EWOULDBLOCK:&lt;br /&gt;
                    return detail[1]&lt;br /&gt;
            if not allowBatching:&lt;br /&gt;
                break&lt;br /&gt;
        return None&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Each TCP connection is represented by an object of this class.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
class AdminConnection(object):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, srv, sock, addr):&lt;br /&gt;
        print &amp;#039;new rcon/admin connection from %s:%d&amp;#039; % (addr[0], addr[1])&lt;br /&gt;
        self.server = srv&lt;br /&gt;
        self.sock = sock&lt;br /&gt;
        self.addr = addr&lt;br /&gt;
        self.sock.setblocking(0)&lt;br /&gt;
        self.buffer = &amp;#039;&amp;#039;&lt;br /&gt;
        self.seed = make_seed(16)&lt;br /&gt;
        self.correct_digest = digest(self.seed, options[&amp;#039;admin.rconPassword&amp;#039;])&lt;br /&gt;
        self.outbuf = OutputBuffer(self.sock)&lt;br /&gt;
       &lt;br /&gt;
        # Welcome message *must* end with \n\n&lt;br /&gt;
        self.outbuf.enqueue(&amp;#039;### Battlefield 2 default RCON/admin ready.\n&amp;#039;)&lt;br /&gt;
        self.outbuf.enqueue(&amp;#039;### Digest seed: %s\n&amp;#039; % (self.seed))&lt;br /&gt;
        self.outbuf.enqueue(&amp;#039;\n&amp;#039;) # terminate welcome message with extra LF&lt;br /&gt;
&lt;br /&gt;
    def update(self):&lt;br /&gt;
        err = None&lt;br /&gt;
        try:&lt;br /&gt;
            allowBatching = options[&amp;#039;admin.allowBatching&amp;#039;]&lt;br /&gt;
            while not err:&lt;br /&gt;
                data = self.sock.recv(1024)&lt;br /&gt;
                if data:&lt;br /&gt;
                    self.buffer += data&lt;br /&gt;
                    while not err:&lt;br /&gt;
                        nlpos = self.buffer.find(&amp;#039;\n&amp;#039;)&lt;br /&gt;
                        if nlpos != -1:&lt;br /&gt;
                            self.server.onRemoteCommand(self, self.buffer[0:nlpos])&lt;br /&gt;
                            self.buffer = self.buffer[nlpos+1:] # keep rest of buffer&lt;br /&gt;
                        else:&lt;br /&gt;
                            if len(self.buffer) &amp;gt; 128:&lt;br /&gt;
                                err = &amp;#039;data format error: no newline in message&amp;#039;&lt;br /&gt;
                            break&lt;br /&gt;
                        if not allowBatching: break&lt;br /&gt;
                else:&lt;br /&gt;
                    err = &amp;#039;peer disconnected&amp;#039;&lt;br /&gt;
               &lt;br /&gt;
                if not allowBatching: break&lt;br /&gt;
&lt;br /&gt;
        except socket.error, detail:&lt;br /&gt;
            if detail[0] != errno.EWOULDBLOCK:&lt;br /&gt;
                err = detail[1]&lt;br /&gt;
&lt;br /&gt;
        if not err:&lt;br /&gt;
            err = self.outbuf.update()&lt;br /&gt;
&lt;br /&gt;
        if err:&lt;br /&gt;
            print &amp;#039;rcon: closing %s:%d: %s&amp;#039; % (self.addr[0], self.addr[1], err)&lt;br /&gt;
            try:&lt;br /&gt;
                self.sock.shutdown(2)&lt;br /&gt;
                self.sock.close()&lt;br /&gt;
            except:&lt;br /&gt;
                print &amp;#039;rcon: warning: failed to close %s&amp;#039; % (self.addr)&lt;br /&gt;
                pass&lt;br /&gt;
            return 0&lt;br /&gt;
        else:&lt;br /&gt;
            return 1&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Context passed to remote command implementations for them to write output to&lt;br /&gt;
# either a remote tcp socket or an in-game client executing &amp;#039;rcon &amp;lt;command&amp;gt;&amp;#039;.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
class CommandContext(object):&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        self.player = None&lt;br /&gt;
        self.socket = None&lt;br /&gt;
        self.output = []&lt;br /&gt;
&lt;br /&gt;
    def isInGame(self): return self.player is not None&lt;br /&gt;
    def isSocket(self): return self.socket is not None&lt;br /&gt;
    def write(self, text): self.output.append(text)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# The server itself.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
class AdminServer(object):&lt;br /&gt;
&lt;br /&gt;
    def __init__(self, port):&lt;br /&gt;
        # state for tcp rcon connections&lt;br /&gt;
        self.port = port&lt;br /&gt;
        self.backlog = 1&lt;br /&gt;
        self.peers = []&lt;br /&gt;
        self.openSocket()&lt;br /&gt;
&lt;br /&gt;
        # state for in-game rcon connections&lt;br /&gt;
        host.registerHandler(&amp;#039;RemoteCommand&amp;#039;, self.onRemoteCommand, 1)&lt;br /&gt;
        host.registerHandler(&amp;#039;PlayerDisconnect&amp;#039;, self.onPlayerDisconnect, 1)&lt;br /&gt;
        host.registerHandler(&amp;#039;ChatMessage&amp;#039;, self.onChatMessage, 1)&lt;br /&gt;
&lt;br /&gt;
        # contains player ids for players which have successfully authenticated&lt;br /&gt;
        # themselves with &amp;#039;rcon login &amp;lt;passwd&amp;gt;&amp;#039;&lt;br /&gt;
        self.authed_players = {}&lt;br /&gt;
        # contains sockets for connections which have successfully authenticated&lt;br /&gt;
        # themselves with &amp;#039;login &amp;lt;passwd&amp;gt;&amp;#039;&lt;br /&gt;
        self.authed_sockets = {}&lt;br /&gt;
&lt;br /&gt;
        # rcon commands supported in this vanilla version&lt;br /&gt;
        self.rcon_cmds = {&lt;br /&gt;
            &amp;#039;login&amp;#039;: self.rcmd_login,&lt;br /&gt;
            &amp;#039;users&amp;#039;: self.rcmd_users,&lt;br /&gt;
            &amp;#039;exec&amp;#039;: self.rcmd_exec&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    # Called when a user types &amp;#039;rcon &amp;#039; followed by any string in a client&lt;br /&gt;
    # console window or when a TCP client sends a complete line to be&lt;br /&gt;
    # evaluated.&lt;br /&gt;
    def onRemoteCommand(self, playerid_or_socket, cmd):&lt;br /&gt;
        cmd = cmd.strip()&lt;br /&gt;
        interactive = True&lt;br /&gt;
&lt;br /&gt;
        # Is this a non-interactive client?&lt;br /&gt;
        if len(cmd) &amp;gt; 0 and cmd[0] == &amp;#039;\x02&amp;#039;:&lt;br /&gt;
            cmd = cmd[1:]&lt;br /&gt;
            interactive = False&lt;br /&gt;
&lt;br /&gt;
        spacepos = cmd.find(&amp;#039; &amp;#039;)&lt;br /&gt;
        if spacepos == -1: spacepos=len(cmd)&lt;br /&gt;
        subcmd = cmd[0:spacepos]&lt;br /&gt;
&lt;br /&gt;
        ctx = CommandContext()&lt;br /&gt;
        authed = 0&lt;br /&gt;
        if type(playerid_or_socket) == types.IntType:&lt;br /&gt;
            ctx.player = playerid_or_socket&lt;br /&gt;
            authed = self.authed_players.has_key(ctx.player)&lt;br /&gt;
        else:&lt;br /&gt;
            ctx.socket = playerid_or_socket&lt;br /&gt;
            authed = self.authed_sockets.has_key(ctx.socket)&lt;br /&gt;
           &lt;br /&gt;
        # you can only login unless you are authenticated&lt;br /&gt;
        if subcmd != &amp;#039;login&amp;#039; and not authed:&lt;br /&gt;
            ctx.write(&amp;#039;error: not authenticated: you can only invoke \&amp;#039;login\&amp;#039;\n&amp;#039;)&lt;br /&gt;
        else:&lt;br /&gt;
            if self.rcon_cmds.has_key(subcmd):&lt;br /&gt;
                self.rcon_cmds[subcmd](ctx, cmd[spacepos+1:])&lt;br /&gt;
            else:&lt;br /&gt;
                ctx.write(&amp;#039;unknown command: \&amp;#039;%s\&amp;#039;\n&amp;#039; % (subcmd))&lt;br /&gt;
&lt;br /&gt;
        feedback = &amp;#039;&amp;#039;.join(ctx.output)&lt;br /&gt;
        if ctx.socket:&lt;br /&gt;
            if interactive:&lt;br /&gt;
                ctx.socket.outbuf.enqueue(feedback)&lt;br /&gt;
            else:&lt;br /&gt;
                ctx.socket.outbuf.enqueue(feedback + &amp;#039;\x04&amp;#039;)&lt;br /&gt;
        else:&lt;br /&gt;
            host.rcon_feedback(ctx.player, feedback)&lt;br /&gt;
&lt;br /&gt;
    # When players disconnect, remove them from the auth map if they were&lt;br /&gt;
    # authenticated so that the next user with the same id doesn&amp;#039;t get rcon&lt;br /&gt;
    # access.&lt;br /&gt;
    def onPlayerDisconnect(self, player_id):&lt;br /&gt;
        if self.authed_players.has_key(player_id):&lt;br /&gt;
            del self.authed_players[player_id]&lt;br /&gt;
&lt;br /&gt;
    # Called whenever a player issues a chat string.&lt;br /&gt;
    def onChatMessage(self, player_id, text, channel, flags):&lt;br /&gt;
        print &amp;#039;chat: pid=%d text=\&amp;#039;%s\&amp;#039; channel=%s&amp;#039; % (player_id, text, channel)&lt;br /&gt;
&lt;br /&gt;
    # Sets up the listening TCP RCON socket. This binds to 0.0.0.0, which may&lt;br /&gt;
    # not be what you want but it&amp;#039;s a sane default for most installations.&lt;br /&gt;
    def openSocket(self):&lt;br /&gt;
        try:&lt;br /&gt;
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)&lt;br /&gt;
            #self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, 0)&lt;br /&gt;
            #self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)&lt;br /&gt;
            self.sock.bind((&amp;#039;0.0.0.0&amp;#039;, self.port))&lt;br /&gt;
            self.sock.listen(self.backlog)&lt;br /&gt;
            self.sock.setblocking(0)&lt;br /&gt;
        except socket.error, detail:&lt;br /&gt;
            print &amp;#039;failed to bind rcon socket--only in-game rcon will be enabled&amp;#039;&lt;br /&gt;
&lt;br /&gt;
    # WARNING: update is called very frequently -- don&amp;#039;t go crazy with logic&lt;br /&gt;
    # here.&lt;br /&gt;
    def update(self):&lt;br /&gt;
        # if we don&amp;#039;t have a socket, just return&lt;br /&gt;
        if not self.sock: return&lt;br /&gt;
&lt;br /&gt;
        # without blocking, check for new connections&lt;br /&gt;
        try:&lt;br /&gt;
            conn, peeraddr = self.sock.accept()&lt;br /&gt;
            self.peers.append(AdminConnection(self, conn, peeraddr))&lt;br /&gt;
        except socket.error, detail:&lt;br /&gt;
            if detail[0] != errno.EWOULDBLOCK:&lt;br /&gt;
                raise socket.error, detail&lt;br /&gt;
&lt;br /&gt;
        # update clients and mark connections that fail their update&lt;br /&gt;
        disc = []&lt;br /&gt;
        for client in self.peers:&lt;br /&gt;
            if not client.update(): disc.append(client)&lt;br /&gt;
&lt;br /&gt;
        # delete any auth status for closed tcp connections&lt;br /&gt;
        for d in disc:&lt;br /&gt;
            if self.authed_sockets.has_key(d): del self.authed_sockets[d]&lt;br /&gt;
&lt;br /&gt;
        # now keep the remaining clients&lt;br /&gt;
        self.peers = filter(lambda x: x not in disc, self.peers)&lt;br /&gt;
&lt;br /&gt;
    def shutdown(self):&lt;br /&gt;
        if self.sock:&lt;br /&gt;
            self.sock.close()&lt;br /&gt;
&lt;br /&gt;
    # Command implementations go here (member functions of the AdminServer)&lt;br /&gt;
&lt;br /&gt;
    # Allows a in-game rcon client to authenticate and get access.&lt;br /&gt;
    def rcmd_login(self, ctx, cmd):&lt;br /&gt;
        success = 0&lt;br /&gt;
        if ctx.isInGame():&lt;br /&gt;
            # We&amp;#039;re called by an in-game rcon client, use plain-text password&lt;br /&gt;
            # (encoded into bf2 network stream).&lt;br /&gt;
            if cmd.strip() == options[&amp;#039;admin.rconPassword&amp;#039;]:&lt;br /&gt;
                    self.authed_players[ctx.player] = 1&lt;br /&gt;
                    success = 1&lt;br /&gt;
            elif self.authed_players.has_key(ctx.player):&lt;br /&gt;
                    del self.authed_players[ctx.player]&lt;br /&gt;
        else:&lt;br /&gt;
            # tcp client, require seeded digest to match instead of pw&lt;br /&gt;
            if cmd.strip() == ctx.socket.correct_digest:&lt;br /&gt;
                self.authed_sockets[ctx.socket] = 1&lt;br /&gt;
                print &amp;#039;rcon: tcp client from %s:%d logged on&amp;#039; % ctx.socket.addr&lt;br /&gt;
                success = 1&lt;br /&gt;
            else:&lt;br /&gt;
                if self.authed_sockets.has_key(ctx.socket):&lt;br /&gt;
                    del self.authed_sockets[ctx.socket]&lt;br /&gt;
                print &amp;#039;rcon: tcp client from %s:%d failed pw challenge&amp;#039; % ctx.socket.addr&lt;br /&gt;
&lt;br /&gt;
        if success:&lt;br /&gt;
            ctx.write(&amp;#039;Authentication successful, rcon ready.\n&amp;#039;)&lt;br /&gt;
        else:&lt;br /&gt;
            ctx.write(&amp;#039;Authentication failed.\n&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
    # Lists rcon-authenticated players.&lt;br /&gt;
    def rcmd_users(self, ctx, cmd):&lt;br /&gt;
        ctx.write(&amp;#039;active rcon users:\n&amp;#039;)&lt;br /&gt;
        for id in self.authed_players:&lt;br /&gt;
            if id == -1:&lt;br /&gt;
                ctx.write(&amp;#039;-1 (local server console)\n&amp;#039;)&lt;br /&gt;
            else:&lt;br /&gt;
                try:&lt;br /&gt;
                    player = bf2.playerManager.getPlayerByIndex(id)&lt;br /&gt;
                except:&lt;br /&gt;
                    ctx.write(&amp;#039;%d (no info)\n&amp;#039; % (id))&lt;br /&gt;
&lt;br /&gt;
        for peer in self.authed_sockets:&lt;br /&gt;
            ctx.write(&amp;#039;tcp: %s:%d\n&amp;#039; % (peer.addr[0], peer.addr[1]))&lt;br /&gt;
&lt;br /&gt;
    # Executes a console command on the server.&lt;br /&gt;
    def rcmd_exec(self, ctx, cmd):&lt;br /&gt;
        ctx.write(host.rcon_invoke(cmd))&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                         F U N C T I O N S&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# These functions are called from the engine&lt;br /&gt;
# We implement them in terms of a class instance:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def init():&lt;br /&gt;
    print &amp;#039;initializing default admin/rcon module&amp;#039;&lt;br /&gt;
   &lt;br /&gt;
    # load (optional) admin scripts like teamkill punish and autobalance&lt;br /&gt;
    import standard_admin&lt;br /&gt;
&lt;br /&gt;
def shutdown():&lt;br /&gt;
    if server:&lt;br /&gt;
        print &amp;#039;shutting down default admin/rcon module&amp;#039;&lt;br /&gt;
        server.shutdown()&lt;br /&gt;
&lt;br /&gt;
def update():&lt;br /&gt;
    if server: server.update()&lt;br /&gt;
   # NB: Use with care!&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Returns a seed string of random characters to be used as a salt&lt;br /&gt;
# to protect password sniffing.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def make_seed(seed_length):&lt;br /&gt;
    return &amp;#039;&amp;#039;.join([string.ascii_letters[random.randint(0, len(string.ascii_letters)-1)] for x in xrange(0, seed_length)])&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Concats a seed string with the password and returns an ASCII-hex MD5 digest.&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def digest(seed, pw):&lt;br /&gt;
    if not pw: return None&lt;br /&gt;
    m = md5.new()&lt;br /&gt;
    m.update(seed)&lt;br /&gt;
    m.update(pw)&lt;br /&gt;
    return m.hexdigest()&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ---------------------------------------------------------------------&lt;br /&gt;
# Convert string to boolean:&lt;br /&gt;
# ---------------------------------------------------------------------&lt;br /&gt;
def boolFromString(str):&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Returns a true boolean value based on a boolean string&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   str = str(str)&lt;br /&gt;
   if str in [&amp;#039;True&amp;#039;, &amp;#039;true&amp;#039;, &amp;#039;1&amp;#039;]:&lt;br /&gt;
      return True&lt;br /&gt;
   elif value in [&amp;#039;False&amp;#039;, &amp;#039;false&amp;#039;, &amp;#039;0&amp;#039;]:&lt;br /&gt;
      return False&lt;br /&gt;
   else:&lt;br /&gt;
      #raise ValueError # Never mind errors...&lt;br /&gt;
      return False&lt;br /&gt;
# ---------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Parses the config file, if it&amp;#039;s there&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def parseConfig( file ):&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Function for loading a settings file&lt;br /&gt;
&lt;br /&gt;
   Arguments&lt;br /&gt;
   file: Path to the file to load&lt;br /&gt;
&lt;br /&gt;
   Description&lt;br /&gt;
   This function load a file with key-value-pairs on the form &amp;#039;key = value&amp;#039;,&lt;br /&gt;
   and updates the dictionary &amp;#039;options&amp;#039; accordingly.&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
   if a_info: print &amp;quot;ADMIN: Loading &amp;#039;%s&amp;#039;&amp;quot; % ( file )&lt;br /&gt;
&lt;br /&gt;
   try:&lt;br /&gt;
      config = open(file, &amp;#039;r&amp;#039;)&lt;br /&gt;
      lineNo = 0&lt;br /&gt;
      for line in config:&lt;br /&gt;
         lineNo += 1&lt;br /&gt;
         if line.strip() != &amp;#039;&amp;#039; and line.strip() != &amp;#039;\n&amp;#039;:&lt;br /&gt;
            try:&lt;br /&gt;
               ( key, value ) = line.split( &amp;#039; &amp;#039;, 1 )&lt;br /&gt;
               # remove white space&lt;br /&gt;
               value = value.strip()&lt;br /&gt;
               # remove outer quotes&lt;br /&gt;
               value = value.strip( &amp;#039;&amp;quot;&amp;#039; )&lt;br /&gt;
              &lt;br /&gt;
               if a_info: print &amp;quot;ADMIN: setting &amp;#039;%s&amp;#039; = &amp;#039;%s&amp;#039;&amp;quot; % ( key, value )&lt;br /&gt;
               if value == &amp;#039;allowBatching&amp;#039;: value = boolFromString (value)&lt;br /&gt;
               options[key] = value&lt;br /&gt;
&lt;br /&gt;
            except ValueError:&lt;br /&gt;
               if a_debug or a_info: print &amp;#039;ADMIN: WARNING - syntax error in &amp;quot;%s&amp;quot; on line %d&amp;#039; % (file, lineNo)&lt;br /&gt;
   except IOError, detail:&lt;br /&gt;
      if a_debug or a_info: print &amp;#039;ADMIN: WARNING - couldn\&amp;#039;t read &amp;quot;%s&amp;quot;: %s&amp;#039; % (file, detail)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Put stuff you need done by the end of round here&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
def onGameStatusChanged(status):&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;Handles changes in game status.&lt;br /&gt;
&lt;br /&gt;
   Arguments&lt;br /&gt;
   status: Integer indicating game status. (see bf2.GameStatus.*)&lt;br /&gt;
&lt;br /&gt;
   Description&lt;br /&gt;
   This function is registered with the server with host.registerGameStatusHandler(onGameStatusChanged),&lt;br /&gt;
   and its intended use is to reload adminsettnigs at the end of rounds, and other, similar tasks.&lt;br /&gt;
   &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
   global adminSettingsFile&lt;br /&gt;
   if a_debug: print &amp;quot;ADMIN: Entering onGameStatusChanged (&amp;quot; + str(status) +&amp;quot;)&amp;quot;&lt;br /&gt;
   if status == bf2.GameStatus.EndGame:&lt;br /&gt;
      parseConfig(adminSettingsFile)&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
#                        P R O G R A M&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Globalize the admin options:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
bf2.adminoptions = options&lt;br /&gt;
# Now other scripts might benefit from the settings stored in the&lt;br /&gt;
# adminsettings.con file!&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Load admin settings:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Figure out the &amp;quot;overlay&amp;quot; path:&lt;br /&gt;
mapListFileParts = host.rcon_invoke( &amp;#039;mapList.configFile&amp;#039; ).split( &amp;#039;/&amp;#039; );&lt;br /&gt;
del mapListFileParts[len( mapListFileParts ) - 1]&lt;br /&gt;
profileDir = &amp;quot;/&amp;quot;.join( mapListFileParts )&lt;br /&gt;
# Set the full path to our admin settings file:&lt;br /&gt;
adminSettingsFile = profileDir + &amp;quot;/adminsettings.con&amp;quot;&lt;br /&gt;
# parse the configuration file&lt;br /&gt;
parseConfig( adminSettingsFile )&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Register handlers:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Monitor game status:&lt;br /&gt;
host.registerGameStatusHandler(onGameStatusChanged)&lt;br /&gt;
# NB: &amp;#039;onGameStatusChanged&amp;#039; uses the variable &amp;#039;adminSettingsFile&amp;#039;!&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Enable debug logging:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
if a_debug or a_info: sys.stdout = sys.stderr = writer()&lt;br /&gt;
print &amp;quot;Logging enabled&amp;quot;&lt;br /&gt;
print &amp;quot;Starting rcon on port %s&amp;quot; % ( options[&amp;#039;admin.rconPort&amp;#039;] )&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
# Start the RCON server:&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
server = AdminServer(int(options[&amp;#039;admin.rconPort&amp;#039;]))&lt;br /&gt;
# ------------------------------------------------------------------------&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Updates ==&lt;br /&gt;
&lt;br /&gt;
Please add a note here if you update the code above.&lt;br /&gt;
&lt;br /&gt;
* 2005-06-18: Added documentation (Panic)&lt;br /&gt;
* 2005-06-17: Added v1.1 of the code (Panic)&lt;/div&gt;</summary>
		<author><name>Pireax</name></author>
	</entry>
</feed>