def main():
    args = _getParser().parse_args()
    token = input().encode('ascii')

    logPrefix = args.logPrefix + '-bots' if args.logPrefix else 'bots'
    if os.name == 'nt':
        logpath = data.getPath(data.user, 'authserver', 'logs')
        data.makeDirs(logpath)
        initLogging(
            logFile=os.path.join(logpath, 'log{}.txt'.format(logPrefix)))
    else:
        initLogging(prefix='[{}] '.format(logPrefix))

    reactor.callWhenRunning(_twisted_main, args, token)
    reactor.run()
Beispiel #2
0
def getFilename(alias, directory, ext, multipleFiles = True):
    # Figure out the filename to use for the main file
    gamePath = getPath(user, directory)
    makeDirs(gamePath)
    copyCount = 0
    succeeded = False
    if multipleFiles:
        while not succeeded:
            filename = '%s (%s)%s' % (alias, str(copyCount), ext)
            filePath = os.path.join(gamePath, filename)
            succeeded = not os.path.exists(filePath)
            copyCount += 1
    else:
        filename = '%s%s' % (alias, ext)
        filePath = os.path.join(gamePath, filename)
    return filePath
Beispiel #3
0
    def saveMap(self, filename, force=False):
        '''
        Saves the current map layout to the .trosnoth/maps directory.

        @param filename: The filename of the map (with extension)
        @param force: Overwrites the file if it already exists
        '''
        mapDir = getPath(user, 'maps')
        makeDirs(mapDir)
        filename = os.path.join(mapDir, filename)
        if os.path.exists(filename) and not force:
            return 'File already exists (use "force" parameter to overwrite)'

        with open(filename, 'w') as f:
            f.write(repr(self.getWorld().layout.dumpState()))
        return 'Map saved to %s' % (filename,)
Beispiel #4
0
    def __init__(self, dataPath=None, manholePassword=None):
        if dataPath is None:
            dataPath = getPath(data.user, 'authserver')
        makeDirs(dataPath)
        self.dataPath = dataPath
        self.manholePassword = None

        self.authManager = self.authManagerClass(dataPath)
        self.pubKey, self.privKey = self.loadKeys()
        self.arenaProxies = {}
        self.arenaAMPListener = None
        self.adminTokens = set()

        self.onArenaStarting = Event(['proxy'])
        self.onArenaStopped = Event(['proxy'])

        AuthenticationFactory.instance = self
Beispiel #5
0
    def __init__(self, dataPath=None):
        if dataPath is None:
            dataPath = getPath(data.user, 'authserver')
        makeDirs(dataPath)
        self.dataPath = dataPath

        self.onPrimaryGameChanged = Event()
        self.primaryGameId = None

        self.authManager = self.authManagerClass(dataPath)
        self.pubKey, self.privKey = self.loadKeys()
        self.servers = {}  # Game id -> game.
        self.nextId = 0
        self.registeredGames = []
        self.gameStats = {}

        self.layoutDatabase = LayoutDatabase()

        self.notifier = self.settings.createNotificationClient()
        if self.notifier is not None:
            self.notifier.startService()
Beispiel #6
0
    def _addDatastoreByPaths(self, *paths):
        for path in paths:
            try:
                makeDirs(path)
            except (OSError, WindowsError):
                log.warning('Could not create datastore path')
                return

        store = LayoutDatastore(pathGetter=self.pathGetter)
        self.datastores.append(store)

        # Read map blocks from files.
        for path in paths:
            filenames = os.listdir(path)

            # Go through all files in the blocks directory.
            for fn in filenames:
                # Check for files with a .block extension.
                if os.path.splitext(fn)[1] == '.block':
                    store.addLayoutAtFilename(os.path.join(path, fn))
        return store
