Skip to content

Commit

Permalink
Merge pull request #34 from EboMike/cleanup
Browse files Browse the repository at this point in the history
Add the mini-pies into the SM5 chart.
  • Loading branch information
spookybear0 authored Mar 29, 2024
2 parents 87565a4 + 6b001ba commit 80f8d4d
Show file tree
Hide file tree
Showing 11 changed files with 232 additions and 90 deletions.
48 changes: 48 additions & 0 deletions assets/html/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,54 @@
>
<meta property="og:image" content="">

{% macro alive_time_chart(entity_id, chart_data) -%}

new Chart("time_in_game_{{entity_id}}", {
type: "pie",
data: {
labels: ["In game", "Eliminated"],
datasets: [{
backgroundColor: ["#00ff00", "#000000"],
data: {{ chart_data }}
}]
},
options: {
legend: {
display: false,
fullSize: false
},
title: {
display: false,
}
}
});

{%- endmacro %}

{% macro uptime_chart(entity_id, state_distribution) -%}

new Chart("uptime_{{entity_id}}", {
type: "pie",
data: {
labels: {{ state_distribution.labels }},
datasets: [{
backgroundColor: {{ state_distribution.colors }},
data: {{ state_distribution.data }}
}]
},
options: {
legend: {
display: false,
fullSize: false
},
title: {
display: false,
}
}
});

{%- endmacro %}

<script>
function toggleNav() {
// animate the nav-items
Expand Down
65 changes: 3 additions & 62 deletions assets/html/game/scorecard_sm5.html
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ <h2 class="{{ team.class_name }}_team_header">{{ team.name }} ({{ team.score }})
},
options: {
legend: {
display: false,
display: true,
fullSize: false
},
title: {
Expand Down Expand Up @@ -477,67 +477,8 @@ <h2 class="{{ team.class_name }}_team_header">{{ team.name }} ({{ team.score }})

{% for team in teams %}
{% for player in team.players %}
new Chart("uptime_{{player.entity_end_id}}", {
type: "pie",
data: {
labels: {{ state_distribution_labels }},
datasets: [{
backgroundColor: {{ state_distribution_colors }},
data: {{ player.state_distribution_values }}
}]
},
options: {
legend: {
display: false,
fullSize: false
},
title: {
display: false,
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
const index = tooltipItem["index"];
const label = data.labels[index];
const milliseconds = data.datasets[0].data[index];

return `${label}: ${ms_to_mmss(milliseconds)}`;
}
}
},
}
});

new Chart("time_in_game_{{player.entity_end_id}}", {
type: "pie",
data: {
labels: ["In game", "Eliminated"],
datasets: [{
backgroundColor: ["#00ff00", "#000000"],
data: {{ player.time_in_game_values }}
}]
},
options: {
legend: {
display: false,
fullSize: false
},
title: {
display: false,
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
const index = tooltipItem["index"];
const label = data.labels[index];
const milliseconds = data.datasets[0].data[index];

return `${label}: ${ms_to_mmss(milliseconds)}`;
}
}
},
}
});
{{ uptime_chart(player.entity_end_id, player.state_distribution) }}
{{ alive_time_chart(player.entity_end_id, player.time_in_game_values) }}
{% endfor %}
{% endfor %}

Expand Down
15 changes: 15 additions & 0 deletions assets/html/game/sm5.html
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@
}
}

.mini-chart {
max-width: 64px;
display: flex;
}

