Skip to content

Commit

Permalink
Merge branch 'master' into feature/191
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMaximum committed Oct 4, 2017
2 parents 162862a + 96beaf0 commit ae0e20f
Show file tree
Hide file tree
Showing 12 changed files with 444 additions and 24 deletions.
11 changes: 9 additions & 2 deletions pyplanet/apps/contrib/admin/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ async def on_start(self):
await self.instance.permission_manager.register('kick', 'Kick a player', app=self.app, min_level=1)
await self.instance.permission_manager.register('ban', 'Ban a player', app=self.app, min_level=2)
await self.instance.permission_manager.register('unban', 'Unban a player', app=self.app, min_level=2)
await self.instance.permission_manager.register('blacklist', 'Blacklist a player', app=self.app, min_level=3)
await self.instance.permission_manager.register('unblacklist', 'Unblacklist a player', app=self.app, min_level=3)
await self.instance.permission_manager.register('manage_admins', 'Manage admin', app=self.app, min_level=3)
await self.instance.permission_manager.register('force_spec', 'Force player into spectate', app=self.app, min_level=1)
await self.instance.permission_manager.register('force_team', 'Force player into a team', app=self.app, min_level=1)
Expand All @@ -31,6 +33,8 @@ async def on_start(self):
Command(command='kick', target=self.kick_player, perms='admin:kick', admin=True).add_param(name='login', required=True),
Command(command='ban', target=self.ban_player, perms='admin:ban', admin=True).add_param(name='login', required=True),
Command(command='unban', target=self.unban_player, perms='admin:unban', admin=True).add_param(name='login', required=True),
Command(command='blacklist', aliases=['black'], target=self.blacklist_player, perms='admin:blacklist', admin=True).add_param(name='login', required=True),
Command(command='unblacklist', aliases=['unblack'], target=self.unblacklist_player, perms='admin:unblacklist', admin=True).add_param(name='login', required=True),
Command(command='level', target=self.change_level, perms='admin:manage_admins', description='Change admin level for player.', admin=True)
.add_param(name='login', required=True)
.add_param(name='level', required=False, help='Level, 0 = player, 1 = operator, 2 = admin, 3 = master admin.', type=int, default=0),
Expand Down Expand Up @@ -191,8 +195,11 @@ async def blacklist_player(self, player, data, **kwargs):
self.instance.chat(message)
)
except PlayerNotFound:
message = '$i$f00Unknown login!'
await self.instance.chat(message, player)
message = '$ff0Admin $fff{}$z$s$ff0 has blacklisted $fff{}$z$s$ff0.'.format(player.nickname, data.login)
await self.instance.gbx.multicall(
self.instance.gbx('BlackList', data.login),
self.instance.chat(message)
)

async def unblacklist_player(self, player, data, **kwargs):
message = '$ff0Admin $fff{}$z$s$ff0 has un-blacklisted $fff{}$z$s$ff0.'.format(player.nickname, data.login)
Expand Down
25 changes: 25 additions & 0 deletions pyplanet/apps/core/statistics/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

from pyplanet.apps.config import AppConfig
from pyplanet.apps.core.statistics.processor import StatisticsProcessor
from pyplanet.apps.core.statistics.tm import TrackmaniaComponent


class Statistics(AppConfig):
core = True

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

# Initiate components.
self.processor = StatisticsProcessor(self)
self.trackmania = TrackmaniaComponent(self)

async def on_init(self):
# Call components.
if self.instance.game.game == 'tm':
await self.trackmania.on_init()

async def on_start(self):
# Call components.
if self.instance.game.game == 'tm':
await self.trackmania.on_start()
21 changes: 2 additions & 19 deletions pyplanet/apps/core/statistics/app.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,4 @@
from pyplanet.apps.config import AppConfig
from pyplanet.apps.core.statistics.tm import TrackmaniaComponent

from . import Statistics as RealStatistics

class StatisticsConfig(AppConfig):
name = 'pyplanet.apps.core.statistics'
core = True

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

# Initiate components.
self.trackmania = TrackmaniaComponent(self)

async def on_init(self):
# Call components.
await self.trackmania.on_init()