Beispiel #7
0
    def refresh(self):
        # Get a list of files with the name '*.tros'
        logDir = getPath(user, gameDir)
        makeDirs(logDir)
        self.games = []

        for fname in os.listdir(logDir):
            if os.path.splitext(fname)[1] != gameExt:
                continue

            try:
                game = RecordedGame(os.path.join(logDir, fname))
            except RecordedGameException:
                continue

            if game.recordedGameVersion != recordedGameVersion:
                continue

            self.games.append(game)

        self.games.sort(key=lambda game: (-game.unixTimestamp, game.filename))
def generateHtml(htmlPath, statPath):
    def plural(value):
        if value == 1:
            return ''
        else:
            return 's'

    def add(value, statName=None, altText=None, spacing=True, className=None):
        if altText is not None:
            points = POINT_VALUES[altText] * value
            if type(points) == float:
                points = '%2.2f' % points
            altText = ' title="%s point%s\"' % (points, plural(points))
        else:
            altText = ''

        if className is not None:
            classText = ' class="%s"' % (className)
        else:
            classText = ''

        if type(value) == float:
            value = '%2.2f' % value

        if statName is None:
            html.append('\t\t\t\t<td%s%s>%s</td>' %
                        (altText, classText, value))
        else:
            nbsp = ''
            if spacing is False:
                pluralStr = ''
            else:
                nbsp = '&nbsp;'
                pluralStr = plural(value)
            html.append('\t\t\t\t<td%s>%s%s%s%s</td>' %
                        (altText, value, nbsp, statName, pluralStr))

    def addList(title, data):
        html.append('\t\t\t\t\t<li><b>%s:</b> ' % title)

        if len(data) == 0:
            html.append('\t\t\t\t\t\tNone')
        else:
            data = sorted(list(data.items()),
                          key=operator.itemgetter(1),
                          reverse=True)
            string = []
            for details in data:
                string.append('%s (%d)' % details)
            html.append('\t\t\t\t\t\t' + ', '.join(string))

        html.append('\t\t\t\t\t</li>')

    def accuracy(shotsHit, shotsFired):
        try:
            return ((shotsHit**2) / (shotsFired + 0.0)) * 30
        except ZeroDivisionError:
            return 0

    from trosnoth.gamerecording.gamerecorder import statDir

    makeDirs(statDir)

    if statPath == '':
        files = os.listdir(statDir)
    else:
        files = [statPath]

    playerStats = {}
    statNames = [
        'aliveStreak', 'deaths', 'killStreak', 'kills', 'roundsLost',
        'roundsWon', 'shotsFired', 'shotsHit', 'coinsEarned', 'coinsUsed',
        'coinsWasted', 'tagStreak', 'timeAlive', 'timeDead', 'zoneAssists',
        'zoneTags'
    ]
    statEnemies = ['playerDeaths', 'playerKills', 'upgradesUsed']
    leaders = list(
        map(str.lower,
            list(leaderAchievements.keys()) + list(additionalLeaders.keys())))

    tableHeaders = [
        [
            '#', 'Nick', 'Kills', 'Deaths', 'KDR', 'Zone Tags', 'Shots Fired',
            'Shots Hit', 'Accuracy', 'Coins Used', 'Killed the most:',
            'Died the most to:', 'Points'
        ],
        [
            '#', 'Nick', 'Coins Earned', 'Coins Used', 'Coins Wasted',
            'Favourite Upgrade', 'Time Alive', 'Time Dead', 'ADR',
            'Longest Life', 'Points'
        ],
        [
            '#', 'Nick', 'Kills', 'Kill Streak', 'Zone Tags', 'Zone Assists',
            'Tag Streak', 'Points'
        ],
    ]

    tableNames = ['General Overview', 'Coins and Time', 'Kills and Tags']

    for x in range(0, len(tableNames)):
        style = ''
        if x == 0:
            style = " style='color: black;'"
        tableNames[x] = ('<span class="name topLink" id="link%s" '
                         'onClick="navigate(\'%s\', %d)"%s>%s</span>' %
                         (x, x, len(tableHeaders[x]), style, tableNames[x]))

    navigation = ' &ndash; '.join(tableNames)

    html = []
    fileMatrix = {}

    for filename in files:

        if filename[-9:] != '.trosstat':
            filename = filename + '.trosstat'
        statLocation = os.path.join(statPath, filename)

        try:
            statFile = open(statLocation)
        except IOError:
            raise Exception("'%s' does not exist!" % filename)

        loadedStats = simplejson.load(statFile)

        for nick in loadedStats['players']:
            if nick not in playerStats:
                playerStats[nick] = loadedStats['players'][nick]
                fileMatrix[nick] = [filename]
            else:
                for stat in statNames:
                    playerStats[nick][stat] += (
                        loadedStats['players'][nick][stat])
                for stat in statEnemies:
                    for enemy in loadedStats['players'][nick][stat]:
                        if enemy not in playerStats[nick][stat]:
                            playerStats[nick][stat][enemy] = 0
                        playerStats[nick][stat][enemy] += (
                            loadedStats['players'][nick][stat][enemy])
                fileMatrix[nick].append(filename)

    ranking = {}
    allData = {}

    for nick in playerStats:
        data = playerStats[nick]
        try:
            data['accuracy'] = (100.0 * data['shotsHit']) / data['shotsFired']
        except ZeroDivisionError:
            data['accuracy'] = 0

        for stat in statEnemies:
            data[stat + 'Full'] = data[stat].copy()
            highest = 0
            highestName = '----'
            names = data[stat]
            for k, v in list(names.items()):
                if v > highest:
                    highest = v
                    highestName = k
            if highest == 0:
                data[stat] = highestName
            else:
                data[stat] = '%s (%s)' % (highestName, highest)

        data['score'] = 0
        for stat, value in list(POINT_VALUES.items()):
            points = data[stat] * value
            data['score'] += points

        try:
            data['kdr'] = '%2.2f' % (float(data['kills']) / data['deaths'])
        except ZeroDivisionError:
            data['kdr'] = '----'

        try:
            data['adr'] = '%2.2f' % (float(data['timeAlive']) /
                                     data['timeDead'])
        except ZeroDivisionError:
            data['adr'] = '----'

        ranking[nick] = data['score']
        allData[nick] = data

    rankingList = sorted(list(ranking.items()),
                         key=operator.itemgetter(1),
                         reverse=True)
    ranking = {}

    rankCount = 0

    html.append("\t\t<table class='ladder'>")

    for count in range(0, len(tableNames)):
        style = ''
        if count != 0:
            style = " style='display: none;'"
        html.append("\t\t\t<tr class='allRows group%s'%s>" % (count, style))
        for caption in tableHeaders[count]:
            html.append('\t\t\t\t<th>%s</th>' % caption)
        html.append('\t\t\t</tr>')

    teamNames = ('Blue', 'Red')
    if 'winningTeamId' in loadedStats:
        winningTeamId = loadedStats['winningTeamId']
        if winningTeamId == b'A':
            winText = '%s Team won' % (teamNames[0], )
            colour = 'navy'
        elif winningTeamId == b'B':
            winText = '%s Team won' % (teamNames[1], )
            colour = 'maroon'
        else:
            winText = 'Game was a draw'
            colour = 'green'
    else:
        winText = 'Game was not finished'
        colour = 'gray'

    html.append('<p class="wintext" style="color: %s;">%s</p>' %
                (colour, winText))
    for pair in rankingList:

        nick = pair[0]
        rankCount += 1
        rankStr = str(rankCount)

        classy = ''
        if stripPunctuation(nick).lower() in leaders:
            classy = ' leader'
            rankCount -= 1
            rankStr = '--'

        data = allData[nick]

        if data['bot']:
            classy = ' bot'
            rankCount -= 1
            rankStr = 'B'

        if sys.version_info.major == 2:
            nickId = ''.join('{:02x}'.format(ord(c))
                             for c in 'abc'.encode('utf-8'))
        else:
            nickId = ''.join('{:02x}'.format(c for c in 'abc'.encode('utf-8')))

        for count in range(0, len(tableNames)):

            style = ''
            if count != 0:
                style = " style='display: none;'"

            html.append("\t\t\t<tr class='allRows group%s%s'%s>" %
                        (count, classy, style))
            if (data['team'] == b'A'):
                bgColour = 'blueteam'
            elif (data['team'] == b'B'):
                bgColour = 'redteam'
            elif (data['team'] == NEUTRAL_TEAM_ID):
                bgColour = 'rogue'
            add('<strong>%s</strong>' % rankStr, className=bgColour)
            add('<span class="name" onClick="toggle(\'details-%s\')">%s</span>'
                % (nickId, nick))

            if count == 0:
                add(data['kills'], 'kill', 'kills')
                add(data['deaths'], 'death', 'deaths')
                add(data['kdr'])
                add(data['zoneTags'], 'tag', 'zoneTags')
                add(data['shotsFired'], 'shot')
                add(data['shotsHit'], 'shot')
                add(data['accuracy'], '%', 'accuracy', False)
                add(data['coinsUsed'], 'coin', 'coinsUsed')
                add(data['playerKills'])
                add(data['playerDeaths'])
            elif count == 1:
                add(data['coinsEarned'], 'coin')
                add(data['coinsUsed'], 'coin', 'coinsUsed')
                add(data['coinsWasted'], 'coin')
                add(data['upgradesUsed'])
                add(int(data['timeAlive']), 'second')
                add(int(data['timeDead']), 'second')
                add(data['adr'])
                add(int(data['aliveStreak']), 'second')
            elif count == 2:
                add(data['kills'], 'kill', 'kills')
                add(data['killStreak'], 'kill')
                add(data['zoneTags'], 'tag', 'zoneTags')
                add(data['zoneAssists'], 'assist', 'zoneAssists')
                add(data['tagStreak'], 'zone')
            elif count == 3:
                add(data['shotsFired'], 'shot')
                add(data['shotsHit'], 'shot')
                add(data['accuracy'], '%', spacing=False)
                old = data['accuracy'] * 20
                new = accuracy(data['shotsHit'], data['shotsFired'])
                add(old, 'point')
                add(new, 'point')
                add(new - old)

            add('<strong>%2.2f</strong>' % data['score'])
            html.append('\t\t\t</tr>')

            if count == len(tableNames) - 1:
                html.append(
                    "\t\t\t<tr id='details-%s' style='display: none;'>" %
                    nickId)
                html.append("\t\t\t\t<td colspan='%d' class='details'"
                            "style='text-align: left;'>" %
                            len(tableHeaders[0]))
                html.append('\t\t\t\t\t<ul>')

                addList('Players killed', data['playerKillsFull'])
                addList('Players died to', data['playerDeathsFull'])
                addList('Upgrades used', data['upgradesUsedFull'])

                html.append('\t\t\t\t\t</ul>')
                html.append('\t\t\t\t</td>')
                html.append('\t\t\t</tr>')

    html.append('\t\t</table>')

    html = '\n' + '\n'.join(html) + '\n'

    baseHTML = open(getPath(statGeneration, 'statGenerationBase.htm'),
                    'r').read()

    html = baseHTML.replace('[[TABLE]]', html)
    html = html.replace('[[NAVIGATION]]', navigation)

    with open(htmlPath, 'w') as f:
        f.write(html)
    def populateList(self):

        defaultTheme = {
            "name": "Default Theme",
            "filename": "default",
            "author": "Trosnoth Team",
            "content": None,
            "source": "internal"
        }

        # Clear out the sidebar
        self.themeNameText.setText('')
        self.themeAuthorText.setText('')
        for element in self.contents:
            element.setText('')
        self.useThemeButton.setText('')
        self.restartButton.setText('')
        self.listHeaderText.setText('available themes:')
        self.themeList.index = -1

        userThemeDir = getPath(user, 'themes')
        internalThemeDir = getPath(themes)
        makeDirs(userThemeDir)

        themeList = []

        # Get a list of internal themes
        for dirName in os.listdir(internalThemeDir):
            if os.path.isdir(os.path.join(internalThemeDir, dirName)):
                themeList.append("i/%s" % dirName)

        # Get a list of user-defined themes
        for dirName in os.listdir(userThemeDir):
            if os.path.isdir(os.path.join(userThemeDir, dirName)):
                # Internal themes overrule user-defined themes
                if "i/" + dirName not in themeList and dirName != "default":
                    themeList.append("u/%s" % dirName)

        # Assume all themes are valid for now
        validThemes = themeList[:]

        self.themeInfo = {}

        for themeName in themeList:
            themeInfo = {"content": {}}

            if themeName.startswith("i/"):
                themeInfo['source'] = 'internal'
                directory = internalThemeDir
            else:
                themeInfo['source'] = 'user-defined'
                directory = userThemeDir

            themeNameList = themeName
            themeName = themeName[2:]

            themeInfo['filename'] = themeName[2:]

            anyContent = False

            for contentType in list(self.contentTypes.keys()):
                if themeInfo['source'] == 'internal':
                    contentDir = os.path.join(directory, themeName,
                                              contentType)
                else:
                    contentDir = os.path.join(directory, themeName,
                                              contentType)

                if not os.path.isdir(contentDir):
                    continue
                else:
                    fileCount = len([
                        f for f in os.listdir(contentDir)
                        if os.path.isfile(os.path.join(contentDir, f))
                    ])
                    if fileCount > 0:
                        anyContent = True
                        themeInfo["content"][contentType] = fileCount

            if not anyContent:
                validThemes.remove(themeNameList)
                continue

            infoFile = os.path.join(directory, themeName, "info.txt")
            if os.path.isfile(infoFile):
                infoFile = open(infoFile)
                infoContents = infoFile.readlines()
            else:
                infoContents = []

            if len(infoContents) >= 2:
                themeInfo["author"] = infoContents[1].strip()
            else:
                themeInfo["author"] = None

            if len(infoContents) >= 1:
                themeInfo["name"] = infoContents[0].strip()
            else:
                themeInfo["name"] = themeName

            self.themeInfo[themeName] = themeInfo

        self.themeInfo["default"] = defaultTheme

        # Sort the themes alphabetically
        items = [(v['filename'], n) for n, v in self.themeInfo.items()]
        items.sort()
        items = [n for v, n in items]
        self.themeList.setItems(items)

        if len(self.themeInfo) == 1:
            self.listHeaderText.setText("1 available theme:")
            self.themeList.index = 0
            self.updateSidebar(0)
        else:
            self.listHeaderText.setText("%d available themes:" %
                                        len(self.themeInfo))
