all latent changes, undisclosed and without warranty.

This commit is contained in:
Gabor Körber 2014-10-20 18:47:28 +02:00
parent 8411ed858c
commit 10c557dea3
10 changed files with 180 additions and 23 deletions

View File

@ -27,31 +27,39 @@ if __name__ == '__main__':
'Documents', 'My Games', 'sc')) 'Documents', 'My Games', 'sc'))
coll.collect_unique() coll.collect_unique()
#f = open('output.txt', 'w') #f = open('output.txt', 'w')
rex = {} rex_combat = {}
rex_game = {}
for logf in coll.sessions: for logf in coll.sessions:
logf.parse_files(['game.log',]) logf.parse_files(['game.log', 'combat.log'])
print "Combat Log %s" % logf.idstr print "----- Log %s -----" % logf.idstr
if logf.combat_log: if logf.combat_log:
for l in logf.combat_log.lines: for l in logf.combat_log.lines:
if isinstance(l, dict): if isinstance(l, dict):
#print l #print l
pass rex_combat['dict'] = rex_combat.get('dict', 0) + 1
else: else:
if not l.unpack(): if not l.unpack():
rex[l.__class__.__name__] = rex.get(l.__class__.__name__, 0) + 1 rex_combat[l.__class__.__name__] = rex_combat.get(l.__class__.__name__, 0) + 1
if not isinstance(l, combat.UserEvent): if not isinstance(l, combat.UserEvent):
print l.values['log'] print l.values['log']
if logf.game_log: if logf.game_log:
for l in logf.game_log.lines: for l in logf.game_log.lines:
if isinstance(l, dict): if isinstance(l, dict):
pass rex_game['dict'] = rex_game.get('dict', 0) + 1
elif isinstance(l, str):
print l
else: else:
if l.unpack(): if l.unpack():
pass pass
else: else:
rex_game[l.__class__.__name__] = rex_game.get(l.__class__.__name__, 0) + 1
print l.values['log'] print l.values['log']
# ClientInfo introspection for ping # ClientInfo introspection for ping
if isinstance(l, ClientInfo) and l.values.get('clinfo', '') == 'avgPing': #if isinstance(l, ClientInfo) and l.values.get('clinfo', '') == 'avgPing':
print l.values # print l.values
# fix avgPing parsing! # # fix avgPing parsing!
print rex print 'Analysis complete:'
print '#'*20+' RexCombat ' + '#' *20
print rex_combat
print '#'*20+' RexGame ' + '#' *20
print rex_game

View File

