Git repository creation. Added initial files

This commit is contained in:
Rooty 2020-07-29 15:31:44 +02:00
parent 1236824d92
commit d1990aa41f
5 changed files with 643 additions and 0 deletions

3
README Executable file
View File

@ -0,0 +1,3 @@
Swtor combat log parser (work in progress)
To use: parser.py filename

147
parser.py Executable file
View File

@ -0,0 +1,147 @@
# Danial Afzal
# iotasquared@gmail.com
import os
import re
from datetime import datetime
import sys
#[03/16/2012 22:53:45] [@Asdffljklasdfj] [@Asdffljklasdfj] [Unnatural Might {1781509484707840}] [RemoveEffect {836045448945478}: Unnatural Might {1781509484707840}] ()
#[date] [src] [target] [ability] [effect] (value) <threat>
#src = [foo {id}] or [@player]
# ability = abil {id}
# effect = type:effect
# value = # or # type
# roll? int
class Event:
regex = r'[\[<\(]([^\[<\(\]>\)]*)[\]>\)]'
def __init__(self, x):
#print x
data = re.findall(Event.regex, x)
data.append('')
self.to_string = ' '.join(data)
date = datetime.strptime(data[0], '%m/%d/%Y %H:%M:%S')
self.date = date
self.source = Entity(data[1])
self.target = Entity(data[2])
self.ability = Ability(data[3])
self.effect = Effect(data[4])
self.value = Value(data[5])
self.threat = Threat(data[6])
class Entity:
def __init__(self, x):
if not x:
self.name = x
self.player = False
elif x[0] == '@':
self.name = x[1:]
self.player = True
else:
self.name = x
self.player = False
class Ability:
def __init__(self, x):
self.name = x
class Effect:
def __init__(self, x):
if not x:
self.type = ''
self.detail = ''
return
foo = x.split(':')
if len(foo) > 1:
self.type = foo[0]
self.detail = foo[1]
else:
self.type = x
self.detail = ''
class Value:
def __init__(self, x):
if not x:
self.value = 0
self.type = ''
return
foo = x.replace('*','').split(' ')
self.value = int(foo[0])
if len(foo) > 1:
self.type = foo[1]
else:
self.type=''
class Threat:
def __init__(self, x):
if not x:
self.value = 0
self.type = ''
return
foo = x.replace('*','').split(' ')
self.value = int(foo[0])
if len(foo) > 1:
self.type = foo[1]
else:
self.type=''
#date, source, target, ability, effect.type/detail, value.value/type, threat
# TODO:
# multiple sources
# more interesting output, graphs? What about that metric site? Google charts?
# App engine seems fun
# Details for abilities:
# dmg per ability
# Combine multiple entries per ability
def main():
if len(sys.argv) == 1:
filename = 'argorash.txt'
print 'File not specified, defaulting to ' + filename
else:
filename = sys.argv[1]
file = open(filename, 'r')
events = []
for line in file.readlines():
events.append(Event(line))
players = set([event.source.name for event in events])
fights = []
fight = []
for event in events:
if 'EnterCombat' in event.effect.detail:
fight = []
if 'ExitCombat' in event.effect.detail:
fight.append(event)
fights.append(fight)
fight = []
continue
fight.append(event)
for i, fight in enumerate(fights):
duration = fight[-1].date - fight[0].date
print '\nCombat Statistics for Fight # %d (duration: %s)' %(i+1, str(duration))
print str(fight[0].date) +" -> " + str(fight[-1].date)
for player in players:
dmg = 0
heal = 0
threat = 0
for event in fight:
if event.source.name == player and 'Damage ' in event.effect.detail:
dmg += event.value.value
if event.source.name == player and event.threat.value:
threat += event.threat.value
if event.source.name == player and 'Heal ' in event.effect.detail:
heal += event.value.value
secs = duration.seconds
if not secs:
secs = 1
if dmg:
print '%s did %d damage in %s (%d DPS)' % (player, dmg, str(duration), dmg/secs)
if heal:
print '%s did %d heals in %s (%d HPS)' % (player, heal, str(duration), heal/secs)
if threat:
print '%s did %d threat in %s (%d TPS)' % (player, threat, str(duration), threat/secs)
#print "\n".join([event.to_string for event in events])
if __name__ == "__main__":
main()

4
setup.py Executable file
View File

@ -0,0 +1,4 @@
from distutils.core import setup
import py2exe
setup(console=['parser.py'])

171
swtor-parser.php Executable file
View File

