From bf85d61fd2659fa0b23513d9ccd2bc2ba6665f5d Mon Sep 17 00:00:00 2001 From: Fedor Glazov Date: Mon, 12 Apr 2021 20:54:48 +0200 Subject: [PATCH] Fix bug where top 24 fighter pilots wasn't properly filtering jabo flights. --- changelog.txt | 6 ++- readme.txt | 5 +++ .../migrations/0001_initial.py | 28 +++++++++++++ src/mod_rating_by_type/migrations/__init__.py | 0 src/mod_rating_by_type/models.py | 24 +++++++++++ src/mod_rating_by_type/stats_whore.py | 15 +++++++ src/mod_rating_by_type/variant_utils.py | 15 ++++--- src/mod_rating_by_type/views.py | 42 +++++++++---------- 8 files changed, 108 insertions(+), 27 deletions(-) create mode 100644 src/mod_rating_by_type/migrations/0001_initial.py create mode 100644 src/mod_rating_by_type/migrations/__init__.py create mode 100644 src/mod_rating_by_type/models.py diff --git a/changelog.txt b/changelog.txt index cb5fd09..b3ac055 100644 --- a/changelog.txt +++ b/changelog.txt @@ -32,4 +32,8 @@ Version 2.0.1 Version 2.0.2 -- Update Spanish localization. \ No newline at end of file +- Update Spanish localization. + +Version 2.0.3 + +- Fix bug where "Best Fighter/Attacker pilot in the last 24 hours" was not properly counting jabo flights towards attacker pilots. \ No newline at end of file diff --git a/readme.txt b/readme.txt index 7f74606..b58d79c 100644 --- a/readme.txt +++ b/readme.txt @@ -58,6 +58,11 @@ Installation 4. Inside your src/conf.ini add the config parameter modules under [stats]. Set it to the modules you want using their config names, seperated by commas. For example, if you want the Split Ranking and Ammo Breakdown modules, you need to add the line "modules = split_rankings, ammo_breakdown". +After step 3 and 4 your config should contain two lines like: + +mods = mod_rating_by_type +modules = split_rankings, ammo_breakdown, ironman_stats + 5. Run collect_static in your run folder. Otherwise you will likely get a 500 error on the pilot rankings page. Uninstallation diff --git a/src/mod_rating_by_type/migrations/0001_initial.py b/src/mod_rating_by_type/migrations/0001_initial.py new file mode 100644 index 0000000..39741e8 --- /dev/null +++ b/src/mod_rating_by_type/migrations/0001_initial.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.29 on 2021-04-12 18:36 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('stats', '0035_score_ai_value'), + ] + + operations = [ + migrations.CreateModel( + name='SortieAugmentation', + fields=[ + ('sortie', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, primary_key=True, related_name='SortieAugmentation_MOD_SPLIT_RANKINGS', serialize=False, to='stats.Sortie')), + ('cls', models.CharField(blank=True, choices=[('heavy', 'heavy'), ('medium', 'medium'), ('light', 'light'), ('placeholder', 'placeholder')], max_length=16)), + ], + options={ + 'db_table': 'Sortie_MOD_SPLIT_RANKINGS', + }, + ), + ] diff --git a/src/mod_rating_by_type/migrations/__init__.py b/src/mod_rating_by_type/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/mod_rating_by_type/models.py b/src/mod_rating_by_type/models.py new file mode 100644 index 0000000..ed9b72c --- /dev/null +++ b/src/mod_rating_by_type/models.py @@ -0,0 +1,24 @@ +from django.db import models +from stats.models import Sortie + + +# Additional fields to Sortie objects used by this mod. +class SortieAugmentation(models.Model): + sortie = models.OneToOneField(Sortie, on_delete=models.PROTECT, primary_key=True, + related_name='SortieAugmentation_MOD_SPLIT_RANKINGS') + + CLASSES = ( + ('heavy', 'heavy'), + ('medium', 'medium'), + ('light', 'light'), + ('placeholder', 'placeholder') + ) + + # This class differs from the cls found in a Sortie object. + # Namely: Jabo flights are considred "medium", and P-38/Me-262 without bombs are considered "light" + # In all other cases, it should be equal to the one found in + cls = models.CharField(choices=CLASSES, max_length=16, blank=True) + + class Meta: + # The long table name is to avoid any conflicts with new tables defined in the main branch of IL2 Stats. + db_table = "Sortie_MOD_SPLIT_RANKINGS" diff --git a/src/mod_rating_by_type/stats_whore.py b/src/mod_rating_by_type/stats_whore.py index 622dbb4..da1df62 100644 --- a/src/mod_rating_by_type/stats_whore.py +++ b/src/mod_rating_by_type/stats_whore.py @@ -3,6 +3,7 @@ from datetime import timedelta from stats.models import Sortie from .variant_utils import is_jabo, is_fighter +from .models import SortieAugmentation SORTIE_MIN_TIME = settings.SORTIE_MIN_TIME @@ -110,6 +111,18 @@ def create_new_sortie(mission, profile, player, sortie, sortie_aircraft_id): is_ignored=is_ignored, ) + new_sortie.save() + + cls = 'placeholder' + if is_fighter(new_sortie): + cls = 'light' + elif new_sortie.aircraft.cls == "aircraft_medium" or is_jabo(new_sortie): + cls = 'medium' + elif new_sortie.aircraft.cls == "aircraft_heavy": + cls = 'heavy' + + SortieAugmentation(sortie=new_sortie, cls=cls).save() + return new_sortie @@ -129,6 +142,8 @@ def create_ammo(sortie): result['ammo_breakdown'] = sortie.ammo_breakdown return result + + # ======================== MODDED PART END diff --git a/src/mod_rating_by_type/variant_utils.py b/src/mod_rating_by_type/variant_utils.py index bf8d9a1..3b59470 100644 --- a/src/mod_rating_by_type/variant_utils.py +++ b/src/mod_rating_by_type/variant_utils.py @@ -1,7 +1,6 @@ BOMB_VARIANT_WHITE_LIST = {'P-38J-25', 'Me 262 A', 'Bristol F2B (F.II)', 'Bristol F2B (F.III)', 'Halberstadt CL.II', 'Halberstadt CL.II 200hp'} FIGHTER_WHITE_LIST = {'P-38J-25', 'Me 262 A'} - JABO_MODS = {'Ground attack modification', 'U17 strike modification'} @@ -11,15 +10,21 @@ def is_jabo(sortie): if sortie.aircraft.cls != 'aircraft_light' and sortie.aircraft.name_en not in BOMB_VARIANT_WHITE_LIST: return False - for modification in sortie.modifications: - if 'bomb' in modification.lower() or 'rocket' in modification.lower(): - return True - if modification in JABO_MODS: + for mod in sortie.modifications: + if __is_modification_jabo(mod): return True return False +def __is_modification_jabo(mod): + if 'bomb' in mod.lower() or 'rocket' in mod.lower(): + return True + if mod in JABO_MODS: + return True + return False + + def is_fighter(sortie): if is_jabo(sortie): return False diff --git a/src/mod_rating_by_type/views.py b/src/mod_rating_by_type/views.py index 014f516..4519472 100644 --- a/src/mod_rating_by_type/views.py +++ b/src/mod_rating_by_type/views.py @@ -1,20 +1,20 @@ from datetime import timedelta from django.conf import settings -from django.db.models import Sum, OuterRef, Subquery +from django.db.models import Sum, OuterRef, Subquery, Q from django.http import Http404 from django.shortcuts import render, get_object_or_404, redirect from django.utils import timezone from mission_report.constants import Coalition - from stats.helpers import Paginator, get_sort_by, redirect_fix_url -from stats.models import (Player, Mission, PlayerMission, PlayerAircraft, Sortie, KillboardPvP, - Tour, LogEntry, Profile, Squad, Reward, PlayerOnline, VLife) -from stats import sortie_log -from stats.views import _get_rating_position, _get_squad +from stats.models import (Player, Mission, PlayerMission, PlayerAircraft, Sortie, Tour, Profile, Squad, PlayerOnline, + VLife) from stats.views import * +from stats.views import _get_rating_position, _get_squad + from .bullets_types import translate_ammo_breakdown from .config_modules import * +from .variant_utils import FIGHTER_WHITE_LIST INACTIVE_PLAYER_DAYS = settings.INACTIVE_PLAYER_DAYS ITEMS_PER_PAGE = 20 @@ -155,7 +155,7 @@ def pilot(request, profile_id, nickname=None): }) -def _top_24_queryset(tour_id, aircraft_cls=None): +def __top_24_pilots(tour_id, cls=None): _queryset = (Sortie.objects .exclude(score=0) .filter(tour_id=tour_id, @@ -163,13 +163,17 @@ def _top_24_queryset(tour_id, aircraft_cls=None): player__type='pilot', profile__is_hide=False, date_start__gt=timezone.now() - timedelta(hours=24))) - if aircraft_cls: - _queryset = _queryset.filter(aircraft__cls=aircraft_cls) - return _queryset.values('player').annotate(sum_score=Sum('score')) + if cls: + aircraft_cls = 'aircraft_' + cls + _queryset = _queryset.filter( + (Q(SortieAugmentation_MOD_SPLIT_RANKINGS__cls=cls) # Expected case. E.g. recorded jabos as type 'medium'. + + # The edge case, when this mod is freshly installed we haven't recorded type. So instead use aircraft type. + | (Q(aircraft__cls=aircraft_cls) & Q(SortieAugmentation_MOD_SPLIT_RANKINGS=None)))) -def _top_pilots(tour_id, queryset): - top_24_score = queryset.order_by('-sum_score')[:10] + _queryset = _queryset.values('player').annotate(sum_score=Sum('score')) + top_24_score = _queryset.order_by('-sum_score')[:10] top_24_pilots = Player.players.pilots(tour_id=tour_id).filter(id__in=[s['player'] for s in top_24_score]) top_24_pilots = {p.id: p for p in top_24_pilots} top_24 = [] @@ -191,8 +195,7 @@ def main(request): .exclude(score_streak_current=0) .active(tour=request.tour).order_by('-score_streak_current')[:10]) - top_24 = _top_pilots(tour_id=request.tour.id, - queryset=_top_24_queryset(tour_id=request.tour.id)) + top_24 = __top_24_pilots(tour_id=request.tour.id) if module_active(MODULE_SPLIT_RANKINGS): top_streak_heavy = (Player.players.pilots(tour_id=request.tour.id) @@ -204,12 +207,9 @@ def main(request): top_streak_light = (Player.players.pilots(tour_id=request.tour.id) .exclude(score_streak_current_light=0) .active(tour=request.tour).order_by('-score_streak_current_light')[:10]) - top_24_heavy = _top_pilots(tour_id=request.tour.id, - queryset=_top_24_queryset(tour_id=request.tour.id, aircraft_cls='aircraft_heavy')) - top_24_medium = _top_pilots(tour_id=request.tour.id, - queryset=_top_24_queryset(tour_id=request.tour.id, aircraft_cls='aircraft_medium')) - top_24_light = _top_pilots(tour_id=request.tour.id, - queryset=_top_24_queryset(tour_id=request.tour.id, aircraft_cls='aircraft_light')) + top_24_heavy = __top_24_pilots(tour_id=request.tour.id, cls='heavy') + top_24_medium = __top_24_pilots(tour_id=request.tour.id, cls='medium') + top_24_light = __top_24_pilots(tour_id=request.tour.id, cls='light') else: top_streak_heavy = None top_streak_medium = None @@ -389,7 +389,7 @@ def pilot_sortie(request, sortie_id): return render(request, 'pilot_sortie.html', { 'player': sortie.player, 'sortie': sortie, - 'score_dict': mission_score_dict or sortie.mission.score_dict, + 'score_dict': mission_score_dict or sortie.mission.score_dict, 'ammo_breakdown': ammo_breakdown, })