Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Goran Topic committed Oct 30, 2017
2 parents 4eb6e8e + 7fd7e33 commit 0ea9e77
Show file tree
Hide file tree
Showing 14 changed files with 236 additions and 122 deletions.
19 changes: 9 additions & 10 deletions analyser/analyser.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,26 +128,25 @@ def preprocess_agents(self, agents, collector, events):
['dst_instid']].groupby('dst_instid').size().rename('hit_count')
agents = agents.join(agents_that_get_hit_a_lot)
agents.hit_count.fillna(0, inplace=True)


#Fix player parties
if (self.boss_info.force_single_party) | (not agents[(agents.prof >= 1) & (agents.prof <= 9) & (agents.party == 0)].empty):
agents.loc[(agents.prof >= 1) & (agents.prof <= 9), 'party'] = 1

#identify specific ones we care about
players = agents[(agents.prof >= 1) & (agents.prof <= 9)]

if len(players) < 1:
raise EvtcAnalysisException("No players found in this log")
elif len(players) > 50:
raise EvtcAnalysisException("Too many players found in this log: {0}".format(len(agents)))

if not players[players.party == 0].empty:
for player in players.index.values:
agents.loc[player, 'party'] = 1
players = agents[(agents.prof >= 1) & (agents.prof <= 9)]

bosses = agents[(agents.prof.isin(self.boss_info.boss_ids)) |
(self.boss_info.has_structure_boss
& (agents.prof < 0)
& (agents.hit_count >= 100))]
final_bosses = agents[agents.prof == self.boss_info.boss_ids[-1]]

#set up important preprocessed data
self.subgroups = dict([(number, subgroup.index.values) for number, subgroup in players.groupby("party")])

Expand All @@ -157,7 +156,7 @@ def preprocess_agents(self, agents, collector, events):
print(self.boss_instids)
self.final_boss_instids = final_bosses.index.values
collector.set_context_value(ContextType.AGENT_NAME, create_mapping(agents, 'name'))
return players, bosses, final_bosses
return agents, players, bosses, final_bosses

def preprocess_events(self, events):
#experimental phase calculations
Expand Down Expand Up @@ -253,7 +252,7 @@ def __init__(self, encounter):

agents = encounter.agents
skills = encounter.skills
players, bosses, final_bosses = self.preprocess_agents(agents, collector, events)
agents, players, bosses, final_bosses = self.preprocess_agents(agents, collector, events)

self.preprocess_skills(skills, collector)
self.players = players
Expand Down
15 changes: 8 additions & 7 deletions analyser/bosses.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def __repr__(self):
return "%s (%s, %s)" % (self.name, self.data_type, self.desired)

