-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for multiple player ratings #486
Conversation
2ad84e6
to
8bbfbc7
Compare
server/players.py
Outdated
if global_rating is not None: | ||
self.global_rating = global_rating | ||
if ladder_rating is not None: | ||
self.ladder_rating = ladder_rating |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bad naming for global_rating
, self.global_rating
and self._global_rating
, how about to create and use set_global_rating()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit does not change existent naming, and the name
property backed by a _name
attribute is pretty common practice. The property already acts like a setter and has no side effects beyond setting the backing value anyway.
@@ -76,6 +79,39 @@ def __init__( | |||
self._game = lambda: None | |||
self._game_connection = lambda: None | |||
|
|||
@property |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't use @property
, it doesn't give you anything, only hiding call functions + add wrappers, without proper IDE impossible to detect with naked eye.
Use property only if you're trying to not to break same API during refactoring.
Better to use set_
methods. It's more explicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has no side effects beyond setting the backing value. Sounds like a perfectly fine usage of @property
to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact it has. If you see below, you'll find condition that decides what to do with Rating instance. It is hiding behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was talking about side effects. The only thing setting this value ever affects is the value returned by the getter. This is a valid use case for a property, what you're describing restricts @property
to trivial cases.
@@ -35,18 +35,21 @@ def __init__( | |||
permission_group: int = 0, | |||
lobby_connection: "LobbyConnection" = None | |||
): | |||
super().__init__(player_id, login) | |||
self._faction = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typing for local variables + typing for incoming variables like clan
, global_rating
, ladder_rating
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had no reason to touch this code beyond copying it. Faction could use an enum anyway rather than just an obvious typing hint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can make it better ;-) you're refactoring, isn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whenever possible, one commit is one feature.
server/players.py
Outdated
return self._global_rating | ||
|
||
@global_rating.setter | ||
def global_rating(self, value: Rating): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrong typing, use Union[Tuple[int, int], Rating]
https://docs.python.org/3/library/typing.html#typing.Union
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is copied from BasePlayer, so I didn't bother touching it. Frankly you know my opinion on type hints, in trivial cases like this one they bring exactly zero benefit.
server/players.py
Outdated
self._global_rating = value | ||
|
||
@property | ||
def ladder_rating(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing return typing, if it would be just variable, not property, code would be much easier to read, and for outside world it behaves the same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above, didn't bother changing copied code. It deserves to be a named tuple anyway, we can change it then.
server/players.py
Outdated
if isinstance(value, Rating): | ||
self._global_rating = (value.mu, value.sigma) | ||
else: | ||
self._global_rating = value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if value
is None
, you may achieve bad behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the original behaviour and it was not my intention to change it. It's not set to None
internally and if there's an inconsistency with how other code uses it, then you can show and fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it would be a good opportunity to add assert value is not None
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see benefit from moving code from one place to another, if we can make it better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@norraxx Because it's a lot of extra work and a lot higher chance that you mess something up on accident. I'd be happy if you wanted to make a PR though :)
@@ -35,18 +35,21 @@ def __init__( | |||
permission_group: int = 0, | |||
lobby_connection: "LobbyConnection" = None | |||
): | |||
super().__init__(player_id, login) | |||
self._faction = 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't use fraction 0
, it doesn't looks like it's undefined. Maybe use None
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commit has no intention to change original behaviour.
42213ff
to
6ac9a67
Compare
@@ -1,6 +1,8 @@ | |||
import time | |||
|
|||
from .game import Game, ValidityState | |||
from server.rating import RatingType |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now this makes sense, but it won't anymore once you finish multiple rating support :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You want something else than an enum? Is it supposed to be populated from the db?
server/games/game.py
Outdated
@@ -242,6 +247,16 @@ def connections(self): | |||
|
|||
@property | |||
def teams(self): | |||
""" | |||
A dictionary of lists representing teams |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It returns a set not a dict. It would look like {2, 3}
assuming that there are 2 teams
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copypasted from BaseGame, didn't touch it yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please fix or delete this comment, because it's wrong
return rounded_mu - 100, rounded_mu + 100 | ||
@property | ||
def boundary_75(self): | ||
""" Achieves roughly 75% quality. FIXME - why is it MORE restrictive??? """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess my TODO comment was poorly worded. But how are these boundaries going to make sense in a team context?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dunno, I didn't want to change behaviour here yet.
from trueskill import Rating | ||
|
||
|
||
# Values correspond to legacy table names. This will be fixed when db gets |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
ee39b36
to
249f501
Compare
Popped this onto the test server real quick and got the following error:
|
1e8903c
to
4d44bb2
Compare
Server launch issue should be fixed now. |
4d44bb2
to
ef48680
Compare
Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
The Player class is essentially plain old data right now. Remove all mocking of it to make it easier to modify. If we ever bless Player with non-trivial behaviour, we can make a mock or an abstract class for it. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
Preparations for adding new rating types. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
This will save us some manual mucking around with asyncio's sleep. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
Everything inherits from the Game class anyway, and all "abstract" methods are already implemented there. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
This should make tests a bit more manageable. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
This replaces homegrown tools for coroutine testing with asynctest and pytest-asyncio. One benefit is that each test gets its own fresh event loop, another will come with proper tools for fast-forwarding event loops. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
This removes the need for ugly asyncio.sleep monkeypatching. It also exposes some issues with tests not closing the server after the test ends; we ignore it for now, eventually we'll fix that too. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
ef48680
to
73befb7
Compare
Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
* Get rid of BasePlayer class Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Remove Player class mocking in tests The Player class is essentially plain old data right now. Remove all mocking of it to make it easier to modify. If we ever bless Player with non-trivial behaviour, we can make a mock or an abstract class for it. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Improve game stats coverage Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Use a dict-like object for player ratings Preparations for adding new rating types. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Add asynctest to dependencies This will save us some manual mucking around with asyncio's sleep. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Replace CoroMock with asynctest's CoroutineMock Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Remove BaseGame class Everything inherits from the Game class anyway, and all "abstract" methods are already implemented there. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Fix ban test by formatting >100 year bans as 'forever' Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Make the DB non-global This should make tests a bit more manageable. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Use asynctest/pytest-asyncio for tests This replaces homegrown tools for coroutine testing with asynctest and pytest-asyncio. One benefit is that each test gets its own fresh event loop, another will come with proper tools for fast-forwarding event loops. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Add an event loop fast-forwarding decorator This removes the need for ugly asyncio.sleep monkeypatching. It also exposes some issues with tests not closing the server after the test ends; we ignore it for now, eventually we'll fix that too. Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Fix some sleep usage in tests Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * A bit more test coverage Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Remove no longer needed loop fixture Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com> * Update game docstring Signed-off-by: Igor Kotrasinski <i.kotrasinsk@gmail.com>
This PR will eventually add support for more player ratings in preparation for team matchmaking. For now though, it's a few misc cleanups.