@ -0,0 +1,171 @@
#!/usr/bin/php
<?php
$listEncounters = array(
## The Dread Fortress
'Nefra, Who Bars the Way {3266533082005504}','Gate Commander Draxus {3273924720721920}','Grob\'thok, Who Feeds the Forge {3273929015689216}','Corruptor Zero {3273933310656512}','Dread Master Brontes {3273937605623808}',
## Eternity Vault
'Soa {2289823159156736}',
## Assation
'The Writhing Horror {2938874321960960}','Heirad {2938002443599872}','Ciphas {2938011033534464}','Kel\'sara {2938006738567168}','Operator IX {2942606648541184}','Kephess the Undying {2937620191510528}','The Terror From Beyond {2978340776443904}',
##
'The Eyeless {3328380611067904}',
## Toborro
'Golden Fury {3232800408862720}', 'Golden Fury {3232817588731904}',
## The False Emperor
'Tregg the Destroyer {1690314444111872}','Jindo Krey {770959514533888}','HK-47 {770955219566592}','Chondrus Berani {1690331623981056}','Sith Entity {1695962326106112}','Forsaken Sith Lord {781830076760064}','Darth Malgus {770963809501184}',
## Battle of Rishi
'Marko Ka {3533564083699712}','Rarrook {3533559788732416}','Lord Vodd {3533585558536192}','Shield Squadron Unit 1 {3533594148470784}','Darth Yun {4257506591244288}',
## Objective Meridian
'Commander Aster {4258021987319808}','Darth Malgus {4257502296276992}',
## Heart of Ruin
'Colossal Monolith {3541140406009856}',
##
'Toxxun {3340011382505472}',
## Mutated Geonosian Queen
'Mutated Geonosian Queen {4197299739688960}'
);
$dmgTypes = array('energy','elemental','kinetic','internal');
$instTypes = array('Story','Veteran','Master');
$zoneNames = array(
# Planet zones
'Corellia','Coruscant','CZ-198','Rishi','Taris','Tatooine','Voss','Yavin 4','Ziost',
# Instances zones
'Lair of the Eyeless','Toborro\'s Palace Courtyard','The False Emperor','Battle of Rishi','Objective Meridian','Hive of the Mountain Queen'
);
class loadFile
{
// Declare properties
public $filename = "";
public $handle = null;
// Constructor
public function __construct(){
// echo 'The class "' . __CLASS__ . '" was initiated!<br>';
$this->fileName = "";
$this->handle = null;
}
// Destructor
public function __destruct(){
// echo 'The class "' . __CLASS__ . '" was destroyed.<br>';
}
// Method to get the filename
public function getFileName(){
return $this->fileName;
}
// Method to set the filename
public function setFileName($filename){
$this->fileName = $filename;
}
// Method to get the handle content
public function getHandle(){
// TODO Check file exists
$this->handle = fopen($this->fileName, "r");
// if($this->handle) {
// while (($line = fgets($this->handle)) !== false) {
// echo $line;
// }
// fclose($this->handle);
// } else {
// $this->handle = False;
// }
return $this->handle;
}
}
// class Event:
// regex = r'[\[<\(]([^\[<\(\]>\)]*)[\]>\)]'
// def __init__(self, x):
// data = re.findall(Event.regex, x)
// data.append('')
// self.to_string = ' '.join(data)
//
// dateandtime = datetime.strptime(list(sys.argv[1].split("_"))[1]+" "+data[0], '%Y-%m-%d %H:%M:%S.%f')
//
// self.date = dateandtime
// self.source = Entity(data[1])
// self.target = Entity(data[2])
// self.ability = Ability(data[3])
// self.effect = Effect(data[4])
// self.value = Value(data[5])
// self.threat = Threat(data[6])
class LogEvent
{
// Properties declaration
public $event = "";
// public $date = "";
// public $source = "";
// public $target = "";
// public $ability = "";
// public $effect = "";
// public $value = 0;
// public $threat = 0;
// Constructor
public function __construct()
{
// echo 'The class "' . __CLASS__ . '" was initiated!<br>';
$this->event = "";
// $this->date = $date;
// $this->source = $source;
// $this->target = $target;
// $this->ability = $ability;
// $this->effect = $effect;
// $this->value = $value;
// $this->threat = $threat;
}
// Destructor
public function __destruct(){
// echo 'The class "' . __CLASS__ . '" was destroyed.<br>';
}
// Method to set the event
public function arrayEvent($logEvent){
// [23:40:42.150] [@Comendatore] [Combat Training Target MK-10 {2816257300627456}:133000004817] [Ion Pulse {2199843594305536}] [ApplyEffect {836045448945477}: Damage {836045448945501}] (7659* elemental {836045448940875}) <19146>
// [date] [src] [target] [ability] [effect] (value) <threat>
$isMatching = preg_match_all('/[\[<\(]([^\[<\(\]>\)]*)[\]>\)]/m', $logEvent, $this->event, PREG_SET_ORDER, 0);
return $this->event;
}
}
// $handle = fopen("combat_2020-06-11_18_06_42_493608.txt", "r");
$handlecontent = new loadFile;
$handlecontent->setFileName("combat_2020-07-25_22_39_58_532658.txt");
$handleresult = $handlecontent->getHandle();
if($handleresult) {
$totalAmount=0;$totalThreat=0;
while (($line = fgets($handleresult)) !== false) {
$log = new LogEvent;
$log = $log->arrayEvent($line);
if( array_key_exists(6, $log) );
// print_r($log);
$logDate = $log[0][1];
$logSource = $log[1][1];
$logTarget = $log[2][1];
$logAbility = $log[3][1];
$logEffect = $log[4][1];
$logValue = (isset($log[5][1]) && ($log[5][1] != 0))?$log[5][1]:null;
$logThreat = isset($log[6][1])?$log[6][1]:null;
print("Date : ".$logDate." Source : ".$logSource." Target : ".$logTarget." Ability : ".$logAbility." Effect : ".$logEffect." Amount : ".$logValue." Menace : ".$logThreat."\n");
// if( $log[1][1]
$totalAmount+=$logValue;$totalThreat+=$logThreat;
}
print("Total Damages : ".$totalAmount."\n");
print("Total Menace : ".$totalThreat."\n");
} else {
echo "Error while loading file handle !";
}
?>