class Boss:
def __init__(self, name, kind, boss_ids, metrics=None, sub_boss_ids=None, key_npc_ids = None, phases=None, despawns_instead_of_dying = False, has_structure_boss = False, success_health_limit = None, cm_detector = no_cm):
def __init__(self, name, kind, boss_ids, metrics=None, sub_boss_ids=None, key_npc_ids = None, phases=None, despawns_instead_of_dying = False, has_structure_boss = False, success_health_limit = None, cm_detector = no_cm, force_single_party = False):
self.name = name
self.kind = kind
self.boss_ids = boss_ids
Expand All @@ -59,6 +59,7 @@ def __init__(self, name, kind, boss_ids, metrics=None, sub_boss_ids=None, key_np
self.has_structure_boss = has_structure_boss
self.success_health_limit = success_health_limit
self.cm_detector = cm_detector
self.force_single_party = force_single_party

class Phase:
def __init__(self, name, important,
Expand Down Expand Up @@ -270,14 +271,14 @@ def find_end_time(self,
Phase("Phase 2", True, phase_end_health = 33, phase_end_damage_stop = 15000),
Phase("Second split", False, phase_end_damage_start = 15000),
Phase("Phase 3", True, phase_end_health=1)
], cm_detector = yes_cm),
], cm_detector = yes_cm, force_single_party = True),
Boss('Artsariiv (CM)', Kind.FRACTAL, [0x461d], despawns_instead_of_dying = True, success_health_limit = 3, phases = [
Phase("Phase 1", True, phase_end_health = 66, phase_end_damage_stop = 10000),
Phase("First split", False, phase_end_damage_start = 10000),
Phase("Phase 2", True, phase_end_health = 33, phase_end_damage_stop = 10000),
Phase("Second split", False, phase_end_damage_start = 10000),
Phase("Phase 3", True, phase_end_health=1)
], cm_detector = yes_cm),
], cm_detector = yes_cm, force_single_party = True),
Boss('Arkk (CM)', Kind.FRACTAL,[0x455f], despawns_instead_of_dying = True, success_health_limit = 3, phases =[
Phase("100-80", True, phase_end_health = 80, phase_end_damage_stop = 10000),
Phase("First orb", False, phase_end_damage_start = 10000),
Expand All @@ -290,7 +291,7 @@ def find_end_time(self,
Phase("40-30", True, phase_end_health = 30, phase_end_damage_stop = 10000),
Phase("Third orb", False, phase_end_damage_start = 10000),
Phase("30-0", True, phase_end_health = 1, phase_end_damage_stop = 10000)
], cm_detector = yes_cm),
], cm_detector = yes_cm, force_single_party = True),
Boss('MAMA (CM)', Kind.FRACTAL, [0x427d], phases = [
Phase("Phase 1", True, phase_end_health = 75, phase_end_damage_stop = 3000),
Phase("First split", False, phase_end_damage_start = 3000),
Expand All @@ -299,21 +300,21 @@ def find_end_time(self,
Phase("Phase 3", True, phase_end_health = 25, phase_end_damage_stop = 3000),
Phase("Second split", False, phase_end_damage_start = 3000),
Phase("Phase 4", True, phase_end_health=1)
], cm_detector = yes_cm),
], cm_detector = yes_cm, force_single_party = True),
Boss('Siax (CM)', Kind.FRACTAL,[0x4284], phases = [
Phase("Phase 1", True, phase_end_health = 66, phase_end_damage_stop = 15000),
Phase("First split", False, phase_end_damage_start = 15000),
Phase("Phase 2", True, phase_end_health = 33, phase_end_damage_stop = 15000),
Phase("Second split", False, phase_end_damage_start = 15000),
Phase("Phase 3", True, phase_end_health=1)
], cm_detector = yes_cm),
], cm_detector = yes_cm, force_single_party = True),
Boss('Ensolyss (CM)', Kind.FRACTAL,[0x4234], phases = [
Phase("Phase 1", True, phase_end_health = 66, phase_end_damage_stop = 15000),
Phase("First split", False, phase_end_damage_start = 15000),
Phase("Phase 2", True, phase_end_health = 33, phase_end_damage_stop = 15000),
Phase("Second split", False, phase_end_damage_start = 15000),
Phase("Phase 3", True, phase_end_health=15),
Phase("Phase 4", True, phase_end_health=1)
], cm_detector = yes_cm)
], cm_detector = yes_cm, force_single_party = True)
]
BOSSES = {boss.boss_ids[0]: boss for boss in BOSS_ARRAY}
7 changes: 7 additions & 0 deletions raidar/management/commands/process_uploads.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ def analyse_upload(self, upload):
started_at = dump['Category']['encounter']['start']
duration = dump['Category']['encounter']['duration']
success = dump['Category']['encounter']['success']
upload_val = upload.val
category_id = upload_val.get('category_id', None)
tagstring = upload_val.get('tagstring', '')
if duration < 60:
raise EvtcAnalysisException('Encounter shorter than 60s')

Expand Down Expand Up @@ -238,6 +241,8 @@ def analyse_upload(self, upload):
encounter.started_at = started_at
encounter.started_at_full = started_at_full
encounter.started_at_half = started_at_half
encounter.category_id = category_id
encounter.tagstring = tagstring
if not zipfile:
encounter.filename += ".zip"
encounter.save()
Expand All @@ -248,8 +253,10 @@ def analyse_upload(self, upload):
duration=duration, success=success, val=dump,
area=area, era=era, started_at=started_at,
started_at_full=started_at_full, started_at_half=started_at_half,
category_id=category_id,
account_hash=account_hash
)
encounter.tagstring = tagstring

file.close()
file = None
Expand Down
33 changes: 15 additions & 18 deletions raidar/management/commands/restat.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from ._qsetiter import queryset_iterator
from collections import defaultdict
from functools import partial
from contextlib import contextmanager
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
Expand Down Expand Up @@ -90,10 +91,7 @@ def bound_stats(output, name, value):
if minprop not in output or value < output[minprop]:
output[minprop] = value

def advanced_stats(maximum_percentile_samples):
return lambda a,b,c: advanced_stats_internal(maximum_percentile_samples, a, b, c)

def advanced_stats_internal(maximum_percentile_samples, output, name, value):
def advanced_stats(maximum_percentile_samples, output, name, value):
bound_stats(output, name, value)
average_stats(output, name, value)
l = output.get('values|' + name, [])
Expand Down Expand Up @@ -155,11 +153,10 @@ def calculate_standard_stats(f, stats, main_stat_targets, incoming_buff_targets,
incoming_buff_stats = _safe_get(lambda: stats['Metrics']['buffs']['From']['*All'], {})

for stat in ['dps','crit','seaweed','scholar','flanking']:
calculate(main_stat_targets, f, stat, _safe_get(lambda: stats_in_phase_to_all[stat]))
calculate(main_stat_targets, f, 'dps_boss', _safe_get(lambda: stats_in_phase_to_boss['dps']))
calculate(main_stat_targets, f, 'dps_received', _safe_get(lambda: stats_in_phase_from_all['dps']))
calculate(main_stat_targets, f, 'total_received', _safe_get(lambda: stats_in_phase_from_all['total']))
calculate(main_stat_targets, f, 'total_shielded', _safe_get(lambda: shielded_in_phase_from_all['total']))
calculate(main_stat_targets, f, stat, stats_in_phase_to_all.get(stat, 0))
calculate(main_stat_targets, f, 'dps_boss', stats_in_phase_to_boss.get('dps', 0))
calculate(main_stat_targets, f, 'dps_received', stats_in_phase_from_all.get('dps', 0))
calculate(main_stat_targets, f, 'total_received', stats_in_phase_from_all.get('total', 0))

for buff, value in incoming_buff_stats.items():
calculate(incoming_buff_targets, f, buff, value)
Expand Down Expand Up @@ -250,7 +247,7 @@ def calculate_stats(self, *args, **options):
"area": {},
"user": {}
}
era_queryset = era.encounters.all().order_by('?')
era_queryset = era.encounters.prefetch_related('participations__character', 'participations__character__account').all().order_by('?')
totals_in_era = {}
for encounter in queryset_iterator(era_queryset):
boss = BOSSES[encounter.area_id]
Expand All @@ -260,6 +257,7 @@ def calculate_stats(self, *args, **options):
phases = data['Category']['combat']['Phase']
totals_in_area = navigate(totals['area'], encounter.area_id)

