coc.py
coc.py copied to clipboard
Support for Builder Base & Clan Capital clan rank events
Currently, we can track changes in the main base clan leaderboard sorted by trophies using ClanEvents.member_clan_rank(). I would like to be able to track changes to builder base and clan capital leaderboards as well.
there is no information in the clan response about the member rank for other sorting except the normal trophies. That would mean you would have to sort the list of members yourself for the versus trophies and then get the index of your player.
For the clan capital, you would have request every players detail and sort them based on their contributions, but be aware that this number isnt the contributions only in this clan. So in my opinion sorting by clan capital contribution is kind of useless.
@mathsman5133 @majordoobie what do you think would be the best way to implement a builder base rank? I think the one way would be to add the vs_rank before initializing the self._iter_members. So instead of directly passing the list of the response to the init function, we add the vs_ranking attribute to every member. -> Downside would be that it isn't very flexible and for most users completely irrelevant. The other way I can see, is to add like a get_ranking('ClanMember.attribute',ascending=True) function to the Clan object. This would allow everyone to get the ranking for whatever attribute they want. -> Downside would be that it isn't that compatible with the events.
What are your thoughts about this?
Hmmm. Since this is very easy to create, it only really makes sense for events. But even though I love the builder base, I don't think that it makes sense to add such an attribute to the default player object that would overall barely be used by most people.
If that is possible, my preferred solution would be a new example in the docs where such an event is implemented using a custom player class.
Alright, I tried to implement versus clan rank events using custom classes. Here is my code:
import coc
class CustomClan(coc.Clan):
def __init__(self, *, data, client, **_):
super().__init__(data=data, client=client)
self.member_cls = CustomMember
# update members globally. only available via /clans/{clanTag}
member_cls = self.member_cls
member_data = data.get("memberList", [])
for rank, mdata in enumerate(sorted(member_data, key=lambda x: x["versusTrophies"], reverse=True), 1):
mdata["versusRank"] = rank
self._iter_members = (
member_cls(data=mdata, client=self._client, clan=self) for mdata in member_data
)
class CustomMember(coc.ClanMember):
def __init__(self, *, data, client, clan=None, **_):
super().__init__(data=data, client=client, clan=clan, **_)
self.clan_cls = CustomClan
self.versus_rank = data.get("versusRank")
async def events(coc_client):
@coc_client.event
@coc.ClanEvents.member_versus_rank(['#RLCC2VLL'], custom_class=CustomClan)
async def clan_versus_rank(old_member, new_member):
print(f'{new_member.name} changed versus clan rank from {old_member.versus_rank} to {new_member.versus_rank}')
Sadly this did not work with stock coc.py. For it to work, I needed to add the following two lines of code to the ClanEvents
class in events.pyi
:
@classmethod
def member_versus_rank(cls, tags: Iterable = None, custom_class: _ClanType = Clan, retry_interval: int = None) -> _EventDecoratorReturn: ...
Just adding these two lines is not possible because that would give people type hinting for something that does not work with the default classes. So in my eyes the only option to support this is adding a versus_rank
attribute to the ClanMember
class like I did here. Even though this is irrelevant for most people, I would be up to do that.
capital_rank
sadly is not possible because the clan endpoint for whatever reason provides information on how members decorated their capital player house, but not their capital gold donations.
I just implemented the member_versus_rank
event here: https://github.com/mathsman5133/coc.py/commit/377ef8bd628ba9e58d4b715e63e6c9ef6c9a65bd