318
swtor-parser.py Executable file
View File

@ -0,0 +1,318 @@
#!/usr/bin/python
import os, re, sys
from time import strftime
from datetime import datetime
#import matplotlib.pyplot as plt
## Declaring the points for first line plot
#X1 = [1,2,3,4,5]
#Y1 = [2,4,6,8,10]
## Setting the figure size
#fig = plt.figure(figsize=(10,5))
## plotting the first plot
#plt.plot(X1, Y1, label = "plot 1")
## Declaring the points for second line plot
#X2 = [1,2,3,4,5]
#Y2 = [1,4,9,16,25]
## plotting the second plot
#plt.plot(X2, Y2, label = "plot 2")
## Labeling the X-axis
#plt.xlabel('X-axis')
## Labeling the Y-axis
#plt.ylabel('Y-axis')
## Give a title to the graph
#plt.title('Two plots on the same graph')
## Show a legend on the plot
#plt.legend()
##Saving the plot as an image
#fig.savefig('line plot.png', bbox_inches='tight', dpi=150)
##Showing the plot
#plt.show()
# [03/16/2012 22:53:45] [@Asdffljklasdfj] [@Asdffljklasdfj] [Unnatural Might {1781509484707840}] [RemoveEffect {836045448945478}: Unnatural Might {1781509484707840}] ()
# [21:18:16.172] [@Comendatore] [@Comendatore] [] [Event {836045448945472}: EnterCombat {836045448945489}] (Asation (8 Player Story))
#[date] [src] [target] [ability] [effect] (value) <threat>
#src = [foo {id}] or [@player]
# ability = abil {id}
# effect = type:effect
# value = # or # type
# roll? int
listEncounters = [
## The Dread Fortress
'Nefra, Who Bars the Way {3266533082005504}','Gate Commander Draxus {3273924720721920}','Grob\'thok, Who Feeds the Forge {3273929015689216}','Corruptor Zero {3273933310656512}','Dread Master Brontes {3273937605623808}',
## Eternity Vault
'Soa {2289823159156736}',
##
'The Writhing Horror {2938874321960960}','Heirad {2938002443599872}','Ciphas {2938011033534464}','Kel\'sara {2938006738567168}','Operator IX {2942606648541184}','Kephess the Undying {2937620191510528}','The Terror From Beyond {2978340776443904}','The Terror From Beyond {3025233229381632}',
##
'The Eyeless {3328380611067904}','Golden Fury {3232800408862720}','Golden Fury {3232817588731904}',
## The False Emperor
'Tregg the Destroyer {1690314444111872}','Jindo Krey {770959514533888}','HK-47 {770955219566592}','Chondrus Berani {1690331623981056}','Sith Entity {1695962326106112}','Forsaken Sith Lord {781830076760064}','Darth Malgus {770963809501184}',
## Battle of Rishi
'Marko Ka {3533564083699712}','Rarrook {3533559788732416}','Lord Vodd {3533585558536192}','Shield Squadron Unit 1 {3533594148470784}','Darth Yun {4257506591244288}',
## Objective Meridian
'Commander Aster {4258021987319808}','Darth Malgus {4257502296276992}',
## Heart of Ruin
'Colossal Monolith {3541140406009856}',
##
'Toxxun {3340011382505472}',
## Mutated Geonosian Queen
'Mutated Geonosian Queen {4197299739688960}',
##
'SCYVA {4108140513591296}'
]
dmgTypes = ['energy','elemental','kinetic','internal']
instTypes = ['Story','Veteran','Master']
zoneNames = [
# Planet zones
'Corellia','Coruscant','CZ-198','Rishi','Taris','Tatooine','Voss','Yavin 4','Ziost',
# Instances zones
'Asation','Lair of the Eyeless','Toborro\'s Palace Courtyard','The False Emperor','Battle of Rishi','Objective Meridian','Hive of the Mountain Queen',
# Operations Zones
'Valley of the Machine Gods'
]
class Event:
regex = r'[\[<\(]([^\[<\(\]>\)]*)[\]>\)]'
def __init__(self, x):
data = re.findall(Event.regex, x)
data.append('')
self.to_string = ' '.join(data)
dateandtime = datetime.strptime(list(sys.argv[1].split("_"))[1]+" "+data[0], '%Y-%m-%d %H:%M:%S.%f')
self.date = dateandtime
self.source = Entity(data[1])
self.target = Entity(data[2])
self.ability = Ability(data[3])
self.effect = Effect(data[4])
self.value = Value(data[5])
self.threat = Threat(data[6])
class Entity:
def __init__(self, x):
if not x:
self.name = x
self.player = False
#print(x+" is not a player !")
elif x[0] == '@':
self.name = x[1:]
self.player = True
#print(x+" is a player !")
else:
self.name = x
self.player = False
#print(x+" is not a player !")
class Ability:
def __init__(self, x):
self.name = x
class Effect:
def __init__(self, x):
if not x:
self.type = ''
self.detail = ''
return
foo = x.split(':')
if len(foo) > 1:
self.type = foo[0]
self.detail = foo[1]
else:
self.type = x
self.detail = ''
#class Value:
#def __init__(self, x):
#if not x:
#self.value = 0
#self.type = ''
#return
#foo = x.replace('*','').split(' ')
#self.value = int(foo[0])
#if len(foo) > 1:
#self.type = foo[1]
#else:
#self.type=''
# [20:06:53.053] [@Comendatore] [@Comendatore] [] [Event {836045448945472}: EnterCombat {836045448945489}] (Ziost)
# [21:31:45.974] [@Comendatore] [@Comendatore] [] [Event {836045448945472}: EnterCombat {836045448945489}] (Hive of the Mountain Queen (8 Player Story))
# [21:32:18.105] [@Bidobulle] [@Comendatore] [Slow-release Medpac {3406415871868928}] [ApplyEffect {836045448945477}: Heal {836045448945500}] (5683*)
# [21:32:19.499] [@Bidobulle] [@Comendatore] [Slow-release Medpac {3406415871868928}] [ApplyEffect {836045448945477}: Heal {836045448945500}] (3641)
# [22:37:11.036] [@Comendatore] [Colossal Monolith {3541140406009856}:15814000004760] [Shocked {2044520397013249}] [ApplyEffect {836045448945477}: Damage {836045448945501}] (165 energy {836045448940874}) <1646>
# [22:37:46.168] [@Comendatore] [Colossal Monolith {3541140406009856}:15814000004760] [Ion Storm {3389987621961728}] [ApplyEffect {836045448945477}: Damage {836045448945501}] (20879* elemental {836045448940875}) <52197>
# [22:37:51.623] [Colossal Monolith {3541140406009856}:15814000004760] [@Comendatore] [Great Slam {3543287889657856}] [ApplyEffect {836045448945477}: Damage {836045448945501}] (86 kinetic {836045448940873} -shield {836045448945509} (86 absorbed {836045448945511})) <86>
# [22:38:30.231] [Colossal Monolith {3541140406009856}:15814000004760] [@Comendatore] [Bleeding {3546045258662192}] [ApplyEffect {836045448945477}: Damage {836045448945501}] (10668 internal {836045448940876}) <10668>
class Value:
def __init__(self, x):
if not x:
self.value = 0
self.type = ''
return
foo = x.replace('*','')
#print(foo)
#if not re.search('[a-zA-Z]+', x):
#print(foo)
if any(z in foo for z in dmgTypes) and not any(y in foo for y in instTypes) or not any(w in foo for w in zoneNames) or foo.isdigit():
foo = x.replace('*','').split(' ')
if foo[0].isdigit():
self.value = int(foo[0])
else:
self.value = 0
if len(foo) > 1:
self.type = foo[1]
else:
self.type=''
else:
#print(foo)
self.type = ''
class Threat:
def __init__(self, x):
if not x:
self.value = 0
self.type = ''
return
foo = x.replace('*','').split(' ')
self.value = int(foo[0])
if len(foo) > 1:
self.type = foo[1]
else:
self.type=''
#date, source, target, ability, effect.type/detail, value.value/type, threat
# TODO:
# multiple sources
# more interesting output, graphs? What about that metric site? Google charts?
# App engine seems fun
# Details for abilities:
# dmg per ability
# Combine multiple entries per ability
def main():
if len(sys.argv) == 1:
filename = 'combat_2020-07-25_22_39_58_532658.txt'
print('File not specified, defaulting to ' + filename)
else:
filename = sys.argv[1]
file = open(filename, 'r')
events = []
for line in file.readlines():
events.append(Event(line))
players = set([event.source.name for event in events])
fights = []
isBoss = False
fight = []
for event in events:
if 'EnterCombat' in event.effect.detail:
fight = []
#fight.extend(fight)
#isBoss = False
if 'Death' in event.effect.detail:
#print(event.effect.detail)
#if any(t in event.target.name for t in listEncounters):
fight.append(event)
#print(listEncounters)
#isBoss = False
for event in fight:
##print(event.source.name)
if any(t in event.target.name for t in listEncounters):
isBoss = True
if isBoss:
fights.append(fight)
fight = []
continue
if 'ExitCombat' in event.effect.detail:
#if any(t in event.effect.detail for t in ['ExitCombat','Death']):
fight.append(event)
#print(listEncounters)
isBoss = False
for event in fight:
#print(event.source.name)
if any(t in event.target.name for t in listEncounters):
isBoss = True
if isBoss:
fights.append(fight)
fight = []
continue
fight.append(event)
for i, fight in enumerate(fights):
duration = fight[-1].date - fight[0].date
for event in fight:
if any(t in event.target.name for t in listEncounters):
namedTarget = event.target.name.split(' {')
namedTarget = namedTarget[0]
#print('\nCombat Statistics for Fight # %d (duration: %s)' %(i+1, str(duration)))
print('\nCombat Statistics for Fight #%d -> %s (%s)' %(i+1, namedTarget, str(duration)))
print("Started: " + str(fight[0].date) +" Ended: " + str(fight[-1].date))
for player in players:
if '{' not in player:
dmg = 0
tdmg = 0
heal = 0
theal = 0
threat = 0
death = False
for event in fight:
## Domages done by player (DPS)
if event.source.name == player and 'Damage ' in event.effect.detail:
dmg += event.value.value
## Domages taken by player (DTPS)
if event.target.name == player and 'Damage ' in event.effect.detail:
tdmg += event.value.value
## Heal done by player (HPS)
if event.source.name == player and 'Heal ' in event.effect.detail:
heal += event.value.value
## Heal received by player (HTPS)
if event.target.name == player and 'Heal ' in event.effect.detail:
theal += event.value.value
## Generated threat by player (TPS)
if event.source.name == player and event.threat.value:
threat += event.threat.value
## Dead
if event.source.name == player and 'Death' in event.effect.detail:
death = True
secs = duration.seconds
if not secs:
secs = 1
if dmg:
print('%s did %d damage in %s (%d DPS)' % (player, dmg, str(duration), dmg/secs))
if tdmg:
print('%s took %d damage in %s (%d DTPS)' % (player, tdmg, str(duration), tdmg/secs))
if heal:
print('%s did %d heals in %s (%d HPS)' % (player, heal, str(duration), heal/secs))
if theal:
print('%s received %d heals in %s (%d HTPS)' % (player, theal, str(duration), theal/secs))
if threat:
print('%s did %d threat in %s (%d TPS)' % (player, threat, str(duration), threat/secs))
if death:
print('%s died on %s' % (player, namedTarget))
#print("\n".join([event.to_string for event in events]))
if __name__ == "__main__":
main()