Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions django/discordbot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ def create_invitation(squad, discord_name):
return None


@sync_to_async
def calculate_preview_player_value(squad):
current_session = squad.sessions.filter(is_closed = False).order_by('-id').first()
if current_session:
return current_session.calculate_preview_player_value()
return None


class BotError(Exception):

def __init__(self, msg):
Expand Down Expand Up @@ -134,6 +142,19 @@ async def who_is_your_creator(ctx):
await ctx.response.send_message('The only and almighty, *TEH VOID OF THE AETHER!!1*'.upper())


@bot.tree.command(description='Preview your updated 30-days average player value based on current session.')
async def preview(ctx):
squad = await get_squad(channel_id = ctx.channel_id)
if squad is None:
await ctx.response.send_message(f'No squad registered for this Discord channel')
else:
preview_value = await calculate_preview_player_value(squad)
if preview_value is None:
await ctx.response.send_message(f'No active session found or unable to calculate preview value.')
else:
await ctx.response.send_message(f'The preview of the updated 30-days average player value is: {preview_value:.2f}')


if os.environ.get('CS2PB_DISCORD_ENABLED', False):
log.info(f'Discord integration enabled')
enabled = True
Expand Down
23 changes: 23 additions & 0 deletions django/stats/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,29 @@ def close(self) -> None:
self.rising_star = top_player
self.save()

def calculate_preview_player_value(self) -> Optional[float]:
"""
Calculate the preview of the updated 30-days average player value.
"""
if self.is_closed:
return None

# Calculate the player value for each participant in the current session
player_values = []
for m in self.squad.memberships.all():
ctx = FeatureContext(
MatchParticipation.objects.filter(player = m.player, pmatch__sessions = self),
m.player,
)
pv_today = Features.player_value(ctx)
if pv_today is not None:
player_values.append(pv_today)

# Calculate the average player value
if player_values:
return sum(player_values) / len(player_values)
return None
Comment on lines +204 to +225
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code computes the average player value of all participants in the current session, instead of computing the 30-days average of only a single player.


@staticmethod
def sessions_changed(sender, action, pk_set, instance, **kwargs):
if action == 'pre_add':
Expand Down
137 changes: 137 additions & 0 deletions django/stats/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1335,3 +1335,140 @@ def test_rising_star_with_avatar(self):
actual = attachment,
expected = 'tests/data/radarplot_with_avatar.png',
)


class GamingSession__calculate_preview_player_value(TestCase):

@testsuite.fake_api('accounts.models')
def setUp(self):
self.player1 = SteamProfile.objects.create(steamid = '12345678900000001')
self.player2 = SteamProfile.objects.create(steamid = '12345678900000002')
self.squad = Squad.objects.create(name = 'Test Squad', discord_channel_id = '1234')
SquadMembership.objects.create(squad = self.squad, player = self.player1)
SquadMembership.objects.create(squad = self.squad, player = self.player2)

# Create a currently played session
self.session = models.GamingSession.objects.create(squad = self.squad)
self.match = models.Match.objects.create(
timestamp = int(time.time()),
score_team1 = 12, score_team2 = 13,
duration = 1653,
map_name = 'de_dust2',
)
self.match.sessions.add(self.session)
self.participation1 = models.MatchParticipation.objects.create(
player = self.player1,
pmatch = self.match,
team = 1,
result = 'l',
kills = 20,
assists = 10,
deaths = 15,
score = 30,
mvps = 5,
headshots = 15,
adr = 120.5,
)
self.participation2 = models.MatchParticipation.objects.create(
player = self.player2,
pmatch = self.match,
team = 1,
result = 'l',
kills = 10,
assists = 5,
deaths = 10,
score = 15,
mvps = 3,
headshots = 10,
adr = 90,
)

def test_calculate_preview_player_value(self):
preview_value = self.session.calculate_preview_player_value()
expected_value = (math.sqrt((20 / 15) * 120.5 / 100) + math.sqrt((10 / 10) * 90 / 100)) / 2
self.assertAlmostEqual(preview_value, expected_value, places=2)

def test_calculate_preview_player_value_closed_session(self):
self.session.is_closed = True
self.session.save()
preview_value = self.session.calculate_preview_player_value()
self.assertIsNone(preview_value)

def test_calculate_preview_player_value_no_participation(self):
self.participation1.delete()
self.participation2.delete()
preview_value = self.session.calculate_preview_player_value()
self.assertIsNone(preview_value)


class DiscordBotPreviewCommandTest(TestCase):

@testsuite.fake_api('accounts.models')
def setUp(self):
self.player1 = SteamProfile.objects.create(steamid = '12345678900000001')
self.player2 = SteamProfile.objects.create(steamid = '12345678900000002')
self.squad = Squad.objects.create(name = 'Test Squad', discord_channel_id = '1234')
SquadMembership.objects.create(squad = self.squad, player = self.player1)
SquadMembership.objects.create(squad = self.squad, player = self.player2)

# Create a currently played session
self.session = models.GamingSession.objects.create(squad = self.squad)
self.match = models.Match.objects.create(
timestamp = int(time.time()),
score_team1 = 12, score_team2 = 13,
duration = 1653,
map_name = 'de_dust2',
)
self.match.sessions.add(self.session)
self.participation1 = models.MatchParticipation.objects.create(
player = self.player1,
pmatch = self.match,
team = 1,
result = 'l',
kills = 20,
assists = 10,
deaths = 15,
score = 30,
mvps = 5,
headshots = 15,
adr = 120.5,
)
self.participation2 = models.MatchParticipation.objects.create(
player = self.player2,
pmatch = self.match,
team = 1,
result = 'l',
kills = 10,
assists = 5,
deaths = 10,
score = 15,
mvps = 3,
headshots = 10,
adr = 90,
)

@patch('discordbot.bot.get_squad')
@patch('discordbot.bot.calculate_preview_player_value')
@patch('discordbot.bot.ctx')
async def test_preview_command(self, mock_ctx, mock_calculate_preview_player_value, mock_get_squad):
mock_get_squad.return_value = self.squad
mock_calculate_preview_player_value.return_value = 1.23

await discordbot.bot.preview(mock_ctx)

mock_ctx.response.send_message.assert_called_once_with(
f'The preview of the updated 30-days average player value is: 1.23'
)

@patch('discordbot.bot.get_squad')
@patch('discordbot.bot.calculate_preview_player_value')
@patch('discordbot.bot.ctx')
async def test_preview_command_no_active_session(self, mock_ctx, mock_calculate_preview_player_value, mock_get_squad):
mock_get_squad.return_value = self.squad
mock_calculate_preview_player_value.return_value = None

await discordbot.bot.preview(mock_ctx)

mock_ctx.response.send_message.assert_called_once_with(
f'No active session found or unable to calculate preview value.'
)
Loading