Leaderboard
Idem generates a leaderboard for your game which you can query via API.
POST /games/{game_id}/leaderboard
You can extract the leaderboard in three ways:
- From-top Extracts the first n records starting from above
{"count": "int"}
- From-rank Gives you a number n of records starting at a rank. This can also be used to extract the leaderboard page-wise (e.g. 1-50, 51-100 etc.)
{"count": "int", "fromRank": "int"}
- Around-player Returns a number of players around a player of your choice. Used generally to show a players immediate sourrounding in the ranking table.
{"count": "int", "playerId": "str"}
Below is simple demo of how to retrieve your leaderboard data:
- demo.py
- pull_leaderboard.py
import pull_leaderboard
# Credentials
secret = {
"websocket_url": "wss://ws.beta.idem.gg",
"api_url": "https://api.beta.idem.gg",
"client_id": "3ns1sc0lkrdqh25qvrqb9k3a80",
"username": "YOUR_USERNAME",
"password": "YOUR_PASSWORD",
}
game_id = "1v1"
def main():
# From top
print("-- Leaderboard from top --")
leaderboard_from_top = pull_leaderboard.get_leaderboard_from_top(
game_id=game_id, count=10, secret=secret
)
pull_leaderboard.print_leaderboard(leaderboard_from_top)
# From rank
print("-- Leaderboard from specified rank --")
leaderboard_from_rank = pull_leaderboard.get_leaderboard_from_rank(
game_id=game_id, count=10, from_rank=5, secret=secret
)
pull_leaderboard.print_leaderboard(leaderboard_from_rank)
# Around player
print("-- Leaderboard around specified player --")
leaderboard_around_playerid = pull_leaderboard.get_leaderboard_around_playerid(
game_id=game_id, count=10, player_id="#someUser", secret=secret
)
pull_leaderboard.print_leaderboard(leaderboard_around_playerid)
if __name__ == "__main__":
main()
import ssl
from typing import Any, Dict, Optional, Union
import httpx
from attr import define
from attrs import field
import boto3
from botocore.exceptions import ClientError
@define
class AuthenticatedClient:
raise_on_unexpected_status: bool = field(default=False, kw_only=True)
_base_url: str
_cookies: Dict[str, str] = field(factory=dict, kw_only=True)
_headers: Dict[str, str] = field(factory=dict, kw_only=True)
_timeout: Optional[httpx.Timeout] = field(default=None, kw_only=True)
_verify_ssl: Union[str, bool, ssl.SSLContext] = field(default=True, kw_only=True)
_follow_redirects: bool = field(default=False, kw_only=True)
_httpx_args: Dict[str, Any] = field(factory=dict, kw_only=True)
_client: Optional[httpx.Client] = field(default=None, init=False)
_async_client: Optional[httpx.AsyncClient] = field(default=None, init=False)
token: str
prefix: str = None
auth_header_name: str = "Authorization"
def get_httpx_client(self) -> httpx.Client:
"""Get the underlying httpx.Client, constructing a new one if not previously set"""
if self._client is None:
self._headers[self.auth_header_name] = (
f"{self.prefix} {self.token}" if self.prefix else self.token
)
self._client = httpx.Client(
base_url=self._base_url,
cookies=self._cookies,
headers=self._headers,
timeout=self._timeout,
verify=self._verify_ssl,
follow_redirects=self._follow_redirects,
**self._httpx_args,
)
return self._client
def _get_auth_token(username, password, client_id):
try:
client = boto3.client("cognito-idp", region_name="eu-central-1")
response = client.initiate_auth(
AuthFlow="USER_PASSWORD_AUTH",
AuthParameters={"USERNAME": username, "PASSWORD": password},
ClientId=client_id,
)
return response["AuthenticationResult"]["IdToken"]
except ClientError as e:
error_code = e.response["Error"]["Code"]
if error_code == "NotAuthorizedException":
print("Authentication failed: Incorrect username or password.")
elif error_code == "UserNotFoundException":
print("Authentication failed: Username does not exist.")
else:
print(f"Authentication failed: {e.response['Error']['Message']}")
return ""
def authenticate(secret):
assert "username" in secret and secret["username"], "Username missing from secrets"
assert "password" in secret and secret["password"], "Password missing from secrets"
assert (
"client_id" in secret and secret["client_id"]
), "client_id missing from secrets"
token = _get_auth_token(secret["username"], secret["password"], secret["client_id"])
client = AuthenticatedClient(base_url=secret["api_url"], token=token)
return client
def print_leaderboard(data):
if "leaderboard" in data:
print(data)
for player in data["leaderboard"]:
print(f"{player['rank']} - {player['playerId']} - {player['score']}")
print()
else:
print(data)
def get_leaderboard_from_rank(game_id, count, from_rank, secret):
# Starting at a specified rank (page wise)
client = authenticate(secret)
response = client.get_httpx_client().request(
method="post",
url=f"/games/{game_id}/leaderboard",
json={"count": count, "fromRank": from_rank},
)
data = response.json()
return data
def get_leaderboard_from_top(game_id, count, secret):
# Starting at the top
client = authenticate(secret)
response = client.get_httpx_client().request(
method="post", url=f"/games/{game_id}/leaderboard", json={"count": count}
)
data = response.json()
return data
def get_leaderboard_around_playerid(game_id, count, player_id, secret):
# Around a specific player
client = authenticate(secret)
response = client.get_httpx_client().request(
method="post",
url=f"/games/{game_id}/leaderboard",
json={"count": count, "playerId": player_id},
)
data = response.json()
return data
Retrival limits
The size of the return of each request is limited by default. If you want to retrieve larger chunks of the leaderboard, we recommend From-Rank. That way you can iterate in steps through larger sets of the leaderboard
Method | Limit |
---|---|
Overall limit | 500 |
From-top | 500 |
From-rank | 100 |
Around-player | 50 |