.link-button {
background: none;
Expand Down Expand Up @@ -285,9 +289,11 @@ <h2 style="font-size: 20px;" class="team_score {{ team.css_class }}">{{ team.ele
{% endif %}
<th><p>Score</p></th>
<th><p>Lives</p></th>
<th><p>Alive</p></th>
<th><p>Shots</p></th>
<th><p>Accuracy</p></th>
<th><p>K/D</p></th>
<th><p>States</p></th>
<th><p>Missiled Other</p></th>
<th><p>Missiled</p></th>
<th><p>Shot Team</p></th>
Expand Down Expand Up @@ -315,9 +321,11 @@ <h2 style="font-size: 20px;" class="team_score {{ team.css_class }}">{{ team.ele
<td title="Scorecard"><a href="/game/sm5/{{game.id}}/scorecard/{{entity_end.id}}">{{ entity_end.score }}</a></td>
{% endif %}
<td><p>{{ sm5_stats.lives_left }}</p></td>
<td class="scorecard_player_stat"><canvas class="mini-chart" id="time_in_game_{{entity_end.id}}"></canvas></td>
<td><p>{{ sm5_stats.shots_left }}</p></td>
<td title="{{sm5_stats.shots_hit}}/{{sm5_stats.shots_fired}}"><p>{{ sm5_stats.shots_fired and "%.2f" % (((sm5_stats.shots_hit/sm5_stats.shots_fired)*100)|round(2)) }}%</p></td>
<td title="{{sm5_stats.shot_opponent}}/{{sm5_stats.times_zapped}}"><p>{{ sm5_stats.times_zapped and "%.2f" % ((sm5_stats.shot_opponent/sm5_stats.times_zapped)|round(2)) }}</p></td>
<td class="scorecard_player_stat"><canvas class="mini-chart" id="uptime_{{player.entity_end.id}}"></canvas></td>
<td><p>{{ sm5_stats.missiled_opponent }}</p></td>
<td><p>{{ sm5_stats.times_missiled }}</p></td>
<td><p>{{ sm5_stats.shot_team }}</p></td>
Expand Down Expand Up @@ -471,6 +479,13 @@ <h1 class="desktop_notif">For more detailed stats, please view the website on de
}
});
{% endif %}

{% for team in team_ranking %}
{% for player in team_rosters[team] %}
{{ uptime_chart(player.entity_end.id, uptime_values[player.entity_end.id]) }}
{{ alive_time_chart(player.entity_end.id, time_in_game_values[player.entity_end.id]) }}
{% endfor %}
{% endfor %}
</script>

</body>
Expand Down
13 changes: 12 additions & 1 deletion db/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

from __future__ import annotations

from dataclasses import dataclass
from typing import Optional

from db.types import Team, IntRole, EventType, PlayerStateType
from tortoise import Model, fields
from db.sm5 import SM5Stats
Expand Down Expand Up @@ -190,4 +193,12 @@ def __str__(self) -> str:
return f"<EntityEnd {self.entity} score={self.score}>"

def __repr__(self) -> str:
return str(self)
return str(self)


@dataclass
class PlayerInfo:
"""Information about a player in one particular game."""
entity_start: EntityStarts
entity_end: Optional[EntityEnds]
display_name: str
12 changes: 10 additions & 2 deletions db/types.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dataclasses import dataclass
from typing import Optional
from typing import Optional, List
from enum import Enum, IntEnum


Expand Down Expand Up @@ -201,4 +201,12 @@ class PlayerStateDetailType(IntEnum):
class PlayerStateEvent:
"""This denotes a time at which the player state changed."""
timestamp_millis: int
state: Optional[PlayerStateDetailType]
state: Optional[PlayerStateDetailType]


@dataclass
class PieChartData:
"""Data sent to a frontend template to display a pie chart."""
labels: List[str]
colors: List[str]
data: List[int]
33 changes: 29 additions & 4 deletions handlers/game/game.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
from itertools import chain

from sanic import Request

from helpers.gamehelper import SM5_STATE_LABEL_MAP, SM5_STATE_COLORS
from shared import app
from utils import render_template, is_admin
from db.game import EntityEnds, EntityStarts
from db.sm5 import SM5Game, SM5Stats
from db.laserball import LaserballGame, LaserballStats
from helpers.gamehelper import get_team_rosters, get_matchmaking_teams, get_player_display_names
from helpers.gamehelper import get_team_rosters, get_matchmaking_teams
from db.types import Team
from sanic import exceptions
from helpers.statshelper import sentry_trace, get_sm5_team_score_graph_data
from helpers.statshelper import sentry_trace, get_sm5_team_score_graph_data, get_sm5_player_alive_times, \
get_player_state_distribution, get_player_state_distribution_pie_chart
from numpy import arange
from typing import List, Optional

Expand All @@ -30,12 +35,30 @@ async def game_index(request: Request, type: str, id: int) -> str:
if not game:
raise exceptions.NotFound("Not found: Invalid game ID")

game_duration = await game.get_actual_game_duration()
team_rosters = await get_team_rosters(await game.entity_starts.all(), await game.entity_ends.all())

# Get a flat list of all players across all teams.
all_players = list(chain.from_iterable(team_rosters.values()))

scores = {
team: await game.get_team_score(team) for team in team_rosters.keys()
}

time_in_game_values = {
player.entity_end.id: get_sm5_player_alive_times(game_duration, player.entity_end) for player in
all_players if player
}

uptime_values = {
player.entity_end.id: get_player_state_distribution_pie_chart(
await get_player_state_distribution(player.entity_start, player.entity_end,
game.player_states, game.events, SM5_STATE_LABEL_MAP),
SM5_STATE_COLORS)
for player in
all_players if player
}

score_chart_data = await get_sm5_team_score_graph_data(game, list(team_rosters.keys()))

players_matchmake_team1, players_matchmake_team2 = get_matchmaking_teams(team_rosters)
Expand All @@ -56,8 +79,10 @@ async def game_index(request: Request, type: str, id: int) -> str:
team_rosters=team_rosters,
scores=scores,
game=game,
time_in_game_values=time_in_game_values,
uptime_values=uptime_values,
get_sm5stats=get_sm5stats,
score_chart_labels=[t for t in arange(0, 900000//1000//60+0.5, 0.5)],
score_chart_labels=[t for t in arange(0, 900000 // 1000 // 60 + 0.5, 0.5)],
score_chart_data=score_chart_data,
win_chance_before_game=win_chance_before_game,
win_chance_after_game=win_chance_after_game,
Expand All @@ -84,7 +109,7 @@ async def game_index(request: Request, type: str, id: int) -> str:

# Sort the teams in order of their score.
team_ranking = sorted(scores.keys(), key=lambda team: scores[team], reverse=True)

if game.ranked:
win_chance_after_game = await game.get_win_chance_after_game()
win_chance_before_game = await game.get_win_chance_before_game()
Expand Down
11 changes: 6 additions & 5 deletions handlers/game/scorecard.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
from db.game import EntityEnds, EntityStarts
from db.laserball import LaserballGame, LaserballStats
from helpers.statshelper import sentry_trace, _millis_to_time, count_zaps, count_missiles, count_blocks, \
get_player_state_distribution, get_sm5_score_components, get_sm5_kd_ratio
get_player_state_distribution, get_sm5_score_components, get_sm5_kd_ratio, get_sm5_single_player_score_graph_data, \
get_sm5_player_alive_times, get_player_state_distribution_pie_chart
from sanic import exceptions


Expand Down Expand Up @@ -114,15 +115,15 @@ async def scorecard(request: Request, type: str, id: int, entity_end_id: int) ->
" eliminated_player" if player_sm5_stats[player.id] or player_sm5_stats[player.id].lives_left == 0 else ""),
"score": player_entity_ends[player.id].score,
"lives_left": player_sm5_stats[player.id].lives_left if player.id in player_sm5_stats else "",
"time_in_game_values": [player_entity_ends[player.id].time, game_duration - player_entity_ends[player.id].time],
"time_in_game_values": get_sm5_player_alive_times(game_duration, player_entity_ends[player.id]),
"kd_ratio": ("%.2f" % get_sm5_kd_ratio(player_sm5_stats[player.id])) if player.id in player_sm5_stats else "",
"mvp_points": "%.2f" % await player_sm5_stats[player.id].mvp_points(),
"you_zapped": await count_zaps(game, entity_start.entity_id, player.entity_id),
"zapped_you": await count_zaps(game, player.entity_id, entity_start.entity_id),
"you_missiled": await count_missiles(game, entity_start.entity_id, player.entity_id),
"missiled_you": await count_missiles(game, player.entity_id, entity_start.entity_id),
"state_distribution_values": list((await get_player_state_distribution(player, player_entity_ends[player.id],
game.player_states, game.events, SM5_STATE_LABEL_MAP)).values())
"state_distribution": get_player_state_distribution_pie_chart(await get_player_state_distribution(player, player_entity_ends[player.id],
game.player_states, game.events, SM5_STATE_LABEL_MAP), SM5_STATE_COLORS)
} for player in player_entities
])
all_players.sort(key=lambda x: x["score"], reverse=True)
Expand All @@ -142,7 +143,7 @@ async def scorecard(request: Request, type: str, id: int, entity_end_id: int) ->
},
]

score_chart_data = [await game.get_entity_score_at_time(entity_start.id, t) for t in range(0, 900000+30000, 30000)]
score_chart_data = await get_sm5_single_player_score_graph_data(game, entity_start.id)

return await render_template(
request,
Expand Down
13 changes: 2 additions & 11 deletions helpers/gamehelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
only deals with getting and extracting and visualizing data.
"""
from collections import defaultdict
from dataclasses import dataclass
from typing import List, Optional, Dict
from typing import List, Dict

from sanic import exceptions

from db.game import EntityStarts, EntityEnds
from db.game import EntityStarts, EntityEnds, PlayerInfo
from db.types import PlayerStateDetailType, Team

"""Map of every possible player state and the display name for it in SM5 games.
Expand Down Expand Up @@ -39,14 +38,6 @@
}


@dataclass
class PlayerInfo:
"""Information about a player in one particular game."""
entity_start: EntityStarts
entity_end: Optional[EntityEnds]
display_name: str


def get_players_from_team(all_players: List[dict], team_index: int) -> List[dict]:
"""Returns subset of the list of players - only those in the given team.
Expand Down
Loading

0 comments on commit 80f8d4d

Please sign in to comment.