@ -1,2 +1,33 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""
Tool to analyze Logs in general.
"""
import os, sys, logging
from logs.logfiles import LogFileResolver as LogFile
from logs import combat, game, chat
from logs.session import LogSessionCollector
from logs.game import ClientInfo
# for windows its kinda this:
settings = {'root_path': os.path.join(os.path.expanduser('~'),
'Documents',
'My Games',
'StarConflict',),
'logfiles': os.path.join(os.path.expanduser('~'),
'Documents',
'My Games',
'StarConflict',
'logs'
)}
if __name__ == '__main__':
coll = LogSessionCollector(os.path.join(os.path.expanduser('~'),
'Documents', 'My Games', 'sc'))
coll.collect_unique()
for logf in coll.sessions:
logf.parse_files(['game.log', 'combat.log'])
logf.clean()
if logf.combat_log:
print 'length combat log ', len(logf.combat_log.lines)
if logf.game_log:
print 'length game log ', len(logf.game_log.lines)

View File

@ -28,6 +28,7 @@ QUALITY_TYPES = (
(5, 'Mk5'), (5, 'Mk5'),
(10, 'Universal'), (10, 'Universal'),
(14, 'Pirate Mk4'), (14, 'Pirate Mk4'),
(99, 'Alien'),
) )
D_QUALITY = dict(QUALITY_TYPES) D_QUALITY = dict(QUALITY_TYPES)
@ -51,9 +52,13 @@ ROLE_TYPES = (
(6, 'Gunship'), (6, 'Gunship'),
(7, 'Engineer'), (7, 'Engineer'),
(8, 'Guard'), (8, 'Guard'),
(9, 'Longrange') (9, 'Longrange'),
(10, 'Interceptors'),
(20, 'Fighters'),
(30, 'Frigates'),
) )
# Create your models here.
class Item(models.Model): class Item(models.Model):
name = models.CharField(max_length=128) name = models.CharField(max_length=128)
description = models.TextField(blank=True, null=True) description = models.TextField(blank=True, null=True)

View File

@ -5,13 +5,25 @@
""" """
class Battle(object): class Battle(object):
__slots__ = ['players',
'teams',
'time_start',
'time_end',]
def __init__(self, parent=None): def __init__(self, parent=None):
# parent is a log-session usually # parent is a log-session usually
self.players = []
self.teams = []
self.time_start = None
self.time_end = None
self.owner = None
def battle_factory(logs):
''' takes a log session and returns the battles in it
makes a preliminary scan for information
'''
if logs.combat_log and logs.game_log:
# without these it does not make sense
# check combat_log
pass pass
return []

28
game/screener.py Normal file
View File

@ -0,0 +1,28 @@
#
#
#
"""
Screener Module.
Upon receiving a logfile, the screener module tries a first pass to retrieve the informations:
- who am i? am i in steam?
- which os do i use? whats the date? other specifics?
- battles, when did they begin, when did they end, which players were in it, which teams (game.log)
It should act as a factory for a second, more in depth parsing mechanism, which can retrieve and
manage the rest of the details.
"""
class Information:
def __init__(self):
self.steam_id = None # steam id
self.steam_username = None # optional steam username.
self.username = None # ingame username.
self.uid = None # does not change.
self.pid = None # changes per battle. needed once to identify pilot.
class Screener(object):
def __init__(self):
pass

View File

@ -92,11 +92,14 @@ class WarningLog(Log):
# Individual logs. # Individual logs.
class SteamInitialization(GameLog): class SteamInitialization(GameLog):
matcher = [] matcher = [
re.compile(r"^Steam\sinitialized\sappId\s(?P<steam_app_id>\d+),\suserSteamID\s(?P<steam_id_universe>\d+)\|(?P<steam_id_type>\d+)\|(?P<steam_id_account_hex>\w+),\suserName\s'(?P<steam_username>[^']+)'"),
]
class MasterServerSession(GameLog): class MasterServerSession(GameLog):
matcher = [ matcher = [
re.compile(r"^MasterServerSession\:\sconnect\sto\sdedicated\sserver(?:,\s|session\s(?P<session_id>\d+)|at addr (?P<addr>\d+\.\d+\.\d+\.\d+)\|(?P<port>\d+))+"), re.compile(r"^MasterServerSession\:\sconnect\sto\sdedicated\sserver(?:,\s|session\s(?P<session_id>\d+)|at addr (?P<addr>\d+\.\d+\.\d+\.\d+)\|(?P<port>\d+))+"),
re.compile(r"^MasterServerSession:\sconnect\sto\sZoneInstance,\ssession\s(?P<session_id>\d+),\sat\saddr\s(?P<addr>\d+\.\d+\.\d+\.\d+)\|(?P<port>\d+),\szoneId\s(?P<zone_id>\d+)"),
] ]
@classmethod @classmethod

View File

@ -9,6 +9,7 @@
data by setting the LogFile<instance>._data yourself. data by setting the LogFile<instance>._data yourself.
""" """
import re import re
from .base import Log
RE_SCLOG = r'^(?P<hh>\d{2,2})\:(?P<mm>\d{2,2})\:(?P<ss>\d{2,2})\.(?P<ns>\d{3,3})\s(?P<logtype>\s*[^\|\s]+\s*|\s+)\|\s(?P<log>.*)' RE_SCLOG = r'^(?P<hh>\d{2,2})\:(?P<mm>\d{2,2})\:(?P<ss>\d{2,2})\.(?P<ns>\d{3,3})\s(?P<logtype>\s*[^\|\s]+\s*|\s+)\|\s(?P<log>.*)'
R_SCLOG = re.compile(RE_SCLOG) R_SCLOG = re.compile(RE_SCLOG)
@ -34,6 +35,15 @@ class LogFile(object):
def _unset_data(self): def _unset_data(self):
self._data = None self._data = None
def filter(self, klasses):
ret = []
for line in self.lines:
for k in klasses:
if isinstance(line, k):
ret.append(line)
break
return ret
def parse(self): def parse(self):
# parse _data if we still have no lines. # parse _data if we still have no lines.
if self._data: if self._data:
@ -84,3 +94,17 @@ class LogFile(object):
# try to find a class that is responsible for this log. # try to find a class that is responsible for this log.
return line return line
def clean(self):
# cleans the logs by removing all non parsed packets.
lines = []
for l in self.lines:
if isinstance(l, Log):
if l.unpack():
if not getattr(l, 'trash', False):
lines.append(l)
else:
print type(l)
print l
self.lines = lines
self._unset_data()

View File

@ -15,6 +15,7 @@ class LogSession(object):
''' if directory is a file, it will be handled as a compressed folder ''' ''' if directory is a file, it will be handled as a compressed folder '''
self.battles = [] self.battles = []
self.user = None self.user = None
self.files_parsed = []
# various logfiles used. # various logfiles used.
self.combat_log = None self.combat_log = None
@ -27,6 +28,15 @@ class LogSession(object):
self.idstr = None # id string to identify this log instance. self.idstr = None # id string to identify this log instance.
self._error = False self._error = False
def clean(self):
if self.combat_log:
self.combat_log.clean()
if self.game_log:
self.game_log.clean()
if self.chat_log:
self.chat_log.clean()
def validate(self, contents=False): def validate(self, contents=False):
""" """
- validates if the logfiles are within this package. - validates if the logfiles are within this package.
@ -56,14 +66,18 @@ class LogSession(object):
if self._zip_source: if self._zip_source:
self._unzip_logs(files) self._unzip_logs(files)
else: else:
if 'combat.log' in files: if files is None:
files = self.VALID_FILES
if 'combat.log' in files and not 'combat.log' in self.files_parsed:
self.combat_log = CombatLogFile(os.path.join(self.directory, 'combat.log')) self.combat_log = CombatLogFile(os.path.join(self.directory, 'combat.log'))
self.combat_log.read() self.combat_log.read()
self.combat_log.parse() self.combat_log.parse()
if 'game.log' in files: self.files_parsed.append('combat.log')
if 'game.log' in files and not 'game.log' in self.files_parsed:
self.game_log = GameLogFile(os.path.join(self.directory, 'game.log')) self.game_log = GameLogFile(os.path.join(self.directory, 'game.log'))
self.game_log.read() self.game_log.read()
self.game_log.parse() self.game_log.parse()
self.files_parsed.append('game.log')
def determine_owner(self): def determine_owner(self):
''' determines the user in the parsed gamelog ''' ''' determines the user in the parsed gamelog '''
@ -80,12 +94,16 @@ class LogSession(object):
fn = os.path.split(filename)[1] or '' fn = os.path.split(filename)[1] or ''
fn = fn.lower() fn = fn.lower()
if fn: if fn:
if fn == 'combat.log' and (not files or fn in files): if fn == 'combat.log' and (not files or fn in files) and not 'combat.log' in self.files_parsed:
self.combat_log = CombatLogFile(fn) self.combat_log = CombatLogFile(fn)
self.combat_log.set_data(z.read(filename)) self.combat_log.set_data(z.read(filename))
elif fn == 'game.log' and (not files or fn in files): self.combat_log.parse()
self.files_parsed.append('combat.log')
elif fn == 'game.log' and (not files or fn in files) and not 'game.log' in self.files_parsed:
self.game_log = GameLogFile(fn) self.game_log = GameLogFile(fn)
self.game_log.set_data(z.read(filename)) self.game_log.set_data(z.read(filename))
self.game_log.parse()
self.files_parsed.append('game.log')
except: except:
self._error = True self._error = True
return return

0
utils/__init__.py Normal file
View File

28
utils/steam.py Normal file
View File

@ -0,0 +1,28 @@
"""
X:Y:Z
X - Universe
0 Individual / Unspecified
1 Public
2 Beta
3 Internal
4 Dev
5 RC
Y - Steam Type
0 I Invalid No
1 U Individual Yes profiles / id 0x0110000100000000
2 M Multiseat Yes
3 G GameServer Yes
4 A AnonGameServer Yes
5 P Pending No
6 C ContentServer Unknown
7 g Clan Yes groups / gid 0x0170000000000000
8 c, L, T Chat Yes
9 P2P SuperSeeder No
10 AnonUser No
Z - account or group uid
"""