Beispiel #10
0
def startServer(port=6787,
                dataPath=None,
                manholePort=6799,
                password=None,
                webPort=None):

    # Ensure that the authserver directories exist
    authDir = getPath(user, 'authserver', 'accounts')
    makeDirs(authDir)

    # Ensure that any database migrations have happened
    management.call_command('migrate')

    # If murmur communication is enabled, try to connect
    if murmur.init() == 'initialised':
        reactor.addSystemEventTrigger('before', 'shutdown',
                                      murmur.tearDownRooms)

    dbqueue.init()

    pf = AuthenticationFactory(dataPath)

    def getManholeFactory(namespace, password):
        realm = manhole_ssh.TerminalRealm()

        # If we don't do this, the server will generate an exception when
        # you resize the SSH window
        def windowChanged(self, size):
            pass

        realm.sessionFactory.windowChanged = windowChanged

        def getManhole(_):
            return Manhole(namespace)

        realm.chainedProtocolFactory.protocolFactory = getManhole
        p = portal.Portal(realm)

        # Username/Password authentication
        passwordDB = checkers.InMemoryUsernamePasswordDatabaseDontUse()
        passwordDB.addUser('trosnoth', password)
        p.registerChecker(passwordDB)

        factory = manhole_ssh.ConchFactory(p)

        privatePath = getPath(user, 'authserver', 'manhole_rsa')
        if os.path.isfile(privatePath):
            factory.privateKeys[b'ssh-rsa'] = keys.Key.fromFile(privatePath)
        publicPath = privatePath + '.pub'
        if os.path.isfile(publicPath):
            factory.publicKeys[b'ssh-rsa'] = keys.Key.fromFile(publicPath)

        return factory

    if password is None:
        password = ''.join(random.choice('0123456789') for i in range(6))

    namespace = {}
    namespace['authFactory'] = pf
    namespace['helper'] = AuthServerManholeHelper(pf)
    factory = getManholeFactory(namespace, password)

    try:
        reactor.listenTCP(manholePort, factory)
    except CannotListenError:
        log.error('Error starting manhole on port %d', manholePort)
    except ConchError as e:
        log.error('Error starting manhole on port %d: %s', manholePort,
                  e.value)
    else:
        log.warning('SSH manhole started on port %d with password %r',
                    manholePort, password)

    if webPort is not None:
        from trosnoth.web.server import startWebServer
        startWebServer(pf, webPort)

    try:
        reactor.listenTCP(port, pf)
    except CannotListenError:
        log.error('Error listening on port %d.', port)
    else:
        log.info('Started Trosnoth authentication server on port %d.', port)
        reactor.run()
