done in last month:
* crafting fixture update * efefays logic implementation done today: * added game.log log basics for the parser. * updated utf-8 headers.
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
"""
|
||||
Library dedicated to Star Conflict Logs.
|
||||
|
||||
Development plan:
|
||||
- Make Combat Log parse completely.
|
||||
- Make Game Log parse to get information like the local nickname or other needed infos.
|
||||
- Create a soft emulation, which keeps track of the basic game outcome / events.
|
||||
|
||||
Additional Goals:
|
||||
- probably save games in own format to keep space.
|
||||
- database entries for kills, encountered players, etc.
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Library dedicated to Star Conflict Logs.
|
||||
|
||||
Development plan:
|
||||
- Make Combat Log parse completely.
|
||||
- Make Game Log parse to get information like the local nickname or other needed infos.
|
||||
- Create a soft emulation, which keeps track of the basic game outcome / events.
|
||||
|
||||
Additional Goals:
|
||||
- probably save games in own format to keep space.
|
||||
- database entries for kills, encountered players, etc.
|
||||
|
||||
"""
|
||||
@@ -1,9 +1,16 @@
|
||||
|
||||
L_CMBT = 'CMBT'
|
||||
L_WARNING = 'WARNING'
|
||||
L_NET = 'NET'
|
||||
L_CHAT = 'CHAT'
|
||||
|
||||
class Log(object):
|
||||
matcher = None
|
||||
trash = False
|
||||
|
||||
@classmethod
|
||||
def is_handler(cls, log):
|
||||
return False
|
||||
|
||||
|
||||
def unpack(self):
|
||||
pass
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
todo:
|
||||
- English implementation first.
|
||||
@@ -19,9 +21,10 @@
|
||||
The typical log entry
|
||||
"""
|
||||
import re
|
||||
from base import Log
|
||||
from base import Log, L_CMBT
|
||||
|
||||
class CombatLog(Log):
|
||||
__slots__ = ['matcher', 'trash', '_match_id', 'values']
|
||||
@classmethod
|
||||
def _log_handler(cls, log):
|
||||
if log.get('log', '').strip().startswith(cls.__name__):
|
||||
@@ -30,7 +33,7 @@ class CombatLog(Log):
|
||||
|
||||
@classmethod
|
||||
def is_handler(cls, log):
|
||||
if log.get('logtype', None) == 'CMBT':
|
||||
if log.get('logtype', None) == L_CMBT:
|
||||
return cls._log_handler(log)
|
||||
return False
|
||||
|
||||
@@ -38,22 +41,28 @@ class CombatLog(Log):
|
||||
self.values = values
|
||||
|
||||
def unpack(self):
|
||||
self._match_id = None
|
||||
# unpacks the data from the values.
|
||||
if hasattr(self, 'matcher') and self.matcher:
|
||||
matchers = self.matcher
|
||||
if not isinstance(matchers, list):
|
||||
matchers = [matchers,]
|
||||
for matcher in matchers:
|
||||
for i, matcher in enumerate(matchers):
|
||||
m = matcher.match(self.values.get('log', ''))
|
||||
if m:
|
||||
self.values.update(m.groupdict())
|
||||
self._match_id = i
|
||||
return True
|
||||
# unknown?
|
||||
self.trash = True
|
||||
|
||||
# @todo: where does this come from?
|
||||
class Action(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
pass
|
||||
|
||||
class Gameplay(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = [
|
||||
# usual: team(reason). explained reason.
|
||||
re.compile(r"^Gameplay\sfinished\.\sWinner\steam\:\s+(?P<winner_team>\d+)\((?P<winner_reason>\w+)\)\.\sFinish\sreason\:\s'(?P<reason_verbose>[^']+)'\.\sActual\sgame\stime\s+(?P<game_time>\d+|\d+\.\d+)\ssec"),
|
||||
@@ -62,27 +71,35 @@ class Gameplay(CombatLog):
|
||||
]
|
||||
|
||||
class Apply(CombatLog): # Apply Aura.
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = re.compile(r"^Apply\saura\s'(?P<aura_name>\w+)'\sid\s(?P<id>\d+)\stype\s(?P<aura_type>\w+)\sto\s'(?P<target_name>[^\']+)'")
|
||||
|
||||
class Damage(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = re.compile(r"^Damage\s+(?P<source_name>[^\s]+)\s\->\s+(?P<target_name>[^\s]+)\s+(?P<amount>(?:\d+|\d+\.\d+))(?:\s(?P<module_class>[^\s]+)\s|\s{2,2})(?P<flags>(?:\w|\|)+)")
|
||||
|
||||
class Spawn(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = re.compile(r"^Spawn\sSpaceShip\sfor\splayer(?P<player>\d+)\s\((?P<name>[^,]+),\s+(?P<hash>#\w+)\)\.\s+'(?P<ship_class>\w+)'")
|
||||
|
||||
class Spell(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = re.compile(r"^Spell\s'(?P<spell_name>\w+)'\sby\s+(?P<source_name>.*)(?:\((?P<module_name>\w+)\)|)\stargets\((?P<target_num>\d+)\)\:(?:$|\s(?P<targets>.+))")
|
||||
|
||||
class Reward(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = re.compile(r"^Reward\s+(?P<name>[^\s]+)(?:\s(?P<ship_class>\w+)\s+|\s+)(?P<amount>\d+)\s(?P<reward_type>.*)\s+for\s(?P<reward_reason>.*)")
|
||||
|
||||
class Participant(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = re.compile(r"^\s+Participant\s+(?P<source_name>[^\s]+)(?:\s{2}(?P<ship_class>\w+)|\s{30,})\s+(?:totalDamage\s(?P<total_damage>(?:\d+|\d+\.\d+));\smostDamageWith\s'(?P<module_class>[^']+)';(?P<additional>.*)|<(?P<other>\w+)>)")
|
||||
|
||||
class Rocket(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = re.compile(r"^Rocket\s(?P<event>launch|detonation)\.\sowner\s'(?P<name>[^']+)'(?:,\s(?:def\s'(?P<missile_type>\w+)'|target\s'(?P<target>[^']+)'|reason\s'(?P<reason>\w+)'|directHit\s'(?P<direct_hit>[^']+)'))+")
|
||||
|
||||
class Heal(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = [
|
||||
# heal by module
|
||||
re.compile(r"^Heal\s+(?P<source_name>[^\s]+)\s\->\s+(?P<target_name>[^\s]+)\s+(?P<amount>(?:\d+|\d+\.\d+))\s(?P<module_class>[^\s]+)"),
|
||||
@@ -91,6 +108,7 @@ class Heal(CombatLog):
|
||||
]
|
||||
|
||||
class Killed(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = [
|
||||
re.compile(r"^Killed\s(?P<target_name>[^\s]+)\s+(?P<ship_class>\w+);\s+killer\s(?P<source_name>[^\s]+)\s*"),
|
||||
re.compile(r"^Killed\s(?P<object>[^\(]+)\((?P<target_name>\w+)\);\s+killer\s(?P<source_name>[^\s]+)\s*"),
|
||||
@@ -98,19 +116,24 @@ class Killed(CombatLog):
|
||||
]
|
||||
|
||||
class Captured(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = re.compile(r"^Captured\s'(?P<objective>[^']+)'\(team\s(?P<team>\d+)\)\.(?:\sAttackers\:(?P<attackers>.*)|.*)")
|
||||
|
||||
class AddStack(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = re.compile(r"^AddStack\saura\s'(?P<spell_name>\w+)'\sid\s(?P<id>\d+)\stype\s(?P<type>\w+)\.\snew\sstacks\scount\s(?P<stack_count>\d+)")
|
||||
|
||||
class Cancel(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = re.compile(r"^Cancel\saura\s'(?P<spell_name>\w+)'\sid\s(?P<id>\d+)\stype\s(?P<type>\w+)\sfrom\s'(?P<source_name>[^']+)'")
|
||||
|
||||
class Scores(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = re.compile(r"^Scores\s+-\sTeam1\((?P<team1_score>(?:\d+|\d+\.\d+))\)\sTeam2\((?P<team2_score>(?:\d+|\d+\.\d+))\)")
|
||||
|
||||
# Special classes
|
||||
class GameEvent(CombatLog):
|
||||
__slots__ = CombatLog.__slots__
|
||||
matcher = [
|
||||
# game session identifier.
|
||||
re.compile(r"^Connect\sto\sgame\ssession\s+(?P<game_session>\d+)"),
|
||||
@@ -127,20 +150,25 @@ class GameEvent(CombatLog):
|
||||
return False
|
||||
|
||||
def unpack(self):
|
||||
self._match_id = None
|
||||
# unpacks the data from the values.
|
||||
# small override to remove trailing "="s in the matching.
|
||||
if hasattr(self, 'matcher') and self.matcher:
|
||||
matchers = self.matcher
|
||||
if not isinstance(matchers, list):
|
||||
matchers = [matchers,]
|
||||
for matcher in matchers:
|
||||
for i, matcher in enumerate(matchers):
|
||||
m = matcher.match(self.values.get('log', '').strip('=').strip())
|
||||
if m:
|
||||
self.values.update(m.groupdict())
|
||||
self._match_id = i
|
||||
return True
|
||||
# unknown?
|
||||
self.trash = True
|
||||
|
||||
class UserEvent(CombatLog):
|
||||
""" special class for combat logs that might be associated with the playing player """
|
||||
__slots__ = CombatLog.__slots__
|
||||
@classmethod
|
||||
def _log_handler(cls, log):
|
||||
if log.get('log', '').strip():
|
||||
|
||||
170
logs/game.py
170
logs/game.py
@@ -1,4 +1,172 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from logs.base import Log, L_WARNING
|
||||
import re
|
||||
"""
|
||||
Interesting Lines:
|
||||
|
||||
23:16:27.427 | Steam initialized appId 212070, userSteamID 1|1|4c5a01, userName 'G4bOrg'
|
||||
23:16:36.214 | ====== starting level: 'levels/mainmenu/mainmenu' ======
|
||||
23:16:38.822 | ====== level started: 'levels/mainmenu/mainmenu' success ======
|
||||
23:16:44.251 | ====== starting level: 'levels\mainmenu\mm_empire' ======
|
||||
23:16:46.464 | ====== level started: 'levels\mainmenu\mm_empire' success ======
|
||||
|
||||
--- Date: 2014-07-18 (Fri Jul 2014) Mitteleuropäische Sommerzeit UTC+01:00
|
||||
|
||||
23:55:55.517 | MasterServerSession: connect to dedicated server, session 6777304, at addr 159.253.138.162|35005
|
||||
23:55:55.543 | client: start connecting to 159.253.138.162|35005...
|
||||
23:55:55.683 | client: connected to 159.253.138.162|35005, setting up session...
|
||||
23:55:55.886 | client: ADD_PLAYER 0 (OregyenDuero [OWL], 00039C86) status 6 team 1 group 1178422
|
||||
23:55:55.886 | client: ADD_PLAYER 1 (R0gue, 0012768A) status 6 team 2 group 1178451
|
||||
23:55:55.886 | client: ADD_PLAYER 2 (g4borg [OWL], 0003A848) status 1 team 1 group 1178422
|
||||
23:55:55.886 | client: ADD_PLAYER 3 (WladTepes, 001210D8) status 6 team 1
|
||||
23:55:55.886 | client: ADD_PLAYER 4 (oberus [], 000FE9B2) status 6 team 2
|
||||
23:55:55.886 | client: ADD_PLAYER 5 (TheGuns58, 00121C58) status 6 team 1
|
||||
23:55:55.886 | client: ADD_PLAYER 6 (Belleraphon, 0004C744) status 2 team 2
|
||||
23:55:55.886 | client: ADD_PLAYER 7 (TopoL, 00007E1F) status 6 team 1
|
||||
23:55:55.886 | client: ADD_PLAYER 8 (unicoimbraPT, 000C4FAC) status 6 team 2
|
||||
23:55:55.886 | client: ADD_PLAYER 9 (AeroBobik [], 00082047) status 6 team 1
|
||||
23:55:55.886 | client: ADD_PLAYER 10 (Samson4321 [], 000B93AF) status 6 team 2
|
||||
23:55:55.886 | client: ADD_PLAYER 11 (nol [], 00069165) status 6 team 1
|
||||
23:55:55.886 | client: ADD_PLAYER 12 (Pudwoppa, 000334A4) status 2 team 2
|
||||
23:55:55.886 | client: ADD_PLAYER 13 (IgorMad [], 000D2AF3) status 6 team 1
|
||||
23:55:55.886 | client: ADD_PLAYER 14 (YokaI, 000F1CC9) status 6 team 2
|
||||
23:55:55.886 | client: ADD_PLAYER 15 (MrAnyKey [], 0012246C) status 6 team 2 group 1178451
|
||||
23:55:55.886 | client: ADD_PLAYER 30 ((bot)David, 00000000) status 4 team 1
|
||||
23:55:55.886 | client: ADD_PLAYER 31 ((bot)George, 00000000) status 4 team 2
|
||||
23:55:55.886 | client: server assigned id 2
|
||||
23:55:55.886 | client: got level load message 's1340_thar_aliendebris13'
|
||||
23:55:55.889 | reset d3d device
|
||||
23:55:56.487 | ReplayManager: stopping activity due to map change
|
||||
23:55:56.576 | ====== starting level: 'levels\area2\s1340_thar_aliendebris13' KingOfTheHill client ======
|
||||
|
||||
|
||||
"""
|
||||
|
||||
class GameLog(Log):
|
||||
__slots__ = ['matcher', 'trash', '_match_id', 'values']
|
||||
@classmethod
|
||||
def is_handler(cls, log):
|
||||
if log.get('logtype', None) == '': # we handle only logs with empty logtype.
|
||||
return cls._is_handler(log)
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def _is_handler(cls, log):
|
||||
return False
|
||||
|
||||
def __init__(self, values=None):
|
||||
self.values = values
|
||||
|
||||
def unpack(self):
|
||||
self._match_id = None
|
||||
# unpacks the data from the values.
|
||||
if hasattr(self, 'matcher') and self.matcher:
|
||||
matchers = self.matcher
|
||||
if not isinstance(matchers, list):
|
||||
matchers = [matchers,]
|
||||
for i, matcher in enumerate(matchers):
|
||||
m = matcher.match(self.values.get('log', ''))
|
||||
if m:
|
||||
self.values.update(m.groupdict())
|
||||
self._match_id = i
|
||||
return True
|
||||
# unknown?
|
||||
self.trash = True
|
||||
|
||||
class WarningLog(Log):
|
||||
__slots__ = ['trash',]
|
||||
trash = True
|
||||
|
||||
@classmethod
|
||||
def is_handler(cls, log):
|
||||
if log.get('logtype', None) == L_WARNING:
|
||||
return True
|
||||
return False
|
||||
|
||||
def __init__(self, values=None):
|
||||
pass
|
||||
|
||||
########################################################################################################
|
||||
# Individual logs.
|
||||
|
||||
class SteamInitialization(GameLog):
|
||||
matcher = []
|
||||
|
||||
class MasterServerSession(GameLog):
|
||||
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+))+"),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _is_handler(cls, log):
|
||||
if log.get('log', '').startswith('MasterServerSession'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class ClientInfo(GameLog):
|
||||
# Note: clinfo holds the subtype of this packet.
|
||||
matcher = [
|
||||
# connecting; addr, port
|
||||
re.compile(r"^client\:\sstart\s(?P<clinfo>connecting)\sto\s(?P<addr>\d+\.\d+\.\d+\.\d+)\|(?P<port>\d+)\.\.\."),
|
||||
# connected; addr, port
|
||||
re.compile(r"^client\:\s(?P<clinfo>connected)\sto\s(?P<addr>\d+\.\d+\.\d+\.\d+)\|(?P<port>\d+).*"),
|
||||
# ADD_PLAYER; pnr, player, clantag, player_id, status, team, group
|
||||
re.compile(r"^client\:\s(?P<clinfo>ADD_PLAYER)\s+(?P<pnr>\d+)\s+\((?P<player>[^\s\,]+)(?:\s\[(?P<clantag>\w+)\],|\s\[\],|,)\s(?P<player_id>\w+)\)(?:\s|status\s(?P<status>\d+)|team\s(?P<team>\d+)|group\s(?P<group>\d+))+"),
|
||||
# assigned; myid
|
||||
re.compile(r"^client\:\sserver\s(?P<clinfo>assigned)\sid\s(?P<myid>\d+)"),
|
||||
# level; level
|
||||
re.compile(r"^client\:\sgot\s(?P<clinfo>level)\sload\smessage\s'(?P<level>[^']+)'"),
|
||||
# leave; pnr
|
||||
re.compile(r"^client\:\splayer\s(?P<pnr>\d+)\s(?P<clinfo>leave)\sgame"),
|
||||
# avgPing; avg_ping, avg_packet_loss, avg_snapshot_loss
|
||||
re.compile(r"^client\:\s(?P<clinfo>avgPing)\s(?P<avg_ping>[^;]+)(?:\;|\s|avgPacketLoss\s(?P<avg_packet_loss>[^;]+)|avgSnapshotLoss\s(?P<avg_snapshot_loss>[^;$]+))+"),
|
||||
# closed; dr
|
||||
re.compile(r"^client\:\sconnection\s(?P<clinfo>closed)\.(?:\s|(?P<dr>.*))+"),
|
||||
# disconnect; addr, port, dr
|
||||
re.compile(r"^client\:\s(?P<clinfo>disconnect)\sfrom\sserver\s(?P<addr>\d+\.\d+\.\d+\.\d+)\|(?P<port>\d+)\.(?:\s|(?P<dr>\w+))+"),
|
||||
# ready;
|
||||
re.compile(r"^client\:\ssend\s(?P<clinfo>ready)\smessage"),
|
||||
# init; ping
|
||||
re.compile(r"^client\:\sgot\s(?P<clinfo>init)\smessage\s+\(and\s1st\ssnapshot\)\.\sping\s(?P<ping>\d+)"),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _is_handler(cls, log):
|
||||
if log.get('log', '').startswith('client:'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class StartingLevel(GameLog):
|
||||
# level, gametype, unknown_gametype
|
||||
matcher = [
|
||||
re.compile(r"^======\sstarting\slevel\:\s'(?P<level>[^']+)'(?:\s|client|(?P<gametype>KingOfTheHill)|(?P<unknown_gametype>[^\s]+))+======"),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _is_handler(cls, log):
|
||||
if log.get('log', '').startswith('====== starting'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class LevelStarted(GameLog):
|
||||
matcher = []
|
||||
|
||||
@classmethod
|
||||
def _is_handler(cls, log):
|
||||
if log.get('log', '').startswith('====== level'):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
GAME_LOGS = []
|
||||
GAME_LOGS = [#SteamInitialization,
|
||||
MasterServerSession,
|
||||
ClientInfo,
|
||||
StartingLevel,
|
||||
#LevelStarted,
|
||||
]
|
||||
@@ -1,4 +1,5 @@
|
||||
#
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Author: Gabor Guzmics, 2013-2014
|
||||
|
||||
@@ -30,6 +31,9 @@ class LogFile(object):
|
||||
def set_data(self, data):
|
||||
self._data = data
|
||||
|
||||
def _unset_data(self):
|
||||
self._data = None
|
||||
|
||||
def parse(self):
|
||||
# parse _data if we still have no lines.
|
||||
if self._data:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Resolves Logs.
|
||||
"""
|
||||
|
||||
133
logs/session.py
133
logs/session.py
@@ -9,6 +9,7 @@ class LogSession(object):
|
||||
The Log-Session is supposed to save one directory of logs.
|
||||
It can parse its logs, and build up its internal structure into Battle Instances etc.
|
||||
"""
|
||||
VALID_FILES = ['combat.log', 'game.log', ] # extend this to other logs.
|
||||
|
||||
def __init__(self, directory):
|
||||
''' if directory is a file, it will be handled as a compressed folder '''
|
||||
@@ -22,22 +23,47 @@ class LogSession(object):
|
||||
# self.net_log = None
|
||||
|
||||
self.directory = directory
|
||||
self._zip_source = False
|
||||
self._zip_source = None
|
||||
self.idstr = None # id string to identify this log instance.
|
||||
self._error = False
|
||||
|
||||
def parse_files(self):
|
||||
''' parses the logfiles '''
|
||||
# check if directory is a file
|
||||
def validate(self, contents=False):
|
||||
"""
|
||||
- validates if the logfiles are within this package.
|
||||
- sets the idstr of this object.
|
||||
@todo: in-depth validation of logs, on contents=True.
|
||||
"""
|
||||
self._zip_source = os.path.isfile(self.directory) or False
|
||||
v = False
|
||||
try:
|
||||
if self._zip_source:
|
||||
v = self._unzip_validate()
|
||||
if v > 0:
|
||||
self.idstr = os.path.split(self.directory)[1].replace('.zip', '').lower()
|
||||
else:
|
||||
v = self._validate_files_exist()
|
||||
if v > 0:
|
||||
self.idstr = os.path.split(self.directory)[1].lower()
|
||||
except:
|
||||
return False
|
||||
return v
|
||||
|
||||
def parse_files(self, files=None):
|
||||
''' parses the logfiles '''
|
||||
# perform simple validation.
|
||||
if self._zip_source is None:
|
||||
self.validate(False)
|
||||
if self._zip_source:
|
||||
self._unzip_logs()
|
||||
self._unzip_logs(files)
|
||||
else:
|
||||
self.combat_log = CombatLogFile(os.path.join(self.directory, 'combat.log'))
|
||||
self.combat_log.read()
|
||||
self.game_log = GameLogFile(os.path.join(self.directory, 'game.log'))
|
||||
self.game_log.read()
|
||||
# parse all files
|
||||
self.combat_log.parse()
|
||||
self.game_log.parse()
|
||||
if 'combat.log' in files:
|
||||
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.game_log = GameLogFile(os.path.join(self.directory, 'game.log'))
|
||||
self.game_log.read()
|
||||
self.game_log.parse()
|
||||
|
||||
def determine_owner(self):
|
||||
''' determines the user in the parsed gamelog '''
|
||||
@@ -47,19 +73,79 @@ class LogSession(object):
|
||||
''' parses the battles '''
|
||||
pass
|
||||
|
||||
def _unzip_logs(self):
|
||||
def _unzip_logs(self, files=None):
|
||||
z = zipfile.ZipFile(self.directory, "r")
|
||||
try:
|
||||
for filename in z.namelist():
|
||||
fn = os.path.split(filename)[1] or ''
|
||||
fn = fn.lower()
|
||||
if fn:
|
||||
if fn == 'combat.log' and (not files or fn in files):
|
||||
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.game_log = GameLogFile(fn)
|
||||
self.game_log.set_data(z.read(filename))
|
||||
except:
|
||||
self._error = True
|
||||
return
|
||||
finally:
|
||||
z.close()
|
||||
|
||||
def _unzip_validate(self):
|
||||
z = zipfile.ZipFile(self.directory, "r")
|
||||
found = 0
|
||||
for filename in z.namelist():
|
||||
fn = os.path.split(filename)[1] or ''
|
||||
fn = fn.lower()
|
||||
if fn:
|
||||
if fn == 'combat.log':
|
||||
self.combat_log = CombatLogFile(fn)
|
||||
self.combat_log.set_data(z.read(filename))
|
||||
elif fn == 'game.log':
|
||||
self.game_log = GameLogFile(fn)
|
||||
self.game_log.set_data(z.read(filename))
|
||||
|
||||
if fn and fn in self.VALID_FILES:
|
||||
found += 1
|
||||
z.close()
|
||||
return found
|
||||
|
||||
def _validate_files_exist(self):
|
||||
found = 0
|
||||
for f in self.VALID_FILES:
|
||||
if os.path.exists(os.path.join(self.directory, f)):
|
||||
found += 1
|
||||
return found
|
||||
|
||||
class LogSessionCollector(object):
|
||||
def __init__(self, directory):
|
||||
self.initial_directory = directory
|
||||
self.sessions = []
|
||||
self.find_sessions()
|
||||
|
||||
def find_sessions(self):
|
||||
for f in os.listdir(self.initial_directory):
|
||||
full_dir = os.path.join(self.initial_directory, f)
|
||||
if os.path.isdir(full_dir) or full_dir.lower().endswith('.zip'):
|
||||
self.sessions.append(LogSession(full_dir))
|
||||
|
||||
def collect(self):
|
||||
sessions = []
|
||||
for session in self.sessions:
|
||||
try:
|
||||
if session.validate():
|
||||
sessions.append(session)
|
||||
except:
|
||||
continue
|
||||
return sessions
|
||||
|
||||
def collect_unique(self):
|
||||
''' collects all sessions into a dictionary ordered by their idstr.
|
||||
sessions without idstr, or already existing (first served) are omitted
|
||||
parsing is not done.
|
||||
'''
|
||||
# note this function resets sessions to the working ones.
|
||||
self.sessions = self.collect()
|
||||
sessions_dict = {}
|
||||
for session in self.sessions:
|
||||
if session.idstr and not session.idstr in sessions_dict.keys():
|
||||
sessions_dict[session.idstr] = session
|
||||
return sessions_dict
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
@@ -67,4 +153,7 @@ if __name__ == '__main__':
|
||||
l_zip = LogSession('D:\\Users\\g4b\\Documents\\My Games\\sc\\2014.05.20 23.49.19.zip')
|
||||
|
||||
l_zip.parse_files()
|
||||
print l_zip.combat_log.lines
|
||||
print l_zip.combat_log.lines
|
||||
|
||||
collector = LogSessionCollector('D:\\Users\\g4b\\Documents\\My Games\\sc\\')
|
||||
print collector.collect_unique()
|
||||
Reference in New Issue
Block a user