noxaeapi-sdk 0.4.0__tar.gz → 0.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/PKG-INFO +1 -1
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/pyproject.toml +1 -1
- noxaeapi_sdk-0.4.1/src/noxaeapi_sdk/modules/leaderboard.py +89 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/players.py +19 -1
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/types.py +73 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/leaderboard.py +0 -39
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/LICENSE +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/README.md +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/__init__.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/client.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/errors.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/http_engine.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/__init__.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/economy.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/luckperms.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/misc.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/network.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/network_hub.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/noxauth.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/plugins.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/server.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/skills.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/worlds.py +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/py.typed +0 -0
- {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/socket.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: noxaeapi-sdk
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: Typed Python SDK for the NoxAeApi REST + WebSocket API (Fabric, Bukkit/Spigot/Paper) and the NoxAeApi-Velocity network hub
|
|
5
5
|
Project-URL: Homepage, https://github.com/WumXPro/noxaeapi-sdk
|
|
6
6
|
Project-URL: Documentation, https://noxapi.noxlydev.xyz
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "noxaeapi-sdk"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.1"
|
|
8
8
|
description = "Typed Python SDK for the NoxAeApi REST + WebSocket API (Fabric, Bukkit/Spigot/Paper) and the NoxAeApi-Velocity network hub"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import urllib.parse
|
|
4
|
+
from typing import List, Optional, Sequence
|
|
5
|
+
|
|
6
|
+
from ..http_engine import HttpEngine
|
|
7
|
+
from ..types import (
|
|
8
|
+
LeaderboardEntry,
|
|
9
|
+
LeaderboardSourceInfo,
|
|
10
|
+
PlayerProfile,
|
|
11
|
+
PlayerProfilesResponse,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _q(value: str) -> str:
|
|
16
|
+
return urllib.parse.quote(value, safe="")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class LeaderboardModule:
|
|
20
|
+
"""Wraps the generic, pluggable ``/v1/leaderboards/*`` routes.
|
|
21
|
+
|
|
22
|
+
This is a unified view over every ranking source registered on the
|
|
23
|
+
server — economy currencies, mcMMO power level, AuraSkills power
|
|
24
|
+
level, etc — so you don't need to know ahead of time which plugins
|
|
25
|
+
are installed.
|
|
26
|
+
|
|
27
|
+
Use :meth:`list` to discover available source IDs, then pass one to
|
|
28
|
+
:meth:`get_top`. Sources that are registered but currently
|
|
29
|
+
unavailable (e.g. the backing plugin isn't loaded) raise
|
|
30
|
+
``NoxAeApiError`` with the source's own unavailable status (424 for
|
|
31
|
+
economy currencies, 503 for mcMMO/AuraSkills) when you call
|
|
32
|
+
:meth:`get_top`.
|
|
33
|
+
|
|
34
|
+
This module also wraps the player-profile routes
|
|
35
|
+
(``/v1/players/{uuid}/profile`` and ``/v1/players/profiles``), which live
|
|
36
|
+
server-side alongside the leaderboard sources since they're built on top
|
|
37
|
+
of them.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, http: HttpEngine) -> None:
|
|
41
|
+
self._http = http
|
|
42
|
+
|
|
43
|
+
def list(self) -> List[LeaderboardSourceInfo]:
|
|
44
|
+
"""List every registered leaderboard source and its availability."""
|
|
45
|
+
return self._http.request("GET", "leaderboards")
|
|
46
|
+
|
|
47
|
+
def get_top(self, id: str, limit: Optional[int] = None) -> List[LeaderboardEntry]:
|
|
48
|
+
"""Get ranked entries for one leaderboard source (see :meth:`list` for valid IDs)."""
|
|
49
|
+
return self._http.request("GET", f"leaderboards/{_q(id)}/top", query={"limit": limit})
|
|
50
|
+
|
|
51
|
+
def get_player_profile(self, uuid: str) -> PlayerProfile:
|
|
52
|
+
"""One-call player profile: identity, whitelist/ban status, Vault balance,
|
|
53
|
+
and this player's entry in every registered leaderboard source. Built so
|
|
54
|
+
clients never have to know how many leaderboard sources exist or scan
|
|
55
|
+
top-N lists themselves.
|
|
56
|
+
|
|
57
|
+
Raises ``NoxAeApiNotFoundError`` if no known player with that UUID has
|
|
58
|
+
ever joined.
|
|
59
|
+
"""
|
|
60
|
+
return self._http.request("GET", f"players/{_q(uuid)}/profile")
|
|
61
|
+
|
|
62
|
+
def get_player_profiles(
|
|
63
|
+
self,
|
|
64
|
+
*,
|
|
65
|
+
uuids: Optional[Sequence[str]] = None,
|
|
66
|
+
page: Optional[int] = None,
|
|
67
|
+
limit: Optional[int] = None,
|
|
68
|
+
online_only: Optional[bool] = None,
|
|
69
|
+
) -> PlayerProfilesResponse:
|
|
70
|
+
"""Bulk player profiles — same shape as :meth:`get_player_profile`, for many
|
|
71
|
+
players at once. Computes each leaderboard source's full ranking exactly
|
|
72
|
+
once for the whole batch rather than once per player, so this is far
|
|
73
|
+
cheaper than calling :meth:`get_player_profile` in a loop.
|
|
74
|
+
|
|
75
|
+
Pass ``uuids`` to fetch an exact, specific set of players — unknown UUIDs
|
|
76
|
+
are silently skipped rather than raising. Omit ``uuids`` to page through
|
|
77
|
+
every known player instead, using ``page``/``limit``, optionally narrowed
|
|
78
|
+
to only currently-online players via ``online_only``.
|
|
79
|
+
"""
|
|
80
|
+
return self._http.request(
|
|
81
|
+
"GET",
|
|
82
|
+
"players/profiles",
|
|
83
|
+
query={
|
|
84
|
+
"uuids": ",".join(uuids) if uuids else None,
|
|
85
|
+
"page": page,
|
|
86
|
+
"limit": limit,
|
|
87
|
+
"onlineOnly": online_only,
|
|
88
|
+
},
|
|
89
|
+
)
|
|
@@ -4,7 +4,14 @@ import urllib.parse
|
|
|
4
4
|
from typing import Any, Dict, List, Optional, Union
|
|
5
5
|
|
|
6
6
|
from ..http_engine import HttpEngine
|
|
7
|
-
from ..types import
|
|
7
|
+
from ..types import (
|
|
8
|
+
Gamemode,
|
|
9
|
+
InventoryItem,
|
|
10
|
+
OfflinePlayer,
|
|
11
|
+
OnlinePlayer,
|
|
12
|
+
PlayerResolveResult,
|
|
13
|
+
PlayerStats,
|
|
14
|
+
)
|
|
8
15
|
|
|
9
16
|
|
|
10
17
|
def _q(value: str) -> str:
|
|
@@ -27,6 +34,17 @@ class PlayersModule:
|
|
|
27
34
|
"""Get a single player by UUID (works for online or offline players)."""
|
|
28
35
|
return self._http.request("GET", f"players/{_q(uuid)}")
|
|
29
36
|
|
|
37
|
+
def resolve(self, name: str) -> PlayerResolveResult:
|
|
38
|
+
"""Resolve a player name to their UUID using the server's own local player cache.
|
|
39
|
+
|
|
40
|
+
Works on both online-mode and offline-mode servers, unlike Mojang's public
|
|
41
|
+
API - the UUID returned matches whatever this server actually uses for that
|
|
42
|
+
player's stats/economy/etc. Checks currently online players first, then
|
|
43
|
+
falls back to the server's offline player cache. Raises
|
|
44
|
+
``NoxAeApiNotFoundError`` if no known player with that name has ever joined.
|
|
45
|
+
"""
|
|
46
|
+
return self._http.request("GET", f"players/resolve/{_q(name)}")
|
|
47
|
+
|
|
30
48
|
def get_inventory(self, player_uuid: str, world_uuid: str) -> List[InventoryItem]:
|
|
31
49
|
"""Get a player's inventory in a specific world."""
|
|
32
50
|
return self._http.request("GET", f"players/{_q(player_uuid)}/{_q(world_uuid)}/inventory")
|
|
@@ -45,6 +45,13 @@ class OfflinePlayer(TypedDict):
|
|
|
45
45
|
lastPlayed: int
|
|
46
46
|
|
|
47
47
|
|
|
48
|
+
class PlayerResolveResult(TypedDict):
|
|
49
|
+
"""Result of resolving a player name to their UUID via ``GET /players/resolve/{name}``."""
|
|
50
|
+
|
|
51
|
+
name: str
|
|
52
|
+
uuid: str
|
|
53
|
+
|
|
54
|
+
|
|
48
55
|
class ServerHealth(TypedDict):
|
|
49
56
|
cpus: int
|
|
50
57
|
uptime: int
|
|
@@ -221,6 +228,72 @@ class LeaderboardEntry(TypedDict):
|
|
|
221
228
|
value: float
|
|
222
229
|
|
|
223
230
|
|
|
231
|
+
class PlayerProfileBan(TypedDict, total=False):
|
|
232
|
+
"""Ban details for a player, as reported by ``GET /v1/players/{uuid}/profile``'s ``status.ban``."""
|
|
233
|
+
|
|
234
|
+
banned: bool
|
|
235
|
+
reason: str
|
|
236
|
+
"""Only present when ``banned`` is true."""
|
|
237
|
+
source: str
|
|
238
|
+
"""Only present when ``banned`` is true."""
|
|
239
|
+
created: str
|
|
240
|
+
"""Only present when ``banned`` is true. Serialized server-side as a locale-formatted date string, not ISO-8601."""
|
|
241
|
+
expires: Optional[str]
|
|
242
|
+
"""Only present when ``banned`` is true. ``None``/absent means a permanent ban. Same date-string format as ``created``."""
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class PlayerProfileStatus(TypedDict):
|
|
246
|
+
"""Whitelist + ban status for a player, as reported by ``GET /v1/players/{uuid}/profile``'s ``status`` field."""
|
|
247
|
+
|
|
248
|
+
whitelisted: bool
|
|
249
|
+
ban: PlayerProfileBan
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class PlayerProfileEconomy(TypedDict, total=False):
|
|
253
|
+
"""Vault economy info for a player, as reported by ``GET /v1/players/{uuid}/profile``'s ``economy`` field.
|
|
254
|
+
|
|
255
|
+
Single-currency (Vault), not ExcellentEconomy's multi-currency system - see
|
|
256
|
+
:meth:`EconomyModule.get_currency_balance` for that.
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
available: bool
|
|
260
|
+
balance: float
|
|
261
|
+
"""Only present when ``available`` is true."""
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
class PlayerProfileStatTile(TypedDict, total=False):
|
|
265
|
+
"""One leaderboard source's contribution to a player profile's ``stats`` array."""
|
|
266
|
+
|
|
267
|
+
id: str
|
|
268
|
+
label: str
|
|
269
|
+
status: Literal["ranked", "not_ranked", "unavailable"]
|
|
270
|
+
value: float
|
|
271
|
+
"""Only present when ``status`` is "ranked"."""
|
|
272
|
+
rank: int
|
|
273
|
+
"""Only present when ``status`` is "ranked" and the source reports a positive rank."""
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
class PlayerProfile(TypedDict):
|
|
277
|
+
"""One-call player profile combining identity, whitelist/ban status, Vault balance, and this
|
|
278
|
+
player's entry in every registered leaderboard source. Returned by
|
|
279
|
+
``GET /v1/players/{uuid}/profile`` and (as the ``players`` array) by ``GET /v1/players/profiles``.
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
name: Optional[str]
|
|
283
|
+
uuid: str
|
|
284
|
+
online: bool
|
|
285
|
+
status: PlayerProfileStatus
|
|
286
|
+
economy: PlayerProfileEconomy
|
|
287
|
+
stats: List[PlayerProfileStatTile]
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
class PlayerProfilesResponse(TypedDict):
|
|
291
|
+
"""Response shape of ``GET /v1/players/profiles`` (bulk player profiles)."""
|
|
292
|
+
|
|
293
|
+
count: int
|
|
294
|
+
players: List[PlayerProfile]
|
|
295
|
+
|
|
296
|
+
|
|
224
297
|
class NetworkServerStatus(TypedDict):
|
|
225
298
|
id: str
|
|
226
299
|
label: str
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import urllib.parse
|
|
4
|
-
from typing import List, Optional
|
|
5
|
-
|
|
6
|
-
from ..http_engine import HttpEngine
|
|
7
|
-
from ..types import LeaderboardEntry, LeaderboardSourceInfo
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def _q(value: str) -> str:
|
|
11
|
-
return urllib.parse.quote(value, safe="")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class LeaderboardModule:
|
|
15
|
-
"""Wraps the generic, pluggable ``/v1/leaderboards/*`` routes.
|
|
16
|
-
|
|
17
|
-
This is a unified view over every ranking source registered on the
|
|
18
|
-
server — economy currencies, mcMMO power level, AuraSkills power
|
|
19
|
-
level, etc — so you don't need to know ahead of time which plugins
|
|
20
|
-
are installed.
|
|
21
|
-
|
|
22
|
-
Use :meth:`list` to discover available source IDs, then pass one to
|
|
23
|
-
:meth:`get_top`. Sources that are registered but currently
|
|
24
|
-
unavailable (e.g. the backing plugin isn't loaded) raise
|
|
25
|
-
``NoxAeApiError`` with the source's own unavailable status (424 for
|
|
26
|
-
economy currencies, 503 for mcMMO/AuraSkills) when you call
|
|
27
|
-
:meth:`get_top`.
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
def __init__(self, http: HttpEngine) -> None:
|
|
31
|
-
self._http = http
|
|
32
|
-
|
|
33
|
-
def list(self) -> List[LeaderboardSourceInfo]:
|
|
34
|
-
"""List every registered leaderboard source and its availability."""
|
|
35
|
-
return self._http.request("GET", "leaderboards")
|
|
36
|
-
|
|
37
|
-
def get_top(self, id: str, limit: Optional[int] = None) -> List[LeaderboardEntry]:
|
|
38
|
-
"""Get ranked entries for one leaderboard source (see :meth:`list` for valid IDs)."""
|
|
39
|
-
return self._http.request("GET", f"leaderboards/{_q(id)}/top", query={"limit": limit})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|