From 10c557dea396bbf5b5878d8cbab9eb63b3c0b4e4 Mon Sep 17 00:00:00 2001 From: Gabor Guzmics Date: Mon, 20 Oct 2014 18:47:28 +0200 Subject: [PATCH] all latent changes, undisclosed and without warranty. --- analyze.py | 28 ++++++++++++++++++---------- battle.py | 31 +++++++++++++++++++++++++++++++ dj/scon/models.py | 9 +++++++-- game/battle.py | 22 +++++++++++++++++----- game/screener.py | 28 ++++++++++++++++++++++++++++ logs/game.py | 7 +++++-- logs/logfile.py | 24 ++++++++++++++++++++++++ logs/session.py | 26 ++++++++++++++++++++++---- utils/__init__.py | 0 utils/steam.py | 28 ++++++++++++++++++++++++++++ 10 files changed, 180 insertions(+), 23 deletions(-) create mode 100644 game/screener.py create mode 100644 utils/__init__.py create mode 100644 utils/steam.py diff --git a/analyze.py b/analyze.py index 79a4607..e521d94 100644 --- a/analyze.py +++ b/analyze.py @@ -27,31 +27,39 @@ if __name__ == '__main__': 'Documents', 'My Games', 'sc')) coll.collect_unique() #f = open('output.txt', 'w') - rex = {} + rex_combat = {} + rex_game = {} for logf in coll.sessions: - logf.parse_files(['game.log',]) - print "Combat Log %s" % logf.idstr + logf.parse_files(['game.log', 'combat.log']) + print "----- Log %s -----" % logf.idstr if logf.combat_log: for l in logf.combat_log.lines: if isinstance(l, dict): #print l - pass + rex_combat['dict'] = rex_combat.get('dict', 0) + 1 else: 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): print l.values['log'] if logf.game_log: for l in logf.game_log.lines: if isinstance(l, dict): - pass + rex_game['dict'] = rex_game.get('dict', 0) + 1 + elif isinstance(l, str): + print l else: if l.unpack(): pass else: + rex_game[l.__class__.__name__] = rex_game.get(l.__class__.__name__, 0) + 1 print l.values['log'] # ClientInfo introspection for ping - if isinstance(l, ClientInfo) and l.values.get('clinfo', '') == 'avgPing': - print l.values - # fix avgPing parsing! - print rex + #if isinstance(l, ClientInfo) and l.values.get('clinfo', '') == 'avgPing': + # print l.values + # # fix avgPing parsing! + print 'Analysis complete:' + print '#'*20+' RexCombat ' + '#' *20 + print rex_combat + print '#'*20+' RexGame ' + '#' *20 + print rex_game diff --git a/battle.py b/battle.py index 5bcfe9b..8b81c05 100644 --- a/battle.py +++ b/battle.py @@ -1,2 +1,33 @@ #!/usr/bin/python # -*- 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) \ No newline at end of file diff --git a/dj/scon/models.py b/dj/scon/models.py index 8666ab7..ad2244e 100644 --- a/dj/scon/models.py +++ b/dj/scon/models.py @@ -28,6 +28,7 @@ QUALITY_TYPES = ( (5, 'Mk5'), (10, 'Universal'), (14, 'Pirate Mk4'), + (99, 'Alien'), ) D_QUALITY = dict(QUALITY_TYPES) @@ -51,9 +52,13 @@ ROLE_TYPES = ( (6, 'Gunship'), (7, 'Engineer'), (8, 'Guard'), - (9, 'Longrange') + (9, 'Longrange'), + (10, 'Interceptors'), + (20, 'Fighters'), + (30, 'Frigates'), ) -# Create your models here. + + class Item(models.Model): name = models.CharField(max_length=128) description = models.TextField(blank=True, null=True) diff --git a/game/battle.py b/game/battle.py index 33891d5..1a3e64d 100644 --- a/game/battle.py +++ b/game/battle.py @@ -5,13 +5,25 @@ """ class Battle(object): - __slots__ = ['players', - 'teams', - 'time_start', - 'time_end',] def __init__(self, parent=None): # parent is a log-session usually - pass + 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 + return [] \ No newline at end of file diff --git a/game/screener.py b/game/screener.py new file mode 100644 index 0000000..06fdd71 --- /dev/null +++ b/game/screener.py @@ -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 \ No newline at end of file diff --git a/logs/game.py b/logs/game.py index e21bb66..1e2a802 100644 --- a/logs/game.py +++ b/logs/game.py @@ -92,11 +92,14 @@ class WarningLog(Log): # Individual logs. class SteamInitialization(GameLog): - matcher = [] + matcher = [ + re.compile(r"^Steam\sinitialized\sappId\s(?P\d+),\suserSteamID\s(?P\d+)\|(?P\d+)\|(?P\w+),\suserName\s'(?P[^']+)'"), + ] class MasterServerSession(GameLog): matcher = [ - re.compile(r"^MasterServerSession\:\sconnect\sto\sdedicated\sserver(?:,\s|session\s(?P\d+)|at addr (?P\d+\.\d+\.\d+\.\d+)\|(?P\d+))+"), + re.compile(r"^MasterServerSession\:\sconnect\sto\sdedicated\sserver(?:,\s|session\s(?P\d+)|at addr (?P\d+\.\d+\.\d+\.\d+)\|(?P\d+))+"), + re.compile(r"^MasterServerSession:\sconnect\sto\sZoneInstance,\ssession\s(?P\d+),\sat\saddr\s(?P\d+\.\d+\.\d+\.\d+)\|(?P\d+),\szoneId\s(?P\d+)"), ] @classmethod diff --git a/logs/logfile.py b/logs/logfile.py index b59f0f6..8b1d658 100644 --- a/logs/logfile.py +++ b/logs/logfile.py @@ -9,6 +9,7 @@ data by setting the LogFile._data yourself. """ import re +from .base import Log RE_SCLOG = r'^(?P\d{2,2})\:(?P\d{2,2})\:(?P\d{2,2})\.(?P\d{3,3})\s(?P\s*[^\|\s]+\s*|\s+)\|\s(?P.*)' R_SCLOG = re.compile(RE_SCLOG) @@ -33,6 +34,15 @@ class LogFile(object): def _unset_data(self): 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): # parse _data if we still have no lines. @@ -83,4 +93,18 @@ class LogFile(object): # line is a dict. # try to find a class that is responsible for this log. 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() diff --git a/logs/session.py b/logs/session.py index c29ed3f..fc01b14 100644 --- a/logs/session.py +++ b/logs/session.py @@ -15,6 +15,7 @@ class LogSession(object): ''' if directory is a file, it will be handled as a compressed folder ''' self.battles = [] self.user = None + self.files_parsed = [] # various logfiles used. self.combat_log = None @@ -27,6 +28,15 @@ class LogSession(object): self.idstr = None # id string to identify this log instance. 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): """ - validates if the logfiles are within this package. @@ -56,14 +66,18 @@ class LogSession(object): if self._zip_source: self._unzip_logs(files) 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.read() 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.read() self.game_log.parse() + self.files_parsed.append('game.log') def determine_owner(self): ''' determines the user in the parsed gamelog ''' @@ -80,12 +94,16 @@ class LogSession(object): fn = os.path.split(filename)[1] or '' fn = fn.lower() 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.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.set_data(z.read(filename)) + self.game_log.parse() + self.files_parsed.append('game.log') except: self._error = True return diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/steam.py b/utils/steam.py new file mode 100644 index 0000000..893959b --- /dev/null +++ b/utils/steam.py @@ -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 + + +""" \ No newline at end of file