Ranking¶
Highscore lists and leaderboards behind client.ranking.
ranking.service¶
Highscore lists and event leaderboards.
Classes:
| Name | Description |
|---|---|
RankingService |
Highscore lists and event leaderboards. |
Attributes:
| Name | Type | Description |
|---|---|---|
logger |
|
RankingService
¶
Bases: BaseService
Highscore lists and event leaderboards.
Methods:
| Name | Description |
|---|---|
get_highscore |
Search for a highscore entry (e.g. player rank). |
get_ranking_list |
Get a page of an event leaderboard, from a rank. |
get_own_ranking_page |
Get the page of an event leaderboard that holds your own score. |
get_ranking_window |
Get the page of an event leaderboard around a score, e.g. a search hit. |
search_leaderboard |
Search an event leaderboard for a name. |
get_highscore
¶
get_highscore(list_type: RankingType, search_value: str, league_type_id: int = -1, timeout: float = 5.0) -> list[HighscoreRow]
Search for a highscore entry (e.g. player rank).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
list_type
|
RankingType
|
The highscore list (LT) |
required |
search_value
|
str
|
Name to search for, a rank as text, or "-1" for your own rank |
required |
league_type_id
|
int
|
League type id (LID); -1 for none, the client default |
-1
|
timeout
|
float
|
Timeout in seconds |
5.0
|
Returns:
| Type | Description |
|---|---|
list[HighscoreRow]
|
The page's rows, each in its list's layout (see |
Note: 'hgh' is shared with the alliance-search command. Requests for it
run one at a time, but after one times out its late reply can be taken
by the next, a search_alliances() call included: the reply's LT and
LID need not be the ones asked for, so no reply is refused on them
(see GetHighscoreRequest).
get_ranking_list
¶
get_ranking_list(list_type: RankingType, rank: int, max_results: int, league_type_id: int, sub_division_id: int | None = None, event_id: int | None = None, timeout: float = 5.0) -> list[LeaderboardScore]
Get a page of an event leaderboard, from a rank.
Only works while the list's event runs: the client sends llsp only
from event leaderboards, and a live server answered NO_EVENT (145)
for every list with no event running, the regular highscore lists
included (use get_highscore for those).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
list_type
|
RankingType
|
The event's highscore list (LT), e.g. |
required |
rank
|
int
|
The first rank on the page |
required |
max_results
|
int
|
Entries per page (M) |
required |
league_type_id
|
int
|
The league (LID): the league of the event whose leaderboard it is, as its
sei entry names it ( |
required |
sub_division_id
|
int | None
|
The alliance event subdivision (SDI), for an alliance event's subdivision ranking |
None
|
event_id
|
int | None
|
The alliance mobilisation or raid event (EID), for those events' rankings |
None
|
timeout
|
float
|
Timeout in seconds |
5.0
|
Returns:
| Type | Description |
|---|---|
list[LeaderboardScore]
|
List of entries from that rank |
Raises:
| Type | Description |
|---|---|
CommandError
|
NO_EVENT (145) when the list's event is not running |
Client: LeaderBoardDataProvider (bundle line 75933), built only by
GlobalLeaderBoardComponent.init (bundle line 34989) for event leaderboard dialogs
get_own_ranking_page
¶
get_own_ranking_page(list_type: RankingType, max_results: int, league_type_id: int, sub_division_id: int | None = None, event_id: int | None = None, timeout: float = 5.0) -> list[LeaderboardScore]
Get the page of an event leaderboard that holds your own score.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
list_type
|
RankingType
|
The event's highscore list (LT) |
required |
max_results
|
int
|
Entries per page (M) |
required |
league_type_id
|
int
|
The league (LID), as for |
required |
sub_division_id
|
int | None
|
The alliance event subdivision (SDI), as for |
None
|
event_id
|
int | None
|
The alliance mobilisation or raid event (EID), as for |
None
|
timeout
|
float
|
Timeout in seconds |
5.0
|
Returns:
| Type | Description |
|---|---|
list[LeaderboardScore]
|
The entries on your page |
Raises:
| Type | Description |
|---|---|
CommandError
|
a live server refused a long-term point list's own page with league -1 (GENERAL_ERROR, 1) and answered it with the event's league |
Client: LeaderBoardDataProvider.getCurrentPlayerPage (bundle line 75941)
get_ranking_window
¶
get_ranking_window(list_type: RankingType, score_id: str, max_results: int, league_type_id: int | None, sub_division_id: int | None = None, event_id: int | None = None, timeout: float = 5.0) -> list[LeaderboardScore]
Get the page of an event leaderboard around a score, e.g. a search hit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
list_type
|
RankingType
|
The event's highscore list (LT) |
required |
score_id
|
str
|
A score id from |
required |
max_results
|
int
|
Entries per page (M) |
required |
league_type_id
|
int | None
|
The league the score is in (LID): the search result's |
required |
sub_division_id
|
int | None
|
The alliance event subdivision (SDI), as for |
None
|
event_id
|
int | None
|
The alliance mobilisation or raid event (EID), as for |
None
|
timeout
|
float
|
Timeout in seconds |
5.0
|
Returns:
| Type | Description |
|---|---|
list[LeaderboardScore]
|
The entries on that page |
Client: LeaderBoardDataProvider.getCurrentSearchPage (bundle line 75943)
search_leaderboard
¶
search_leaderboard(list_type: RankingType, search_value: str, sub_division_id: int | None = None, event_id: int | None = None, timeout: float = 5.0) -> list[LeaderboardSearchResult]
Search an event leaderboard for a name.
Page to a hit with get_ranking_window, passing its
league_type_id and one of its score_ids; the client pages to
the first hit, or to your own page when there is none. The search
itself takes no league: C2SSearchLeaderboardScoresEventVO sends
only LT and SV, and the answer groups the hits by league.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
list_type
|
RankingType
|
The event's highscore list (LT) |
required |
search_value
|
str
|
The name to search for (SV); must not be empty |
required |
sub_division_id
|
int | None
|
The alliance event subdivision (SDI), as for |
None
|
event_id
|
int | None
|
The alliance mobilisation or raid event (EID), as for |
None
|
timeout
|
float
|
Timeout in seconds |
5.0
|
Returns:
| Type | Description |
|---|---|
list[LeaderboardSearchResult]
|
The matching score ids, grouped by league |
Raises:
| Type | Description |
|---|---|
ValueError
|
For an empty search, which the client never sends |
Client: LeaderBoardDataProvider.searchLeaderBoard (bundle line 75942),
onSearchDataReceived (bundle line 75952)
ranking.models¶
Highscore and leaderboard models.
Commands:
- hgh: A page of a highscore list, around a rank or a searched name
- llsp: A page of an event leaderboard, from a rank
- llsw: A page of an event leaderboard, around a score or your own rank
- slse: Search an event leaderboard for a name
Classes:
| Name | Description |
|---|---|
HighscoreAlliance |
An alliance on a highscore list: |
HighscorePlayerRow |
A player's row: |
HighscoreAllianceRow |
An alliance's row: |
HighscoreIslandRow |
A Storm Islands alliance row: |
HighscoreTournamentRow |
A tournament row: |
GetHighscoreRequest |
A page of a highscore list, around a rank or a searched name. |
GetHighscoreResponse |
A page of a highscore list, the reply to |
GetRankingListRequest |
A page of an event leaderboard, starting at a rank. |
GetRankingWindowRequest |
A page of an event leaderboard around a score, or around your own rank. |
SearchRankingListRequest |
Search an event leaderboard for a name. |
LeaderboardScore |
One entry of an event leaderboard page: an entry of |
GetRankingListResponse |
A page of an event leaderboard, the reply to |
GetRankingWindowResponse |
A page of an event leaderboard around a score, the reply to |
LeaderboardSearchResult |
The scores that matched a search in one league: an entry of |
SearchRankingListResponse |
The scores that matched a leaderboard search, the reply to |
Attributes:
| Name | Type | Description |
|---|---|---|
logger |
|
|
HighscoreRow |
One row of a |
|
HIGHSCORE_ROW_LAYOUTS |
dict[int, _RowModel]
|
The lists whose rows have a layout of their own. |
HighscoreRow
module-attribute
¶
HighscoreRow = HighscorePlayerRow | HighscoreAllianceRow | HighscoreIslandRow | HighscoreTournamentRow
One row of a hgh reply; HIGHSCORE_ROW_LAYOUTS and the row's shape pick which.
HIGHSCORE_ROW_LAYOUTS
module-attribute
¶
HIGHSCORE_ROW_LAYOUTS: dict[int, _RowModel] = {RankingType.ALLIANCE_AQUA_POINTS: HighscoreIslandRow, RankingType.TOURNAMENT_FAME: HighscoreTournamentRow}
The lists whose rows have a layout of their own.
Every other list's row is an alliance's when its third entry is an array, else a player's, as
SeasonLeagueMainDialogRanksItem tells them apart (bundle lines 91889, 91908); the other
dialogs each read one of those two layouts.
HighscoreAlliance
pydantic-model
¶
Bases: BasePayload
An alliance on a highscore list: [alliance_id, name, member_count, fame].
Client: AllianceHighscoreInfoVO.fillFromParamObject (bundle line 27680), which reads
nothing from a value that is not an array
Fields:
Validators:
-
_from_row -
_text→name
HighscorePlayerRow
pydantic-model
¶
Bases: BasePayload
A player's row: [rank, score, owner_record, display_name?, shown_rank?], or [rank, owner_record]
without a score.
Client: CastleHighscoreDialog.onGetHighscoreData (bundle lines 27559-27568),
CastleGenericHighscoreDialog.onGetHighscoreData (bundle lines 30827-30836),
CastleSingleplayerRankingItem.update (bundle line 91695) for the row without a score,
TempServerEventDialogRankingItem.updateWithNewData (bundle lines 118343-118344) for the
display name and the shown rank, which 0 leaves at rank
Fields:
-
rank(ClientInt) -
score(ClientInt) -
owner(MapObject | None) -
display_name(str | None) -
shown_rank(int | None)
Validators:
-
_from_row -
_owner→owner
HighscoreAllianceRow
pydantic-model
¶
Bases: BasePayload
An alliance's row: [rank, score, alliance].
Client: CastleHighscoreDialog.onGetHighscoreData (bundle lines 27541-27558),
CastleAllianceRankingItem.update (bundle line 91645), the generic alliance highscore
dialog (bundle lines 38131-38134)
Fields:
Validators:
-
_from_row -
_alliance→alliance
HighscoreIslandRow
pydantic-model
¶
Bases: HighscoreAllianceRow
A Storm Islands alliance row: [is_stormlord, rank, score, alliance].
Client: CastleEilandAllianceRankingItem.update (bundle lines 98076-98079), shown for
HighscoreConst.ALLIANCE_AQUA_POINTS (bundle line 98052)
Fields:
Validators:
-
_alliance→alliance -
_from_row
HighscoreTournamentRow
pydantic-model
¶
Bases: BasePayload
A tournament row: [rank, score, player_id, player_name], with no owner record.
Client: ACastleTournamentRankListItem.parseItemData (bundle line 59120),
CastleTournamentRankListItem.parseItemData (bundle line 118660)
Fields:
Validators:
-
_from_row -
_text→player_name
GetHighscoreRequest
pydantic-model
¶
Bases: BaseRequest
A page of a highscore list, around a rank or a searched name.
Payload: {"LT": list_type, "LID": league_type_id, "SV": search_value}
The keys follow the client's order: the constructor initialises LT and LID before it sets SV, which it encodes as it encodes any text it sends.
The reply carries LT and LID, but not always the ones asked for, so
no reply is refused on them: the highscore dialog switches to the list and
league the reply names (CastleHighscoreDialog.onGetHighscoreData, bundle
lines 27533-27535), and offers the legend list (7) only in the level-cap
league, falling back to honor (5) elsewhere (setLeague, bundle line
27482; switchOverallCategory, bundle lines 27506-27519). A live server
answered LT 7 around your own rank ("-1", LID -1) for a league-1 player with
LT 5 and LID 1.
Client: C2SGetHighscoreVO (bundle line 14674)
Fields:
GetHighscoreResponse
pydantic-model
¶
Bases: BaseResponse
A page of a highscore list, the reply to hgh.
The client has no row parser of its own: each dialog reads the rows in its list's
layout, so the rows are read by HIGHSCORE_ROW_LAYOUTS and their shape.
Client: HGHCommand.executeCommand (bundle line 124377)
Fields:
-
error_code(int) -
list_type(int | None) -
league_type_id(int) -
last_rank(int | None) -
search_value(str | None) -
rows(tuple[HighscoreRow, ...])
Validators:
-
_falsy_league_reads_as_minus_one→league_type_id -
_rows→rows
rows
pydantic-field
¶
rows: tuple[HighscoreRow, ...] = ()
Wire key L
The page's rows, in the list's layout
GetRankingListRequest
pydantic-model
¶
Bases: BaseRequest
A page of an event leaderboard, starting at a rank.
Payload: {"LT": list_type, "LID": league_type_id, "M": max_results, "R": rank}
The client pages only event leaderboards this way (score, long-term
point, alliance mobilisation/raid and donation events), and always with
a league: LeaderBoardDataProvider sends the league it was built with
on every page. The score and long-term point dialogs build it with the
event's league, the LID of the event's sei entry, and page through
leagues 1 to the event's league count (GlobalLeaderBoardLeagueComponent,
bundle line 100470; AScoreEventVO.parseBasicsFromParamObject, bundle
line 14967); the alliance mobilisation dialog passes the event's league
(bundle line 47284); only the donation ranking passes none, so -1 (bundle
line 115740). A live server answered NO_EVENT (145) for every list with
no event running, the regular highscore lists included; read those with
hgh.
Client: C2SListLeaderboardScoresPageVO (bundle line 76002), sent by
LeaderBoardDataProvider (bundle line 75933), which only
GlobalLeaderBoardComponent.init (bundle line 34989) builds, for
ScoreEventGlobalLeaderBoardDialog and
LongtermPointEventGlobalLeaderBoardDialog (AGlobalLeaderBoardDialog.showLoaded,
bundle line 100442), AllianceMobilizationEventDialogLeaderboard.show
(bundle line 47278) and DonationEventDialogRanking (bundle line 115737)
The alliance mobilisation and raid leaderboards also send SDI and
EID: LeaderBoardDataProvider.sendCommand (bundle line 75949) copies
the {SDI, EID} (subdivision tab) or {EID} (division tab) that
AllianceMobilizationEventDialogRanking.switchTab (bundle line 75910) and
AllianceRaidEventRankingDialog.switchTab (bundle line 75633) show the
leaderboard with onto every request, after the VO's own keys.
Fields:
-
list_type(RankingType) -
league_type_id(int) -
max_results(int) -
rank(int) -
sub_division_id(int | None) -
event_id(int | None)
league_type_id
pydantic-field
¶
league_type_id: int
Wire key LID
The event's league, a level band (see GameData.league_type); -1 for the donation ranking
sub_division_id
pydantic-field
¶
sub_division_id: int | None = None
Wire key SDI
The alliance event subdivision, for its subdivision ranking
event_id
pydantic-field
¶
event_id: int | None = None
Wire key EID
The alliance mobilisation or raid event
accepts_reply
¶
Whether a reply is for this request, as the client tells.
A reply is refused only when its LT is another list and its league
(LID, or -1 without one) is the one asked for; a reply for another
list in another league is taken, as the client takes it.
Client: LeaderBoardDataProvider.onScoreDataReceived (bundle line 75957),
which then adopts the reply's LID
GetRankingWindowRequest
pydantic-model
¶
Bases: BaseRequest
A page of an event leaderboard around a score, or around your own rank.
Payload: {"LT": list_type, "LID": league_type_id, "M": max_results, "SI": score_id}
SI is a score id from a slse search result, or empty for the page
holding your own score; the client encodes it as it encodes any text it
sends. The reply is shaped like llsp's. LID, SDI and EID
are sent as for llsp: your own page goes with the event's league,
a search hit's page with the hit's league. A live server refused a
long-term point list's own page with league -1 (GENERAL_ERROR, 1) and
answered it with the event's league.
Client: C2SListLeaderboardScoresWindowVO (bundle line 76012), sent by
LeaderBoardDataProvider.getCurrentPlayerPage (bundle line 75941) with no
score id and getCurrentSearchPage (bundle line 75943) with a search result's
league and score id
Fields:
-
list_type(RankingType) -
league_type_id(int | None) -
max_results(int) -
score_id(str) -
sub_division_id(int | None) -
event_id(int | None)
league_type_id
pydantic-field
¶
league_type_id: int | None
Wire key LID
The event's league, or a search hit's, a level band (see GameData.league_type); -1 for the donation ranking, None for a hit without one
score_id
pydantic-field
¶
score_id: str = ''
Wire key SI
The score to page around, from a search result; empty for your own
sub_division_id
pydantic-field
¶
sub_division_id: int | None = None
Wire key SDI
The alliance event subdivision, for its subdivision ranking
event_id
pydantic-field
¶
event_id: int | None = None
Wire key EID
The alliance mobilisation or raid event
accepts_reply
¶
Whether a reply is for this request, as the client tells.
A reply is refused only when its LT is another list and its league
(LID, or -1 without one) is the one asked for; a reply for another
list in another league is taken, as the client takes it.
Client: LeaderBoardDataProvider.onScoreDataReceived (bundle line 75957),
which then adopts the reply's LID
SearchRankingListRequest
pydantic-model
¶
Bases: BaseRequest
Search an event leaderboard for a name.
Payload: {"LT": list_type, "SV": search_value}
The client encodes SV as it encodes any text it sends, and sends nothing
for an empty search. It then pages to the first hit with llsw, or to
your own page when there is none. SDI and EID are sent as for llsp.
Client: C2SSearchLeaderboardScoresEventVO (bundle line 76022), sent by
LeaderBoardDataProvider.searchLeaderBoard (bundle line 75942)
Fields:
-
list_type(RankingType) -
search_value(str) -
sub_division_id(int | None) -
event_id(int | None)
sub_division_id
pydantic-field
¶
sub_division_id: int | None = None
Wire key SDI
The alliance event subdivision, for its subdivision ranking
event_id
pydantic-field
¶
event_id: int | None = None
Wire key EID
The alliance mobilisation or raid event
accepts_reply
¶
Whether a reply is for this list: its LT, when sent, is the one asked for.
Client: LeaderBoardDataProvider.onSearchDataReceived (bundle line 75953) skips a
reply only when its LT differs and the dialog's league is the reply's
LID or -1. The search sends no league, so the library cannot tell the
dialog's and refuses any other LT.
LeaderboardScore
pydantic-model
¶
Bases: BasePayload
One entry of an event leaderboard page: an entry of llsp's L.
Client: AGlobalLeaderBoardItem getters (bundle lines 47303-47316) and
LeaderBoardDataProvider.onScoreDataReceived (bundle line 75957).
Fields:
-
rank(ClientInt) -
score(int | float) -
player_name(str) -
alliance_name(str) -
instance_id(ClientInt | None) -
score_id(int | str | None)
Validators:
-
_getters_guard_every_key
GetRankingListResponse
pydantic-model
¶
Bases: BaseResponse
A page of an event leaderboard, the reply to llsp.
Client: LLSPCommand.executeCommand (bundle line 124397), LeaderBoardDataProvider.onScoreDataReceived
(bundle line 75957).
Fields:
-
error_code(int) -
list_type(int | None) -
league_type_id(int | None) -
scores(list[LeaderboardScore]) -
total(int)
Validators:
-
_falsy_league_reads_as_none→league_type_id -
_rows_without_data_read_as_empty→scores
GetRankingWindowResponse
pydantic-model
¶
Bases: GetRankingListResponse
A page of an event leaderboard around a score, the reply to llsw.
Client: LLSWCommand.executeCommand (bundle line 124411), which hands the
reply to LeaderBoardDataProvider.onScoreDataReceived (bundle line 75957)
as LLSPCommand does
Fields:
-
error_code(int) -
list_type(int | None) -
league_type_id(int | None) -
scores(list[LeaderboardScore]) -
total(int)
Validators:
-
_falsy_league_reads_as_none→league_type_id -
_rows_without_data_read_as_empty→scores
LeaderboardSearchResult
pydantic-model
¶
Bases: BasePayload
The scores that matched a search in one league: an entry of slse's L.
Client: LeaderBoardDataProvider.onSearchDataReceived (bundle line 75952)
Fields:
-
league_type_id(int | None) -
score_ids(list[str])
Validators:
-
_readable_score_ids→score_ids
SearchRankingListResponse
pydantic-model
¶
Bases: BaseResponse
The scores that matched a leaderboard search, the reply to slse.
The client throws on a missing L or a result that is not an object; the
library reads those as no results, and a score id that is a number as text.
Client: SLSECommand.executeCommand (bundle line 124440),
LeaderBoardDataProvider.onSearchDataReceived (bundle line 75952)
Fields:
-
error_code(int) -
list_type(int | None) -
league_type_id(int) -
results(list[LeaderboardSearchResult])
Validators:
-
_falsy_league_reads_as_minus_one→league_type_id -
_readable_results→results