diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ff77b7..2f6210c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,19 @@ on: branches: [main] jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Run pre-commit + uses: pre-commit/action@v3.0.1 + test: runs-on: ubuntu-latest strategy: @@ -27,14 +40,5 @@ jobs: - name: Install dependencies run: uv sync --all-extras - - name: Run ruff check - run: uv run ruff check src/ - - - name: Run ruff format check - run: uv run ruff format --check src/ - - - name: Run mypy - run: uv run mypy src/ - - name: Run tests run: uv run pytest -v diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 692487d..b85ee96 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,3 +14,13 @@ repos: - id: check-yaml - id: check-added-large-files - id: check-toml + + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.14.1 + hooks: + - id: mypy + pass_filenames: false + additional_dependencies: + - pydantic>=2.0.0 + - httpx>=0.27.0 + - pytest>=8.0.0 diff --git a/examples/leaderboards.py b/examples/leaderboards.py index ff362a1..23c5b9e 100644 --- a/examples/leaderboards.py +++ b/examples/leaderboards.py @@ -25,9 +25,9 @@ phase_lb = mcsrranked.leaderboards.phase() if phase_lb.phase.number: print(f"Phase {phase_lb.phase.number}") -for player in phase_lb.users[:5]: - points = player.season_result.phase_point - print(f"{player.nickname}: {points} points") +for phase_player in phase_lb.users[:5]: + points = phase_player.season_result.phase_point + print(f"{phase_player.nickname}: {points} points") print() # Record leaderboard (best times) diff --git a/examples/matches.py b/examples/matches.py index 49cb18d..07d33fd 100644 --- a/examples/matches.py +++ b/examples/matches.py @@ -54,8 +54,8 @@ def format_time(ms: int) -> str: print("Elo Changes:") for change in match.changes: - player = next((p for p in match.players if p.uuid == change.uuid), None) - name = player.nickname if player else change.uuid + found_player = next((p for p in match.players if p.uuid == change.uuid), None) + name = found_player.nickname if found_player else change.uuid change_str = ( f"+{change.change}" if change.change and change.change > 0 @@ -67,6 +67,6 @@ def format_time(ms: int) -> str: if match.timelines: print("Timeline:") for event in match.timelines[:10]: - player = next((p for p in match.players if p.uuid == event.uuid), None) - name = player.nickname if player else event.uuid[:8] + found_player = next((p for p in match.players if p.uuid == event.uuid), None) + name = found_player.nickname if found_player else event.uuid[:8] print(f" {format_time(event.time)} - {name}: {event.type}") diff --git a/examples/versus.py b/examples/versus.py index 8c7237a..9ab5270 100644 --- a/examples/versus.py +++ b/examples/versus.py @@ -30,8 +30,8 @@ def format_time(ms: int) -> str: total = ranked.get("total", 0) for uuid, wins in ranked.items(): if uuid != "total": - player = next((p for p in stats.players if p.uuid == uuid), None) - name = player.nickname if player else uuid[:8] + found_player = next((p for p in stats.players if p.uuid == uuid), None) + name = found_player.nickname if found_player else uuid[:8] print(f" {name}: {wins} wins") print(f" Total matches: {total}") print() @@ -42,8 +42,8 @@ def format_time(ms: int) -> str: total = casual.get("total", 0) for uuid, wins in casual.items(): if uuid != "total": - player = next((p for p in stats.players if p.uuid == uuid), None) - name = player.nickname if player else uuid[:8] + found_player = next((p for p in stats.players if p.uuid == uuid), None) + name = found_player.nickname if found_player else uuid[:8] print(f" {name}: {wins} wins") print(f" Total matches: {total}") print() @@ -51,8 +51,8 @@ def format_time(ms: int) -> str: # Display elo changes print("Total Elo Changes:") for uuid, change in stats.changes.items(): - player = next((p for p in stats.players if p.uuid == uuid), None) - name = player.nickname if player else uuid[:8] + found_player = next((p for p in stats.players if p.uuid == uuid), None) + name = found_player.nickname if found_player else uuid[:8] sign = "+" if change > 0 else "" print(f" {name}: {sign}{change}") print() diff --git a/pyproject.toml b/pyproject.toml index 4469206..f3a033d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,6 +77,7 @@ quote-style = "double" indent-style = "space" [tool.mypy] +files = ["src", "tests", "examples"] python_version = "3.11" strict = true warn_return_any = true diff --git a/src/mcsrranked/types/shared.py b/src/mcsrranked/types/shared.py index ccad54f..d715675 100644 --- a/src/mcsrranked/types/shared.py +++ b/src/mcsrranked/types/shared.py @@ -49,15 +49,20 @@ class MatchSeed(BaseModel): """Match seed information.""" id: str | None = Field(default=None, description="Seed identifier") - overworld: str | None = Field(default=None, description="Overworld seed") - bastion: str | None = Field(default=None, description="Bastion type") - end_towers: list[int] = Field( - default_factory=list, alias="endTowers", description="End tower positions" + overworld: str | None = Field(default=None, description="Overworld structure type") + nether: str | None = Field(default=None, description="Bastion type") + end_towers: list[int] | None = Field( + default=None, alias="endTowers", description="End tower positions" ) variations: list[str] = Field(default_factory=list, description="Seed variations") model_config = {"populate_by_name": True} + @property + def bastion(self) -> str | None: + """Alias for nether field (bastion type).""" + return self.nether + class EloChange(BaseModel): """Elo change data for a player in a match.""" diff --git a/src/mcsrranked/types/user.py b/src/mcsrranked/types/user.py index 607fd95..74b5cd6 100644 --- a/src/mcsrranked/types/user.py +++ b/src/mcsrranked/types/user.py @@ -1,6 +1,8 @@ from __future__ import annotations -from pydantic import BaseModel, Field +from typing import Any + +from pydantic import BaseModel, Field, model_validator from mcsrranked.types.shared import Achievement @@ -48,6 +50,51 @@ class MatchTypeStats(BaseModel): model_config = {"populate_by_name": True} +def _pivot_stats(data: dict[str, Any]) -> dict[str, Any]: + """Transform API format {stat: {mode: val}} to {mode: {stat: val}}. + + The API returns statistics grouped by stat type first (e.g., wins.ranked), + but we want them grouped by mode first (e.g., ranked.wins) for easier access. + """ + if not isinstance(data, dict): + return data + + # If already in correct format (ranked/casual at top level with nested stats) + if "ranked" in data and isinstance(data.get("ranked"), dict): + ranked_val = data["ranked"] + # Check if it looks like MatchTypeStats (has wins/losses as direct int values) + if isinstance(ranked_val.get("wins"), int | None): + return data + + # Pivot from {wins: {ranked: X, casual: Y}} to {ranked: {wins: X}, casual: {wins: Y}} + ranked: dict[str, Any] = {} + casual: dict[str, Any] = {} + + field_mapping = { + # API key -> model field name + "wins": "wins", + "loses": "losses", # Note: API uses 'loses' not 'losses' + "draws": "draws", + "forfeits": "forfeits", + "completions": "completions", + "playtime": "playtime", + "bestTime": "best_time", + "bestTimeId": "best_time_id", + "playedMatches": "played_matches", + "currentWinStreak": "current_winstreak", + "highestWinStreak": "highest_winstreak", + } + + for api_key, model_key in field_mapping.items(): + if api_key in data and isinstance(data[api_key], dict): + if data[api_key].get("ranked") is not None: + ranked[model_key] = data[api_key]["ranked"] + if data[api_key].get("casual") is not None: + casual[model_key] = data[api_key]["casual"] + + return {"ranked": ranked, "casual": casual} + + class SeasonStats(BaseModel): """Season statistics container.""" @@ -60,6 +107,12 @@ class SeasonStats(BaseModel): model_config = {"populate_by_name": True} + @model_validator(mode="before") + @classmethod + def pivot_stats(cls, data: dict[str, Any]) -> dict[str, Any]: + """Transform API stat-first format to mode-first format.""" + return _pivot_stats(data) + class TotalStats(BaseModel): """All-time statistics container.""" @@ -73,6 +126,12 @@ class TotalStats(BaseModel): model_config = {"populate_by_name": True} + @model_validator(mode="before") + @classmethod + def pivot_stats(cls, data: dict[str, Any]) -> dict[str, Any]: + """Transform API stat-first format to mode-first format.""" + return _pivot_stats(data) + class UserStatistics(BaseModel): """User statistics for season and total.""" @@ -235,8 +294,14 @@ class SeasonResultEntry(BaseModel): """Season result entry for user seasons endpoint.""" last: LastSeasonState = Field(description="Final season state") - highest: int = Field(description="Highest elo rating of season") - lowest: int = Field(description="Lowest elo rating of season") + highest: int | float | None = Field( + default=None, + description="Highest elo rating of season. None if no ranked matches.", + ) + lowest: int | float | None = Field( + default=None, + description="Lowest elo rating of season. None if no ranked matches.", + ) phases: list[PhaseResult] = Field( default_factory=list, description="Phase results for the season" ) diff --git a/tests/conftest.py b/tests/conftest.py index aca1045..bc8e7ae 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,10 +1,24 @@ """Pytest configuration and fixtures.""" +import json +from collections.abc import Generator +from pathlib import Path +from typing import Any + import pytest import respx from mcsrranked import MCSRRanked +FIXTURES_DIR = Path(__file__).parent / "fixtures" + + +def load_fixture(name: str) -> dict[str, Any] | list[Any]: + """Load a JSON fixture file.""" + with open(FIXTURES_DIR / name) as f: + data: dict[str, Any] | list[Any] = json.load(f) + return data + @pytest.fixture def client() -> MCSRRanked: @@ -13,7 +27,103 @@ def client() -> MCSRRanked: @pytest.fixture -def mock_api() -> respx.MockRouter: +def mock_api() -> Generator[respx.MockRouter, None, None]: """Create a mock API router.""" with respx.mock(base_url="https://api.mcsrranked.com") as respx_mock: yield respx_mock + + +@pytest.fixture +def user_fixture() -> dict[str, Any]: + """Load user.json fixture (Feinberg's profile).""" + result = load_fixture("user.json") + assert isinstance(result, dict) + return result + + +@pytest.fixture +def user_matches_fixture() -> list[Any]: + """Load user_matches.json fixture (Feinberg's recent matches).""" + result = load_fixture("user_matches.json") + assert isinstance(result, list) + return result + + +@pytest.fixture +def user_seasons_fixture() -> dict[str, Any]: + """Load user_seasons.json fixture (Feinberg's season history).""" + result = load_fixture("user_seasons.json") + assert isinstance(result, dict) + return result + + +@pytest.fixture +def versus_fixture() -> dict[str, Any]: + """Load versus.json fixture (Feinberg vs Couriway stats).""" + result = load_fixture("versus.json") + assert isinstance(result, dict) + return result + + +@pytest.fixture +def versus_matches_fixture() -> list[Any]: + """Load versus_matches.json fixture (Feinberg vs Couriway matches).""" + result = load_fixture("versus_matches.json") + assert isinstance(result, list) + return result + + +@pytest.fixture +def matches_fixture() -> list[Any]: + """Load matches.json fixture (recent ranked matches).""" + result = load_fixture("matches.json") + assert isinstance(result, list) + return result + + +@pytest.fixture +def match_detail_fixture() -> dict[str, Any]: + """Load match_detail.json fixture (single match details).""" + result = load_fixture("match_detail.json") + assert isinstance(result, dict) + return result + + +@pytest.fixture +def leaderboard_fixture() -> dict[str, Any]: + """Load leaderboard.json fixture (elo leaderboard).""" + result = load_fixture("leaderboard.json") + assert isinstance(result, dict) + return result + + +@pytest.fixture +def phase_leaderboard_fixture() -> dict[str, Any]: + """Load phase_leaderboard.json fixture.""" + result = load_fixture("phase_leaderboard.json") + assert isinstance(result, dict) + return result + + +@pytest.fixture +def record_leaderboard_fixture() -> list[Any]: + """Load record_leaderboard.json fixture.""" + result = load_fixture("record_leaderboard.json") + assert isinstance(result, list) + return result + + +@pytest.fixture +def live_fixture() -> dict[str, Any]: + """Load live.json fixture (live matches).""" + result = load_fixture("live.json") + assert isinstance(result, dict) + return result + + +@pytest.fixture +def weekly_race_fixture() -> dict[str, Any]: + """Load weekly_race.json fixture.""" + result = load_fixture("weekly_race.json") + assert isinstance(result, dict) + return result diff --git a/tests/fixtures/leaderboard.json b/tests/fixtures/leaderboard.json new file mode 100644 index 0000000..f135164 --- /dev/null +++ b/tests/fixtures/leaderboard.json @@ -0,0 +1,1959 @@ +{ + "season": { + "startsAt": 1767312000, + "endsAt": 1777680000, + "number": 10 + }, + "users": [ + { + "uuid": "a54e3bc4c6354b07a236b81efbcfe791", + "nickname": "Infume", + "roleType": 2, + "eloRate": 2152, + "eloRank": 1, + "country": "us", + "seasonResult": { + "eloRate": 2152, + "eloRank": 1, + "phasePoint": 0 + } + }, + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "nickname": "Feinberg", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "us", + "seasonResult": { + "eloRate": 2100, + "eloRank": 2, + "phasePoint": 0 + } + }, + { + "uuid": "635f35ee69ed4f0c94ff26ece4818956", + "nickname": "edcr", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "cf", + "seasonResult": { + "eloRate": 2100, + "eloRank": 2, + "phasePoint": 0 + } + }, + { + "uuid": "ac601ce7376f49cea7ce14cd577dac85", + "nickname": "BlazeMind", + "roleType": 3, + "eloRate": 2061, + "eloRank": 4, + "country": "au", + "seasonResult": { + "eloRate": 2061, + "eloRank": 4, + "phasePoint": 0 + } + }, + { + "uuid": "92b63a39b36a445fa94c77ae212dcea3", + "nickname": "bing_pigs", + "roleType": 3, + "eloRate": 2002, + "eloRank": 5, + "country": "au", + "seasonResult": { + "eloRate": 2002, + "eloRank": 5, + "phasePoint": 0 + } + }, + { + "uuid": "cc432b2626a44ae1836a50244adbf468", + "nickname": "XSpocony_MaciekX", + "roleType": 1, + "eloRate": 1981, + "eloRank": 6, + "country": "pl", + "seasonResult": { + "eloRate": 1981, + "eloRank": 6, + "phasePoint": 0 + } + }, + { + "uuid": "3b01d4b4fef14f178b75f05c04dd34ef", + "nickname": "BeefSalad", + "roleType": 3, + "eloRate": 1952, + "eloRank": 7, + "country": "gb", + "seasonResult": { + "eloRate": 1952, + "eloRank": 7, + "phasePoint": 0 + } + }, + { + "uuid": "bbd1dbd2f3ed4c43b62fc7572229ee61", + "nickname": "romuxii", + "roleType": 0, + "eloRate": 1907, + "eloRank": 8, + "country": "by", + "seasonResult": { + "eloRate": 1907, + "eloRank": 8, + "phasePoint": 0 + } + }, + { + "uuid": "2ef2bfed3d084649b56290328970ace9", + "nickname": "nahhann", + "roleType": 1, + "eloRate": 1903, + "eloRank": 9, + "country": "us", + "seasonResult": { + "eloRate": 1903, + "eloRank": 9, + "phasePoint": 0 + } + }, + { + "uuid": "bc80af38933f4ae19b0494681a54422b", + "nickname": "Ancoboyy", + "roleType": 1, + "eloRate": 1890, + "eloRank": 10, + "country": "tr", + "seasonResult": { + "eloRate": 1890, + "eloRank": 10, + "phasePoint": 0 + } + }, + { + "uuid": "a5d83ff042164ff1b862dedc118c1dae", + "nickname": "steez", + "roleType": 0, + "eloRate": 1873, + "eloRank": 11, + "country": "gb", + "seasonResult": { + "eloRate": 1873, + "eloRank": 11, + "phasePoint": 0 + } + }, + { + "uuid": "ba31689fe7d24431bf7997a52efcc21c", + "nickname": "meebie", + "roleType": 1, + "eloRate": 1852, + "eloRank": 12, + "country": "cf", + "seasonResult": { + "eloRate": 1852, + "eloRank": 12, + "phasePoint": 0 + } + }, + { + "uuid": "4cf401d7b9474756b06a653867d22fca", + "nickname": "BadGamer", + "roleType": 1, + "eloRate": 1833, + "eloRank": 13, + "country": "ca", + "seasonResult": { + "eloRate": 1833, + "eloRank": 13, + "phasePoint": 0 + } + }, + { + "uuid": "78a8ec9f99d34371b73decd2a78ff9b0", + "nickname": "TUDORULE", + "roleType": 1, + "eloRate": 1818, + "eloRank": 14, + "country": "ro", + "seasonResult": { + "eloRate": 1818, + "eloRank": 14, + "phasePoint": 0 + } + }, + { + "uuid": "0b6c44a481e14c7e88ac836c92499ff4", + "nickname": "TIGERMCSR", + "roleType": 3, + "eloRate": 1803, + "eloRank": 15, + "country": "pt", + "seasonResult": { + "eloRate": 1803, + "eloRank": 15, + "phasePoint": 0 + } + }, + { + "uuid": "0b164a03002048d3955715422179eedf", + "nickname": "KenanKardes", + "roleType": 0, + "eloRate": 1802, + "eloRank": 16, + "country": "az", + "seasonResult": { + "eloRate": 1802, + "eloRank": 16, + "phasePoint": 0 + } + }, + { + "uuid": "388533d5a2ad4b349a31db4738670a4b", + "nickname": "v_strid", + "roleType": 1, + "eloRate": 1798, + "eloRank": 17, + "country": "se", + "seasonResult": { + "eloRate": 1798, + "eloRank": 17, + "phasePoint": 0 + } + }, + { + "uuid": "70eb9286e3e24153a8b37c8f884f1292", + "nickname": "7rowl", + "roleType": 3, + "eloRate": 1797, + "eloRank": 18, + "country": "ua", + "seasonResult": { + "eloRate": 1797, + "eloRank": 18, + "phasePoint": 0 + } + }, + { + "uuid": "253b53d832ab4bafb5ee0308d5164ccf", + "nickname": "Aquacorde", + "roleType": 3, + "eloRate": 1794, + "eloRank": 19, + "country": "ca", + "seasonResult": { + "eloRate": 1794, + "eloRank": 19, + "phasePoint": 0 + } + }, + { + "uuid": "7665f76f431b41c6b321bea16aff913b", + "nickname": "lowk3y_", + "roleType": 3, + "eloRate": 1777, + "eloRank": 20, + "seasonResult": { + "eloRate": 1777, + "eloRank": 20, + "phasePoint": 0 + }, + "country": null + }, + { + "uuid": "41d79a18ef5540d6bb3d68634f06a3b1", + "nickname": "okrzej_", + "roleType": 1, + "eloRate": 1774, + "eloRank": 21, + "country": "pl", + "seasonResult": { + "eloRate": 1774, + "eloRank": 21, + "phasePoint": 0 + } + }, + { + "uuid": "0d0f007a376a462299bf23f2f713b0e5", + "nickname": "MrBudgiee", + "roleType": 1, + "eloRate": 1761, + "eloRank": 22, + "country": "ca", + "seasonResult": { + "eloRate": 1761, + "eloRank": 22, + "phasePoint": 0 + } + }, + { + "uuid": "0c3cc22849a343b0964a89ac842fa3ca", + "nickname": "HDMICables", + "roleType": 2, + "eloRate": 1760, + "eloRank": 23, + "country": "nl", + "seasonResult": { + "eloRate": 1760, + "eloRank": 23, + "phasePoint": 0 + } + }, + { + "uuid": "3da9e8cec2d348f781a98d095b1d0325", + "nickname": "dolqhin", + "roleType": 0, + "eloRate": 1751, + "eloRank": 24, + "country": "us", + "seasonResult": { + "eloRate": 1751, + "eloRank": 24, + "phasePoint": 0 + } + }, + { + "uuid": "5a32f1e5609847c691c07730f973397c", + "nickname": "DARVY__X1", + "roleType": 2, + "eloRate": 1749, + "eloRank": 25, + "country": "cf", + "seasonResult": { + "eloRate": 1749, + "eloRank": 25, + "phasePoint": 0 + } + }, + { + "uuid": "734a1c6118754829acc234135470152c", + "nickname": "yeopgihoney", + "roleType": 2, + "eloRate": 1749, + "eloRank": 25, + "country": "kr", + "seasonResult": { + "eloRate": 1749, + "eloRank": 25, + "phasePoint": 0 + } + }, + { + "uuid": "2988fcfbc6b141a497faa915e13b6592", + "nickname": "AutomattPLUS", + "roleType": 3, + "eloRate": 1747, + "eloRank": 27, + "country": "pl", + "seasonResult": { + "eloRate": 1747, + "eloRank": 27, + "phasePoint": 0 + } + }, + { + "uuid": "3c8757790ab0400b8b9e3936e0dd535b", + "nickname": "doogile", + "roleType": 3, + "eloRate": 1743, + "eloRank": 28, + "country": "us", + "seasonResult": { + "eloRate": 1743, + "eloRank": 28, + "phasePoint": 0 + } + }, + { + "uuid": "5fe66e8b389f4dc384222e8cc09485f0", + "nickname": "sanjinhu", + "roleType": 0, + "eloRate": 1742, + "eloRank": 29, + "country": "br", + "seasonResult": { + "eloRate": 1742, + "eloRank": 29, + "phasePoint": 0 + } + }, + { + "uuid": "d7d0b271136647fea7398a444ab51c13", + "nickname": "JustAltoid", + "roleType": 1, + "eloRate": 1741, + "eloRank": 30, + "country": "us", + "seasonResult": { + "eloRate": 1741, + "eloRank": 30, + "phasePoint": 0 + } + }, + { + "uuid": "f2061f886c254191871f635dc2ce80b9", + "nickname": "iluappi", + "roleType": 1, + "eloRate": 1723, + "eloRank": 31, + "seasonResult": { + "eloRate": 1723, + "eloRank": 31, + "phasePoint": 0 + }, + "country": null + }, + { + "uuid": "410e5776b03a424d8740557bac2d9014", + "nickname": "JoomzMonkey", + "roleType": 0, + "eloRate": 1715, + "eloRank": 32, + "country": "us", + "seasonResult": { + "eloRate": 1715, + "eloRank": 32, + "phasePoint": 0 + } + }, + { + "uuid": "c32cdd142a0147dcb91771319d745194", + "nickname": "Erikfzf", + "roleType": 1, + "eloRate": 1706, + "eloRank": 33, + "country": "au", + "seasonResult": { + "eloRate": 1706, + "eloRank": 33, + "phasePoint": 0 + } + }, + { + "uuid": "7fad8dae2ab04971bc07a6440f84d609", + "nickname": "suravil", + "roleType": 1, + "eloRate": 1705, + "eloRank": 34, + "country": "pl", + "seasonResult": { + "eloRate": 1705, + "eloRank": 34, + "phasePoint": 0 + } + }, + { + "uuid": "bcb0f43558d745ee977841180b121267", + "nickname": "pavkin", + "roleType": 2, + "eloRate": 1702, + "eloRank": 35, + "country": "us", + "seasonResult": { + "eloRate": 1702, + "eloRank": 35, + "phasePoint": 0 + } + }, + { + "uuid": "625146b684804a29af2eaeb483a59ddf", + "nickname": "ColoOnPhilippine", + "roleType": 2, + "eloRate": 1701, + "eloRank": 36, + "country": "jp", + "seasonResult": { + "eloRate": 1701, + "eloRank": 36, + "phasePoint": 0 + } + }, + { + "uuid": "17e787d1d6374f818b294f2319db370d", + "nickname": "silverrruns", + "roleType": 2, + "eloRate": 1700, + "eloRank": 37, + "country": "ca", + "seasonResult": { + "eloRate": 1700, + "eloRank": 37, + "phasePoint": 0 + } + }, + { + "uuid": "4aed1e5e8f5c44e2bc0666e0c03781af", + "nickname": "nEmerald", + "roleType": 2, + "eloRate": 1697, + "eloRank": 38, + "country": "us", + "seasonResult": { + "eloRate": 1697, + "eloRank": 38, + "phasePoint": 0 + } + }, + { + "uuid": "fe6771646c5d43c1b713023fb69c10c6", + "nickname": "SammmyG", + "roleType": 0, + "eloRate": 1690, + "eloRank": 39, + "country": "au", + "seasonResult": { + "eloRate": 1690, + "eloRank": 39, + "phasePoint": 0 + } + }, + { + "uuid": "d1718c79c34e4bce93cd688ac5254b58", + "nickname": "cornflakesmcsr", + "roleType": 1, + "eloRate": 1688, + "eloRank": 40, + "country": "de", + "seasonResult": { + "eloRate": 1688, + "eloRank": 40, + "phasePoint": 0 + } + }, + { + "uuid": "e4808bc3e1e347988cbb59b55d723e0f", + "nickname": "dandannyboy", + "roleType": 1, + "eloRate": 1687, + "eloRank": 41, + "country": "ca", + "seasonResult": { + "eloRate": 1687, + "eloRank": 41, + "phasePoint": 0 + } + }, + { + "uuid": "dd34e44dfe5d4e05923d876b9c34ca5f", + "nickname": "Waluyoshi", + "roleType": 1, + "eloRate": 1684, + "eloRank": 42, + "country": "sx", + "seasonResult": { + "eloRate": 1684, + "eloRank": 42, + "phasePoint": 0 + } + }, + { + "uuid": "c473d5e8b71a4fcc91c9d132bb61360c", + "nickname": "Lenged", + "roleType": 1, + "eloRate": 1683, + "eloRank": 43, + "country": "au", + "seasonResult": { + "eloRate": 1683, + "eloRank": 43, + "phasePoint": 0 + } + }, + { + "uuid": "d10be6f072a34e069882ae04bfe60c98", + "nickname": "Unknwonc", + "roleType": 1, + "eloRate": 1679, + "eloRank": 44, + "country": "se", + "seasonResult": { + "eloRate": 1679, + "eloRank": 44, + "phasePoint": 0 + } + }, + { + "uuid": "7751d507ab364914bac767a4d2574753", + "nickname": "lumeh_CAR89", + "roleType": 0, + "eloRate": 1677, + "eloRank": 45, + "country": "cf", + "seasonResult": { + "eloRate": 1677, + "eloRank": 45, + "phasePoint": 0 + } + }, + { + "uuid": "553414a2c89b4d6b8c0ba5bd89284508", + "nickname": "ulsah1n", + "roleType": 0, + "eloRate": 1676, + "eloRank": 46, + "country": "tr", + "seasonResult": { + "eloRate": 1676, + "eloRank": 46, + "phasePoint": 0 + } + }, + { + "uuid": "7d3a6bb9f62645ae80cf40840ca84c50", + "nickname": "Frigbob", + "roleType": 1, + "eloRate": 1670, + "eloRank": 47, + "country": "ie", + "seasonResult": { + "eloRate": 1670, + "eloRank": 47, + "phasePoint": 0 + } + }, + { + "uuid": "64858295eb754646b03caead840391a2", + "nickname": "Casssual", + "roleType": 1, + "eloRate": 1668, + "eloRank": 48, + "country": "pl", + "seasonResult": { + "eloRate": 1668, + "eloRank": 48, + "phasePoint": 0 + } + }, + { + "uuid": "aa5a894a4d5340f49683fdfd1ea9c523", + "nickname": "Pinne", + "roleType": 1, + "eloRate": 1667, + "eloRank": 49, + "country": "no", + "seasonResult": { + "eloRate": 1667, + "eloRank": 49, + "phasePoint": 0 + } + }, + { + "uuid": "8826e1e6d21b46ecbc5d5246b836f36a", + "nickname": "4antoo", + "roleType": 0, + "eloRate": 1664, + "eloRank": 50, + "country": "it", + "seasonResult": { + "eloRate": 1664, + "eloRank": 50, + "phasePoint": 0 + } + }, + { + "uuid": "6c4b4e74963d40e3b5a7118f3e0b0dc4", + "nickname": "leah_mp3", + "roleType": 0, + "eloRate": 1659, + "eloRank": 51, + "country": "ca", + "seasonResult": { + "eloRate": 1659, + "eloRank": 51, + "phasePoint": 0 + } + }, + { + "uuid": "be4ad7e999e14a74974d47ac650062a3", + "nickname": "bbiddd", + "roleType": 1, + "eloRate": 1659, + "eloRank": 51, + "country": "ca", + "seasonResult": { + "eloRate": 1659, + "eloRank": 51, + "phasePoint": 0 + } + }, + { + "uuid": "f250f722cd8441b297b6e680b0110d47", + "nickname": "4prl", + "roleType": 0, + "eloRate": 1659, + "eloRank": 51, + "seasonResult": { + "eloRate": 1659, + "eloRank": 51, + "phasePoint": 0 + }, + "country": null + }, + { + "uuid": "4bf064c642dc4937a5b0d9b6327a7119", + "nickname": "TasGamer409", + "roleType": 1, + "eloRate": 1658, + "eloRank": 54, + "country": "pl", + "seasonResult": { + "eloRate": 1658, + "eloRank": 54, + "phasePoint": 0 + } + }, + { + "uuid": "25349f93cf194f3baeee93d024eccc21", + "nickname": "retropog", + "roleType": 0, + "eloRate": 1655, + "eloRank": 55, + "country": "au", + "seasonResult": { + "eloRate": 1655, + "eloRank": 55, + "phasePoint": 0 + } + }, + { + "uuid": "dd5fbfd77b35431e97e8e0ec36817f29", + "nickname": "Traden", + "roleType": 1, + "eloRate": 1654, + "eloRank": 56, + "country": "tw", + "seasonResult": { + "eloRate": 1654, + "eloRank": 56, + "phasePoint": 0 + } + }, + { + "uuid": "eb136e7e26124f8daa99e521da609135", + "nickname": "Frolde", + "roleType": 1, + "eloRate": 1653, + "eloRank": 57, + "country": "dk", + "seasonResult": { + "eloRate": 1653, + "eloRank": 57, + "phasePoint": 0 + } + }, + { + "uuid": "3fa40d15dadb46368aa72bc4827dae73", + "nickname": "staremc", + "roleType": 1, + "eloRate": 1652, + "eloRank": 58, + "country": "us", + "seasonResult": { + "eloRate": 1652, + "eloRank": 58, + "phasePoint": 0 + } + }, + { + "uuid": "3c59ed02bccf4ea3a0f626af7955be91", + "nickname": "Tookannn", + "roleType": 1, + "eloRate": 1648, + "eloRank": 59, + "country": "ca", + "seasonResult": { + "eloRate": 1648, + "eloRank": 59, + "phasePoint": 0 + } + }, + { + "uuid": "5fe4da47c5bb44628b32327a4d73b247", + "nickname": "SneakyNO", + "roleType": 0, + "eloRate": 1644, + "eloRank": 60, + "country": "se", + "seasonResult": { + "eloRate": 1644, + "eloRank": 60, + "phasePoint": 0 + } + }, + { + "uuid": "d41f0f3caebe45e1bc6a380fedf54ca9", + "nickname": "boosterruns", + "roleType": 0, + "eloRate": 1644, + "eloRank": 60, + "country": "br", + "seasonResult": { + "eloRate": 1644, + "eloRank": 60, + "phasePoint": 0 + } + }, + { + "uuid": "9a61b87c6a16403da56541258e74ed3e", + "nickname": "Blad_d", + "roleType": 0, + "eloRate": 1642, + "eloRank": 62, + "country": "de", + "seasonResult": { + "eloRate": 1642, + "eloRank": 62, + "phasePoint": 0 + } + }, + { + "uuid": "5cd115f0ec1240659db152406c0984a3", + "nickname": "yjako", + "roleType": 1, + "eloRate": 1641, + "eloRank": 63, + "country": "ph", + "seasonResult": { + "eloRate": 1641, + "eloRank": 63, + "phasePoint": 0 + } + }, + { + "uuid": "aa0aee82f7a94591a076331d899f836c", + "nickname": "sacanagem_online", + "roleType": 0, + "eloRate": 1641, + "eloRank": 63, + "country": "br", + "seasonResult": { + "eloRate": 1641, + "eloRank": 63, + "phasePoint": 0 + } + }, + { + "uuid": "fa1bec35058546c98f9279f8be7cf9bc", + "nickname": "MoleyG", + "roleType": 1, + "eloRate": 1641, + "eloRank": 63, + "country": "au", + "seasonResult": { + "eloRate": 1641, + "eloRank": 63, + "phasePoint": 0 + } + }, + { + "uuid": "7d320034571e405a9b6889104489a3c4", + "nickname": "kohout135", + "roleType": 1, + "eloRate": 1639, + "eloRank": 66, + "country": "cz", + "seasonResult": { + "eloRate": 1639, + "eloRank": 66, + "phasePoint": 0 + } + }, + { + "uuid": "8d52ed9bf12146c68321f1729e28cbf5", + "nickname": "WarioTime1", + "roleType": 0, + "eloRate": 1639, + "eloRank": 66, + "country": "va", + "seasonResult": { + "eloRate": 1639, + "eloRank": 66, + "phasePoint": 0 + } + }, + { + "uuid": "4c1fdb69c9b8483d8cfcb0b4ae870cc8", + "nickname": "incel_chud", + "roleType": 0, + "eloRate": 1636, + "eloRank": 68, + "country": "cl", + "seasonResult": { + "eloRate": 1636, + "eloRank": 68, + "phasePoint": 0 + } + }, + { + "uuid": "f2e05ad464b54d288fa18da14e9a2786", + "nickname": "LEC666888", + "roleType": 0, + "eloRate": 1635, + "eloRank": 69, + "country": "cn", + "seasonResult": { + "eloRate": 1635, + "eloRank": 69, + "phasePoint": 0 + } + }, + { + "uuid": "23e7466f0a1b4597bf89c17d53c4d0ae", + "nickname": "LexanYT", + "roleType": 1, + "eloRate": 1633, + "eloRank": 70, + "country": "se", + "seasonResult": { + "eloRate": 1633, + "eloRank": 70, + "phasePoint": 0 + } + }, + { + "uuid": "b0dea0d890de4eecb781481130c3c1d1", + "nickname": "Mixray_", + "roleType": 1, + "eloRate": 1632, + "eloRank": 71, + "country": "pl", + "seasonResult": { + "eloRate": 1632, + "eloRank": 71, + "phasePoint": 0 + } + }, + { + "uuid": "f55a7e31e65a453e941ebec79cd39992", + "nickname": "Brunted", + "roleType": 1, + "eloRate": 1632, + "eloRank": 71, + "country": "gb", + "seasonResult": { + "eloRate": 1632, + "eloRank": 71, + "phasePoint": 0 + } + }, + { + "uuid": "bc55d2999bf24ba2b764c4135a53255f", + "nickname": "Sadekeppi", + "roleType": 0, + "eloRate": 1630, + "eloRank": 73, + "country": "fi", + "seasonResult": { + "eloRate": 1630, + "eloRank": 73, + "phasePoint": 0 + } + }, + { + "uuid": "939ddf85303441de901d60bfa4109318", + "nickname": "thecamo6", + "roleType": 3, + "eloRate": 1628, + "eloRank": 74, + "country": "us", + "seasonResult": { + "eloRate": 1628, + "eloRank": 74, + "phasePoint": 0 + } + }, + { + "uuid": "d30aa493035d4b168c8a4a1c20c766c8", + "nickname": "CxrtxR", + "roleType": 1, + "eloRate": 1626, + "eloRank": 75, + "country": "id", + "seasonResult": { + "eloRate": 1626, + "eloRank": 75, + "phasePoint": 0 + } + }, + { + "uuid": "6d160110ea1e4ab3b1513b3b45c53556", + "nickname": "MaybeSoul", + "roleType": 1, + "eloRate": 1625, + "eloRank": 76, + "country": "us", + "seasonResult": { + "eloRate": 1625, + "eloRank": 76, + "phasePoint": 0 + } + }, + { + "uuid": "a00913f1079c4b0c9d68d32f57dfbe73", + "nickname": "sevensix_", + "roleType": 0, + "eloRate": 1625, + "eloRank": 76, + "country": "hk", + "seasonResult": { + "eloRate": 1625, + "eloRank": 76, + "phasePoint": 0 + } + }, + { + "uuid": "5a6272a8951745d7afd87eb0d8fae915", + "nickname": "rqichu", + "roleType": 1, + "eloRate": 1625, + "eloRank": 76, + "country": "de", + "seasonResult": { + "eloRate": 1625, + "eloRank": 76, + "phasePoint": 0 + } + }, + { + "uuid": "040e328fcb6e47b594c57ee9fc24333e", + "nickname": "LilMinien", + "roleType": 1, + "eloRate": 1623, + "eloRank": 79, + "country": "no", + "seasonResult": { + "eloRate": 1623, + "eloRank": 79, + "phasePoint": 0 + } + }, + { + "uuid": "a162fe30a8074cc6b9600719bc5e5ed9", + "nickname": "Maraico", + "roleType": 1, + "eloRate": 1622, + "eloRank": 80, + "country": "de", + "seasonResult": { + "eloRate": 1622, + "eloRank": 80, + "phasePoint": 0 + } + }, + { + "uuid": "ea96ade538b3498d9de431a5aec6ffbf", + "nickname": "jonahhhhhhhh", + "roleType": 3, + "eloRate": 1620, + "eloRank": 81, + "country": "us", + "seasonResult": { + "eloRate": 1620, + "eloRank": 81, + "phasePoint": 0 + } + }, + { + "uuid": "1fcc556edb414dce89ee0ee31799e4e2", + "nickname": "pandaendoz", + "roleType": 1, + "eloRate": 1619, + "eloRank": 82, + "country": "us", + "seasonResult": { + "eloRate": 1619, + "eloRank": 82, + "phasePoint": 0 + } + }, + { + "uuid": "b7797e44bd994c6ea281073798e03d27", + "nickname": "lvckyruns", + "roleType": 1, + "eloRate": 1619, + "eloRank": 82, + "country": "de", + "seasonResult": { + "eloRate": 1619, + "eloRank": 82, + "phasePoint": 0 + } + }, + { + "uuid": "00f996cd910f479ba0903d85c2bdb1e0", + "nickname": "Bloonskiller", + "roleType": 1, + "eloRate": 1618, + "eloRank": 84, + "seasonResult": { + "eloRate": 1618, + "eloRank": 84, + "phasePoint": 0 + }, + "country": null + }, + { + "uuid": "54efac4c73db48c19234ff20e390c08e", + "nickname": "Ch0ok_ERC", + "roleType": 0, + "eloRate": 1616, + "eloRank": 85, + "country": "jp", + "seasonResult": { + "eloRate": 1616, + "eloRank": 85, + "phasePoint": 0 + } + }, + { + "uuid": "350579d3e06341a0997ac47a91f2ac98", + "nickname": "xFray_", + "roleType": 0, + "eloRate": 1615, + "eloRank": 86, + "country": "sg", + "seasonResult": { + "eloRate": 1615, + "eloRank": 86, + "phasePoint": 0 + } + }, + { + "uuid": "e811fb301b1a41ea81c1f481ea93c3be", + "nickname": "nyachloe", + "roleType": 3, + "eloRate": 1615, + "eloRank": 86, + "country": "us", + "seasonResult": { + "eloRate": 1615, + "eloRank": 86, + "phasePoint": 0 + } + }, + { + "uuid": "31bb6401944d4fc5ad97f6cf90c54616", + "nickname": "darkk575", + "roleType": 1, + "eloRate": 1613, + "eloRank": 88, + "country": "br", + "seasonResult": { + "eloRate": 1613, + "eloRank": 88, + "phasePoint": 0 + } + }, + { + "uuid": "4eea0516cb0c4c528cefe85448cac786", + "nickname": "blobserr", + "roleType": 1, + "eloRate": 1610, + "eloRank": 89, + "country": "vn", + "seasonResult": { + "eloRate": 1610, + "eloRank": 89, + "phasePoint": 0 + } + }, + { + "uuid": "8fc93aecda5b4f699cf76694116eaf11", + "nickname": "rekrap2", + "roleType": 3, + "eloRate": 1610, + "eloRank": 89, + "country": "us", + "seasonResult": { + "eloRate": 1610, + "eloRank": 89, + "phasePoint": 0 + } + }, + { + "uuid": "97800bfa7f1c42e19162ea1c2bc7078b", + "nickname": "misfitO1", + "roleType": 1, + "eloRate": 1610, + "eloRank": 89, + "country": "br", + "seasonResult": { + "eloRate": 1610, + "eloRank": 89, + "phasePoint": 0 + } + }, + { + "uuid": "ac0c2ba5ec5546aea0d94fd38cd55682", + "nickname": "Coach_Side", + "roleType": 1, + "eloRate": 1608, + "eloRank": 92, + "country": "hu", + "seasonResult": { + "eloRate": 1608, + "eloRank": 92, + "phasePoint": 0 + } + }, + { + "uuid": "11dd5549074b4cb1830d7ca103a01cc7", + "nickname": "m1kky_", + "roleType": 0, + "eloRate": 1606, + "eloRank": 93, + "country": "au", + "seasonResult": { + "eloRate": 1606, + "eloRank": 93, + "phasePoint": 0 + } + }, + { + "uuid": "a0a672a0bc194540bc195220dc170dba", + "nickname": "JackoWacko62", + "roleType": 3, + "eloRate": 1606, + "eloRank": 93, + "country": "us", + "seasonResult": { + "eloRate": 1606, + "eloRank": 93, + "phasePoint": 0 + } + }, + { + "uuid": "d93d53f5b7bd4fdc970d67a772936c81", + "nickname": "Shiny_Chingling", + "roleType": 1, + "eloRate": 1606, + "eloRank": 93, + "country": "be", + "seasonResult": { + "eloRate": 1606, + "eloRank": 93, + "phasePoint": 0 + } + }, + { + "uuid": "dd382293fed04a3e9fa850bb139279fc", + "nickname": "vorbh", + "roleType": 1, + "eloRate": 1606, + "eloRank": 93, + "country": "no", + "seasonResult": { + "eloRate": 1606, + "eloRank": 93, + "phasePoint": 0 + } + }, + { + "uuid": "a3165d3bf73a4eb6a69c110f2fdd58a9", + "nickname": "cocuski", + "roleType": 1, + "eloRate": 1605, + "eloRank": 97, + "country": "cc", + "seasonResult": { + "eloRate": 1605, + "eloRank": 97, + "phasePoint": 0 + } + }, + { + "uuid": "86334fc9e38344bdabf1a97f63c7be23", + "nickname": "Anjo___", + "roleType": 2, + "eloRate": 1604, + "eloRank": 98, + "country": "us", + "seasonResult": { + "eloRate": 1604, + "eloRank": 98, + "phasePoint": 0 + } + }, + { + "uuid": "c92021f449a94bdc9811a3e5e299820e", + "nickname": "oshgay", + "roleType": 1, + "eloRate": 1603, + "eloRank": 99, + "country": "mo", + "seasonResult": { + "eloRate": 1603, + "eloRank": 99, + "phasePoint": 0 + } + }, + { + "uuid": "3b945bbc6cef48c8b76e1f65580df71d", + "nickname": "ThaShape", + "roleType": 0, + "eloRate": 1602, + "eloRank": 100, + "seasonResult": { + "eloRate": 1602, + "eloRank": 100, + "phasePoint": 0 + }, + "country": null + }, + { + "uuid": "97559a8303d44690b85db9e1e1f6764f", + "nickname": "shrddr", + "roleType": 0, + "eloRate": 1602, + "eloRank": 100, + "country": "yt", + "seasonResult": { + "eloRate": 1602, + "eloRank": 100, + "phasePoint": 0 + } + }, + { + "uuid": "4f3e7905554345698e41f88caa4c088e", + "nickname": "rcolee", + "roleType": 1, + "eloRate": 1602, + "eloRank": 100, + "country": "ca", + "seasonResult": { + "eloRate": 1602, + "eloRank": 100, + "phasePoint": 0 + } + }, + { + "uuid": "09985aa919494b5daf4f767ef09259e9", + "nickname": "b1ur_", + "roleType": 1, + "eloRate": 1600, + "eloRank": 103, + "country": "us", + "seasonResult": { + "eloRate": 1600, + "eloRank": 103, + "phasePoint": 0 + } + }, + { + "uuid": "bdb7f407200d4882b78e656ca161bddf", + "nickname": "pjfqepojedfpo", + "roleType": 1, + "eloRate": 1600, + "eloRank": 103, + "country": "fk", + "seasonResult": { + "eloRate": 1600, + "eloRank": 103, + "phasePoint": 0 + } + }, + { + "uuid": "0388b80ebe6c4216b4a8305c0cd27894", + "nickname": "tomscaredfamrow", + "roleType": 1, + "eloRate": 1599, + "eloRank": 105, + "country": "mn", + "seasonResult": { + "eloRate": 1599, + "eloRank": 105, + "phasePoint": 0 + } + }, + { + "uuid": "185b039b70284aa9a98850db4ba88e0d", + "nickname": "ElegantRobin", + "roleType": 0, + "eloRate": 1599, + "eloRank": 105, + "country": "cn", + "seasonResult": { + "eloRate": 1599, + "eloRank": 105, + "phasePoint": 0 + } + }, + { + "uuid": "7447dd83b8bc4b7fb97d3ec316f529dc", + "nickname": "Kxpow", + "roleType": 1, + "eloRate": 1597, + "eloRank": 107, + "country": "tz", + "seasonResult": { + "eloRate": 1597, + "eloRank": 107, + "phasePoint": 0 + } + }, + { + "uuid": "da5e15a7d3c04a84b432defd5a15c910", + "nickname": "paukll", + "roleType": 1, + "eloRate": 1597, + "eloRank": 107, + "country": "im", + "seasonResult": { + "eloRate": 1597, + "eloRank": 107, + "phasePoint": 0 + } + }, + { + "uuid": "681679a877ef413c97da63162e835935", + "nickname": "skylewl", + "roleType": 0, + "eloRate": 1594, + "eloRank": 109, + "country": "rs", + "seasonResult": { + "eloRate": 1594, + "eloRank": 109, + "phasePoint": 0 + } + }, + { + "uuid": "dfa196645c454568bede4966614beeca", + "nickname": "xSzymi__", + "roleType": 1, + "eloRate": 1593, + "eloRank": 110, + "country": "pl", + "seasonResult": { + "eloRate": 1593, + "eloRank": 110, + "phasePoint": 0 + } + }, + { + "uuid": "8c7208adf2784bacb3715ab657cd80bd", + "nickname": "BinEin", + "roleType": 1, + "eloRate": 1593, + "eloRank": 110, + "country": "pl", + "seasonResult": { + "eloRate": 1593, + "eloRank": 110, + "phasePoint": 0 + } + }, + { + "uuid": "2beddb5776d347b8b1f5ab0a71023f38", + "nickname": "Poomy1234", + "roleType": 1, + "eloRate": 1593, + "eloRank": 110, + "country": "th", + "seasonResult": { + "eloRate": 1593, + "eloRank": 110, + "phasePoint": 0 + } + }, + { + "uuid": "2fe70934e7be458dba747c4ac830391c", + "nickname": "nhb_", + "roleType": 2, + "eloRate": 1591, + "eloRank": 113, + "country": "cf", + "seasonResult": { + "eloRate": 1591, + "eloRank": 113, + "phasePoint": 0 + } + }, + { + "uuid": "529c478ae270415ba12044771a99249a", + "nickname": "mukvl", + "roleType": 1, + "eloRate": 1591, + "eloRank": 113, + "country": "in", + "seasonResult": { + "eloRate": 1591, + "eloRank": 113, + "phasePoint": 0 + } + }, + { + "uuid": "de8e3203f8674303ad4a2baa55a15c87", + "nickname": "fnhvr", + "roleType": 1, + "eloRate": 1590, + "eloRank": 115, + "seasonResult": { + "eloRate": 1590, + "eloRank": 115, + "phasePoint": 0 + }, + "country": null + }, + { + "uuid": "93c09b58a2a74ec8802ef0d01b98dfd0", + "nickname": "GabzlynMC", + "roleType": 2, + "eloRate": 1589, + "eloRank": 116, + "country": "mx", + "seasonResult": { + "eloRate": 1589, + "eloRank": 116, + "phasePoint": 0 + } + }, + { + "uuid": "2e12870c08ec4337bc2e8fbf54e79853", + "nickname": "TapL", + "roleType": 3, + "eloRate": 1588, + "eloRank": 117, + "country": "us", + "seasonResult": { + "eloRate": 1588, + "eloRank": 117, + "phasePoint": 0 + } + }, + { + "uuid": "ed0605bc88fa411f8f1d530323efd867", + "nickname": "Prince_01", + "roleType": 0, + "eloRate": 1588, + "eloRank": 117, + "country": "in", + "seasonResult": { + "eloRate": 1588, + "eloRank": 117, + "phasePoint": 0 + } + }, + { + "uuid": "2d214574a5bf4d47afaa6396cc855556", + "nickname": "P3n9uin", + "roleType": 0, + "eloRate": 1587, + "eloRank": 119, + "country": "aq", + "seasonResult": { + "eloRate": 1587, + "eloRank": 119, + "phasePoint": 0 + } + }, + { + "uuid": "ac94f87ac4714cb1873847f6c3432f0b", + "nickname": "CyberOG", + "roleType": 1, + "eloRate": 1586, + "eloRank": 120, + "country": "us", + "seasonResult": { + "eloRate": 1586, + "eloRank": 120, + "phasePoint": 0 + } + }, + { + "uuid": "06dcddbb0a82458bbf9bef66da684eb1", + "nickname": "Yahiamice", + "roleType": 1, + "eloRate": 1582, + "eloRank": 121, + "country": "ma", + "seasonResult": { + "eloRate": 1582, + "eloRank": 121, + "phasePoint": 0 + } + }, + { + "uuid": "728fdcab24b249b686c081a7fc53176e", + "nickname": "ContraVz", + "roleType": 1, + "eloRate": 1582, + "eloRank": 121, + "country": "ie", + "seasonResult": { + "eloRate": 1582, + "eloRank": 121, + "phasePoint": 0 + } + }, + { + "uuid": "be7a79f3331042f19c07230752b26725", + "nickname": "dinonuggieboi", + "roleType": 1, + "eloRate": 1582, + "eloRank": 121, + "country": "ua", + "seasonResult": { + "eloRate": 1582, + "eloRank": 121, + "phasePoint": 0 + } + }, + { + "uuid": "132807fea3a54a02b6b1ad057430b002", + "nickname": "ulqt", + "roleType": 1, + "eloRate": 1582, + "eloRank": 121, + "country": "de", + "seasonResult": { + "eloRate": 1582, + "eloRank": 121, + "phasePoint": 0 + } + }, + { + "uuid": "f0103fdd182548828ba66883fdd05214", + "nickname": "Magmania", + "roleType": 1, + "eloRate": 1581, + "eloRank": 125, + "country": "au", + "seasonResult": { + "eloRate": 1581, + "eloRank": 125, + "phasePoint": 0 + } + }, + { + "uuid": "addd890764404097b3f12acdde2adf33", + "nickname": "Hypn0ic", + "roleType": 1, + "eloRate": 1579, + "eloRank": 126, + "country": "us", + "seasonResult": { + "eloRate": 1579, + "eloRank": 126, + "phasePoint": 0 + } + }, + { + "uuid": "5ee577fdc1af45d3a6fb3e086cc293fb", + "nickname": "Ranik_", + "roleType": 3, + "eloRate": 1578, + "eloRank": 127, + "country": "il", + "seasonResult": { + "eloRate": 1578, + "eloRank": 127, + "phasePoint": 0 + } + }, + { + "uuid": "c7802cb7c30c47aabc1a7ec790ff2260", + "nickname": "iKme_", + "roleType": 0, + "eloRate": 1576, + "eloRank": 128, + "country": "hu", + "seasonResult": { + "eloRate": 1576, + "eloRank": 128, + "phasePoint": 0 + } + }, + { + "uuid": "02afb683c67849b2b0266aa222980400", + "nickname": "catpats", + "roleType": 1, + "eloRate": 1575, + "eloRank": 129, + "country": null, + "seasonResult": { + "eloRate": 1575, + "eloRank": 129, + "phasePoint": 0 + } + }, + { + "uuid": "c0ee21f8d5904827b57349507ae2721b", + "nickname": "hsbi", + "roleType": 1, + "eloRate": 1575, + "eloRank": 129, + "country": "id", + "seasonResult": { + "eloRate": 1575, + "eloRank": 129, + "phasePoint": 0 + } + }, + { + "uuid": "6b557be7e08a447a9092d30f669ea614", + "nickname": "sanshynE", + "roleType": 0, + "eloRate": 1575, + "eloRank": 129, + "seasonResult": { + "eloRate": 1575, + "eloRank": 129, + "phasePoint": 0 + }, + "country": null + }, + { + "uuid": "c41b14ac0f1547aeb7690276d82aa458", + "nickname": "Psemcovici", + "roleType": 0, + "eloRate": 1574, + "eloRank": 132, + "country": "br", + "seasonResult": { + "eloRate": 1574, + "eloRank": 132, + "phasePoint": 0 + } + }, + { + "uuid": "0264ac7f4abf45c786ad5122296805cc", + "nickname": "vuanh", + "roleType": 0, + "eloRate": 1574, + "eloRank": 132, + "country": "vn", + "seasonResult": { + "eloRate": 1574, + "eloRank": 132, + "phasePoint": 0 + } + }, + { + "uuid": "3910d98bea254b488a10d6e91e469f7e", + "nickname": "dwoh", + "roleType": 3, + "eloRate": 1573, + "eloRank": 134, + "country": "kr", + "seasonResult": { + "eloRate": 1573, + "eloRank": 134, + "phasePoint": 0 + } + }, + { + "uuid": "7096b050a76c44218e1ff2ca51b7f735", + "nickname": "rickypizzaaa", + "roleType": 0, + "eloRate": 1573, + "eloRank": 134, + "country": "it", + "seasonResult": { + "eloRate": 1573, + "eloRank": 134, + "phasePoint": 0 + } + }, + { + "uuid": "048de51800794a208de7f01652513c32", + "nickname": "q3awreh4yu78i", + "roleType": 1, + "eloRate": 1572, + "eloRank": 136, + "country": "cw", + "seasonResult": { + "eloRate": 1572, + "eloRank": 136, + "phasePoint": 0 + } + }, + { + "uuid": "3a07fee4ce5a4f22b5f2bf207d075e0f", + "nickname": "21mustard", + "roleType": 0, + "eloRate": 1572, + "eloRank": 136, + "country": "ca", + "seasonResult": { + "eloRate": 1572, + "eloRank": 136, + "phasePoint": 0 + } + }, + { + "uuid": "7f93d3e698cd4d648accc2a4d46ce119", + "nickname": "woofdoggo_", + "roleType": 0, + "eloRate": 1572, + "eloRank": 136, + "seasonResult": { + "eloRate": 1572, + "eloRank": 136, + "phasePoint": 0 + }, + "country": null + }, + { + "uuid": "879c8136d42c4222b42f1c090616fa5e", + "nickname": "webwormy", + "roleType": 1, + "eloRate": 1571, + "eloRank": 139, + "country": "ca", + "seasonResult": { + "eloRate": 1571, + "eloRank": 139, + "phasePoint": 0 + } + }, + { + "uuid": "d747ce3625a34c9d902bf7a475449202", + "nickname": "ua0", + "roleType": 0, + "eloRate": 1565, + "eloRank": 140, + "country": "af", + "seasonResult": { + "eloRate": 1565, + "eloRank": 140, + "phasePoint": 0 + } + }, + { + "uuid": "0bc85d154d184dcd8d5cd351459096cc", + "nickname": "yuunihact", + "roleType": 1, + "eloRate": 1563, + "eloRank": 141, + "country": "my", + "seasonResult": { + "eloRate": 1563, + "eloRank": 141, + "phasePoint": 0 + } + }, + { + "uuid": "8b8a76f907e7479fa9032f6eeff70a3f", + "nickname": "IBringSuffering", + "roleType": 0, + "eloRate": 1563, + "eloRank": 141, + "country": null, + "seasonResult": { + "eloRate": 1563, + "eloRank": 141, + "phasePoint": 0 + } + }, + { + "uuid": "23d90bddb2364cd3a25447dce6b99f8c", + "nickname": "sopeii", + "roleType": 1, + "eloRate": 1561, + "eloRank": 143, + "country": "pl", + "seasonResult": { + "eloRate": 1561, + "eloRank": 143, + "phasePoint": 0 + } + }, + { + "uuid": "542eca51763f42ed925b8a68122a99fd", + "nickname": "m3rcuryOvO", + "roleType": 0, + "eloRate": 1560, + "eloRank": 144, + "country": "cn", + "seasonResult": { + "eloRate": 1560, + "eloRank": 144, + "phasePoint": 0 + } + }, + { + "uuid": "560bab25a00a46398a36a09b2ab77f6f", + "nickname": "dxw3950", + "roleType": 0, + "eloRate": 1559, + "eloRank": 145, + "country": "us", + "seasonResult": { + "eloRate": 1559, + "eloRank": 145, + "phasePoint": 0 + } + }, + { + "uuid": "1f88c82f9cc84c9885a5d38dd531f4c6", + "nickname": "RRed", + "roleType": 1, + "eloRate": 1556, + "eloRank": 146, + "country": "us", + "seasonResult": { + "eloRate": 1556, + "eloRank": 146, + "phasePoint": 0 + } + }, + { + "uuid": "c2a087551dcc41548835f29368bd2c15", + "nickname": "WishIWasAGirl", + "roleType": 0, + "eloRate": 1556, + "eloRank": 146, + "country": "de", + "seasonResult": { + "eloRate": 1556, + "eloRank": 146, + "phasePoint": 0 + } + }, + { + "uuid": "09725eb3c2bc4d3788b11f3acd25455a", + "nickname": "Alpha_1644", + "roleType": 1, + "eloRate": 1556, + "eloRank": 146, + "country": "yt", + "seasonResult": { + "eloRate": 1556, + "eloRank": 146, + "phasePoint": 0 + } + }, + { + "uuid": "878a61e32b2b4a30bfab364820bf079c", + "nickname": "Japonk", + "roleType": 1, + "eloRate": 1555, + "eloRank": 149, + "country": "pl", + "seasonResult": { + "eloRate": 1555, + "eloRank": 149, + "phasePoint": 0 + } + }, + { + "uuid": "07cce518e5b2475881a09963f36775d8", + "nickname": "superman_J", + "roleType": 2, + "eloRate": 1552, + "eloRank": 150, + "country": "ca", + "seasonResult": { + "eloRate": 1552, + "eloRank": 150, + "phasePoint": 0 + } + } + ] +} diff --git a/tests/fixtures/live.json b/tests/fixtures/live.json new file mode 100644 index 0000000..c5609e2 --- /dev/null +++ b/tests/fixtures/live.json @@ -0,0 +1,132 @@ +{ + "players": 1181, + "liveMatches": [ + { + "currentTime": 592956, + "players": [ + { + "uuid": "bc80af38933f4ae19b0494681a54422b", + "nickname": "Ancoboyy", + "roleType": 1, + "eloRate": 1890, + "eloRank": 10, + "country": "tr" + } + ], + "data": { + "ba31689fe7d24431bf7997a52efcc21c": { + "liveUrl": null, + "timeline": { + "time": 581528, + "type": "nether.find_fortress" + } + }, + "bc80af38933f4ae19b0494681a54422b": { + "liveUrl": "https://twitch.tv/ancoboyyy", + "timeline": { + "time": 548824, + "type": "story.enter_the_end" + } + } + } + }, + { + "currentTime": 477133, + "players": [ + { + "uuid": "8277a8b59d024e55863efd7e60dd8b39", + "nickname": "Rowan", + "roleType": 0, + "eloRate": 668, + "eloRank": 6332, + "country": null + } + ], + "data": { + "b2df06a1bb96442c90159da75c3f852e": { + "liveUrl": null, + "timeline": { + "time": 433290, + "type": "nether.find_bastion" + } + }, + "8277a8b59d024e55863efd7e60dd8b39": { + "liveUrl": "https://twitch.tv/rowannmc", + "timeline": { + "time": 325087, + "type": "nether.find_bastion" + } + } + } + }, + { + "currentTime": 114391, + "players": [ + { + "uuid": "4eea0516cb0c4c528cefe85448cac786", + "nickname": "blobserr", + "roleType": 1, + "eloRate": 1610, + "eloRank": 89, + "country": "vn" + } + ], + "data": { + "fe6771646c5d43c1b713023fb69c10c6": { + "liveUrl": null, + "timeline": null + }, + "4eea0516cb0c4c528cefe85448cac786": { + "liveUrl": "https://twitch.tv/blobserr", + "timeline": null + } + } + }, + { + "currentTime": 42021, + "players": [ + { + "uuid": "4f3e7905554345698e41f88caa4c088e", + "nickname": "rcolee", + "roleType": 1, + "eloRate": 1602, + "eloRank": 100, + "country": "ca" + } + ], + "data": { + "7d3a6bb9f62645ae80cf40840ca84c50": { + "liveUrl": null, + "timeline": null + }, + "4f3e7905554345698e41f88caa4c088e": { + "liveUrl": "https://twitch.tv/rcolee_", + "timeline": null + } + } + }, + { + "currentTime": 23380, + "players": [ + { + "uuid": "2e12870c08ec4337bc2e8fbf54e79853", + "nickname": "TapL", + "roleType": 3, + "eloRate": 1588, + "eloRank": 117, + "country": "us" + } + ], + "data": { + "2e12870c08ec4337bc2e8fbf54e79853": { + "liveUrl": "https://twitch.tv/tapl", + "timeline": null + }, + "b140bbd0317d4eba89d34288f1b8f0c7": { + "liveUrl": null, + "timeline": null + } + } + } + ] +} diff --git a/tests/fixtures/match_detail.json b/tests/fixtures/match_detail.json new file mode 100644 index 0000000..2ad7f18 --- /dev/null +++ b/tests/fixtures/match_detail.json @@ -0,0 +1,226 @@ +{ + "id": 4816894, + "type": 2, + "seed": { + "id": "m723auzy73cgue8f", + "overworld": "SHIPWRECK", + "nether": "HOUSING", + "endTowers": [ + 97, + 76, + 79, + 100 + ], + "variations": [ + "biome:structure:deep_ocean", + "type:structure:normal", + "biome:structure:deep_ocean", + "type:structure:normal", + "bastion:triple:2", + "biome:bastion:crimson_forest", + "biome:fortress:nether_wastes", + "end_spawn:buried:57", + "end_tower:caged:back" + ] + }, + "category": "ANY", + "gameMode": "default", + "players": [ + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "nickname": "Derapchu", + "roleType": 0, + "eloRate": 1143, + "eloRank": 2186, + "country": "au" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "nickname": "Astraliss_", + "roleType": 0, + "eloRate": 1124, + "eloRank": 1958, + "country": null + } + ], + "spectators": [], + "result": { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 328933 + }, + "forfeited": true, + "decayed": false, + "rank": { + "season": null, + "allTime": null + }, + "vod": [], + "changes": [ + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "change": 21, + "eloRate": 1122 + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "change": -21, + "eloRate": 1145 + } + ], + "completions": [], + "timelines": [ + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 328933, + "type": "projectelo.timeline.forfeit" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 317982, + "type": "husbandry.root" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 315424, + "type": "story.obtain_armor" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 312633, + "type": "nether.obtain_crying_obsidian" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 309910, + "type": "projectelo.timeline.death" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 309846, + "type": "adventure.root" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 259598, + "type": "nether.distract_piglin" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 255099, + "type": "story.form_obsidian" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 250944, + "type": "nether.loot_bastion" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 249052, + "type": "husbandry.root" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 245921, + "type": "nether.distract_piglin" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 233216, + "type": "story.form_obsidian" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 233114, + "type": "nether.find_bastion" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 229293, + "type": "nether.loot_bastion" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 206614, + "type": "nether.find_bastion" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 160478, + "type": "story.enter_the_nether" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 160269, + "type": "nether.root" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 149922, + "type": "nether.root" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 149914, + "type": "story.enter_the_nether" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 145596, + "type": "story.lava_bucket" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 137758, + "type": "story.lava_bucket" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 83698, + "type": "story.mine_stone" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 67706, + "type": "story.mine_stone" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 63892, + "type": "story.iron_tools" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 54208, + "type": "story.root" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 48463, + "type": "story.iron_tools" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 39118, + "type": "story.root" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "time": 29474, + "type": "story.smelt_iron" + }, + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 16656, + "type": "story.smelt_iron" + } + ], + "beginner": false, + "botSource": null, + "season": 10, + "date": 1767945386, + "seedType": "SHIPWRECK", + "bastionType": "HOUSING", + "tag": null, + "replayExist": false +} diff --git a/tests/fixtures/matches.json b/tests/fixtures/matches.json new file mode 100644 index 0000000..d0eee88 --- /dev/null +++ b/tests/fixtures/matches.json @@ -0,0 +1,370 @@ +[ + { + "id": 4816894, + "type": 2, + "seed": { + "id": "m723auzy73cgue8f", + "overworld": "SHIPWRECK", + "nether": "HOUSING", + "endTowers": [ + 97, + 76, + 79, + 100 + ], + "variations": [ + "biome:structure:deep_ocean", + "type:structure:normal", + "biome:structure:deep_ocean", + "type:structure:normal", + "bastion:triple:2", + "biome:bastion:crimson_forest", + "biome:fortress:nether_wastes", + "end_spawn:buried:57", + "end_tower:caged:back" + ] + }, + "category": "ANY", + "gameMode": "default", + "players": [ + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "nickname": "Derapchu", + "roleType": 0, + "eloRate": 1143, + "eloRank": 2186, + "country": "au" + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "nickname": "Astraliss_", + "roleType": 0, + "eloRate": 1124, + "eloRank": 1958, + "country": null + } + ], + "spectators": [], + "result": { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "time": 328933 + }, + "forfeited": true, + "decayed": false, + "rank": { + "season": null, + "allTime": null + }, + "vod": [], + "changes": [ + { + "uuid": "68ec42a99c3d4538afe574cc9d8e06b6", + "change": 21, + "eloRate": 1122 + }, + { + "uuid": "e42b35a5c3da46f080c460849845af40", + "change": -21, + "eloRate": 1145 + } + ], + "beginner": false, + "botSource": null, + "season": 10, + "date": 1767945386, + "seedType": "SHIPWRECK", + "bastionType": "HOUSING", + "tag": null + }, + { + "id": 4816893, + "type": 2, + "seed": { + "id": "m72341ka2bm0cgmc", + "overworld": "DESERT_TEMPLE", + "nether": "STABLES", + "endTowers": [ + 79, + 91, + 103, + 88 + ], + "variations": [ + "bastion:good_gap:2", + "bastion:single:1", + "bastion:small_single:2", + "biome:bastion:crimson_forest", + "biome:fortress:warped_forest", + "end_tower:caged:front" + ] + }, + "category": "ANY", + "gameMode": "default", + "players": [ + { + "uuid": "584d03d5c4e847cd9c6f2a271e2f79c2", + "nickname": "Its_CircleZ", + "roleType": 1, + "eloRate": 996, + "eloRank": 3407, + "country": null + }, + { + "uuid": "eb33b5f8f29f41a6983a58d820e022b0", + "nickname": "hodaga", + "roleType": 0, + "eloRate": 1099, + "eloRank": 2654, + "country": null + } + ], + "spectators": [], + "result": { + "uuid": "eb33b5f8f29f41a6983a58d820e022b0", + "time": 1133459 + }, + "forfeited": false, + "decayed": false, + "rank": { + "season": null, + "allTime": null + }, + "vod": [], + "changes": [ + { + "uuid": "eb33b5f8f29f41a6983a58d820e022b0", + "change": 17, + "eloRate": 1082 + }, + { + "uuid": "584d03d5c4e847cd9c6f2a271e2f79c2", + "change": -17, + "eloRate": 1013 + } + ], + "beginner": false, + "botSource": null, + "season": 10, + "date": 1767945381, + "seedType": "DESERT_TEMPLE", + "bastionType": "STABLES", + "tag": null + }, + { + "id": 4816890, + "type": 2, + "seed": { + "id": "m722uwdjacbs8peu", + "overworld": "VILLAGE", + "nether": "TREASURE", + "endTowers": [ + 79, + 91, + 100, + 76 + ], + "variations": [ + "biome:structure:desert", + "biome:structure:desert", + "biome:bastion:nether_wastes", + "biome:fortress:crimson_forest", + "end_tower:caged:front" + ] + }, + "category": "ANY", + "gameMode": "default", + "players": [ + { + "uuid": "9caf8a76565a42149b35e8e0bc4a4932", + "nickname": "a_selfish_guy", + "roleType": 0, + "eloRate": 1299, + "eloRank": 702, + "country": null + }, + { + "uuid": "7279a3e7a92d4074bd096cb249cc4fb4", + "nickname": "Azaleacolon3", + "roleType": 1, + "eloRate": 1328, + "eloRank": 753, + "country": "us" + } + ], + "spectators": [], + "result": { + "uuid": "7279a3e7a92d4074bd096cb249cc4fb4", + "time": 811748 + }, + "forfeited": false, + "decayed": false, + "rank": { + "season": null, + "allTime": null + }, + "vod": [], + "changes": [ + { + "uuid": "7279a3e7a92d4074bd096cb249cc4fb4", + "change": 20, + "eloRate": 1308 + }, + { + "uuid": "9caf8a76565a42149b35e8e0bc4a4932", + "change": -20, + "eloRate": 1319 + } + ], + "beginner": false, + "botSource": null, + "season": 10, + "date": 1767945372, + "seedType": "VILLAGE", + "bastionType": "TREASURE", + "tag": null + }, + { + "id": 4816888, + "type": 2, + "seed": { + "id": "m722zjwmcmugaojm", + "overworld": "DESERT_TEMPLE", + "nether": "HOUSING", + "endTowers": [ + 103, + 100, + 82, + 76 + ], + "variations": [ + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_tower:caged:back" + ] + }, + "category": "ANY", + "gameMode": "default", + "players": [ + { + "uuid": "372d0bf2d12a405fbb28ada332ea1b2d", + "nickname": "LagArmy", + "roleType": 0, + "eloRate": 781, + "eloRank": 5378, + "country": "ca" + }, + { + "uuid": "150b6ac52d9a49c4abb1c888822a1afb", + "nickname": "FrankBots", + "roleType": 0, + "eloRate": 736, + "eloRank": 5424, + "country": null + } + ], + "spectators": [], + "result": { + "uuid": "372d0bf2d12a405fbb28ada332ea1b2d", + "time": 1619541 + }, + "forfeited": false, + "decayed": false, + "rank": { + "season": null, + "allTime": null + }, + "vod": [], + "changes": [ + { + "uuid": "372d0bf2d12a405fbb28ada332ea1b2d", + "change": 20, + "eloRate": 761 + }, + { + "uuid": "150b6ac52d9a49c4abb1c888822a1afb", + "change": -20, + "eloRate": 756 + } + ], + "beginner": false, + "botSource": null, + "season": 10, + "date": 1767945370, + "seedType": "DESERT_TEMPLE", + "bastionType": "HOUSING", + "tag": null + }, + { + "id": 4816887, + "type": 2, + "seed": { + "id": "m723e92fa45vv3ow", + "overworld": "VILLAGE", + "nether": "TREASURE", + "endTowers": [ + 100, + 91, + 103, + 88 + ], + "variations": [ + "biome:structure:plains", + "biome:structure:plains", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes" + ] + }, + "category": "ANY", + "gameMode": "default", + "players": [ + { + "uuid": "e7c02a7516b14ae48bda1de5cbb1a2bf", + "nickname": "TheGoldnPig", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": null + }, + { + "uuid": "0c76c67013284b0d8d634e0df98b2c31", + "nickname": "Joeletyc", + "roleType": 1, + "eloRate": 598, + "eloRank": 8041, + "country": "mx" + } + ], + "spectators": [], + "result": { + "uuid": "0c76c67013284b0d8d634e0df98b2c31", + "time": 1735693 + }, + "forfeited": false, + "decayed": false, + "rank": { + "season": null, + "allTime": null + }, + "vod": [], + "changes": [ + { + "uuid": "0c76c67013284b0d8d634e0df98b2c31", + "change": 20, + "eloRate": 578 + }, + { + "uuid": "e7c02a7516b14ae48bda1de5cbb1a2bf", + "change": null, + "eloRate": null + } + ], + "beginner": false, + "botSource": null, + "season": 10, + "date": 1767945369, + "seedType": "VILLAGE", + "bastionType": "TREASURE", + "tag": null + } +] diff --git a/tests/fixtures/phase_leaderboard.json b/tests/fixtures/phase_leaderboard.json new file mode 100644 index 0000000..2835a0f --- /dev/null +++ b/tests/fixtures/phase_leaderboard.json @@ -0,0 +1,8 @@ +{ + "phase": { + "endsAt": 1769990400, + "number": 1, + "season": 10 + }, + "users": [] +} diff --git a/tests/fixtures/record_leaderboard.json b/tests/fixtures/record_leaderboard.json new file mode 100644 index 0000000..b8c51e0 --- /dev/null +++ b/tests/fixtures/record_leaderboard.json @@ -0,0 +1,3631 @@ +[ + { + "rank": 1, + "id": 3489002, + "season": 9, + "date": 1761876457, + "time": 347271, + "user": { + "uuid": "a54e3bc4c6354b07a236b81efbcfe791", + "nickname": "Infume", + "roleType": 2, + "eloRate": 2152, + "eloRank": 1, + "country": "us" + }, + "seed": { + "id": "m72326d0x51kz9m0", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 94, + 82, + 85, + 79 + ], + "variations": [ + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:beach", + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:beach", + "bastion:triple:2", + "biome:bastion:soul_sand_valley", + "biome:fortress:soul_sand_valley", + "end_spawn:buried:57", + "end_tower:caged:front_center", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 2, + "id": 2199947, + "season": 8, + "date": 1748204915, + "time": 364035, + "user": { + "uuid": "5fe66e8b389f4dc384222e8cc09485f0", + "nickname": "sanjinhu", + "roleType": 0, + "eloRate": 1742, + "eloRank": 29, + "country": "br" + }, + "seed": { + "id": "m72394zfrilfvz41", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 88, + 94, + 82, + 85 + ], + "variations": [ + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:forest", + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:forest", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:nether_wastes", + "biome:fortress:warped_forest", + "end_spawn:buried:46", + "end_tower:caged:back" + ] + } + }, + { + "rank": 3, + "id": 2972056, + "season": 9, + "date": 1757378341, + "time": 366383, + "user": { + "uuid": "3b01d4b4fef14f178b75f05c04dd34ef", + "nickname": "BeefSalad", + "roleType": 3, + "eloRate": 1952, + "eloRank": 7, + "country": "gb" + }, + "seed": { + "id": "m722umm3426eg11m", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 79, + 85, + 100, + 82 + ], + "variations": [ + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:plains", + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:plains", + "bastion:triple:1", + "biome:bastion:nether_wastes", + "biome:fortress:soul_sand_valley", + "end_tower:caged:front", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 4, + "id": 3943440, + "season": 9, + "date": 1764911051, + "time": 368016, + "user": { + "uuid": "a54e3bc4c6354b07a236b81efbcfe791", + "nickname": "Infume", + "roleType": 2, + "eloRate": 2152, + "eloRank": 1, + "country": "us" + }, + "seed": { + "id": "m722w4rb1k6w2dj4", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 97, + 88, + 82, + 76 + ], + "variations": [ + "type:structure:lava", + "chest:structure:egap", + "biome:structure:forest", + "type:structure:lava", + "chest:structure:egap", + "biome:structure:forest", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_spawn:buried:57", + "end_tower:caged:back" + ] + } + }, + { + "rank": 5, + "id": 3732338, + "season": 9, + "date": 1763537785, + "time": 372000, + "user": { + "uuid": "4aed1e5e8f5c44e2bc0666e0c03781af", + "nickname": "nEmerald", + "roleType": 2, + "eloRate": 1697, + "eloRank": 38, + "country": "us" + }, + "seed": { + "id": "m722x08fooa45q9h", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 94, + 97, + 88, + 103 + ], + "variations": [ + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:forest", + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:forest", + "biome:bastion:soul_sand_valley", + "biome:fortress:soul_sand_valley" + ] + } + }, + { + "rank": 6, + "id": 4767048, + "season": 10, + "date": 1767824990, + "time": 374013, + "user": { + "uuid": "3b01d4b4fef14f178b75f05c04dd34ef", + "nickname": "BeefSalad", + "roleType": 3, + "eloRate": 1952, + "eloRank": 7, + "country": "gb" + }, + "seed": { + "id": "m723629wmniu69ib", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 97, + 85, + 103, + 100 + ], + "variations": [ + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:plains", + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:plains", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_spawn:buried:53" + ] + } + }, + { + "rank": 7, + "id": 3115565, + "season": 9, + "date": 1758766011, + "time": 374515, + "user": { + "uuid": "3b01d4b4fef14f178b75f05c04dd34ef", + "nickname": "BeefSalad", + "roleType": 3, + "eloRate": 1952, + "eloRank": 7, + "country": "gb" + }, + "seed": { + "id": "m722ukgh6gduv8ix", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 100, + 79, + 88, + 76 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "chest:structure:looting_sword", + "biome:structure:beach", + "type:structure:lava", + "chest:structure:golden_carrot", + "chest:structure:looting_sword", + "biome:structure:beach", + "bastion:triple:2", + "biome:bastion:crimson_forest", + "biome:fortress:crimson_forest", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 8, + "id": 2802817, + "season": 8, + "date": 1755728224, + "time": 378719, + "user": { + "uuid": "2fe70934e7be458dba747c4ac830391c", + "nickname": "nhb_", + "roleType": 2, + "eloRate": 1591, + "eloRank": 113, + "country": "cf" + }, + "seed": { + "id": "m723cd31mkynwrja", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 97, + 100, + 79, + 76 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:forest", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:forest", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:warped_forest", + "end_tower:caged:back" + ] + } + }, + { + "rank": 9, + "id": 4517032, + "season": 9, + "date": 1767235809, + "time": 378784, + "user": { + "uuid": "388533d5a2ad4b349a31db4738670a4b", + "nickname": "v_strid", + "roleType": 1, + "eloRate": 1798, + "eloRank": 17, + "country": "se" + }, + "seed": { + "id": "m723c41r5406zjdq", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 88, + 91, + 79, + 76 + ], + "variations": [ + "type:structure:completable", + "chest:structure:golden_carrot", + "chest:structure:looting_sword", + "biome:structure:sunflower_plains", + "type:structure:completable", + "chest:structure:golden_carrot", + "chest:structure:looting_sword", + "biome:structure:sunflower_plains", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:nether_wastes", + "biome:fortress:crimson_forest", + "end_spawn:buried:57", + "end_tower:caged:back" + ] + } + }, + { + "rank": 10, + "id": 4529472, + "season": 9, + "date": 1767276233, + "time": 378785, + "user": { + "uuid": "ac601ce7376f49cea7ce14cd577dac85", + "nickname": "BlazeMind", + "roleType": 3, + "eloRate": 2061, + "eloRank": 4, + "country": "au" + }, + "seed": { + "id": "m7236ytzhq1hpju6", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 85, + 94, + 91, + 97 + ], + "variations": [ + "type:structure:lava", + "chest:structure:egap", + "biome:structure:plains", + "type:structure:lava", + "chest:structure:egap", + "biome:structure:plains", + "biome:bastion:crimson_forest", + "biome:fortress:crimson_forest" + ] + } + }, + { + "rank": 11, + "id": 2171858, + "season": 8, + "date": 1747854149, + "time": 379005, + "user": { + "uuid": "3b01d4b4fef14f178b75f05c04dd34ef", + "nickname": "BeefSalad", + "roleType": 3, + "eloRate": 1952, + "eloRank": 7, + "country": "gb" + }, + "seed": { + "id": "m72360r8a456evcs", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 97, + 100, + 88, + 103 + ], + "variations": [ + "type:structure:completable", + "chest:structure:golden_carrot", + "biome:structure:forest", + "type:structure:completable", + "chest:structure:golden_carrot", + "biome:structure:forest", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes" + ] + } + }, + { + "rank": 12, + "id": 2353416, + "season": 8, + "date": 1750191025, + "time": 379698, + "user": { + "uuid": "048de51800794a208de7f01652513c32", + "nickname": "q3awreh4yu78i", + "roleType": 1, + "eloRate": 1572, + "eloRank": 136, + "country": "cw" + }, + "seed": { + "id": "m722swow8qs9rnxy", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 100, + 94, + 91, + 76 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "chest:structure:looting_sword", + "biome:structure:plains", + "type:structure:lava", + "chest:structure:golden_carrot", + "chest:structure:looting_sword", + "biome:structure:plains", + "bastion:triple:1", + "biome:bastion:nether_wastes", + "biome:fortress:soul_sand_valley" + ] + } + }, + { + "rank": 13, + "id": 652059, + "season": 3, + "date": 1703187393, + "time": 380341, + "user": { + "uuid": "7665f76f431b41c6b321bea16aff913b", + "nickname": "lowk3y_", + "roleType": 3, + "eloRate": 1777, + "eloRank": 20, + "country": null + }, + "seed": { + "id": null, + "overworld": "RUINED_PORTAL", + "nether": null, + "endTowers": null, + "variations": [] + } + }, + { + "rank": 14, + "id": 2994579, + "season": 9, + "date": 1757621302, + "time": 383814, + "user": { + "uuid": "0b164a03002048d3955715422179eedf", + "nickname": "KenanKardes", + "roleType": 0, + "eloRate": 1802, + "eloRank": 16, + "country": "az" + }, + "seed": { + "id": "m7235ttwlgwnobqc", + "overworld": "VILLAGE", + "nether": "HOUSING", + "endTowers": [ + 94, + 103, + 76, + 79 + ], + "variations": [ + "chest:structure:obsidian", + "biome:structure:plains", + "chest:structure:obsidian", + "biome:structure:plains", + "bastion:triple:2", + "biome:bastion:soul_sand_valley", + "biome:fortress:nether_wastes", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 15, + "id": 3741278, + "season": 9, + "date": 1763602665, + "time": 383821, + "user": { + "uuid": "a54e3bc4c6354b07a236b81efbcfe791", + "nickname": "Infume", + "roleType": 2, + "eloRate": 2152, + "eloRank": 1, + "country": "us" + }, + "seed": { + "id": "m72398ug6odia06f", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 79, + 88, + 82, + 91 + ], + "variations": [ + "type:structure:completable", + "chest:structure:egap", + "chest:structure:looting_sword", + "biome:structure:plains", + "type:structure:completable", + "chest:structure:egap", + "chest:structure:looting_sword", + "biome:structure:plains", + "bastion:single:2", + "biome:bastion:nether_wastes", + "biome:fortress:basalt_deltas", + "end_spawn:buried:50", + "end_tower:caged:front", + "end_tower:caged:back" + ] + } + }, + { + "rank": 16, + "id": 3035422, + "season": 9, + "date": 1758037321, + "time": 384643, + "user": { + "uuid": "cc432b2626a44ae1836a50244adbf468", + "nickname": "XSpocony_MaciekX", + "roleType": 1, + "eloRate": 1981, + "eloRank": 6, + "country": "pl" + }, + "seed": { + "id": "m722x0q2kii2y0gy", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 82, + 97, + 85, + 88 + ], + "variations": [ + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:forest", + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:forest", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:crimson_forest", + "biome:fortress:crimson_forest", + "end_spawn:buried:50", + "end_tower:caged:front" + ] + } + }, + { + "rank": 17, + "id": 2061971, + "season": 8, + "date": 1746500453, + "time": 386801, + "user": { + "uuid": "7665f76f431b41c6b321bea16aff913b", + "nickname": "lowk3y_", + "roleType": 3, + "eloRate": 1777, + "eloRank": 20, + "country": null + }, + "seed": { + "id": "m7238ji7pf7zpmsa", + "overworld": "DESERT_TEMPLE", + "nether": "BRIDGE", + "endTowers": [ + 79, + 91, + 85, + 100 + ], + "variations": [ + "chest:structure:egap", + "chest:structure:egap", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_tower:caged:front" + ] + } + }, + { + "rank": 18, + "id": 3469262, + "season": 9, + "date": 1761689007, + "time": 388207, + "user": { + "uuid": "253b53d832ab4bafb5ee0308d5164ccf", + "nickname": "Aquacorde", + "roleType": 3, + "eloRate": 1794, + "eloRank": 19, + "country": "ca" + }, + "seed": { + "id": "m723dcm75kdd7d24", + "overworld": "BURIED_TREASURE", + "nether": "BRIDGE", + "endTowers": [ + 79, + 76, + 94, + 91 + ], + "variations": [ + "biome:structure:deep_ocean", + "biome:structure:deep_ocean", + "bastion:triple:2", + "biome:bastion:soul_sand_valley", + "biome:fortress:basalt_deltas", + "end_tower:caged:front" + ] + } + }, + { + "rank": 19, + "id": 4184249, + "season": 9, + "date": 1766107561, + "time": 389666, + "user": { + "uuid": "2ef2bfed3d084649b56290328970ace9", + "nickname": "nahhann", + "roleType": 1, + "eloRate": 1903, + "eloRank": 9, + "country": "us" + }, + "seed": { + "id": "m722wqv6v6esqqh6", + "overworld": "RUINED_PORTAL", + "nether": "STABLES", + "endTowers": [ + 100, + 82, + 91, + 94 + ], + "variations": [ + "type:structure:completable", + "chest:structure:egap", + "biome:structure:forest", + "type:structure:completable", + "chest:structure:egap", + "biome:structure:forest", + "bastion:good_gap:2", + "bastion:triple:2", + "bastion:single:1", + "biome:bastion:crimson_forest", + "biome:fortress:nether_wastes", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 20, + "id": 4621610, + "season": 10, + "date": 1767485704, + "time": 389995, + "user": { + "uuid": "cc432b2626a44ae1836a50244adbf468", + "nickname": "XSpocony_MaciekX", + "roleType": 1, + "eloRate": 1981, + "eloRank": 6, + "country": "pl" + }, + "seed": { + "id": "m7237qrwo0n718iu", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 100, + 94, + 103, + 97 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:beach", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:beach", + "bastion:triple:2", + "biome:bastion:crimson_forest", + "biome:fortress:crimson_forest" + ] + } + }, + { + "rank": 21, + "id": 3678339, + "season": 9, + "date": 1763175151, + "time": 390762, + "user": { + "uuid": "25349f93cf194f3baeee93d024eccc21", + "nickname": "retropog", + "roleType": 0, + "eloRate": 1655, + "eloRank": 55, + "country": "au" + }, + "seed": { + "id": "m723eaeiylogrikh", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 79, + 76, + 85, + 103 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:plains", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:plains", + "bastion:triple:2", + "biome:bastion:crimson_forest", + "biome:fortress:nether_wastes", + "end_tower:caged:front" + ] + } + }, + { + "rank": 22, + "id": 3289525, + "season": 9, + "date": 1760219528, + "time": 390818, + "user": { + "uuid": "388533d5a2ad4b349a31db4738670a4b", + "nickname": "v_strid", + "roleType": 1, + "eloRate": 1798, + "eloRank": 17, + "country": "se" + }, + "seed": { + "id": "m7234rbb1lp5wvfp", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 85, + 100, + 91, + 76 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:forest", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:forest", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:nether_wastes", + "biome:fortress:basalt_deltas" + ] + } + }, + { + "rank": 23, + "id": 4619138, + "season": 10, + "date": 1767481143, + "time": 390896, + "user": { + "uuid": "bc80af38933f4ae19b0494681a54422b", + "nickname": "Ancoboyy", + "roleType": 1, + "eloRate": 1890, + "eloRank": 10, + "country": "tr" + }, + "seed": { + "id": "m722ypmjzadm7v93", + "overworld": "DESERT_TEMPLE", + "nether": "BRIDGE", + "endTowers": [ + 82, + 103, + 76, + 97 + ], + "variations": [ + "chest:structure:diamond", + "chest:structure:diamond", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_tower:caged:front" + ] + } + }, + { + "rank": 24, + "id": 1634353, + "season": 7, + "date": 1737997449, + "time": 392682, + "user": { + "uuid": "dd34e44dfe5d4e05923d876b9c34ca5f", + "nickname": "Waluyoshi", + "roleType": 1, + "eloRate": 1684, + "eloRank": 42, + "country": "sx" + }, + "seed": { + "id": null, + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": null, + "variations": [] + } + }, + { + "rank": 25, + "id": 2759694, + "season": 8, + "date": 1755305860, + "time": 392826, + "user": { + "uuid": "2ef2bfed3d084649b56290328970ace9", + "nickname": "nahhann", + "roleType": 1, + "eloRate": 1903, + "eloRank": 9, + "country": "us" + }, + "seed": { + "id": "m7235sicxi4crv2g", + "overworld": "SHIPWRECK", + "nether": "BRIDGE", + "endTowers": [ + 85, + 82, + 94, + 100 + ], + "variations": [ + "chest:structure:carrot", + "biome:structure:deep_ocean", + "type:structure:normal", + "chest:structure:carrot", + "biome:structure:deep_ocean", + "type:structure:normal", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:crimson_forest", + "biome:fortress:nether_wastes", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 26, + "id": 4380446, + "season": 9, + "date": 1766862113, + "time": 393647, + "user": { + "uuid": "cc432b2626a44ae1836a50244adbf468", + "nickname": "XSpocony_MaciekX", + "roleType": 1, + "eloRate": 1981, + "eloRank": 6, + "country": "pl" + }, + "seed": { + "id": "m723bfu0l0aa74qd", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 100, + 79, + 88, + 91 + ], + "variations": [ + "type:structure:completable", + "chest:structure:golden_carrot", + "biome:structure:plains", + "type:structure:completable", + "chest:structure:golden_carrot", + "biome:structure:plains", + "biome:bastion:warped_forest", + "biome:fortress:crimson_forest", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 27, + "id": 4733053, + "season": 10, + "date": 1767746088, + "time": 394194, + "user": { + "uuid": "ba31689fe7d24431bf7997a52efcc21c", + "nickname": "meebie", + "roleType": 1, + "eloRate": 1852, + "eloRank": 12, + "country": "cf" + }, + "seed": { + "id": "m723d6fex383ymb0", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 85, + 76, + 100, + 103 + ], + "variations": [ + "type:structure:completable", + "biome:structure:river", + "type:structure:completable", + "biome:structure:river", + "bastion:triple:1", + "biome:bastion:soul_sand_valley", + "biome:fortress:basalt_deltas" + ] + } + }, + { + "rank": 28, + "id": 1458876, + "season": 6, + "date": 1733577948, + "time": 395129, + "user": { + "uuid": "7c92678742eb4e819f3122017697ae3d", + "nickname": "hackingnoises", + "roleType": 3, + "eloRate": null, + "eloRank": null, + "country": "hk" + }, + "seed": { + "id": null, + "overworld": "BURIED_TREASURE", + "nether": "TREASURE", + "endTowers": null, + "variations": [] + } + }, + { + "rank": 29, + "id": 3510422, + "season": 9, + "date": 1762031983, + "time": 395245, + "user": { + "uuid": "4cf401d7b9474756b06a653867d22fca", + "nickname": "BadGamer", + "roleType": 1, + "eloRate": 1833, + "eloRank": 13, + "country": "ca" + }, + "seed": { + "id": "m722zd58e4gizoo2", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 79, + 85, + 94, + 82 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:forest", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:forest", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:crimson_forest", + "end_tower:caged:front", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 30, + "id": 3518502, + "season": 9, + "date": 1762087019, + "time": 395895, + "user": { + "uuid": "553414a2c89b4d6b8c0ba5bd89284508", + "nickname": "ulsah1n", + "roleType": 0, + "eloRate": 1676, + "eloRank": 46, + "country": "tr" + }, + "seed": { + "id": "m722wnm2umffe0de", + "overworld": "RUINED_PORTAL", + "nether": "STABLES", + "endTowers": [ + 85, + 82, + 79, + 88 + ], + "variations": [ + "type:structure:completable", + "biome:structure:beach", + "type:structure:completable", + "biome:structure:beach", + "bastion:good_gap:1", + "bastion:triple:2", + "bastion:small_single:1", + "biome:bastion:nether_wastes", + "biome:fortress:warped_forest", + "end_tower:caged:front_center", + "end_tower:caged:back" + ] + } + }, + { + "rank": 31, + "id": 4576693, + "season": 10, + "date": 1767388221, + "time": 396273, + "user": { + "uuid": "2988fcfbc6b141a497faa915e13b6592", + "nickname": "AutomattPLUS", + "roleType": 3, + "eloRate": 1747, + "eloRank": 27, + "country": "pl" + }, + "seed": { + "id": "m722uwxzo2nj5lsh", + "overworld": "BURIED_TREASURE", + "nether": "BRIDGE", + "endTowers": [ + 85, + 97, + 76, + 88 + ], + "variations": [ + "biome:structure:deep_cold_ocean", + "biome:structure:deep_cold_ocean", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:crimson_forest", + "biome:fortress:soul_sand_valley" + ] + } + }, + { + "rank": 32, + "id": 4680426, + "season": 10, + "date": 1767626895, + "time": 396670, + "user": { + "uuid": "78a8ec9f99d34371b73decd2a78ff9b0", + "nickname": "TUDORULE", + "roleType": 1, + "eloRate": 1818, + "eloRank": 14, + "country": "ro" + }, + "seed": { + "id": "m72366hne5p9qesu", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 88, + 76, + 85, + 94 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:forest", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:forest", + "biome:bastion:warped_forest", + "biome:fortress:crimson_forest" + ] + } + }, + { + "rank": 33, + "id": 2988737, + "season": 9, + "date": 1757557995, + "time": 396692, + "user": { + "uuid": "3c8757790ab0400b8b9e3936e0dd535b", + "nickname": "doogile", + "roleType": 3, + "eloRate": 1743, + "eloRank": 28, + "country": "us" + }, + "seed": { + "id": "m722wb3zot3919bj", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 88, + 100, + 79, + 91 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:plains", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:plains", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:warped_forest", + "end_tower:caged:back" + ] + } + }, + { + "rank": 34, + "id": 3203375, + "season": 9, + "date": 1759514966, + "time": 396947, + "user": { + "uuid": "cc432b2626a44ae1836a50244adbf468", + "nickname": "XSpocony_MaciekX", + "roleType": 1, + "eloRate": 1981, + "eloRank": 6, + "country": "pl" + }, + "seed": { + "id": "m722u91fgtp4tlpp", + "overworld": "RUINED_PORTAL", + "nether": "STABLES", + "endTowers": [ + 97, + 100, + 94, + 88 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "chest:structure:looting_sword", + "biome:structure:beach", + "type:structure:lava", + "chest:structure:golden_carrot", + "chest:structure:looting_sword", + "biome:structure:beach", + "bastion:good_gap:1", + "bastion:triple:2", + "bastion:small_single:1", + "biome:bastion:crimson_forest", + "biome:fortress:nether_wastes" + ] + } + }, + { + "rank": 35, + "id": 2216017, + "season": 8, + "date": 1748412370, + "time": 397415, + "user": { + "uuid": "25349f93cf194f3baeee93d024eccc21", + "nickname": "retropog", + "roleType": 0, + "eloRate": 1655, + "eloRank": 55, + "country": "au" + }, + "seed": { + "id": "m722t4yjps3uj83t", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 82, + 85, + 97, + 76 + ], + "variations": [ + "type:structure:completable", + "chest:structure:golden_carrot", + "biome:structure:plains", + "type:structure:completable", + "chest:structure:golden_carrot", + "biome:structure:plains", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:soul_sand_valley", + "biome:fortress:nether_wastes", + "end_tower:caged:front" + ] + } + }, + { + "rank": 36, + "id": 2994169, + "season": 9, + "date": 1757618131, + "time": 397521, + "user": { + "uuid": "8826e1e6d21b46ecbc5d5246b836f36a", + "nickname": "4antoo", + "roleType": 0, + "eloRate": 1664, + "eloRank": 50, + "country": "it" + }, + "seed": { + "id": "m7237rw2k07hcwbx", + "overworld": "BURIED_TREASURE", + "nether": "STABLES", + "endTowers": [ + 85, + 88, + 94, + 82 + ], + "variations": [ + "biome:structure:deep_ocean", + "biome:structure:deep_ocean", + "bastion:good_gap:2", + "bastion:triple:2", + "bastion:single:1", + "biome:bastion:soul_sand_valley", + "biome:fortress:crimson_forest", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 37, + "id": 2914014, + "season": 9, + "date": 1756775164, + "time": 397869, + "user": { + "uuid": "a54e3bc4c6354b07a236b81efbcfe791", + "nickname": "Infume", + "roleType": 2, + "eloRate": 2152, + "eloRank": 1, + "country": "us" + }, + "seed": { + "id": "m7233yqgtck54dlv", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 76, + 94, + 97, + 85 + ], + "variations": [ + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:beach", + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:beach", + "bastion:triple:1", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes" + ] + } + }, + { + "rank": 38, + "id": 3324455, + "season": 9, + "date": 1760498545, + "time": 398065, + "user": { + "uuid": "3c8757790ab0400b8b9e3936e0dd535b", + "nickname": "doogile", + "roleType": 3, + "eloRate": 1743, + "eloRank": 28, + "country": "us" + }, + "seed": { + "id": "m723bxl3kssgpfph", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 91, + 100, + 79, + 94 + ], + "variations": [ + "type:structure:completable", + "biome:structure:forest", + "type:structure:completable", + "biome:structure:forest", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:warped_forest", + "biome:fortress:nether_wastes", + "end_tower:caged:back" + ] + } + }, + { + "rank": 39, + "id": 3484009, + "season": 9, + "date": 1761841688, + "time": 398090, + "user": { + "uuid": "c670041ed84c480cab4a6ee904905b5f", + "nickname": "paplerr", + "roleType": 2, + "eloRate": null, + "eloRank": null, + "country": "fj" + }, + "seed": { + "id": "m72326kxi6e2825r", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 76, + 79, + 91, + 103 + ], + "variations": [ + "type:structure:completable", + "biome:structure:forest", + "type:structure:completable", + "biome:structure:forest", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:soul_sand_valley", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 40, + "id": 4107616, + "season": 9, + "date": 1765725278, + "time": 398123, + "user": { + "uuid": "048de51800794a208de7f01652513c32", + "nickname": "q3awreh4yu78i", + "roleType": 1, + "eloRate": 1572, + "eloRank": 136, + "country": "cw" + }, + "seed": { + "id": "m723a79dvgoqr56b", + "overworld": "RUINED_PORTAL", + "nether": "STABLES", + "endTowers": [ + 94, + 103, + 82, + 91 + ], + "variations": [ + "type:structure:lava", + "biome:structure:forest", + "type:structure:lava", + "biome:structure:forest", + "bastion:good_gap:1", + "bastion:triple:1", + "bastion:single:1", + "bastion:small_single:1", + "biome:bastion:nether_wastes", + "biome:fortress:soul_sand_valley", + "end_spawn:buried:56", + "end_tower:caged:back" + ] + } + }, + { + "rank": 41, + "id": 3237388, + "season": 9, + "date": 1759782417, + "time": 398460, + "user": { + "uuid": "3c8757790ab0400b8b9e3936e0dd535b", + "nickname": "doogile", + "roleType": 3, + "eloRate": 1743, + "eloRank": 28, + "country": "us" + }, + "seed": { + "id": "m7231480i8k62375", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 79, + 103, + 88, + 82 + ], + "variations": [ + "type:structure:completable", + "biome:structure:plains", + "type:structure:completable", + "biome:structure:plains", + "bastion:triple:1", + "biome:bastion:crimson_forest", + "biome:fortress:crimson_forest", + "end_spawn:buried:57", + "end_tower:caged:front", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 42, + "id": 2358357, + "season": 8, + "date": 1750260465, + "time": 398485, + "user": { + "uuid": "553414a2c89b4d6b8c0ba5bd89284508", + "nickname": "ulsah1n", + "roleType": 0, + "eloRate": 1676, + "eloRank": 46, + "country": "tr" + }, + "seed": { + "id": "m722w30za8rhv1kl", + "overworld": "BURIED_TREASURE", + "nether": "TREASURE", + "endTowers": [ + 79, + 94, + 100, + 97 + ], + "variations": [ + "biome:structure:deep_ocean", + "biome:structure:deep_ocean", + "biome:bastion:nether_wastes", + "biome:fortress:crimson_forest", + "end_tower:caged:front" + ] + } + }, + { + "rank": 43, + "id": 3815634, + "season": 9, + "date": 1764121833, + "time": 398873, + "user": { + "uuid": "a54e3bc4c6354b07a236b81efbcfe791", + "nickname": "Infume", + "roleType": 2, + "eloRate": 2152, + "eloRank": 1, + "country": "us" + }, + "seed": { + "id": "m72393lpqxqb0ncu", + "overworld": "SHIPWRECK", + "nether": "BRIDGE", + "endTowers": [ + 94, + 97, + 76, + 91 + ], + "variations": [ + "chest:structure:carrot", + "biome:structure:deep_cold_ocean", + "type:structure:full", + "chest:structure:carrot", + "biome:structure:deep_cold_ocean", + "type:structure:full", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:warped_forest", + "biome:fortress:warped_forest", + "end_spawn:buried:56" + ] + } + }, + { + "rank": 44, + "id": 944050, + "season": 5, + "date": 1715133418, + "time": 399012, + "user": { + "uuid": "410e5776b03a424d8740557bac2d9014", + "nickname": "JoomzMonkey", + "roleType": 0, + "eloRate": 1715, + "eloRank": 32, + "country": "us" + }, + "seed": { + "id": null, + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": null, + "variations": [] + } + }, + { + "rank": 45, + "id": 4251284, + "season": 9, + "date": 1766383669, + "time": 399336, + "user": { + "uuid": "4cf401d7b9474756b06a653867d22fca", + "nickname": "BadGamer", + "roleType": 1, + "eloRate": 1833, + "eloRank": 13, + "country": "ca" + }, + "seed": { + "id": "m72336z0tu6mkh1s", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 85, + 76, + 94, + 103 + ], + "variations": [ + "type:structure:lava", + "biome:structure:beach", + "type:structure:lava", + "biome:structure:beach", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes" + ] + } + }, + { + "rank": 46, + "id": 2806625, + "season": 9, + "date": 1755775868, + "time": 399786, + "user": { + "uuid": "25349f93cf194f3baeee93d024eccc21", + "nickname": "retropog", + "roleType": 0, + "eloRate": 1655, + "eloRank": 55, + "country": "au" + }, + "seed": { + "id": "m723cwb4axnm4dhm", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 76, + 94, + 88, + 97 + ], + "variations": [ + "type:structure:lava", + "biome:structure:plains", + "type:structure:lava", + "biome:structure:plains", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes" + ] + } + }, + { + "rank": 47, + "id": 3225789, + "season": 9, + "date": 1759686097, + "time": 399994, + "user": { + "uuid": "7665f76f431b41c6b321bea16aff913b", + "nickname": "lowk3y_", + "roleType": 3, + "eloRate": 1777, + "eloRank": 20, + "country": null + }, + "seed": { + "id": "m7233i29kbmc39r0", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 88, + 100, + 103, + 94 + ], + "variations": [ + "type:structure:completable", + "biome:structure:birch_forest", + "type:structure:completable", + "biome:structure:birch_forest", + "biome:bastion:nether_wastes", + "biome:fortress:crimson_forest", + "end_spawn:buried:52" + ] + } + }, + { + "rank": 48, + "id": 3275685, + "season": 9, + "date": 1760121632, + "time": 400050, + "user": { + "uuid": "a5d83ff042164ff1b862dedc118c1dae", + "nickname": "steez", + "roleType": 0, + "eloRate": 1873, + "eloRank": 11, + "country": "gb" + }, + "seed": { + "id": "m722zx4rnn4w8ngr", + "overworld": "BURIED_TREASURE", + "nether": "TREASURE", + "endTowers": [ + 103, + 88, + 79, + 91 + ], + "variations": [ + "biome:structure:deep_cold_ocean", + "biome:structure:deep_cold_ocean", + "biome:bastion:soul_sand_valley", + "biome:fortress:nether_wastes", + "end_tower:caged:back" + ] + } + }, + { + "rank": 49, + "id": 3678099, + "season": 9, + "date": 1763173711, + "time": 400117, + "user": { + "uuid": "25349f93cf194f3baeee93d024eccc21", + "nickname": "retropog", + "roleType": 0, + "eloRate": 1655, + "eloRank": 55, + "country": "au" + }, + "seed": { + "id": "m723axomnoy5lri7", + "overworld": "RUINED_PORTAL", + "nether": "STABLES", + "endTowers": [ + 100, + 76, + 91, + 85 + ], + "variations": [ + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:plains", + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:plains", + "bastion:good_gap:1", + "bastion:triple:1", + "bastion:single:2", + "biome:bastion:nether_wastes", + "biome:fortress:crimson_forest" + ] + } + }, + { + "rank": 50, + "id": 4432960, + "season": 9, + "date": 1767015376, + "time": 400216, + "user": { + "uuid": "92b63a39b36a445fa94c77ae212dcea3", + "nickname": "bing_pigs", + "roleType": 3, + "eloRate": 2002, + "eloRank": 5, + "country": "au" + }, + "seed": { + "id": "m722v74robbaxc1v", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 94, + 79, + 97, + 85 + ], + "variations": [ + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:birch_forest", + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:birch_forest", + "bastion:triple:2", + "biome:bastion:crimson_forest", + "biome:fortress:nether_wastes", + "end_spawn:buried:45", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 51, + "id": 3601652, + "season": 9, + "date": 1762669985, + "time": 400502, + "user": { + "uuid": "70eb9286e3e24153a8b37c8f884f1292", + "nickname": "7rowl", + "roleType": 3, + "eloRate": 1797, + "eloRank": 18, + "country": "ua" + }, + "seed": { + "id": "m7230c5dgz9f52ng", + "overworld": "RUINED_PORTAL", + "nether": "STABLES", + "endTowers": [ + 100, + 88, + 85, + 91 + ], + "variations": [ + "type:structure:lava", + "biome:structure:plains", + "type:structure:lava", + "biome:structure:plains", + "bastion:good_gap:1", + "bastion:triple:2", + "bastion:small_single:1", + "biome:bastion:warped_forest", + "biome:fortress:nether_wastes", + "end_spawn:buried:57" + ] + } + }, + { + "rank": 52, + "id": 3280735, + "season": 9, + "date": 1760158731, + "time": 400505, + "user": { + "uuid": "d7e1777addd845b994867237ba0a6473", + "nickname": "dontfwjosh", + "roleType": 0, + "eloRate": 1506, + "eloRank": 225, + "country": "ca" + }, + "seed": { + "id": "m7237xztegauqk09", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 97, + 88, + 82, + 85 + ], + "variations": [ + "type:structure:lava", + "biome:structure:savanna", + "type:structure:lava", + "biome:structure:savanna", + "bastion:triple:2", + "biome:bastion:soul_sand_valley", + "biome:fortress:soul_sand_valley", + "end_tower:caged:back" + ] + } + }, + { + "rank": 53, + "id": 2725466, + "season": 8, + "date": 1754961889, + "time": 400578, + "user": { + "uuid": "17e787d1d6374f818b294f2319db370d", + "nickname": "silverrruns", + "roleType": 2, + "eloRate": 1700, + "eloRank": 37, + "country": "ca" + }, + "seed": { + "id": "m722vidgqy1soxss", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 82, + 97, + 76, + 91 + ], + "variations": [ + "type:structure:lava", + "biome:structure:plains", + "type:structure:lava", + "biome:structure:plains", + "biome:bastion:soul_sand_valley", + "biome:fortress:crimson_forest", + "end_spawn:buried:56", + "end_tower:caged:front" + ] + } + }, + { + "rank": 54, + "id": 4421418, + "season": 9, + "date": 1766976447, + "time": 400590, + "user": { + "uuid": "a54e3bc4c6354b07a236b81efbcfe791", + "nickname": "Infume", + "roleType": 2, + "eloRate": 2152, + "eloRank": 1, + "country": "us" + }, + "seed": { + "id": "m722zrghgsz7royi", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 82, + 79, + 76, + 88 + ], + "variations": [ + "type:structure:completable", + "biome:structure:beach", + "type:structure:completable", + "biome:structure:beach", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:nether_wastes", + "biome:fortress:basalt_deltas", + "end_spawn:buried:56", + "end_tower:caged:front", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 55, + "id": 4518644, + "season": 9, + "date": 1767240823, + "time": 400846, + "user": { + "uuid": "0d0f007a376a462299bf23f2f713b0e5", + "nickname": "MrBudgiee", + "roleType": 1, + "eloRate": 1761, + "eloRank": 22, + "country": "ca" + }, + "seed": { + "id": "m72380t2ieudcqjd", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 82, + 76, + 100, + 88 + ], + "variations": [ + "type:structure:completable", + "biome:structure:savanna", + "type:structure:completable", + "biome:structure:savanna", + "bastion:triple:1", + "biome:bastion:crimson_forest", + "biome:fortress:soul_sand_valley", + "end_tower:caged:front" + ] + } + }, + { + "rank": 56, + "id": 2177018, + "season": 8, + "date": 1747930987, + "time": 401084, + "user": { + "uuid": "7665f76f431b41c6b321bea16aff913b", + "nickname": "lowk3y_", + "roleType": 3, + "eloRate": 1777, + "eloRank": 20, + "country": null + }, + "seed": { + "id": "m7239wbp2iz26s0r", + "overworld": "BURIED_TREASURE", + "nether": "BRIDGE", + "endTowers": [ + 76, + 79, + 94, + 88 + ], + "variations": [ + "biome:structure:deep_ocean", + "biome:structure:deep_ocean", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_spawn:buried:47", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 57, + "id": 4612935, + "season": 10, + "date": 1767469339, + "time": 401764, + "user": { + "uuid": "78ea25c3db9a4830ba7e78074bd6fd10", + "nickname": "ogurikappa", + "roleType": 0, + "eloRate": 1532, + "eloRank": 179, + "country": "my" + }, + "seed": { + "id": "m7233lgn188b130t", + "overworld": "BURIED_TREASURE", + "nether": "HOUSING", + "endTowers": [ + 82, + 103, + 79, + 97 + ], + "variations": [ + "biome:structure:deep_cold_ocean", + "biome:structure:deep_cold_ocean", + "bastion:triple:1", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_tower:caged:front", + "end_tower:caged:back" + ] + } + }, + { + "rank": 58, + "id": 3507035, + "season": 9, + "date": 1762014270, + "time": 401786, + "user": { + "uuid": "92b63a39b36a445fa94c77ae212dcea3", + "nickname": "bing_pigs", + "roleType": 3, + "eloRate": 2002, + "eloRank": 5, + "country": "au" + }, + "seed": { + "id": "m722w9vaxlb93vxa", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 100, + 76, + 82, + 94 + ], + "variations": [ + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:forest", + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:forest", + "bastion:triple:1", + "biome:bastion:crimson_forest", + "biome:fortress:nether_wastes", + "end_spawn:buried:44", + "end_tower:caged:back" + ] + } + }, + { + "rank": 59, + "id": 1615639, + "season": 7, + "date": 1737607563, + "time": 401967, + "user": { + "uuid": "af22aaab9ee74596a3578bd6345d25b5", + "nickname": "priffie", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": null + }, + "seed": { + "id": null, + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": null, + "variations": [] + } + }, + { + "rank": 60, + "id": 1933335, + "season": 7, + "date": 1744567201, + "time": 402177, + "user": { + "uuid": "3b01d4b4fef14f178b75f05c04dd34ef", + "nickname": "BeefSalad", + "roleType": 3, + "eloRate": 1952, + "eloRank": 7, + "country": "gb" + }, + "seed": { + "id": "m722tn9poflfv8mn", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 82, + 100, + 85, + 103 + ], + "variations": [ + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:plains", + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:plains", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_spawn:buried:57", + "end_tower:caged:front" + ] + } + }, + { + "rank": 61, + "id": 2414802, + "season": 8, + "date": 1750953841, + "time": 402926, + "user": { + "uuid": "78ea25c3db9a4830ba7e78074bd6fd10", + "nickname": "ogurikappa", + "roleType": 0, + "eloRate": 1532, + "eloRank": 179, + "country": "my" + }, + "seed": { + "id": "m72317m04v471tnh", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 97, + 94, + 91, + 79 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:plains", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:plains", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 62, + "id": 2390738, + "season": 8, + "date": 1750631576, + "time": 403007, + "user": { + "uuid": "d93d53f5b7bd4fdc970d67a772936c81", + "nickname": "Shiny_Chingling", + "roleType": 1, + "eloRate": 1606, + "eloRank": 93, + "country": "be" + }, + "seed": { + "id": "m7231ij11ygx4kdx", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 76, + 85, + 91, + 82 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:forest", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:forest", + "bastion:triple:1", + "biome:bastion:crimson_forest", + "biome:fortress:soul_sand_valley", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 63, + "id": 4007831, + "season": 9, + "date": 1765242316, + "time": 403144, + "user": { + "uuid": "3c8757790ab0400b8b9e3936e0dd535b", + "nickname": "doogile", + "roleType": 3, + "eloRate": 1743, + "eloRank": 28, + "country": "us" + }, + "seed": { + "id": "m7230ecci3o6zxm7", + "overworld": "RUINED_PORTAL", + "nether": "STABLES", + "endTowers": [ + 79, + 100, + 82, + 91 + ], + "variations": [ + "type:structure:lava", + "biome:structure:plains", + "type:structure:lava", + "biome:structure:plains", + "bastion:good_gap:2", + "bastion:single:2", + "bastion:small_single:1", + "biome:bastion:crimson_forest", + "biome:fortress:soul_sand_valley", + "end_spawn:buried:36", + "end_tower:caged:front", + "end_tower:caged:back" + ] + } + }, + { + "rank": 64, + "id": 2335009, + "season": 8, + "date": 1749945713, + "time": 403425, + "user": { + "uuid": "939ddf85303441de901d60bfa4109318", + "nickname": "thecamo6", + "roleType": 3, + "eloRate": 1628, + "eloRank": 74, + "country": "us" + }, + "seed": { + "id": "m723duwx4e2mtu1f", + "overworld": "BURIED_TREASURE", + "nether": "STABLES", + "endTowers": [ + 88, + 79, + 85, + 94 + ], + "variations": [ + "biome:structure:deep_ocean", + "biome:structure:deep_ocean", + "bastion:good_gap:1", + "bastion:triple:2", + "bastion:small_single:1", + "biome:bastion:crimson_forest", + "biome:fortress:nether_wastes", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 65, + "id": 2457760, + "season": 8, + "date": 1751498585, + "time": 403739, + "user": { + "uuid": "dd34e44dfe5d4e05923d876b9c34ca5f", + "nickname": "Waluyoshi", + "roleType": 1, + "eloRate": 1684, + "eloRank": 42, + "country": "sx" + }, + "seed": { + "id": "m723b5vxpm61ooez", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 76, + 82, + 94, + 88 + ], + "variations": [ + "type:structure:lava", + "biome:structure:plains", + "type:structure:lava", + "biome:structure:plains", + "bastion:triple:1", + "biome:bastion:nether_wastes", + "biome:fortress:soul_sand_valley", + "end_spawn:buried:57", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 66, + "id": 1763208, + "season": 7, + "date": 1740887045, + "time": 404298, + "user": { + "uuid": "7665f76f431b41c6b321bea16aff913b", + "nickname": "lowk3y_", + "roleType": 3, + "eloRate": 1777, + "eloRank": 20, + "country": null + }, + "seed": { + "id": "m723bwqimw305n16", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 97, + 76, + 91, + 94 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:savanna", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:savanna", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes" + ] + } + }, + { + "rank": 67, + "id": 3469656, + "season": 9, + "date": 1761691628, + "time": 404464, + "user": { + "uuid": "635f35ee69ed4f0c94ff26ece4818956", + "nickname": "edcr", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "cf" + }, + "seed": { + "id": "m7234yfnhc6cfd5z", + "overworld": "RUINED_PORTAL", + "nether": "STABLES", + "endTowers": [ + 103, + 76, + 97, + 82 + ], + "variations": [ + "type:structure:completable", + "chest:structure:golden_carrot", + "biome:structure:forest", + "type:structure:completable", + "chest:structure:golden_carrot", + "biome:structure:forest", + "bastion:good_gap:1", + "bastion:triple:2", + "bastion:single:1", + "biome:bastion:nether_wastes", + "biome:fortress:warped_forest", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 68, + "id": 1000424, + "season": 5, + "date": 1717441437, + "time": 404473, + "user": { + "uuid": "bbd1dbd2f3ed4c43b62fc7572229ee61", + "nickname": "romuxii", + "roleType": 0, + "eloRate": 1907, + "eloRank": 8, + "country": "by" + }, + "seed": { + "id": null, + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": null, + "variations": [] + } + }, + { + "rank": 69, + "id": 4465546, + "season": 9, + "date": 1767099869, + "time": 404594, + "user": { + "uuid": "25349f93cf194f3baeee93d024eccc21", + "nickname": "retropog", + "roleType": 0, + "eloRate": 1655, + "eloRank": 55, + "country": "au" + }, + "seed": { + "id": "m722wau8m4xqmkda", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 103, + 88, + 76, + 85 + ], + "variations": [ + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:savanna", + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:savanna", + "biome:bastion:crimson_forest", + "biome:fortress:warped_forest" + ] + } + }, + { + "rank": 70, + "id": 4527894, + "season": 9, + "date": 1767270840, + "time": 404746, + "user": { + "uuid": "635f35ee69ed4f0c94ff26ece4818956", + "nickname": "edcr", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "cf" + }, + "seed": { + "id": "m7231gpp651v1789", + "overworld": "DESERT_TEMPLE", + "nether": "TREASURE", + "endTowers": [ + 76, + 91, + 85, + 82 + ], + "variations": [ + "biome:bastion:soul_sand_valley", + "biome:fortress:nether_wastes", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 71, + "id": 2653650, + "season": 8, + "date": 1754079867, + "time": 405299, + "user": { + "uuid": "bc80af38933f4ae19b0494681a54422b", + "nickname": "Ancoboyy", + "roleType": 1, + "eloRate": 1890, + "eloRank": 10, + "country": "tr" + }, + "seed": { + "id": "m7233j7gxa4e6lv3", + "overworld": "RUINED_PORTAL", + "nether": "STABLES", + "endTowers": [ + 100, + 88, + 76, + 82 + ], + "variations": [ + "type:structure:completable", + "chest:structure:golden_carrot", + "biome:structure:forest", + "type:structure:completable", + "chest:structure:golden_carrot", + "biome:structure:forest", + "bastion:good_gap:2", + "bastion:triple:1", + "bastion:single:2", + "biome:bastion:crimson_forest", + "biome:fortress:nether_wastes", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 72, + "id": 3371183, + "season": 9, + "date": 1760876780, + "time": 405851, + "user": { + "uuid": "635f35ee69ed4f0c94ff26ece4818956", + "nickname": "edcr", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "cf" + }, + "seed": { + "id": "m722t01i6mn0q4rq", + "overworld": "BURIED_TREASURE", + "nether": "HOUSING", + "endTowers": [ + 91, + 85, + 82, + 97 + ], + "variations": [ + "biome:structure:deep_ocean", + "biome:structure:deep_ocean", + "bastion:triple:2", + "biome:bastion:warped_forest", + "biome:fortress:warped_forest", + "end_tower:caged:back" + ] + } + }, + { + "rank": 73, + "id": 2459232, + "season": 8, + "date": 1751522503, + "time": 405900, + "user": { + "uuid": "dd34e44dfe5d4e05923d876b9c34ca5f", + "nickname": "Waluyoshi", + "roleType": 1, + "eloRate": 1684, + "eloRank": 42, + "country": "sx" + }, + "seed": { + "id": "m723aq0yydejg1mw", + "overworld": "BURIED_TREASURE", + "nether": "TREASURE", + "endTowers": [ + 91, + 82, + 97, + 88 + ], + "variations": [ + "biome:structure:deep_ocean", + "biome:structure:deep_ocean", + "biome:bastion:crimson_forest", + "biome:fortress:nether_wastes", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 74, + "id": 2512424, + "season": 8, + "date": 1752189488, + "time": 405962, + "user": { + "uuid": "fdff6a3e88054664974dbcd30583fe81", + "nickname": "Finnitzko", + "roleType": 1, + "eloRate": 1520, + "eloRank": 199, + "country": "de" + }, + "seed": { + "id": "m723b6ba6hlv1die", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 79, + 97, + 91, + 100 + ], + "variations": [ + "type:structure:completable", + "chest:structure:golden_carrot", + "biome:structure:plains", + "type:structure:completable", + "chest:structure:golden_carrot", + "biome:structure:plains", + "bastion:triple:2", + "biome:bastion:soul_sand_valley", + "biome:fortress:soul_sand_valley", + "end_spawn:buried:44", + "end_tower:caged:front" + ] + } + }, + { + "rank": 75, + "id": 3358159, + "season": 9, + "date": 1760789523, + "time": 406017, + "user": { + "uuid": "cc432b2626a44ae1836a50244adbf468", + "nickname": "XSpocony_MaciekX", + "roleType": 1, + "eloRate": 1981, + "eloRank": 6, + "country": "pl" + }, + "seed": { + "id": "m722vjrzd35r4lds", + "overworld": "BURIED_TREASURE", + "nether": "BRIDGE", + "endTowers": [ + 100, + 91, + 94, + 82 + ], + "variations": [ + "biome:structure:deep_lukewarm_ocean", + "biome:structure:deep_lukewarm_ocean", + "bastion:triple:2", + "biome:bastion:soul_sand_valley", + "biome:fortress:soul_sand_valley", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 76, + "id": 4348789, + "season": 9, + "date": 1766755709, + "time": 406237, + "user": { + "uuid": "2fe70934e7be458dba747c4ac830391c", + "nickname": "nhb_", + "roleType": 2, + "eloRate": 1591, + "eloRank": 113, + "country": "cf" + }, + "seed": { + "id": "m7237ndveahgzgwd", + "overworld": "BURIED_TREASURE", + "nether": "BRIDGE", + "endTowers": [ + 82, + 103, + 76, + 85 + ], + "variations": [ + "biome:structure:deep_ocean", + "biome:structure:deep_ocean", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:crimson_forest", + "biome:fortress:crimson_forest", + "end_spawn:buried:56", + "end_tower:caged:front" + ] + } + }, + { + "rank": 77, + "id": 3707844, + "season": 9, + "date": 1763347375, + "time": 406426, + "user": { + "uuid": "c92021f449a94bdc9811a3e5e299820e", + "nickname": "oshgay", + "roleType": 1, + "eloRate": 1603, + "eloRank": 99, + "country": "mo" + }, + "seed": { + "id": "m722teuja9i77pfi", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 100, + 91, + 94, + 97 + ], + "variations": [ + "type:structure:completable", + "chest:structure:golden_carrot", + "chest:structure:looting_sword", + "biome:structure:plains", + "type:structure:completable", + "chest:structure:golden_carrot", + "chest:structure:looting_sword", + "biome:structure:plains", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:crimson_forest", + "biome:fortress:soul_sand_valley" + ] + } + }, + { + "rank": 78, + "id": 2816658, + "season": 9, + "date": 1755869574, + "time": 406451, + "user": { + "uuid": "25349f93cf194f3baeee93d024eccc21", + "nickname": "retropog", + "roleType": 0, + "eloRate": 1655, + "eloRank": 55, + "country": "au" + }, + "seed": { + "id": "m722t4z3surh2qtr", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 82, + 88, + 79, + 85 + ], + "variations": [ + "type:structure:completable", + "biome:structure:forest", + "type:structure:completable", + "biome:structure:forest", + "bastion:triple:2", + "biome:bastion:crimson_forest", + "biome:fortress:crimson_forest", + "end_tower:caged:front", + "end_tower:caged:back" + ] + } + }, + { + "rank": 79, + "id": 1827549, + "season": 7, + "date": 1742322398, + "time": 406569, + "user": { + "uuid": "8d52ed9bf12146c68321f1729e28cbf5", + "nickname": "WarioTime1", + "roleType": 0, + "eloRate": 1639, + "eloRank": 66, + "country": "va" + }, + "seed": { + "id": "m7233xl038iagmye", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 79, + 94, + 82, + 103 + ], + "variations": [ + "type:structure:completable", + "biome:structure:plains", + "type:structure:completable", + "biome:structure:plains", + "bastion:triple:1", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_tower:caged:front", + "end_tower:caged:back" + ] + } + }, + { + "rank": 80, + "id": 2959523, + "season": 9, + "date": 1757251391, + "time": 406608, + "user": { + "uuid": "410e5776b03a424d8740557bac2d9014", + "nickname": "JoomzMonkey", + "roleType": 0, + "eloRate": 1715, + "eloRank": 32, + "country": "us" + }, + "seed": { + "id": "m723dw7gp8yifr5w", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 94, + 88, + 103, + 97 + ], + "variations": [ + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:plains", + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:plains", + "bastion:triple:2", + "biome:bastion:soul_sand_valley", + "biome:fortress:soul_sand_valley", + "end_spawn:buried:57" + ] + } + }, + { + "rank": 81, + "id": 2816424, + "season": 9, + "date": 1755867865, + "time": 406664, + "user": { + "uuid": "635f35ee69ed4f0c94ff26ece4818956", + "nickname": "edcr", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "cf" + }, + "seed": { + "id": "m7237pnhw5rddioz", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 85, + 103, + 79, + 76 + ], + "variations": [ + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:forest", + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:forest", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:warped_forest", + "biome:fortress:warped_forest", + "end_spawn:buried:58", + "end_tower:caged:back" + ] + } + }, + { + "rank": 82, + "id": 1874087, + "season": 7, + "date": 1743287158, + "time": 406737, + "user": { + "uuid": "939ddf85303441de901d60bfa4109318", + "nickname": "thecamo6", + "roleType": 3, + "eloRate": 1628, + "eloRank": 74, + "country": "us" + }, + "seed": { + "id": "m7238vsi6wwk6phz", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 79, + 76, + 103, + 91 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:savanna", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:savanna", + "biome:bastion:soul_sand_valley", + "biome:fortress:basalt_deltas", + "end_spawn:buried:58", + "end_tower:caged:front" + ] + } + }, + { + "rank": 83, + "id": 3449643, + "season": 9, + "date": 1761512397, + "time": 406950, + "user": { + "uuid": "5a32f1e5609847c691c07730f973397c", + "nickname": "DARVY__X1", + "roleType": 2, + "eloRate": 1749, + "eloRank": 25, + "country": "cf" + }, + "seed": { + "id": "m7236kc79s1fff2u", + "overworld": "RUINED_PORTAL", + "nether": "STABLES", + "endTowers": [ + 76, + 97, + 82, + 79 + ], + "variations": [ + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:forest", + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:forest", + "bastion:good_gap:1", + "bastion:triple:1", + "bastion:single:2", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_tower:caged:back", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 84, + "id": 4413778, + "season": 9, + "date": 1766957625, + "time": 407114, + "user": { + "uuid": "92b63a39b36a445fa94c77ae212dcea3", + "nickname": "bing_pigs", + "roleType": 3, + "eloRate": 2002, + "eloRank": 5, + "country": "au" + }, + "seed": { + "id": "m7230hlyw16s8q0f", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 100, + 88, + 97, + 82 + ], + "variations": [ + "type:structure:completable", + "biome:structure:forest", + "type:structure:completable", + "biome:structure:forest", + "bastion:triple:2", + "biome:bastion:soul_sand_valley", + "biome:fortress:nether_wastes", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 85, + "id": 3944687, + "season": 9, + "date": 1764919141, + "time": 407256, + "user": { + "uuid": "25349f93cf194f3baeee93d024eccc21", + "nickname": "retropog", + "roleType": 0, + "eloRate": 1655, + "eloRank": 55, + "country": "au" + }, + "seed": { + "id": "m7233tbssru5eoib", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 94, + 88, + 91, + 100 + ], + "variations": [ + "type:structure:completable", + "biome:structure:forest", + "type:structure:completable", + "biome:structure:forest", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:basalt_deltas" + ] + } + }, + { + "rank": 86, + "id": 2537017, + "season": 8, + "date": 1752505870, + "time": 407453, + "user": { + "uuid": "0b164a03002048d3955715422179eedf", + "nickname": "KenanKardes", + "roleType": 0, + "eloRate": 1802, + "eloRank": 16, + "country": "az" + }, + "seed": { + "id": "m7232jajx277djsd", + "overworld": "RUINED_PORTAL", + "nether": "STABLES", + "endTowers": [ + 100, + 88, + 79, + 97 + ], + "variations": [ + "type:structure:completable", + "biome:structure:plains", + "type:structure:completable", + "biome:structure:plains", + "bastion:good_gap:1", + "bastion:triple:2", + "bastion:single:1", + "biome:bastion:soul_sand_valley", + "biome:fortress:soul_sand_valley", + "end_spawn:buried:50", + "end_tower:caged:back" + ] + } + }, + { + "rank": 87, + "id": 3423996, + "season": 9, + "date": 1761334079, + "time": 407475, + "user": { + "uuid": "cc432b2626a44ae1836a50244adbf468", + "nickname": "XSpocony_MaciekX", + "roleType": 1, + "eloRate": 1981, + "eloRank": 6, + "country": "pl" + }, + "seed": { + "id": "m7239cxyuf2fvnni", + "overworld": "VILLAGE", + "nether": "HOUSING", + "endTowers": [ + 91, + 85, + 79, + 82 + ], + "variations": [ + "biome:structure:plains", + "biome:structure:plains", + "bastion:triple:2", + "biome:bastion:crimson_forest", + "biome:fortress:soul_sand_valley", + "end_tower:caged:back", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 88, + "id": 2032400, + "season": 8, + "date": 1746121300, + "time": 408047, + "user": { + "uuid": "2fe70934e7be458dba747c4ac830391c", + "nickname": "nhb_", + "roleType": 2, + "eloRate": 1591, + "eloRank": 113, + "country": "cf" + }, + "seed": { + "id": "m7232mhgc3jaj4qk", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 85, + 88, + 103, + 79 + ], + "variations": [ + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:plains", + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:plains", + "biome:bastion:crimson_forest", + "biome:fortress:crimson_forest", + "end_tower:caged:back_center" + ] + } + }, + { + "rank": 89, + "id": 4656621, + "season": 10, + "date": 1767565073, + "time": 408296, + "user": { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "nickname": "Feinberg", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "us" + }, + "seed": { + "id": "m7232qeya1u3v5wz", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 94, + 79, + 76, + 97 + ], + "variations": [ + "type:structure:completable", + "biome:structure:beach", + "type:structure:completable", + "biome:structure:beach", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:soul_sand_valley", + "biome:fortress:basalt_deltas", + "end_spawn:buried:56", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 90, + "id": 2159774, + "season": 8, + "date": 1747698159, + "time": 408380, + "user": { + "uuid": "048de51800794a208de7f01652513c32", + "nickname": "q3awreh4yu78i", + "roleType": 1, + "eloRate": 1572, + "eloRank": 136, + "country": "cw" + }, + "seed": { + "id": "m723ed4jxtcbthoq", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 94, + 100, + 103, + 85 + ], + "variations": [ + "type:structure:lava", + "biome:structure:forest", + "type:structure:lava", + "biome:structure:forest", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes" + ] + } + }, + { + "rank": 91, + "id": 3917208, + "season": 9, + "date": 1764765721, + "time": 408481, + "user": { + "uuid": "553414a2c89b4d6b8c0ba5bd89284508", + "nickname": "ulsah1n", + "roleType": 0, + "eloRate": 1676, + "eloRank": 46, + "country": "tr" + }, + "seed": { + "id": "m722w9kmxmmwl7qo", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 91, + 85, + 88, + 100 + ], + "variations": [ + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:beach", + "type:structure:lava", + "chest:structure:looting_sword", + "biome:structure:beach", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:nether_wastes", + "biome:fortress:crimson_forest", + "end_spawn:buried:56" + ] + } + }, + { + "rank": 92, + "id": 1879682, + "season": 7, + "date": 1743400335, + "time": 409025, + "user": { + "uuid": "25349f93cf194f3baeee93d024eccc21", + "nickname": "retropog", + "roleType": 0, + "eloRate": 1655, + "eloRank": 55, + "country": "au" + }, + "seed": { + "id": "m722xot7nt0lzdpc", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 91, + 103, + 94, + 88 + ], + "variations": [ + "type:structure:completable", + "biome:structure:forest", + "type:structure:completable", + "biome:structure:forest", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:crimson_forest", + "biome:fortress:nether_wastes", + "end_spawn:buried:57" + ] + } + }, + { + "rank": 93, + "id": 3422046, + "season": 9, + "date": 1761322850, + "time": 409061, + "user": { + "uuid": "cc432b2626a44ae1836a50244adbf468", + "nickname": "XSpocony_MaciekX", + "roleType": 1, + "eloRate": 1981, + "eloRank": 6, + "country": "pl" + }, + "seed": { + "id": "m722x8r92facnd5n", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 100, + 82, + 91, + 88 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:beach", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:beach", + "biome:bastion:crimson_forest", + "biome:fortress:soul_sand_valley", + "end_spawn:buried:56", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 94, + "id": 3178135, + "season": 9, + "date": 1759281183, + "time": 409160, + "user": { + "uuid": "a5d83ff042164ff1b862dedc118c1dae", + "nickname": "steez", + "roleType": 0, + "eloRate": 1873, + "eloRank": 11, + "country": "gb" + }, + "seed": { + "id": "m722xtadgr62afgx", + "overworld": "BURIED_TREASURE", + "nether": "HOUSING", + "endTowers": [ + 94, + 88, + 79, + 91 + ], + "variations": [ + "biome:structure:deep_ocean", + "biome:structure:deep_ocean", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_spawn:buried:57", + "end_tower:caged:back" + ] + } + }, + { + "rank": 95, + "id": 2483724, + "season": 8, + "date": 1751831426, + "time": 409197, + "user": { + "uuid": "b5ae858c09384b79989ea305a4b5cedf", + "nickname": "Ayreliaa", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": "ru" + }, + "seed": { + "id": "m722ziax4rifxmjo", + "overworld": "RUINED_PORTAL", + "nether": "STABLES", + "endTowers": [ + 100, + 97, + 103, + 85 + ], + "variations": [ + "type:structure:completable", + "biome:structure:beach", + "type:structure:completable", + "biome:structure:beach", + "bastion:good_gap:1", + "bastion:triple:1", + "bastion:single:1", + "bastion:small_single:1", + "biome:bastion:soul_sand_valley", + "biome:fortress:soul_sand_valley" + ] + } + }, + { + "rank": 96, + "id": 4080503, + "season": 9, + "date": 1765604912, + "time": 409203, + "user": { + "uuid": "bdb7f407200d4882b78e656ca161bddf", + "nickname": "pjfqepojedfpo", + "roleType": 1, + "eloRate": 1600, + "eloRank": 103, + "country": "fk" + }, + "seed": { + "id": "m722wsgcd972jodv", + "overworld": "RUINED_PORTAL", + "nether": "TREASURE", + "endTowers": [ + 94, + 79, + 91, + 103 + ], + "variations": [ + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:forest", + "type:structure:lava", + "chest:structure:golden_carrot", + "biome:structure:forest", + "biome:bastion:nether_wastes", + "biome:fortress:crimson_forest", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 97, + "id": 2845164, + "season": 9, + "date": 1756124847, + "time": 409586, + "user": { + "uuid": "9dcb17d831b24df2bae778cfd750ab1b", + "nickname": "loodlow", + "roleType": 0, + "eloRate": 1448, + "eloRank": 312, + "country": "ua" + }, + "seed": { + "id": "m723a4qr1izj2ksw", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 85, + 82, + 103, + 76 + ], + "variations": [ + "type:structure:completable", + "biome:structure:plains", + "type:structure:completable", + "biome:structure:plains", + "bastion:triple:2", + "biome:bastion:crimson_forest", + "biome:fortress:warped_forest", + "end_tower:caged:front_center" + ] + } + }, + { + "rank": 98, + "id": 3933988, + "season": 9, + "date": 1764864531, + "time": 409779, + "user": { + "uuid": "bdb7f407200d4882b78e656ca161bddf", + "nickname": "pjfqepojedfpo", + "roleType": 1, + "eloRate": 1600, + "eloRank": 103, + "country": "fk" + }, + "seed": { + "id": "m722uacap03yl3mh", + "overworld": "BURIED_TREASURE", + "nether": "HOUSING", + "endTowers": [ + 88, + 103, + 97, + 91 + ], + "variations": [ + "biome:structure:deep_ocean", + "biome:structure:deep_ocean", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:warped_forest", + "biome:fortress:warped_forest" + ] + } + }, + { + "rank": 99, + "id": 4776866, + "season": 10, + "date": 1767851604, + "time": 410315, + "user": { + "uuid": "a54e3bc4c6354b07a236b81efbcfe791", + "nickname": "Infume", + "roleType": 2, + "eloRate": 2152, + "eloRank": 1, + "country": "us" + }, + "seed": { + "id": "m7236ulk6n3vo1c5", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 100, + 91, + 85, + 103 + ], + "variations": [ + "type:structure:completable", + "biome:structure:forest", + "type:structure:completable", + "biome:structure:forest", + "bastion:triple:2", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes" + ] + } + }, + { + "rank": 100, + "id": 4220693, + "season": 9, + "date": 1766262335, + "time": 410386, + "user": { + "uuid": "0562802e736e47c581b2ef095e2ed067", + "nickname": "epik48", + "roleType": 1, + "eloRate": null, + "eloRank": null, + "country": "br" + }, + "seed": { + "id": "m7238sdwq1j0odat", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 79, + 94, + 103, + 85 + ], + "variations": [ + "type:structure:completable", + "biome:structure:forest", + "type:structure:completable", + "biome:structure:forest", + "bastion:triple:2", + "biome:bastion:warped_forest", + "biome:fortress:crimson_forest", + "end_tower:caged:front" + ] + } + } +] diff --git a/tests/fixtures/user.json b/tests/fixtures/user.json new file mode 100644 index 0000000..0ca55eb --- /dev/null +++ b/tests/fixtures/user.json @@ -0,0 +1,361 @@ +{ + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "nickname": "Feinberg", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "achievements": { + "display": [ + { + "id": "playoffsResult", + "date": 1744621721, + "data": [ + "6" + ], + "level": 16, + "value": null, + "goal": null + }, + { + "id": "seasonResult", + "date": 1679875227, + "data": [ + "0", + "1" + ], + "level": 1, + "value": null, + "goal": null + }, + { + "id": "oneshot", + "date": 1727818894, + "data": [], + "level": 1, + "value": null, + "goal": null + }, + { + "id": "seasonResult", + "date": 1686787247, + "data": [ + "1", + "1" + ], + "level": 1, + "value": null, + "goal": null + }, + { + "id": "playoffsResult", + "date": 1746998386, + "data": [ + "7" + ], + "level": 16, + "value": null, + "goal": null + } + ], + "total": [ + { + "id": "seasonResult", + "date": 1767312115, + "data": [ + "9", + "26" + ], + "level": 4, + "value": null, + "goal": null + }, + { + "id": "bestTime", + "date": 1760404765, + "data": [], + "level": 11, + "value": 408296, + "goal": 359999 + }, + { + "id": "playedMatches", + "date": 1759463466, + "data": [], + "level": 10, + "value": 2684, + "goal": 5000 + }, + { + "id": "playoffsResult", + "date": 1757276382, + "data": [ + "8" + ], + "level": 16, + "value": null, + "goal": null + }, + { + "id": "seasonResult", + "date": 1755734804, + "data": [ + "8", + "11" + ], + "level": 4, + "value": null, + "goal": null + }, + { + "id": "wins", + "date": 1748330725, + "data": [], + "level": 9, + "value": 1730, + "goal": 2000 + }, + { + "id": "seasonResult", + "date": 1745193880, + "data": [ + "7", + "3" + ], + "level": 2, + "value": null, + "goal": null + }, + { + "id": "foodless", + "date": 1739004943, + "data": [], + "level": 1, + "value": null, + "goal": null + }, + { + "id": "playtime", + "date": 1738910275, + "data": [], + "level": 7, + "value": 1571592937, + "goal": 1800000000 + }, + { + "id": "seasonResult", + "date": 1734741052, + "data": [ + "6", + "8" + ], + "level": 3, + "value": null, + "goal": null + }, + { + "id": "netherite", + "date": 1729634403, + "data": [], + "level": 1, + "value": null, + "goal": null + }, + { + "id": "egapHolder", + "date": 1728343538, + "data": [], + "level": 1, + "value": null, + "goal": null + }, + { + "id": "armorless", + "date": 1728339833, + "data": [], + "level": 1, + "value": null, + "goal": null + }, + { + "id": "ironHoe", + "date": 1728286566, + "data": [], + "level": 1, + "value": null, + "goal": null + }, + { + "id": "highLevel", + "date": 1728265183, + "data": [], + "level": 1, + "value": null, + "goal": null + }, + { + "id": "classicRun", + "date": 1728168045, + "data": [], + "level": 1, + "value": null, + "goal": null + }, + { + "id": "ironPickless", + "date": 1727822540, + "data": [], + "level": 1, + "value": null, + "goal": null + }, + { + "id": "highestWinStreak", + "date": 1706847228, + "data": [], + "level": 8, + "value": 29, + "goal": null + }, + { + "id": "seasonResult", + "date": 1704499267, + "data": [ + "3", + "110" + ], + "level": 6, + "value": null, + "goal": null + }, + { + "id": "seasonResult", + "date": 1695081661, + "data": [ + "2", + "2" + ], + "level": 2, + "value": null, + "goal": null + } + ] + }, + "timestamp": { + "firstOnline": 1676224745, + "lastOnline": 1767925759, + "lastRanked": 1767918741, + "nextDecay": 1768566741 + }, + "statistics": { + "season": { + "bestTime": { + "ranked": 408296, + "casual": null + }, + "highestWinStreak": { + "ranked": 14, + "casual": 0 + }, + "currentWinStreak": { + "ranked": 14, + "casual": 0 + }, + "playedMatches": { + "ranked": 73, + "casual": 0 + }, + "playtime": { + "ranked": 39981188, + "casual": 0 + }, + "completionTime": { + "ranked": 28956710, + "casual": 0 + }, + "forfeits": { + "ranked": 0, + "casual": 0 + }, + "completions": { + "ranked": 52, + "casual": 0 + }, + "wins": { + "ranked": 57, + "casual": 0 + }, + "loses": { + "ranked": 15, + "casual": 0 + } + }, + "total": { + "bestTime": { + "ranked": 408296, + "casual": 552108 + }, + "highestWinStreak": { + "ranked": 29, + "casual": 2 + }, + "currentWinStreak": { + "ranked": 14, + "casual": 1 + }, + "playedMatches": { + "ranked": 2684, + "casual": 10 + }, + "playtime": { + "ranked": 1571592937, + "casual": 5149678 + }, + "forfeits": { + "ranked": 83, + "casual": 2 + }, + "completions": { + "ranked": 1410, + "casual": 5 + }, + "wins": { + "ranked": 1730, + "casual": 6 + }, + "loses": { + "ranked": 921, + "casual": 4 + }, + "completionTime": { + "ranked": 882778147, + "casual": 3483431 + } + } + }, + "connections": { + "discord": { + "id": "75707773723086848", + "name": "Feinberg#0001" + }, + "youtube": { + "id": "UCAdKNsVKLW1xWNpy4eB_5AQ", + "name": "Feinberg" + }, + "twitch": { + "id": "feinberg", + "name": "Feinberg" + } + }, + "weeklyRaces": [], + "country": "us", + "seasonResult": { + "last": { + "eloRate": 2100, + "eloRank": 2, + "phasePoint": 0 + }, + "highest": 2100, + "lowest": 1623, + "phases": [] + } +} diff --git a/tests/fixtures/user_matches.json b/tests/fixtures/user_matches.json new file mode 100644 index 0000000..c2fba61 --- /dev/null +++ b/tests/fixtures/user_matches.json @@ -0,0 +1,432 @@ +[ + { + "id": 4804805, + "type": 2, + "seed": { + "id": "m7230aq00bzidp16", + "overworld": "BURIED_TREASURE", + "nether": "BRIDGE", + "endTowers": [ + 79, + 76, + 103, + 100 + ], + "variations": [ + "biome:structure:deep_ocean", + "biome:structure:deep_ocean", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:crimson_forest", + "biome:fortress:crimson_forest", + "end_tower:caged:front" + ] + }, + "category": "ANY", + "gameMode": "default", + "players": [ + { + "uuid": "388533d5a2ad4b349a31db4738670a4b", + "nickname": "v_strid", + "roleType": 1, + "eloRate": 1798, + "eloRank": 17, + "country": "se" + }, + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "nickname": "Feinberg", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "us" + } + ], + "spectators": [], + "result": { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "time": 498797 + }, + "forfeited": false, + "decayed": false, + "rank": { + "season": 379, + "allTime": null + }, + "vod": [ + { + "uuid": "388533d5a2ad4b349a31db4738670a4b", + "url": "https://www.twitch.tv/videos/2664727408", + "startsAt": 1767907679 + }, + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "url": "https://www.twitch.tv/videos/2664787828", + "startsAt": 1767912697 + } + ], + "changes": [ + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "change": 10, + "eloRate": 2090 + }, + { + "uuid": "388533d5a2ad4b349a31db4738670a4b", + "change": -10, + "eloRate": 1779 + } + ], + "beginner": false, + "botSource": null, + "season": 10, + "date": 1767918741, + "seedType": "BURIED_TREASURE", + "bastionType": "BRIDGE", + "tag": null + }, + { + "id": 4804022, + "type": 2, + "seed": { + "id": "m722tlempyzg2r64", + "overworld": "RUINED_PORTAL", + "nether": "HOUSING", + "endTowers": [ + 76, + 91, + 97, + 85 + ], + "variations": [ + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:river", + "type:structure:completable", + "chest:structure:looting_sword", + "biome:structure:river", + "bastion:triple:1", + "biome:bastion:nether_wastes", + "biome:fortress:basalt_deltas" + ] + }, + "category": "ANY", + "gameMode": "default", + "players": [ + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "nickname": "Feinberg", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "us" + }, + { + "uuid": "ba31689fe7d24431bf7997a52efcc21c", + "nickname": "meebie", + "roleType": 1, + "eloRate": 1852, + "eloRank": 12, + "country": "cf" + } + ], + "spectators": [], + "result": { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "time": 480101 + }, + "forfeited": false, + "decayed": false, + "rank": { + "season": 209, + "allTime": null + }, + "vod": [ + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "url": "https://www.twitch.tv/videos/2664787828", + "startsAt": 1767912697 + } + ], + "changes": [ + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "change": 10, + "eloRate": 2080 + }, + { + "uuid": "ba31689fe7d24431bf7997a52efcc21c", + "change": -10, + "eloRate": 1777 + } + ], + "beginner": false, + "botSource": null, + "season": 10, + "date": 1767917201, + "seedType": "RUINED_PORTAL", + "bastionType": "HOUSING", + "tag": null + }, + { + "id": 4803643, + "type": 2, + "seed": { + "id": "m7236qrjg674ysxc", + "overworld": "SHIPWRECK", + "nether": "BRIDGE", + "endTowers": [ + 76, + 88, + 97, + 79 + ], + "variations": [ + "biome:structure:deep_ocean", + "type:structure:sideways", + "biome:structure:deep_ocean", + "type:structure:sideways", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:nether_wastes", + "biome:fortress:nether_wastes", + "end_spawn:buried:56", + "end_tower:caged:back_center" + ] + }, + "category": "ANY", + "gameMode": "default", + "players": [ + { + "uuid": "388533d5a2ad4b349a31db4738670a4b", + "nickname": "v_strid", + "roleType": 1, + "eloRate": 1798, + "eloRank": 17, + "country": "se" + }, + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "nickname": "Feinberg", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "us" + } + ], + "spectators": [], + "result": { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "time": 288140 + }, + "forfeited": true, + "decayed": false, + "rank": { + "season": null, + "allTime": null + }, + "vod": [ + { + "uuid": "388533d5a2ad4b349a31db4738670a4b", + "url": "https://www.twitch.tv/videos/2664727408", + "startsAt": 1767907679 + }, + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "url": "https://www.twitch.tv/videos/2664787828", + "startsAt": 1767912697 + } + ], + "changes": [ + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "change": 11, + "eloRate": 2069 + }, + { + "uuid": "388533d5a2ad4b349a31db4738670a4b", + "change": -11, + "eloRate": 1795 + } + ], + "beginner": false, + "botSource": null, + "season": 10, + "date": 1767916453, + "seedType": "SHIPWRECK", + "bastionType": "BRIDGE", + "tag": null + }, + { + "id": 4803385, + "type": 2, + "seed": { + "id": "m723cdvuzvypjayv", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 97, + 94, + 88, + 100 + ], + "variations": [ + "type:structure:lava", + "biome:structure:plains", + "type:structure:lava", + "biome:structure:plains", + "bastion:triple:1", + "bastion:single:1", + "biome:bastion:soul_sand_valley", + "biome:fortress:soul_sand_valley" + ] + }, + "category": "ANY", + "gameMode": "default", + "players": [ + { + "uuid": "ba31689fe7d24431bf7997a52efcc21c", + "nickname": "meebie", + "roleType": 1, + "eloRate": 1852, + "eloRank": 12, + "country": "cf" + }, + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "nickname": "Feinberg", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "us" + } + ], + "spectators": [], + "result": { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "time": 561119 + }, + "forfeited": false, + "decayed": false, + "rank": { + "season": null, + "allTime": null + }, + "vod": [ + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "url": "https://www.twitch.tv/videos/2664787828", + "startsAt": 1767912697 + } + ], + "changes": [ + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "change": 10, + "eloRate": 2059 + }, + { + "uuid": "ba31689fe7d24431bf7997a52efcc21c", + "change": -10, + "eloRate": 1772 + } + ], + "beginner": false, + "botSource": null, + "season": 10, + "date": 1767915976, + "seedType": "RUINED_PORTAL", + "bastionType": "BRIDGE", + "tag": null + }, + { + "id": 4802733, + "type": 2, + "seed": { + "id": "m722vk9l5wuvuaz9", + "overworld": "RUINED_PORTAL", + "nether": "BRIDGE", + "endTowers": [ + 97, + 76, + 79, + 91 + ], + "variations": [ + "type:structure:completable", + "chest:structure:egap", + "biome:structure:beach", + "type:structure:completable", + "chest:structure:egap", + "biome:structure:beach", + "bastion:triple:2", + "biome:bastion:soul_sand_valley", + "biome:fortress:nether_wastes", + "end_spawn:buried:57", + "end_tower:caged:back" + ] + }, + "category": "ANY", + "gameMode": "default", + "players": [ + { + "uuid": "388533d5a2ad4b349a31db4738670a4b", + "nickname": "v_strid", + "roleType": 1, + "eloRate": 1798, + "eloRank": 17, + "country": "se" + }, + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "nickname": "Feinberg", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "us" + } + ], + "spectators": [], + "result": { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "time": 501790 + }, + "forfeited": false, + "decayed": false, + "rank": { + "season": 421, + "allTime": null + }, + "vod": [ + { + "uuid": "388533d5a2ad4b349a31db4738670a4b", + "url": "https://www.twitch.tv/videos/2664727408", + "startsAt": 1767907679 + }, + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "url": "https://www.twitch.tv/videos/2664787828", + "startsAt": 1767912697 + } + ], + "changes": [ + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "change": 12, + "eloRate": 2047 + }, + { + "uuid": "388533d5a2ad4b349a31db4738670a4b", + "change": -12, + "eloRate": 1814 + } + ], + "beginner": false, + "botSource": null, + "season": 10, + "date": 1767914679, + "seedType": "RUINED_PORTAL", + "bastionType": "BRIDGE", + "tag": null + } +] diff --git a/tests/fixtures/user_seasons.json b/tests/fixtures/user_seasons.json new file mode 100644 index 0000000..1709cdd --- /dev/null +++ b/tests/fixtures/user_seasons.json @@ -0,0 +1,194 @@ +{ + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "nickname": "Feinberg", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "us", + "seasonResults": { + "1": { + "last": { + "eloRate": 2309, + "eloRank": 1, + "phasePoint": 0 + }, + "highest": 2309, + "lowest": 1433, + "phases": [] + }, + "2": { + "last": { + "eloRate": 2070, + "eloRank": 2, + "phasePoint": 0 + }, + "highest": 2089, + "lowest": 1196, + "phases": [] + }, + "3": { + "last": { + "eloRate": 1544, + "eloRank": 110, + "phasePoint": 0 + }, + "highest": 1904, + "lowest": 1544, + "phases": [] + }, + "4": { + "last": { + "eloRate": null, + "eloRank": null, + "phasePoint": 0 + }, + "highest": null, + "lowest": null, + "phases": [] + }, + "6": { + "last": { + "eloRate": 2276, + "eloRank": 8, + "phasePoint": 125 + }, + "highest": 2291, + "lowest": 2276, + "phases": [ + { + "phase": 2, + "eloRate": 2089, + "eloRank": 6, + "point": 30 + }, + { + "phase": 3, + "eloRate": 2248, + "eloRank": 4, + "point": 50 + }, + { + "phase": 4, + "eloRate": 2276, + "eloRank": 8, + "point": 45 + } + ] + }, + "7": { + "last": { + "eloRate": 2335, + "eloRank": 3, + "phasePoint": 170 + }, + "highest": 2335, + "lowest": 2123, + "phases": [ + { + "phase": 1, + "eloRate": 1871, + "eloRank": 9, + "point": 20 + }, + { + "phase": 2, + "eloRate": 2047, + "eloRank": 5, + "point": 30 + }, + { + "phase": 3, + "eloRate": 2181, + "eloRank": 4, + "point": 50 + }, + { + "phase": 4, + "eloRate": 2335, + "eloRank": 3, + "point": 70 + } + ] + }, + "8": { + "last": { + "eloRate": 2223, + "eloRank": 11, + "phasePoint": 161 + }, + "highest": 2228, + "lowest": 1530, + "phases": [ + { + "phase": 1, + "eloRate": 1935, + "eloRank": 7, + "point": 36 + }, + { + "phase": 2, + "eloRate": 2030, + "eloRank": 13, + "point": 31 + }, + { + "phase": 3, + "eloRate": 2087, + "eloRank": 14, + "point": 37 + }, + { + "phase": 4, + "eloRate": 2223, + "eloRank": 11, + "point": 57 + } + ] + }, + "9": { + "last": { + "eloRate": 2274, + "eloRank": 26, + "phasePoint": 185 + }, + "highest": 2618, + "lowest": 1670, + "phases": [ + { + "phase": 1, + "eloRate": 2158, + "eloRank": 5, + "point": 40 + }, + { + "phase": 2, + "eloRate": 2327, + "eloRank": 4, + "point": 50 + }, + { + "phase": 3, + "eloRate": 2618, + "eloRank": 3, + "point": 67 + }, + { + "phase": 4, + "eloRate": 2274, + "eloRank": 26, + "point": 28 + } + ] + }, + "10": { + "last": { + "eloRate": 2100, + "eloRank": 2, + "phasePoint": 0 + }, + "highest": 2100, + "lowest": 1623, + "phases": [] + } + } +} diff --git a/tests/fixtures/versus.json b/tests/fixtures/versus.json new file mode 100644 index 0000000..2ae159e --- /dev/null +++ b/tests/fixtures/versus.json @@ -0,0 +1,36 @@ +{ + "players": [ + { + "uuid": "994f93763f8048bc9e72ee92f861911d", + "nickname": "Couriway", + "roleType": 3, + "eloRate": null, + "eloRank": null, + "country": null + }, + { + "uuid": "9a8e24df4c8549d696a6951da84fa5c4", + "nickname": "Feinberg", + "roleType": 3, + "eloRate": 2100, + "eloRank": 2, + "country": "us" + } + ], + "results": { + "ranked": { + "total": 0, + "994f93763f8048bc9e72ee92f861911d": 0, + "9a8e24df4c8549d696a6951da84fa5c4": 0 + }, + "casual": { + "total": 0, + "994f93763f8048bc9e72ee92f861911d": 0, + "9a8e24df4c8549d696a6951da84fa5c4": 0 + } + }, + "changes": { + "994f93763f8048bc9e72ee92f861911d": 0, + "9a8e24df4c8549d696a6951da84fa5c4": 0 + } +} diff --git a/tests/fixtures/versus_matches.json b/tests/fixtures/versus_matches.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/tests/fixtures/versus_matches.json @@ -0,0 +1 @@ +[] diff --git a/tests/fixtures/weekly_race.json b/tests/fixtures/weekly_race.json new file mode 100644 index 0000000..6af67d0 --- /dev/null +++ b/tests/fixtures/weekly_race.json @@ -0,0 +1,663 @@ +{ + "id": 67, + "seed": { + "overworld": "114826611375830332", + "nether": "114826611375830332", + "theEnd": "114826611375830332", + "rng": "114826611375830332", + "flags": null + }, + "endsAt": 1768176000, + "leaderboard": [ + { + "rank": 1, + "player": { + "uuid": "fe6771646c5d43c1b713023fb69c10c6", + "nickname": "SammmyG", + "roleType": 0, + "eloRate": 1690, + "eloRank": 39, + "country": "au" + }, + "time": 215579, + "replayExist": true + }, + { + "rank": 2, + "player": { + "uuid": "a20541925b5648e1ae88a141ca37911e", + "nickname": "xiamoys", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": "cn" + }, + "time": 216599, + "replayExist": true + }, + { + "rank": 3, + "player": { + "uuid": "ff4c9a27aff84089b5d4b2b268c126fa", + "nickname": "Voitto1", + "roleType": 0, + "eloRate": 1252, + "eloRank": 1054, + "country": "fi" + }, + "time": 245326, + "replayExist": true + }, + { + "rank": 4, + "player": { + "uuid": "1c4ab40e861a4240b828f37e9a85c9d6", + "nickname": "nolettuceplz", + "roleType": 1, + "eloRate": 1388, + "eloRank": 475, + "country": "us" + }, + "time": 286836, + "replayExist": true + }, + { + "rank": 5, + "player": { + "uuid": "8c7208adf2784bacb3715ab657cd80bd", + "nickname": "BinEin", + "roleType": 1, + "eloRate": 1593, + "eloRank": 110, + "country": "pl" + }, + "time": 294733, + "replayExist": true + }, + { + "rank": 6, + "player": { + "uuid": "56a31fff7bee477d9c2f50e9351df00f", + "nickname": "BunchaStuff10", + "roleType": 0, + "eloRate": 1240, + "eloRank": 1124, + "country": null + }, + "time": 302745, + "replayExist": true + }, + { + "rank": 7, + "player": { + "uuid": "f20073faa56b4bce858786361b513b46", + "nickname": "beavery", + "roleType": 1, + "eloRate": 1462, + "eloRank": 284, + "country": "lv" + }, + "time": 338304, + "replayExist": true + }, + { + "rank": 8, + "player": { + "uuid": "04cd27316776491d93820565ba17b59c", + "nickname": "lucas2mason1", + "roleType": 0, + "eloRate": 1242, + "eloRank": 1108, + "country": "us" + }, + "time": 345477, + "replayExist": true + }, + { + "rank": 9, + "player": { + "uuid": "78d2310bb25a424ba285f6f25a1d541a", + "nickname": "IPlayTheTuba", + "roleType": 1, + "eloRate": 1159, + "eloRank": 1836, + "country": null + }, + "time": 351223, + "replayExist": true + }, + { + "rank": 10, + "player": { + "uuid": "cb51bbd142db44cc8282d37cdbfc4b70", + "nickname": "BedrockBaby42", + "roleType": 0, + "eloRate": 1364, + "eloRank": 538, + "country": "au" + }, + "time": 359043, + "replayExist": true + }, + { + "rank": 11, + "player": { + "uuid": "35028dddaaf54c1cbe6ed97679f3a3a4", + "nickname": "r4shi", + "roleType": 0, + "eloRate": 1179, + "eloRank": 1651, + "country": "au" + }, + "time": 371280, + "replayExist": true + }, + { + "rank": 12, + "player": { + "uuid": "e239efd76f4d47e19fc70609080d016b", + "nickname": "SpeZyy", + "roleType": 1, + "eloRate": 1381, + "eloRank": 489, + "country": "gb" + }, + "time": 380423, + "replayExist": true + }, + { + "rank": 13, + "player": { + "uuid": "47f8c678105c4190a3a6fc8799b54949", + "nickname": "KnowerMeh", + "roleType": 1, + "eloRate": 1225, + "eloRank": 1231, + "country": "id" + }, + "time": 381148, + "replayExist": true + }, + { + "rank": 14, + "player": { + "uuid": "1522945053ae4b48b7bce6b2e5f5701e", + "nickname": "mewfea", + "roleType": 0, + "eloRate": 1283, + "eloRank": 869, + "country": "is" + }, + "time": 381724, + "replayExist": true + }, + { + "rank": 15, + "player": { + "uuid": "38be701be7204f5287e84ca0427cc921", + "nickname": "Yeeholly", + "roleType": 0, + "eloRate": 1192, + "eloRank": 1561, + "country": "us" + }, + "time": 389330, + "replayExist": true + }, + { + "rank": 16, + "player": { + "uuid": "3900b06340364d379031628b32bed75f", + "nickname": "pawsomesnuggles", + "roleType": 1, + "eloRate": 1401, + "eloRank": 427, + "country": "us" + }, + "time": 403101, + "replayExist": true + }, + { + "rank": 17, + "player": { + "uuid": "9d9882de330d451ea601b464df0f5dbf", + "nickname": "Everbloom_", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": null + }, + "time": 412098, + "replayExist": true + }, + { + "rank": 18, + "player": { + "uuid": "badc2d085dcd443fbe9757681ec46803", + "nickname": "LucasBort", + "roleType": 0, + "eloRate": 1089, + "eloRank": 2579, + "country": "br" + }, + "time": 418111, + "replayExist": true + }, + { + "rank": 19, + "player": { + "uuid": "0ed3dd0aafb44fc1b6c0efd7ecc2fd46", + "nickname": "guideee", + "roleType": 1, + "eloRate": 1417, + "eloRank": 382, + "country": "th" + }, + "time": 423605, + "replayExist": true + }, + { + "rank": 20, + "player": { + "uuid": "f30876ff9c6344de89e4c175d0fca078", + "nickname": "asuhosus", + "roleType": 1, + "eloRate": null, + "eloRank": null, + "country": null + }, + "time": 428105, + "replayExist": true + }, + { + "rank": 21, + "player": { + "uuid": "0e7749bfc9cf43f180586edea0bf611e", + "nickname": "Jos_13", + "roleType": 0, + "eloRate": 1343, + "eloRank": 604, + "country": "ca" + }, + "time": 431056, + "replayExist": true + }, + { + "rank": 22, + "player": { + "uuid": "f1e2dc89c4a3421f92babf15b4612809", + "nickname": "KochyFlake", + "roleType": 0, + "eloRate": 1096, + "eloRank": 2496, + "country": null + }, + "time": 435686, + "replayExist": true + }, + { + "rank": 23, + "player": { + "uuid": "c6d61aa112ab4c8c89d3c662cd3a08b4", + "nickname": "arranamus", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": null + }, + "time": 437121, + "replayExist": true + }, + { + "rank": 24, + "player": { + "uuid": "fc12adac5fb646ee816e0efcc31bb3e7", + "nickname": "Iqy", + "roleType": 1, + "eloRate": 1069, + "eloRank": 2772, + "country": "gb" + }, + "time": 445924, + "replayExist": true + }, + { + "rank": 25, + "player": { + "uuid": "830dd45cc99143d08d4bc5434ccb6ffc", + "nickname": "ALEXEY_GRACH", + "roleType": 0, + "eloRate": 908, + "eloRank": 4463, + "country": "ru" + }, + "time": 446050, + "replayExist": true + }, + { + "rank": 26, + "player": { + "uuid": "fcf7f0c1f748422ab10f354354d5de42", + "nickname": "Redsippycup", + "roleType": 1, + "eloRate": 1033, + "eloRank": 3171, + "country": "us" + }, + "time": 446429, + "replayExist": true + }, + { + "rank": 27, + "player": { + "uuid": "209a5f8e64734af6b2318148cd1c3b98", + "nickname": "ImDtmined", + "roleType": 0, + "eloRate": 1069, + "eloRank": 2772, + "country": "pl" + }, + "time": 449504, + "replayExist": true + }, + { + "rank": 28, + "player": { + "uuid": "2b5a0c1f5a034004850de4587b402e9b", + "nickname": "linecow", + "roleType": 3, + "eloRate": 1103, + "eloRank": 2410, + "country": "kp" + }, + "time": 458999, + "replayExist": true + }, + { + "rank": 29, + "player": { + "uuid": "429f145802ce43648033264bc5888391", + "nickname": "Juknow", + "roleType": 0, + "eloRate": 1051, + "eloRank": 2975, + "country": "lk" + }, + "time": 461107, + "replayExist": true + }, + { + "rank": 30, + "player": { + "uuid": "b50d96ebcf7e43c19c52ccd1e80d6996", + "nickname": "Bobbi_s", + "roleType": 0, + "eloRate": 1121, + "eloRank": 2192, + "country": null + }, + "time": 467975, + "replayExist": true + }, + { + "rank": 31, + "player": { + "uuid": "cbbf967c0add420e9e2cbe511b3c92ba", + "nickname": "Cyan5616", + "roleType": 0, + "eloRate": 1029, + "eloRank": 3219, + "country": null + }, + "time": 469236, + "replayExist": true + }, + { + "rank": 32, + "player": { + "uuid": "1366dcb1d7cd4d978a95038a577c36da", + "nickname": "GlassTony", + "roleType": 0, + "eloRate": 781, + "eloRank": 5231, + "country": "ca" + }, + "time": 470204, + "replayExist": true + }, + { + "rank": 33, + "player": { + "uuid": "de355d2d5dd146f4b80ee0521cb52d4e", + "nickname": "ItzIndigo_", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": null + }, + "time": 474246, + "replayExist": true + }, + { + "rank": 34, + "player": { + "uuid": "29aa2925fe17464a94b7728ec6085338", + "nickname": "Void__Rumble", + "roleType": 2, + "eloRate": null, + "eloRank": null, + "country": null + }, + "time": 476954, + "replayExist": true + }, + { + "rank": 35, + "player": { + "uuid": "cb7540486b984c77839111ff7fe79a8f", + "nickname": "NeoR_", + "roleType": 2, + "eloRate": null, + "eloRank": null, + "country": null + }, + "time": 477962, + "replayExist": true + }, + { + "rank": 36, + "player": { + "uuid": "d6d94ca6fa9447bab933d5914ad4d440", + "nickname": "KelmoTheElmet", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": null + }, + "time": 482686, + "replayExist": true + }, + { + "rank": 37, + "player": { + "uuid": "23fcc96223a34c76acef58763b20b337", + "nickname": "TheCoolTortoise", + "roleType": 1, + "eloRate": 1138, + "eloRank": 2023, + "country": null + }, + "time": 489796, + "replayExist": true + }, + { + "rank": 38, + "player": { + "uuid": "b88e151a63c7458784d14aeed6dce1e2", + "nickname": "dqqu", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": null + }, + "time": 491984, + "replayExist": true + }, + { + "rank": 39, + "player": { + "uuid": "78b55026bb9b4fe8aad7c99f6286181e", + "nickname": "Max_049", + "roleType": 0, + "eloRate": 794, + "eloRank": 5159, + "country": null + }, + "time": 493149, + "replayExist": true + }, + { + "rank": 40, + "player": { + "uuid": "9a845d2afa96496d9d3f5db9e32b19b2", + "nickname": "Nexilius", + "roleType": 0, + "eloRate": 1036, + "eloRank": 3138, + "country": null + }, + "time": 494232, + "replayExist": true + }, + { + "rank": 41, + "player": { + "uuid": "7c212ebab3b24a0ba346a80531386ee6", + "nickname": "hiitzhunter", + "roleType": 1, + "eloRate": null, + "eloRank": null, + "country": null + }, + "time": 497454, + "replayExist": true + }, + { + "rank": 42, + "player": { + "uuid": "427473e5ce9c43d9b5bf68efae42d3c3", + "nickname": "0ntro", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": "cz" + }, + "time": 497888, + "replayExist": true + }, + { + "rank": 43, + "player": { + "uuid": "2392d73c759644808fe1409fe3b039bd", + "nickname": "Vaqrz", + "roleType": 0, + "eloRate": 1043, + "eloRank": 3059, + "country": null + }, + "time": 500177, + "replayExist": true + }, + { + "rank": 44, + "player": { + "uuid": "254f8e7f98024da1a1dcb9c3c2ab8423", + "nickname": "InfernalParrot", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": null + }, + "time": 504067, + "replayExist": true + }, + { + "rank": 45, + "player": { + "uuid": "65b9a0a2066a4f18b68b936dbdb91a26", + "nickname": "Astro890", + "roleType": 0, + "eloRate": 875, + "eloRank": 4670, + "country": null + }, + "time": 504519, + "replayExist": true + }, + { + "rank": 46, + "player": { + "uuid": "abc036331dc94905b29fee9d8473d678", + "nickname": "LightsOut222", + "roleType": 0, + "eloRate": 1080, + "eloRank": 2677, + "country": "au" + }, + "time": 519863, + "replayExist": true + }, + { + "rank": 47, + "player": { + "uuid": "9bb32b8d243b474cbb4cb7985e41d614", + "nickname": "_lifeline", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": null + }, + "time": 520118, + "replayExist": true + }, + { + "rank": 48, + "player": { + "uuid": "6f3f646ea92e4244aee8fafd7c0f13f8", + "nickname": "sa_Vy", + "roleType": 1, + "eloRate": 1194, + "eloRank": 1555, + "country": "au" + }, + "time": 520588, + "replayExist": true + }, + { + "rank": 49, + "player": { + "uuid": "4ebcd248bb234797ad97c67ee92dc106", + "nickname": "WhaleWaffles938", + "roleType": 0, + "eloRate": null, + "eloRank": null, + "country": "ca" + }, + "time": 521477, + "replayExist": true + }, + { + "rank": 50, + "player": { + "uuid": "fe971915997d4a54a287332177dd95b3", + "nickname": "JustBeyondGlue", + "roleType": 0, + "eloRate": 671, + "eloRank": 6286, + "country": "us" + }, + "time": 523778, + "replayExist": true + } + ] +} diff --git a/tests/test_client.py b/tests/test_client.py index c83006e..c7e1476 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,3 +1,4 @@ +# mypy: disable-error-code="no-untyped-def,misc" """Tests for the client module.""" import httpx diff --git a/tests/test_field_coverage.py b/tests/test_field_coverage.py new file mode 100644 index 0000000..bb30347 --- /dev/null +++ b/tests/test_field_coverage.py @@ -0,0 +1,554 @@ +# mypy: disable-error-code="no-untyped-def" +"""Field coverage tests with isinstance() checks.""" + +from mcsrranked.types.leaderboard import ( + EloLeaderboard, + LeaderboardSeasonResult, + LeaderboardUser, + PhaseInfo, + PhaseLeaderboard, + PhaseLeaderboardUser, + RecordEntry, + SeasonInfo, +) +from mcsrranked.types.live import ( + LiveData, + LiveMatch, + LivePlayerData, + LivePlayerTimeline, +) +from mcsrranked.types.match import ( + Completion, + MatchInfo, + MatchRank, + MatchResult, + Timeline, + VersusResults, + VersusStats, +) +from mcsrranked.types.shared import ( + Achievement, + EloChange, + MatchSeed, + UserProfile, + VodInfo, +) +from mcsrranked.types.user import ( + AchievementsContainer, + Connection, + LastSeasonState, + MatchTypeStats, + PhaseResult, + SeasonResult, + SeasonResultEntry, + SeasonStats, + TotalStats, + User, + UserConnections, + UserSeasons, + UserStatistics, + UserTimestamps, + WeeklyRaceResult, +) +from mcsrranked.types.weekly_race import ( + RaceLeaderboardEntry, + WeeklyRace, + WeeklyRaceSeed, +) + + +class TestUserFieldCoverage: + """Test every field in User and related types.""" + + def test_user_all_fields(self, user_fixture): + """Verify all User fields are accessible.""" + user = User.model_validate(user_fixture) + + # User fields + assert isinstance(user.uuid, str) + assert isinstance(user.nickname, str) + assert isinstance(user.role_type, int) + assert user.elo_rate is None or isinstance(user.elo_rate, int) + assert user.elo_rank is None or isinstance(user.elo_rank, int) + assert user.country is None or isinstance(user.country, str) + assert isinstance(user.achievements, AchievementsContainer) + assert user.timestamp is None or isinstance(user.timestamp, UserTimestamps) + assert isinstance(user.statistics, UserStatistics) + assert isinstance(user.connections, UserConnections) + assert user.season_result is None or isinstance( + user.season_result, SeasonResult + ) + assert isinstance(user.weekly_races, list) + + def test_user_timestamps_all_fields(self, user_fixture): + """Verify all UserTimestamps fields.""" + user = User.model_validate(user_fixture) + ts = user.timestamp + + assert ts is not None + assert isinstance(ts.first_online, int) + assert isinstance(ts.last_online, int) + assert ts.last_ranked is None or isinstance(ts.last_ranked, int) + assert ts.next_decay is None or isinstance(ts.next_decay, int) + + def test_user_statistics_all_fields(self, user_fixture): + """Verify all UserStatistics fields.""" + user = User.model_validate(user_fixture) + stats = user.statistics + + assert isinstance(stats.season, SeasonStats) + assert isinstance(stats.total, TotalStats) + assert isinstance(stats.season.ranked, MatchTypeStats) + assert isinstance(stats.season.casual, MatchTypeStats) + assert isinstance(stats.total.ranked, MatchTypeStats) + assert isinstance(stats.total.casual, MatchTypeStats) + + def test_match_type_stats_all_fields(self, user_fixture): + """Verify all MatchTypeStats fields.""" + user = User.model_validate(user_fixture) + mts = user.statistics.season.ranked + + assert isinstance(mts.played_matches, int) + assert isinstance(mts.wins, int) + assert isinstance(mts.losses, int) + assert isinstance(mts.draws, int) + assert isinstance(mts.forfeits, int) + assert isinstance(mts.highest_winstreak, int) + assert isinstance(mts.current_winstreak, int) + assert isinstance(mts.playtime, int) + assert mts.best_time is None or isinstance(mts.best_time, int) + assert mts.best_time_id is None or isinstance(mts.best_time_id, int) + assert isinstance(mts.completions, int) + + def test_season_result_all_fields(self, user_fixture): + """Verify all SeasonResult fields.""" + user = User.model_validate(user_fixture) + sr = user.season_result + + assert sr is not None + assert isinstance(sr.last, LastSeasonState) + assert sr.highest is None or isinstance(sr.highest, int) + assert sr.lowest is None or isinstance(sr.lowest, int) + assert isinstance(sr.phases, list) + + def test_last_season_state_all_fields(self, user_fixture): + """Verify all LastSeasonState fields.""" + user = User.model_validate(user_fixture) + assert user.season_result is not None + last = user.season_result.last + + assert last.elo_rate is None or isinstance(last.elo_rate, int) + assert last.elo_rank is None or isinstance(last.elo_rank, int) + assert last.phase_point is None or isinstance(last.phase_point, int) + + def test_connection_all_fields(self, user_fixture): + """Verify all Connection fields.""" + user = User.model_validate(user_fixture) + + # Feinberg has discord connected + if user.connections.discord: + assert isinstance(user.connections.discord.id, str) + assert isinstance(user.connections.discord.name, str) + + def test_user_connections_all_fields(self, user_fixture): + """Verify all UserConnections fields.""" + user = User.model_validate(user_fixture) + conn = user.connections + + assert conn.discord is None or isinstance(conn.discord, Connection) + assert conn.twitch is None or isinstance(conn.twitch, Connection) + assert conn.youtube is None or isinstance(conn.youtube, Connection) + + def test_achievements_container_all_fields(self, user_fixture): + """Verify all AchievementsContainer fields.""" + user = User.model_validate(user_fixture) + ach = user.achievements + + assert isinstance(ach.display, list) + assert isinstance(ach.total, list) + + def test_achievement_all_fields(self, user_fixture): + """Verify all Achievement fields.""" + user = User.model_validate(user_fixture) + + if user.achievements.display: + a = user.achievements.display[0] + assert isinstance(a, Achievement) + assert isinstance(a.id, str) + assert isinstance(a.date, int) + assert isinstance(a.data, list) + assert isinstance(a.level, int) + assert a.value is None or isinstance(a.value, int) + assert a.goal is None or isinstance(a.goal, int) + + +class TestUserSeasonsFieldCoverage: + """Test every field in UserSeasons and related types.""" + + def test_user_seasons_all_fields(self, user_seasons_fixture): + """Verify all UserSeasons fields.""" + seasons = UserSeasons.model_validate(user_seasons_fixture) + + assert isinstance(seasons.uuid, str) + assert isinstance(seasons.nickname, str) + assert isinstance(seasons.role_type, int) + assert seasons.elo_rate is None or isinstance(seasons.elo_rate, int) + assert seasons.elo_rank is None or isinstance(seasons.elo_rank, int) + assert seasons.country is None or isinstance(seasons.country, str) + assert isinstance(seasons.season_results, dict) + + def test_season_result_entry_all_fields(self, user_seasons_fixture): + """Verify all SeasonResultEntry fields.""" + seasons = UserSeasons.model_validate(user_seasons_fixture) + + for _season_num, entry in seasons.season_results.items(): + assert isinstance(entry, SeasonResultEntry) + assert isinstance(entry.last, LastSeasonState) + assert entry.highest is None or isinstance(entry.highest, int | float) + assert entry.lowest is None or isinstance(entry.lowest, int | float) + assert isinstance(entry.phases, list) + + +class TestMatchFieldCoverage: + """Test every field in Match and related types.""" + + def test_match_info_all_fields(self, match_detail_fixture): + """Verify all MatchInfo fields.""" + match = MatchInfo.model_validate(match_detail_fixture) + + assert isinstance(match.id, int) + assert isinstance(match.type, int) + assert isinstance(match.season, int) + assert match.category is None or isinstance(match.category, str) + assert isinstance(match.date, int) + assert isinstance(match.players, list) + assert isinstance(match.spectators, list) + assert match.seed is None or isinstance(match.seed, MatchSeed) + assert match.result is None or isinstance(match.result, MatchResult) + assert isinstance(match.forfeited, bool) + assert isinstance(match.decayed, bool) + assert match.rank is None or isinstance(match.rank, MatchRank) + assert isinstance(match.changes, list) + assert match.tag is None or isinstance(match.tag, str) + assert isinstance(match.beginner, bool) + assert isinstance(match.vod, list) + assert isinstance(match.completions, list) + assert isinstance(match.timelines, list) + assert isinstance(match.replay_exist, bool) + + def test_match_result_all_fields(self, match_detail_fixture): + """Verify all MatchResult fields.""" + match = MatchInfo.model_validate(match_detail_fixture) + + if match.result: + assert match.result.uuid is None or isinstance(match.result.uuid, str) + assert isinstance(match.result.time, int) + + def test_match_rank_all_fields(self, match_detail_fixture): + """Verify all MatchRank fields.""" + match = MatchInfo.model_validate(match_detail_fixture) + + if match.rank: + assert match.rank.season is None or isinstance(match.rank.season, int) + assert match.rank.all_time is None or isinstance(match.rank.all_time, int) + + def test_timeline_all_fields(self, match_detail_fixture): + """Verify all Timeline fields.""" + match = MatchInfo.model_validate(match_detail_fixture) + + if match.timelines: + tl = match.timelines[0] + assert isinstance(tl, Timeline) + assert isinstance(tl.uuid, str) + assert isinstance(tl.time, int) + assert isinstance(tl.type, str) + + def test_completion_all_fields(self, match_detail_fixture): + """Verify all Completion fields (from match with completions).""" + match = MatchInfo.model_validate(match_detail_fixture) + + # This match was forfeited so no completions + # Test the type definition instead + if match.completions: + c = match.completions[0] + assert isinstance(c.uuid, str) + assert isinstance(c.time, int) + + def test_elo_change_all_fields(self, match_detail_fixture): + """Verify all EloChange fields.""" + match = MatchInfo.model_validate(match_detail_fixture) + + if match.changes: + ec = match.changes[0] + assert isinstance(ec, EloChange) + assert isinstance(ec.uuid, str) + assert ec.change is None or isinstance(ec.change, int) + assert ec.elo_rate is None or isinstance(ec.elo_rate, int) + + def test_match_seed_all_fields(self, match_detail_fixture): + """Verify all MatchSeed fields.""" + match = MatchInfo.model_validate(match_detail_fixture) + + if match.seed: + s = match.seed + assert s.id is None or isinstance(s.id, str) + assert s.overworld is None or isinstance(s.overworld, str) + assert s.nether is None or isinstance(s.nether, str) + assert s.end_towers is None or isinstance(s.end_towers, list) + assert isinstance(s.variations, list) + # Test the bastion property alias + assert s.bastion == s.nether + + def test_user_profile_all_fields(self, match_detail_fixture): + """Verify all UserProfile fields.""" + match = MatchInfo.model_validate(match_detail_fixture) + + if match.players: + p = match.players[0] + assert isinstance(p.uuid, str) + assert isinstance(p.nickname, str) + assert isinstance(p.role_type, int) + assert p.elo_rate is None or isinstance(p.elo_rate, int) + assert p.elo_rank is None or isinstance(p.elo_rank, int) + assert p.country is None or isinstance(p.country, str) + + +class TestVersusFieldCoverage: + """Test every field in Versus types.""" + + def test_versus_stats_all_fields(self, versus_fixture): + """Verify all VersusStats fields.""" + vs = VersusStats.model_validate(versus_fixture) + + assert isinstance(vs.players, list) + assert isinstance(vs.results, VersusResults) + assert isinstance(vs.changes, dict) + + def test_versus_results_all_fields(self, versus_fixture): + """Verify all VersusResults fields.""" + vs = VersusStats.model_validate(versus_fixture) + + assert isinstance(vs.results.ranked, dict) + assert isinstance(vs.results.casual, dict) + + +class TestLeaderboardFieldCoverage: + """Test every field in Leaderboard types.""" + + def test_elo_leaderboard_all_fields(self, leaderboard_fixture): + """Verify all EloLeaderboard fields.""" + lb = EloLeaderboard.model_validate(leaderboard_fixture) + + assert isinstance(lb.season, SeasonInfo) + assert isinstance(lb.users, list) + + def test_season_info_all_fields(self, leaderboard_fixture): + """Verify all SeasonInfo fields.""" + lb = EloLeaderboard.model_validate(leaderboard_fixture) + + assert isinstance(lb.season.number, int) + assert isinstance(lb.season.starts_at, int) + assert isinstance(lb.season.ends_at, int) + + def test_leaderboard_user_all_fields(self, leaderboard_fixture): + """Verify all LeaderboardUser fields.""" + lb = EloLeaderboard.model_validate(leaderboard_fixture) + + if lb.users: + u = lb.users[0] + assert isinstance(u, LeaderboardUser) + assert isinstance(u.uuid, str) + assert isinstance(u.nickname, str) + assert isinstance(u.role_type, int) + assert u.elo_rate is None or isinstance(u.elo_rate, int) + assert u.elo_rank is None or isinstance(u.elo_rank, int) + assert u.country is None or isinstance(u.country, str) + assert isinstance(u.season_result, LeaderboardSeasonResult) + + def test_leaderboard_season_result_all_fields(self, leaderboard_fixture): + """Verify all LeaderboardSeasonResult fields.""" + lb = EloLeaderboard.model_validate(leaderboard_fixture) + + if lb.users: + sr = lb.users[0].season_result + assert isinstance(sr.elo_rate, int) + assert isinstance(sr.elo_rank, int) + assert isinstance(sr.phase_point, int) + + def test_phase_leaderboard_all_fields(self, phase_leaderboard_fixture): + """Verify all PhaseLeaderboard fields.""" + lb = PhaseLeaderboard.model_validate(phase_leaderboard_fixture) + + assert isinstance(lb.phase, PhaseInfo) + assert isinstance(lb.users, list) + + def test_phase_info_all_fields(self, phase_leaderboard_fixture): + """Verify all PhaseInfo fields.""" + lb = PhaseLeaderboard.model_validate(phase_leaderboard_fixture) + + assert isinstance(lb.phase.season, int) + assert lb.phase.number is None or isinstance(lb.phase.number, int) + assert lb.phase.ends_at is None or isinstance(lb.phase.ends_at, int) + + def test_phase_leaderboard_user_all_fields(self, phase_leaderboard_fixture): + """Verify all PhaseLeaderboardUser fields.""" + lb = PhaseLeaderboard.model_validate(phase_leaderboard_fixture) + + if lb.users: + u = lb.users[0] + assert isinstance(u, PhaseLeaderboardUser) + assert isinstance(u.uuid, str) + assert isinstance(u.nickname, str) + assert isinstance(u.season_result, LeaderboardSeasonResult) + assert isinstance(u.pred_phase_point, int) + + def test_record_entry_all_fields(self, record_leaderboard_fixture): + """Verify all RecordEntry fields.""" + records = [RecordEntry.model_validate(r) for r in record_leaderboard_fixture] + + if records: + r = records[0] + assert isinstance(r.rank, int) + assert isinstance(r.season, int) + assert isinstance(r.date, int) + assert isinstance(r.id, int) + assert isinstance(r.time, int) + assert isinstance(r.user, UserProfile) + assert r.seed is None or isinstance(r.seed, MatchSeed) + + +class TestLiveFieldCoverage: + """Test every field in Live types.""" + + def test_live_data_all_fields(self, live_fixture): + """Verify all LiveData fields.""" + live = LiveData.model_validate(live_fixture) + + assert isinstance(live.players, int) + assert isinstance(live.live_matches, list) + + def test_live_match_all_fields(self, live_fixture): + """Verify all LiveMatch fields.""" + live = LiveData.model_validate(live_fixture) + + if live.live_matches: + m = live.live_matches[0] + assert isinstance(m, LiveMatch) + assert isinstance(m.current_time, int) + assert isinstance(m.players, list) + assert isinstance(m.data, dict) + + def test_live_player_data_all_fields(self, live_fixture): + """Verify all LivePlayerData fields.""" + live = LiveData.model_validate(live_fixture) + + if live.live_matches: + m = live.live_matches[0] + if m.data: + uuid, pd = next(iter(m.data.items())) + assert isinstance(pd, LivePlayerData) + assert pd.live_url is None or isinstance(pd.live_url, str) + assert pd.timeline is None or isinstance( + pd.timeline, LivePlayerTimeline + ) + + def test_live_player_timeline_all_fields(self, live_fixture): + """Verify all LivePlayerTimeline fields.""" + live = LiveData.model_validate(live_fixture) + + # Find a match with a timeline + for m in live.live_matches: + for _uuid, pd in m.data.items(): + if pd.timeline: + assert isinstance(pd.timeline.time, int) + assert isinstance(pd.timeline.type, str) + return + + # If no timeline found, that's OK - it's nullable + + +class TestWeeklyRaceFieldCoverage: + """Test every field in WeeklyRace types.""" + + def test_weekly_race_all_fields(self, weekly_race_fixture): + """Verify all WeeklyRace fields.""" + race = WeeklyRace.model_validate(weekly_race_fixture) + + assert isinstance(race.id, int) + assert isinstance(race.seed, WeeklyRaceSeed) + assert isinstance(race.ends_at, int) + assert isinstance(race.leaderboard, list) + + def test_weekly_race_seed_all_fields(self, weekly_race_fixture): + """Verify all WeeklyRaceSeed fields.""" + race = WeeklyRace.model_validate(weekly_race_fixture) + + # Weekly race uses numeric string seeds, different from match seeds + assert race.seed.overworld is None or isinstance(race.seed.overworld, str) + assert race.seed.nether is None or isinstance(race.seed.nether, str) + assert race.seed.the_end is None or isinstance(race.seed.the_end, str) + assert race.seed.rng is None or isinstance(race.seed.rng, str) + + def test_race_leaderboard_entry_all_fields(self, weekly_race_fixture): + """Verify all RaceLeaderboardEntry fields.""" + race = WeeklyRace.model_validate(weekly_race_fixture) + + if race.leaderboard: + e = race.leaderboard[0] + assert isinstance(e, RaceLeaderboardEntry) + assert isinstance(e.rank, int) + assert isinstance(e.player, UserProfile) + assert isinstance(e.time, int) + assert isinstance(e.replay_exist, bool) + + +class TestVodInfoFieldCoverage: + """Test VodInfo fields - need to find a match with VOD.""" + + def test_vod_info_structure(self): + """Test VodInfo can be constructed with all fields.""" + # VodInfo is rare in the fixtures, so test the model directly + vod = VodInfo(uuid="abc123", url="https://twitch.tv/example", starts_at=12345) + + assert isinstance(vod.uuid, str) + assert isinstance(vod.url, str) + assert isinstance(vod.starts_at, int) + + +class TestWeeklyRaceResultFieldCoverage: + """Test WeeklyRaceResult fields.""" + + def test_weekly_race_result_structure(self): + """Test WeeklyRaceResult can be constructed with all fields.""" + # User.weekly_races is usually empty, so test the model directly + result = WeeklyRaceResult(id=1, time=300000, rank=5) + + assert isinstance(result.id, int) + assert isinstance(result.time, int) + assert isinstance(result.rank, int) + + +class TestPhaseResultFieldCoverage: + """Test PhaseResult fields.""" + + def test_phase_result_structure(self): + """Test PhaseResult can be constructed with all fields.""" + # Phases are often empty, so test the model directly + phase = PhaseResult(phase=1, elo_rate=1500, elo_rank=100, point=50) + + assert isinstance(phase.phase, int) + assert isinstance(phase.elo_rate, int) + assert isinstance(phase.elo_rank, int) + assert isinstance(phase.point, int) + + +class TestCompletionFieldCoverage: + """Test Completion fields.""" + + def test_completion_structure(self): + """Test Completion can be constructed with all fields.""" + # Our fixture match was forfeited, so test the model directly + completion = Completion(uuid="abc123", time=300000) + + assert isinstance(completion.uuid, str) + assert isinstance(completion.time, int) diff --git a/tests/test_parsing.py b/tests/test_parsing.py new file mode 100644 index 0000000..b4d1bb4 --- /dev/null +++ b/tests/test_parsing.py @@ -0,0 +1,455 @@ +# mypy: disable-error-code="no-untyped-def" +"""Value assertion tests using real API fixtures.""" + +from mcsrranked.types.leaderboard import EloLeaderboard, PhaseLeaderboard, RecordEntry +from mcsrranked.types.live import LiveData +from mcsrranked.types.match import MatchInfo, VersusStats +from mcsrranked.types.user import User, UserSeasons +from mcsrranked.types.weekly_race import WeeklyRace + + +class TestUserParsing: + """Test User type parsing from real API response.""" + + def test_user_basic_fields(self, user_fixture): + """Verify basic fields are parsed.""" + user = User.model_validate(user_fixture) + + assert user.uuid == "9a8e24df4c8549d696a6951da84fa5c4" + assert user.nickname == "Feinberg" + assert user.role_type == 3 + assert user.elo_rate == 2100 + assert user.elo_rank == 2 + assert user.country == "us" + + def test_user_statistics_season_ranked(self, user_fixture): + """Verify season stats are parsed (not defaulting to 0).""" + user = User.model_validate(user_fixture) + + # Feinberg has many matches, should not be 0 + assert user.statistics.season.ranked.wins > 0 + assert user.statistics.season.ranked.losses > 0 + assert user.statistics.season.ranked.played_matches > 0 + assert user.statistics.season.ranked.best_time is not None + assert user.statistics.season.ranked.highest_winstreak > 0 + assert user.statistics.season.ranked.playtime > 0 + + # Verify actual values from fixture + assert user.statistics.season.ranked.wins == 57 + assert user.statistics.season.ranked.losses == 15 + assert user.statistics.season.ranked.played_matches == 73 + assert user.statistics.season.ranked.best_time == 408296 + + def test_user_statistics_season_casual(self, user_fixture): + """Verify casual season stats are parsed.""" + user = User.model_validate(user_fixture) + + # Feinberg has 0 casual games this season + assert user.statistics.season.casual.wins == 0 + assert user.statistics.season.casual.losses == 0 + + def test_user_statistics_total_ranked(self, user_fixture): + """Verify total stats are parsed.""" + user = User.model_validate(user_fixture) + + # Feinberg has thousands of matches + assert user.statistics.total.ranked.wins > 100 + assert user.statistics.total.ranked.losses > 100 + assert user.statistics.total.ranked.played_matches > 1000 + + # Verify actual values from fixture + assert user.statistics.total.ranked.wins == 1730 + assert user.statistics.total.ranked.losses == 921 + assert user.statistics.total.ranked.played_matches == 2684 + assert user.statistics.total.ranked.highest_winstreak == 29 + + def test_user_statistics_total_casual(self, user_fixture): + """Verify casual total stats are parsed.""" + user = User.model_validate(user_fixture) + + assert user.statistics.total.casual.wins == 6 + assert user.statistics.total.casual.losses == 4 + assert user.statistics.total.casual.best_time == 552108 + + def test_user_achievements_display(self, user_fixture): + """Verify display achievements are parsed.""" + user = User.model_validate(user_fixture) + + assert len(user.achievements.display) > 0 + + # Check first achievement + ach = user.achievements.display[0] + assert ach.id is not None + assert ach.date > 0 + assert ach.level >= 0 + + def test_user_achievements_total(self, user_fixture): + """Verify total achievements are parsed.""" + user = User.model_validate(user_fixture) + + assert len(user.achievements.total) > 0 + + # Find an achievement with value/goal + achievements_with_values = [ + a for a in user.achievements.total if a.value is not None + ] + assert len(achievements_with_values) > 0 + + # Verify one with value + ach = achievements_with_values[0] + assert ach.value is not None + assert ach.value > 0 + + def test_user_connections(self, user_fixture): + """Verify connections are parsed.""" + user = User.model_validate(user_fixture) + + # Feinberg has Discord, YouTube, and Twitch connected + assert user.connections.discord is not None + assert user.connections.discord.id == "75707773723086848" + assert user.connections.discord.name == "Feinberg#0001" + + assert user.connections.youtube is not None + assert user.connections.youtube.name == "Feinberg" + + assert user.connections.twitch is not None + assert user.connections.twitch.id == "feinberg" + + def test_user_timestamps(self, user_fixture): + """Verify timestamps are parsed.""" + user = User.model_validate(user_fixture) + + assert user.timestamp is not None + assert user.timestamp.first_online > 0 + assert user.timestamp.last_online > 0 + assert user.timestamp.last_ranked is not None + assert user.timestamp.next_decay is not None + + def test_user_season_result(self, user_fixture): + """Verify season result is parsed.""" + user = User.model_validate(user_fixture) + + assert user.season_result is not None + assert user.season_result.last is not None + assert user.season_result.last.elo_rate == 2100 + assert user.season_result.last.elo_rank == 2 + assert user.season_result.highest == 2100 + assert user.season_result.lowest == 1623 + + +class TestUserSeasonsParsing: + """Test UserSeasons type parsing.""" + + def test_user_seasons_basic_fields(self, user_seasons_fixture): + """Verify basic fields are parsed.""" + seasons = UserSeasons.model_validate(user_seasons_fixture) + + assert seasons.uuid is not None + assert seasons.nickname == "Feinberg" + + def test_user_seasons_results(self, user_seasons_fixture): + """Verify season results dict is parsed.""" + seasons = UserSeasons.model_validate(user_seasons_fixture) + + # Should have multiple seasons + assert len(seasons.season_results) > 0 + + # Check a specific season + for _season_num, result in seasons.season_results.items(): + assert result.last is not None + # highest/lowest can be None if no ranked matches that season + if result.highest is not None: + assert isinstance(result.highest, int) + + +class TestMatchParsing: + """Test MatchInfo type parsing.""" + + def test_match_basic_fields(self, match_detail_fixture): + """Verify basic fields are parsed.""" + match = MatchInfo.model_validate(match_detail_fixture) + + assert match.id == 4816894 + assert match.type == 2 # Ranked + assert match.season == 10 + assert match.date > 0 + assert match.category == "ANY" + + def test_match_players(self, match_detail_fixture): + """Verify players are parsed.""" + match = MatchInfo.model_validate(match_detail_fixture) + + assert len(match.players) == 2 + + player = match.players[0] + assert player.uuid is not None + assert player.nickname is not None + assert isinstance(player.role_type, int) + + def test_match_seed_fields(self, match_detail_fixture): + """Verify seed is parsed correctly.""" + match = MatchInfo.model_validate(match_detail_fixture) + + assert match.seed is not None + assert match.seed.id == "m723auzy73cgue8f" + assert match.seed.overworld == "SHIPWRECK" + assert match.seed.nether == "HOUSING" # This was previously broken + assert match.seed.bastion == "HOUSING" # Alias should work + assert match.seed.end_towers is not None + assert len(match.seed.end_towers) == 4 + assert len(match.seed.variations) > 0 + + def test_match_result(self, match_detail_fixture): + """Verify result is parsed.""" + match = MatchInfo.model_validate(match_detail_fixture) + + assert match.result is not None + assert match.result.uuid is not None + assert match.result.time > 0 + + def test_match_changes(self, match_detail_fixture): + """Verify elo changes are parsed.""" + match = MatchInfo.model_validate(match_detail_fixture) + + assert len(match.changes) == 2 + + for change in match.changes: + assert change.uuid is not None + assert change.change is not None + assert change.elo_rate is not None + + def test_match_timelines(self, match_detail_fixture): + """Verify timelines are parsed.""" + match = MatchInfo.model_validate(match_detail_fixture) + + assert len(match.timelines) > 0 + + timeline = match.timelines[0] + assert timeline.uuid is not None + assert timeline.time > 0 + assert timeline.type is not None + + def test_match_forfeited(self, match_detail_fixture): + """Verify forfeited flag is parsed.""" + match = MatchInfo.model_validate(match_detail_fixture) + + assert match.forfeited is True # This match was forfeited + + +class TestMatchListParsing: + """Test parsing list of matches.""" + + def test_matches_list(self, matches_fixture): + """Verify list of matches parses correctly.""" + matches = [MatchInfo.model_validate(m) for m in matches_fixture] + + assert len(matches) == 5 + + for match in matches: + assert match.id > 0 + assert match.type == 2 # All ranked + assert len(match.players) >= 1 + + +class TestVersusStatsParsing: + """Test VersusStats type parsing.""" + + def test_versus_basic_fields(self, versus_fixture): + """Verify basic fields are parsed.""" + versus = VersusStats.model_validate(versus_fixture) + + assert len(versus.players) == 2 + + def test_versus_players(self, versus_fixture): + """Verify players are parsed.""" + versus = VersusStats.model_validate(versus_fixture) + + player_names = {p.nickname for p in versus.players} + assert "Feinberg" in player_names + assert "Couriway" in player_names + + def test_versus_results(self, versus_fixture): + """Verify results are parsed.""" + versus = VersusStats.model_validate(versus_fixture) + + assert "total" in versus.results.ranked + assert "total" in versus.results.casual + + def test_versus_changes(self, versus_fixture): + """Verify changes are parsed.""" + versus = VersusStats.model_validate(versus_fixture) + + # Feinberg vs Couriway have 0 matches so 0 changes + assert len(versus.changes) == 2 + + +class TestLeaderboardParsing: + """Test leaderboard type parsing.""" + + def test_elo_leaderboard_season(self, leaderboard_fixture): + """Verify season info is parsed.""" + lb = EloLeaderboard.model_validate(leaderboard_fixture) + + assert lb.season.number == 10 + assert lb.season.starts_at > 0 + assert lb.season.ends_at > 0 + + def test_elo_leaderboard_users(self, leaderboard_fixture): + """Verify users are parsed.""" + lb = EloLeaderboard.model_validate(leaderboard_fixture) + + assert len(lb.users) > 0 + + # Check top user + top_user = lb.users[0] + assert top_user.uuid is not None + assert top_user.nickname is not None + assert top_user.elo_rate is not None + assert top_user.elo_rank == 1 + assert top_user.season_result is not None + assert top_user.season_result.elo_rate > 0 + + def test_elo_leaderboard_has_feinberg(self, leaderboard_fixture): + """Verify Feinberg is in leaderboard.""" + lb = EloLeaderboard.model_validate(leaderboard_fixture) + + feinberg = next((u for u in lb.users if u.nickname == "Feinberg"), None) + assert feinberg is not None + assert feinberg.elo_rank == 2 + + +class TestPhaseLeaderboardParsing: + """Test phase leaderboard parsing.""" + + def test_phase_leaderboard_phase(self, phase_leaderboard_fixture): + """Verify phase info is parsed.""" + lb = PhaseLeaderboard.model_validate(phase_leaderboard_fixture) + + assert lb.phase.season is not None + + def test_phase_leaderboard_users(self, phase_leaderboard_fixture): + """Verify users are parsed.""" + lb = PhaseLeaderboard.model_validate(phase_leaderboard_fixture) + + if len(lb.users) > 0: + user = lb.users[0] + assert user.uuid is not None + assert user.season_result is not None + + +class TestRecordLeaderboardParsing: + """Test record leaderboard parsing.""" + + def test_record_entries(self, record_leaderboard_fixture): + """Verify record entries are parsed.""" + records = [RecordEntry.model_validate(r) for r in record_leaderboard_fixture] + + assert len(records) > 0 + + record = records[0] + assert record.rank == 1 + assert record.time > 0 + assert record.id > 0 + assert record.user is not None + assert record.user.nickname is not None + + def test_record_seed(self, record_leaderboard_fixture): + """Verify record seed is parsed.""" + records = [RecordEntry.model_validate(r) for r in record_leaderboard_fixture] + + # Find a record with seed + record_with_seed = next((r for r in records if r.seed is not None), None) + if record_with_seed: + assert record_with_seed.seed is not None + assert record_with_seed.seed.overworld is not None + # end_towers can be None for some seeds + if record_with_seed.seed.end_towers is not None: + assert isinstance(record_with_seed.seed.end_towers, list) + + +class TestLiveParsing: + """Test LiveData type parsing.""" + + def test_live_basic_fields(self, live_fixture): + """Verify basic fields are parsed.""" + live = LiveData.model_validate(live_fixture) + + assert live.players > 0 # Should have some concurrent players + assert isinstance(live.live_matches, list) + + def test_live_matches(self, live_fixture): + """Verify live matches are parsed.""" + live = LiveData.model_validate(live_fixture) + + if len(live.live_matches) > 0: + match = live.live_matches[0] + assert match.current_time >= 0 + assert isinstance(match.players, list) + assert isinstance(match.data, dict) + + def test_live_match_players(self, live_fixture): + """Verify live match players are parsed.""" + live = LiveData.model_validate(live_fixture) + + if len(live.live_matches) > 0: + match = live.live_matches[0] + if len(match.players) > 0: + player = match.players[0] + assert player.uuid is not None + assert player.nickname is not None + + def test_live_match_data(self, live_fixture): + """Verify live match data (player timelines) are parsed.""" + live = LiveData.model_validate(live_fixture) + + if len(live.live_matches) > 0: + match = live.live_matches[0] + if match.data: + for _uuid, player_data in match.data.items(): + # live_url can be None or a string + assert player_data.live_url is None or isinstance( + player_data.live_url, str + ) + # timeline can be None or have time/type + if player_data.timeline is not None: + assert player_data.timeline.time >= 0 + assert player_data.timeline.type is not None + + +class TestWeeklyRaceParsing: + """Test WeeklyRace type parsing.""" + + def test_weekly_race_basic_fields(self, weekly_race_fixture): + """Verify basic fields are parsed.""" + race = WeeklyRace.model_validate(weekly_race_fixture) + + assert race.id > 0 + assert race.ends_at > 0 + + def test_weekly_race_seed(self, weekly_race_fixture): + """Verify seed is parsed.""" + race = WeeklyRace.model_validate(weekly_race_fixture) + + assert race.seed is not None + assert race.seed.overworld is not None # Weekly race uses numeric seed strings + + def test_weekly_race_leaderboard(self, weekly_race_fixture): + """Verify leaderboard is parsed.""" + race = WeeklyRace.model_validate(weekly_race_fixture) + + assert len(race.leaderboard) > 0 + + entry = race.leaderboard[0] + assert entry.rank == 1 + assert entry.time > 0 + assert entry.player is not None + assert entry.player.nickname is not None + + def test_weekly_race_leaderboard_players(self, weekly_race_fixture): + """Verify leaderboard player profiles are parsed.""" + race = WeeklyRace.model_validate(weekly_race_fixture) + + for entry in race.leaderboard[:5]: # Check first 5 + assert entry.player.uuid is not None + # elo_rate can be None (placement matches) + # elo_rank can be None diff --git a/tests/test_types.py b/tests/test_types.py new file mode 100644 index 0000000..245732d --- /dev/null +++ b/tests/test_types.py @@ -0,0 +1,184 @@ +# mypy: disable-error-code="no-untyped-def" +"""Unit tests with synthetic data and edge cases.""" + +import pytest + +from mcsrranked.types.shared import MatchSeed +from mcsrranked.types.user import SeasonStats, TotalStats + + +class TestSeasonStatsParsing: + """Test that season stats are correctly parsed from API format.""" + + def test_pivot_stats_from_api_format(self): + """Test parsing API stat-first format to mode-first format.""" + # This is how the API actually returns data + api_data = { + "wins": {"ranked": 55, "casual": 10}, + "loses": {"ranked": 42, "casual": 5}, # Note: API uses 'loses' + "bestTime": {"ranked": 505888, "casual": None}, + "playedMatches": {"ranked": 108, "casual": 15}, + "currentWinStreak": {"ranked": 3, "casual": 0}, + "highestWinStreak": {"ranked": 8, "casual": 2}, + "playtime": {"ranked": 72151968, "casual": 1000000}, + "forfeits": {"ranked": 0, "casual": 1}, + "completions": {"ranked": 40, "casual": 8}, + } + + stats = SeasonStats.model_validate(api_data) + + # Verify ranked stats + assert stats.ranked.wins == 55 + assert stats.ranked.losses == 42 + assert stats.ranked.best_time == 505888 + assert stats.ranked.played_matches == 108 + assert stats.ranked.current_winstreak == 3 + assert stats.ranked.highest_winstreak == 8 + assert stats.ranked.playtime == 72151968 + assert stats.ranked.forfeits == 0 + assert stats.ranked.completions == 40 + + # Verify casual stats + assert stats.casual.wins == 10 + assert stats.casual.losses == 5 + assert stats.casual.best_time is None + assert stats.casual.played_matches == 15 + + def test_already_correct_format_passthrough(self): + """Test that already-correct format is not modified.""" + # This is the format we expect (mode-first) + correct_data = { + "ranked": {"wins": 55, "losses": 42, "best_time": 505888}, + "casual": {"wins": 10, "losses": 5}, + } + + stats = SeasonStats.model_validate(correct_data) + + assert stats.ranked.wins == 55 + assert stats.ranked.losses == 42 + assert stats.casual.wins == 10 + + def test_empty_stats(self): + """Test parsing empty/default stats.""" + stats = SeasonStats.model_validate({}) + + assert stats.ranked.wins == 0 + assert stats.ranked.losses == 0 + assert stats.casual.wins == 0 + + def test_partial_api_data(self): + """Test parsing partial API data.""" + api_data = { + "wins": {"ranked": 10}, + "loses": {"ranked": 5}, + } + + stats = SeasonStats.model_validate(api_data) + + assert stats.ranked.wins == 10 + assert stats.ranked.losses == 5 + assert stats.casual.wins == 0 + + +class TestTotalStatsParsing: + """Test that total stats are correctly parsed from API format.""" + + def test_pivot_stats_from_api_format(self): + """Test parsing API stat-first format to mode-first format.""" + api_data = { + "wins": {"ranked": 3571, "casual": 76}, + "loses": {"ranked": 3238, "casual": 44}, + "bestTime": {"ranked": 503742, "casual": 663441}, + "playedMatches": {"ranked": 7035, "casual": 126}, + } + + stats = TotalStats.model_validate(api_data) + + assert stats.ranked.wins == 3571 + assert stats.ranked.losses == 3238 + assert stats.ranked.best_time == 503742 + assert stats.casual.wins == 76 + assert stats.casual.losses == 44 + + +class TestMatchSeedParsing: + """Test that match seed is correctly parsed.""" + + def test_nether_field(self): + """Test that nether field is parsed correctly.""" + api_data = { + "id": "m723ang1dmwgfu9d", + "overworld": "VILLAGE", + "nether": "STABLES", + "endTowers": [88, 94, 85, 91], + "variations": ["bastion:good_gap:1"], + } + + seed = MatchSeed.model_validate(api_data) + + assert seed.id == "m723ang1dmwgfu9d" + assert seed.overworld == "VILLAGE" + assert seed.nether == "STABLES" + assert seed.bastion == "STABLES" # Alias property + assert seed.end_towers == [88, 94, 85, 91] + + def test_missing_nether(self): + """Test parsing seed without nether field.""" + api_data = { + "id": "test", + "overworld": "VILLAGE", + } + + seed = MatchSeed.model_validate(api_data) + + assert seed.nether is None + assert seed.bastion is None + + def test_null_end_towers(self): + """Test parsing seed with null endTowers (occurs in record leaderboard).""" + api_data: dict[str, object] = { + "id": "test", + "overworld": "VILLAGE", + "nether": "STABLES", + "endTowers": None, + "variations": [], + } + + seed = MatchSeed.model_validate(api_data) + + assert seed.end_towers is None + + +class TestIntegrationWithRealAPI: + """Integration tests that verify parsing works with real API data.""" + + @pytest.mark.asyncio + async def test_user_stats_from_real_api(self): + """Test that user stats are correctly parsed from real API.""" + import mcsrranked + + # TapL is a well-known player with stats + user = mcsrranked.users.get("TapL") + + # Should have non-zero stats (TapL has thousands of matches) + assert ( + user.statistics.season.ranked.wins > 0 + or user.statistics.total.ranked.wins > 0 + ) + assert user.statistics.total.ranked.wins > 100 # TapL has 3500+ wins + + @pytest.mark.asyncio + async def test_match_seed_from_real_api(self): + """Test that match seed is correctly parsed from real API.""" + import mcsrranked + + matches = mcsrranked.matches.list(count=1, type=2) + + if matches: + match = matches[0] + if match.seed: + # Seed should have overworld and nether (bastion) types + assert match.seed.overworld is not None + # nether might be None for some seeds, but the field should exist + assert hasattr(match.seed, "nether") + assert hasattr(match.seed, "bastion")