Beispiel #11
0
'''

from configparser import ConfigParser
import logging
import os
import socket

from django.core.management.utils import get_random_secret_key
from trosnoth import data

log = logging.getLogger(__name__)

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

data.makeDirs(data.getPath(data.user, 'authserver'))
CONFIG_PATH = data.getPath(data.user, 'authserver', 'config')
config = ConfigParser(interpolation=None)
config.add_section('security')
config.add_section('web')
config.read(CONFIG_PATH)

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config.get('security', 'key', fallback=None)
if not SECRET_KEY:
    SECRET_KEY = get_random_secret_key().replace('%', '-')
    config.set('security', 'key', SECRET_KEY)
    with open(CONFIG_PATH, 'w') as f:
Beispiel #12
0
    def populateList(self, sender=None):

        # Clear out the sidebar
        for item in self.dynamicText:
            item.setText('')
        self.listHeaderText.setText('available game files:')
        self.gameList.index = -1
        self.elements = self.elementsFiles[:]

        # Get a list of files with the name '*.tros'
        logDir = getPath(user, gameDir)
        makeDirs(logDir)
        fileList = []

        for fname in os.listdir(logDir):
            if os.path.splitext(fname)[1] == gameExt:
                fileList.append(fname)

        # Assume all files are valid for now
        validFiles = fileList[:]

        self.gameInfo = {}
        oldFound = False

        for fname in fileList:
            try:
                game = RecordedGame(os.path.join(logDir, fname))
            except RecordedGameException:
                validFiles.remove(fname)
                continue
            except:
                log.warning('invalid file: %s', fname)
                continue
            else:
                if game.recordedGameVersion != recordedGameVersion:
                    validFiles.remove(fname)
                    oldFound = True

            self.gameInfo[os.path.splitext(fname)[0]] = game

        # Sort the games with most recent first.
        items = [(v.unixTimestamp, n) for n, v in self.gameInfo.iteritems()]
        items.sort(reverse=True)
        items = [n for v, n in items]
        self.gameList.setItems(items)

        if len(self.gameInfo) == 0:
            self.elements = self.elementsNoFiles[:]
            self.listHeaderText.setText('0 available game files:')
            if oldFound:
                self.noFiles1Text.setText('Some games were found from')
                self.noFiles2Text.setText('previous Trosnoth versions')
            else:
                self.noFiles1Text.setText('You have not yet run any')
                self.noFiles2Text.setText('games on this computer')
        else:
            self.gameList.setIndex(0)
            self.updateSidebar(0)
            if len(self.gameInfo) == 1:
                self.listHeaderText.setText('1 available game file:')
            else:
                self.listHeaderText.setText('{} available game files:'.format(
                    len(self.gameInfo)))