async def on_start(self):
# Call components.
await self.trackmania.on_start()
StatisticsConfig = RealStatistics
103 changes: 103 additions & 0 deletions pyplanet/apps/core/statistics/processor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""
This file contains several queries and logic to fetch statistics that can be displayed on the statistics views.
Please note that this file is only meant for the statistics app, and can change at any time!
"""
from pprint import pprint

import asyncio

from pyplanet.apps.contrib.local_records import LocalRecord
from pyplanet.apps.core.maniaplanet.models import Map
from pyplanet.apps.core.statistics.models import Score, fn


class StatisticsProcessor:
"""
Statistics Processor.
Please don't use this outside of the statistics app as the API will change without any info before.
"""
def __init__(self, app):
"""
Init the processor
:param app: App instance.
:type app: pyplanet.apps.core.statistics.Statistics
"""
self.app = app

async def get_dashboard_data(self, player):
"""
Get player fact numbers, such as the number of finishes. Number of top-3 records, etc.
:param player: Player instance.
:type player: pyplanet.apps.core.maniaplanet.models.Player
:return: dictionary with results.
"""
# Combine several calls.
finishes, top_3, records = await asyncio.gather(
self.get_num_finishes(player),
self.get_num_top_3(player),
self.get_num_records(player),
)

return dict(
numbers=dict(
finishes=finishes,
top_3=top_3,
records=records,
),
)

async def get_num_finishes(self, player):
"""
Get the number of finishes.
:param player: Player instance.
:type player: pyplanet.apps.core.maniaplanet.models.Player
:return: count or False when not possible to fetch.
:rtype: int
"""
if self.app.instance.game.game == 'tm':
return await Score.objects.count(
Score.select(Score).where(Score.player == player)
)
return False

async def get_num_records(self, player):
"""
Get the number of local records.
:param player: Player instance.
:type player: pyplanet.apps.core.maniaplanet.models.Player
:return: count or False when not possible to fetch.
:rtype: int
"""
if self.app.instance.game.game == 'tm' and 'local_records' in self.app.instance.apps.apps:
return await LocalRecord.objects.count(
LocalRecord.select(LocalRecord).where(LocalRecord.player == player)
)
return False

async def get_num_top_3(self, player):
"""
Get the number of top-3 records of one player.
:param player: Player instance.
:type player: pyplanet.apps.core.maniaplanet.models.Player
:return: count or False when not possible to fetch.
:rtype: int
"""
# Get the players number of top-3 records (tm only + when local records is active).
if self.app.instance.game.game == 'tm' and 'local_records' in self.app.instance.apps.apps:
top = 0
records = await LocalRecord.objects.execute(
LocalRecord.select(LocalRecord).where(LocalRecord.player == player)
)
for record in records:
top_3 = await LocalRecord.objects.execute(
LocalRecord.select(LocalRecord).where(LocalRecord.map_id == record.map_id).limit(3)
)
if record in top_3:
top += 1
return top
return False
41 changes: 41 additions & 0 deletions pyplanet/apps/core/statistics/templates/dashboard.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<frame pos="0 0">
<quad pos="0 0" size="320 180" halign="center" valign="center" style="Bgs1" substyle="BgDialogBlur" z-index="50" />
<quad pos="{{ sizes.top__pos }}" size="{{ sizes.top__size }}" halign="center" style="Bgs1InRace" substyle="BgGlow2" z-index="52" />
<quad size="{{ sizes.box__size }}" halign="center" valign="center" style="Bgs1InRace" substyle="BgWindow2" z-index="51" />
<quad pos="{{ sizes.bottom__pos }}" size="{{ sizes.bottom__size }}" halign="center" style="Bgs1InRace" substyle="BgMetalBar" z-index="52" />

<frame z-index="55" pos="0 60">
{% block body %}
<label pos="-5 -3" size="180 8" halign="left" valign="center2" textsize="2.5" textcolor="FFF" text="Statistics" />
<quad pos="90 1" size="7 7" style="Icons128x32_1" substyle="Close" action="{{ id }}__button_close"/>

<!-- Left Column -->
<frame z-index="56" pos="-100 -10">

<!-- Numbers -->
<quad pos="0 0" size="100 25" bgcolor="FFFFFF11" />
<label pos="1.5 -1.5" size="70 8" halign="left" valign="left" textsize="2.0" textcolor="FFF" text="$oPersonal Facts and numbers" />
<label pos="85 -3.5" style="CardButtonSmallS" valign="center" halign="center" text="More" translate="1" action="{{ id }}__button_facts" />

<label pos="1.5 -7" size="60 8" halign="left" valign="left" textsize="1.5" textcolor="FFF" text="Number of finishes" />
<label pos="70 -7" size="60 8" halign="left" valign="left" textsize="1.5" textcolor="FFF" text="{{ numbers.finishes }}" />

<label pos="1.5 -11" size="60 8" halign="left" valign="left" textsize="1.5" textcolor="FFF" text="Number of top 3 records" />
<label pos="70 -11" size="60 8" halign="left" valign="left" textsize="1.5" textcolor="FFF" text="{{ numbers.top_3 }}" />

<label pos="1.5 -15.5" size="60 8" halign="left" valign="left" textsize="1.5" textcolor="FFF" text="Number of local records" />
<label pos="70 -15.5" size="60 8" halign="left" valign="left" textsize="1.5" textcolor="FFF" text="{{ numbers.records }}" />

{% if numbers.top_3 and numbers.records %}
{% set percentage_top3 = ((numbers.top_3 / numbers.records) * 100) %}
{% else %}
{% set percentage_top3 = False %}
{% endif %}
{% if percentage_top3 %}
<quad pos="82 -7" size="17.5 17.5" image="https://image-charts.com/chart?cht=p&chf=a,s,00000080&chd=t:{{ percentage_top3 }},{{ 100 - percentage_top3 }}&chs=200x200&chl=Top 3%7CRecords%7C.png" />
{% endif %}
</frame>

{% endblock %}
</frame>
</frame>
22 changes: 21 additions & 1 deletion pyplanet/apps/core/statistics/tm.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
Trackmania app component.
"""
from pyplanet.apps.core.statistics.models import Score
from pyplanet.apps.core.statistics.views.dashboard import StatsDashboardView
from pyplanet.apps.core.statistics.views.score import StatsScoresListView
from pyplanet.apps.core.trackmania.callbacks import finish
from pyplanet.contrib.command import Command