participations = encounter.participations.all()
for phase, stats_in_phase in phases.items():
squad_stats = stats_in_phase['Subgroup']['*All']
phase_duration = data['Category']['encounter']['duration'] if phase == 'All' else _safe_get(lambda: data['Category']['encounter']['Phase'][phase]['duration'])
Expand All @@ -274,20 +272,19 @@ def calculate_stats(self, *args, **options):

if(encounter.success):
calculate([group_totals, group_totals_era],
advanced_stats(options['percentile_samples']),
partial(advanced_stats, options['percentile_samples']),
'duration',
phase_duration)
calculate([group_totals, group_totals_era], count)
calculate_standard_stats(
advanced_stats(options['percentile_samples']),
partial(advanced_stats, options['percentile_samples']),
squad_stats,
[group_totals, group_totals_era],
[buffs_by_party, buffs_by_party_era],
[buffs_out_by_party, buffs_out_by_party_era])

individual_totals = navigate(totals_in_area, phase, 'individual')
individual_totals_era = navigate(totals_in_era, phase, 'individual')
participations = encounter.participations.select_related('character', 'character__account').all()
for participation in participations:
# XXX in case player did not actually participate (hopefully fix in analyser)
if (participation.character.name not in stats_in_phase['Player']):
Expand Down Expand Up @@ -315,7 +312,7 @@ def calculate_stats(self, *args, **options):
calculate([totals_by_build, totals_by_archetype, totals_by_spec, individual_totals,
totals_by_build_era, totals_by_archetype_era, totals_by_spec_era, individual_totals_era], count)
calculate_standard_stats(
advanced_stats(options['percentile_samples']),
partial(advanced_stats, options['percentile_samples']),
player_stats,
[totals_by_build, totals_by_archetype, totals_by_spec, individual_totals,
totals_by_build_era, totals_by_archetype_era, totals_by_spec_era, individual_totals_era],
Expand All @@ -337,11 +334,11 @@ def calculate_stats(self, *args, **options):
player_stats,
profile_output.breakdown,
[],
map(lambda a: navigate(a, 'outgoing'), profile_output.breakdown))
[navigate(a, 'outgoing') for a in profile_output.breakdown])

dead_percentage = 100 * _safe_get(lambda: stats_in_phase_events['dead_time']) / duration
down_percentage = 100 * _safe_get(lambda: stats_in_phase_events['down_time']) / duration
disconnect_percentage = 100 * _safe_get(lambda: stats_in_phase_events['disconnect_time']) / duration
dead_percentage = 100 * stats_in_phase_events.get('dead_time', 0) / duration
down_percentage = 100 * stats_in_phase_events.get('down_time', 0) / duration
disconnect_percentage = 100 * stats_in_phase_events.get('disconnect_time', 0) / duration

calculate(profile_output.all, average_stats, 'dead_percentage', dead_percentage)
calculate(profile_output.all, average_stats, 'down_percentage', down_percentage)
Expand Down
45 changes: 45 additions & 0 deletions raidar/migrations/0028_value_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-10-26 06:48
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('raidar', '0027_era_default_sort'),
]

operations = [
migrations.AlterField(
model_name='encounter',
name='value',
field=models.TextField(default='{}', editable=False),
),
migrations.AlterField(
model_name='era',
name='value',
field=models.TextField(default='{}', editable=False),
),
migrations.AlterField(
model_name='eraareastore',
name='value',
field=models.TextField(default='{}', editable=False),
),
migrations.AlterField(
model_name='erauserstore',
name='value',
field=models.TextField(default='{}', editable=False),
),
migrations.AlterField(
model_name='notification',
name='value',
field=models.TextField(default='{}', editable=False),
),
migrations.AlterField(
model_name='variable',
name='value',
field=models.TextField(default='{}', editable=False),
),
]
20 changes: 20 additions & 0 deletions raidar/migrations/0029_upload_value.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-10-26 06:50
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('raidar', '0028_value_model'),
]

operations = [
migrations.AddField(
model_name='upload',
name='value',
field=models.TextField(default='{}', editable=False),
),
]
Loading

0 comments on commit 0ea9e77

Please sign in to comment.