class TrackmaniaComponent:
Expand All @@ -11,7 +14,7 @@ def __init__(self, app):
Initiate trackmania statistics component.
:param app: App config instance
:type app: pyplanet.apps.core.statistics.app.StatisticsConfig
:type app: pyplanet.apps.core.statistics.Statistics
"""
self.app = app

Expand All @@ -22,6 +25,15 @@ async def on_start(self):
# Listen to signals.
self.app.context.signals.listen(finish, self.on_finish)

# Register commands.
# TODO: Finish work here!
# await self.app.instance.command_manager.register(
# Command('stats', target=self.open_stats)
# )
await self.app.instance.command_manager.register(
Command(command='scoreprogression', aliases=['progression'], target=self.open_score_progression),
)

async def on_finish(self, player, race_time, lap_time, cps, flow, raw, **kwargs):
# Register the score of the player.
await Score(
Expand All @@ -30,3 +42,11 @@ async def on_finish(self, player, race_time, lap_time, cps, flow, raw, **kwargs)
score=race_time,
checkpoints=','.join([str(cp) for cp in cps])
).save()

async def open_stats(self, player, **kwargs):
view = StatsDashboardView(self.app, self.app.context.ui, player)
await view.display()

async def open_score_progression(self, player, **kwargs):
view = StatsScoresListView(self.app, player)
await view.display(player)
Empty file.
10 changes: 10 additions & 0 deletions pyplanet/apps/core/statistics/views/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from pyplanet.views import TemplateView


class StatsView(TemplateView):
def __init__(self, manager, player, *args, **kwargs):
self.player = player
super().__init__(manager, *args, **kwargs)

def display(self, *args, **kwargs):
return super().display([self.player.login], **kwargs)
60 changes: 60 additions & 0 deletions pyplanet/apps/core/statistics/views/dashboard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from .base import StatsView


class StatsDashboardView(StatsView):
"""
The Statistics Dashboard will show the summary of some statistics about the player and the server. The player can click
on one of the 'More' buttons to show more detailed statistics about the subject.
"""
template_name = 'core.statistics/dashboard.xml'

def __init__(self, app, *args, **kwargs):
"""
Init the dashboard.
:param app: App instance
:param args: Args..
:param kwargs: Kwargs...
:type app: pyplanet.apps.core.statistics.Statistics
"""
super().__init__(*args, **kwargs)
self.app = app

self.subscribe('button_close', self.close)

async def get_context_data(self):
context = await super().get_context_data()
context['options'] = [
dict(name='Top Records', view='pyplanet.apps.core.statistics.views.records.TopRecordsView'),
]
context['sizes'] = {
'top__pos': '0 67',
'top__size': '206.5 8',
'box__size': '200 125',
'bottom__pos': '0 -62',
'bottom__size': '200 2',
'input__pos': '0 -40',
'input__size': '185 7',
}
return context

async def get_all_player_data(self, logins):
data = dict()
for login in logins:
player = await self.app.instance.player_manager.get_player(login=login, lock=False)
data[login] = await self.app.processor.get_dashboard_data(player)
# data[login]['numbers_chart'] = 'https://image-charts.com/chart?cht=p&chd=t:10,90&chs=200x200&chl=Top 3%7CRecords%7C.png'

return data

async def close(self, player, *args, **kwargs):
"""
Close the link for a specific player. Will hide manialink and destroy data for player specific to save memory.
:param player: Player model instance.
:type player: pyplanet.apps.core.maniaplanet.models.Player
"""
if self.player_data and player.login in self.player_data:
del self.player_data[player.login]
await self.hide(player_logins=[player.login])
await self.destroy()
11 changes: 11 additions & 0 deletions pyplanet/apps/core/statistics/views/records.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from .base import StatsView


class TopRecordsView(StatsView):
template_name = 'core.statistics/menu.xml'

async def get_context_data(self):
context = await super().get_context_data()
context['options'] = [
dict(name='Top Records', view='pyplanet.apps.core.statistics.views.records.TopRecords'),
]

0 comments on commit ae0e20f

Please sign in to comment.