rlstatsapi 0.1.2__tar.gz → 0.1.3__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.
@@ -0,0 +1,194 @@
1
+ Metadata-Version: 2.4
2
+ Name: rlstatsapi
3
+ Version: 0.1.3
4
+ Summary: Rocket League Stats API client
5
+ Author: Manuel Cabral
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/manucabral/RocketLeagueStatsAPI
8
+ Project-URL: Repository, https://github.com/manucabral/RocketLeagueStatsAPI
9
+ Project-URL: Bug Tracker, https://github.com/manucabral/RocketLeagueStatsAPI/issues
10
+ Keywords: rocket-league,stats,socket,asyncio
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Topic :: Games/Entertainment
16
+ Classifier: Topic :: Software Development :: Libraries
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest>=8; extra == "dev"
22
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
23
+ Dynamic: license-file
24
+
25
+ # Rocket League Stats API
26
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![PyPI version](https://img.shields.io/pypi/v/rlstatsapi.svg)](https://pypi.org/project/rlstatsapi/) [![Pylint](https://github.com/manucabral/RocketLeagueStatsAPI/actions/workflows/pylint.yml/badge.svg)](https://github.com/manucabral/RocketLeagueStatsAPI/actions/workflows/pylint.yml)
27
+
28
+ `rlstatsapi` is a simple and fast Python client for reading live Rocket League Stats API events over a local TCP socket.
29
+
30
+ [Click here for full documentation](https://manucabral.github.io/RocketLeagueStatsAPI/)
31
+
32
+
33
+ ## Install
34
+
35
+ From PyPI:
36
+
37
+ ```bash
38
+ pip install rlstatsapi
39
+ ```
40
+
41
+ From GitHub (latest `main`):
42
+
43
+ ```bash
44
+ pip install git+https://github.com/manucabral/RocketLeagueStatsAPI.git
45
+ ```
46
+
47
+ ## Rocket League setup
48
+
49
+ Before launching Rocket League, edit:
50
+
51
+ `<Install Dir>\TAGame\Config\DefaultStatsAPI.ini`
52
+
53
+ Use at least:
54
+
55
+ - `PacketSendRate=30` (any value `> 0` enables the exporter)
56
+ - `Port=49123`
57
+
58
+ Restart the game after changing the file.
59
+
60
+ ## Quick start
61
+
62
+ ```python
63
+ import asyncio
64
+ from rlstatsapi import StatsClient
65
+
66
+ async def main() -> None:
67
+ async with StatsClient() as client:
68
+ client.on_any(lambda msg: print(msg.event, msg.data))
69
+ await asyncio.Event().wait()
70
+
71
+ asyncio.run(main())
72
+ ```
73
+
74
+ ## Demos
75
+ <img width="800" height="411" alt="allevents" src="https://github.com/manucabral/RocketLeagueStatsAPI/blob/main/docs/videos/allevents.gif" />
76
+ <img width="800" height="411" alt="ui" src="https://github.com/manucabral/RocketLeagueStatsAPI/blob/main/docs/videos/ui.gif" />
77
+
78
+
79
+ ## Typed event handlers
80
+
81
+ Every known event has a typed convenience method. No manual casting needed.
82
+
83
+ ```python
84
+ import asyncio
85
+ from rlstatsapi import StatsClient, TypedEventMessage, GoalScoredPayload
86
+
87
+ async def on_goal(msg: TypedEventMessage[GoalScoredPayload]) -> None:
88
+ scorer = msg.data.get("Scorer", {})
89
+ speed = msg.data.get("GoalSpeed", 0.0)
90
+ print(f"Goal by {scorer.get('Name')} at {speed:.0f} km/h")
91
+
92
+ async def main() -> None:
93
+ async with StatsClient() as client:
94
+ client.on_goal_scored(on_goal)
95
+ await asyncio.Event().wait()
96
+
97
+ asyncio.run(main())
98
+ ```
99
+
100
+ The decorator form of `on()` is also supported:
101
+
102
+ ```python
103
+ @client.on("GoalScored")
104
+ async def on_goal(msg: TypedEventMessage[GoalScoredPayload]) -> None:
105
+ ...
106
+ ```
107
+
108
+ ## Connection events
109
+
110
+ ```python
111
+ client.on_connect(lambda: print("Connected"))
112
+ client.on_disconnect(lambda: print("Disconnected"))
113
+ ```
114
+
115
+ ## Error handling
116
+
117
+ ```python
118
+ def on_error(event_name: str, exc: Exception) -> None:
119
+ print(f"Handler error for {event_name}: {exc}")
120
+
121
+ client.on_handler_error(on_error)
122
+ ```
123
+
124
+ Without a registered error handler, exceptions log at `ERROR` level automatically.
125
+
126
+ ## Handler deregistration
127
+
128
+ ```python
129
+ client.off("GoalScored", my_handler)
130
+ client.off_any(my_handler)
131
+
132
+ # Fire once then auto-remove
133
+ client.once("MatchCreated", lambda msg: print("Match started"))
134
+ ```
135
+
136
+ ## Logging
137
+
138
+ Use the standard `logging` module, no library-specific flags needed:
139
+
140
+ ```python
141
+ import logging
142
+ logging.getLogger("rlstatsapi").setLevel(logging.DEBUG)
143
+ ```
144
+
145
+ ## `StatsClient` parameters
146
+
147
+ | Parameter | Default | Description |
148
+ |---|---|---|
149
+ | `host` | `"127.0.0.1"` | TCP host |
150
+ | `port` | `49123` | TCP port |
151
+ | `reconnect` | `True` | Auto-reconnect on drop |
152
+ | `reconnect_delay` | `0.5` | Initial reconnect delay (s) |
153
+ | `max_reconnect_delay` | `30.0` | Backoff cap (s) |
154
+ | `max_reconnect_attempts` | `None` | Max retries (`None` = infinite) |
155
+ | `connect_timeout` | `5.0` | TCP connect timeout (s) |
156
+ | `include_raw` | `False` | Include raw JSON string in `EventMessage.raw` |
157
+ | `queue_size` | `2048` | Internal event queue size |
158
+ | `overflow` | `"block"` | Queue-full policy: `"block"` / `"drop"` / `"raise"` |
159
+
160
+
161
+ ## `is_connected`
162
+
163
+ ```python
164
+ print(client.is_connected) # True once TCP is established
165
+ ```
166
+
167
+ ## Public API
168
+
169
+ **Registration:**
170
+ `on(event_name, handler)` · `on_any(handler)` · `on_<event>(handler)` · `on_connect(handler)` · `on_disconnect(handler)` · `on_handler_error(handler)`
171
+
172
+ **Deregistration:**
173
+ `off(event_name, handler)` · `off_any(handler)` · `once(event_name, handler)`
174
+
175
+ **Lifecycle:**
176
+ `connect()` · `disconnect()` · `async with StatsClient()`
177
+
178
+ **Async iteration:**
179
+ `events()` async iterator yielding `EventMessage`
180
+
181
+ **Types:**
182
+ `EventName` · `TypedEventMessage[T]` · `KnownEventMessage` · per-event payload types (`GoalScoredPayload`, `UpdateStatePayload`, …)
183
+
184
+ ## Notes
185
+
186
+ - Works for regular matches. Some fields like `MatchGuid` are only present in online/LAN contexts.
187
+ - In current builds this endpoint may behave as a plain TCP JSON stream instead of a WebSocket upgrade. This library handles the TCP stream format.
188
+
189
+ ## Disclaimer
190
+
191
+ This project is an independent, community-made library and is **not affiliated with, endorsed by, or sponsored by Psyonix or Epic Games**.
192
+
193
+ Rocket League and related trademarks are the property of their respective owners.
194
+ Use this library at your own risk and in compliance with Rocket League’s terms and policies.
@@ -0,0 +1,170 @@
1
+ # Rocket League Stats API
2
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![PyPI version](https://img.shields.io/pypi/v/rlstatsapi.svg)](https://pypi.org/project/rlstatsapi/) [![Pylint](https://github.com/manucabral/RocketLeagueStatsAPI/actions/workflows/pylint.yml/badge.svg)](https://github.com/manucabral/RocketLeagueStatsAPI/actions/workflows/pylint.yml)
3
+
4
+ `rlstatsapi` is a simple and fast Python client for reading live Rocket League Stats API events over a local TCP socket.
5
+
6
+ [Click here for full documentation](https://manucabral.github.io/RocketLeagueStatsAPI/)
7
+
8
+
9
+ ## Install
10
+
11
+ From PyPI:
12
+
13
+ ```bash
14
+ pip install rlstatsapi
15
+ ```
16
+
17
+ From GitHub (latest `main`):
18
+
19
+ ```bash
20
+ pip install git+https://github.com/manucabral/RocketLeagueStatsAPI.git
21
+ ```
22
+
23
+ ## Rocket League setup
24
+
25
+ Before launching Rocket League, edit:
26
+
27
+ `<Install Dir>\TAGame\Config\DefaultStatsAPI.ini`
28
+
29
+ Use at least:
30
+
31
+ - `PacketSendRate=30` (any value `> 0` enables the exporter)
32
+ - `Port=49123`
33
+
34
+ Restart the game after changing the file.
35
+
36
+ ## Quick start
37
+
38
+ ```python
39
+ import asyncio
40
+ from rlstatsapi import StatsClient
41
+
42
+ async def main() -> None:
43
+ async with StatsClient() as client:
44
+ client.on_any(lambda msg: print(msg.event, msg.data))
45
+ await asyncio.Event().wait()
46
+
47
+ asyncio.run(main())
48
+ ```
49
+
50
+ ## Demos
51
+ <img width="800" height="411" alt="allevents" src="https://github.com/manucabral/RocketLeagueStatsAPI/blob/main/docs/videos/allevents.gif" />
52
+ <img width="800" height="411" alt="ui" src="https://github.com/manucabral/RocketLeagueStatsAPI/blob/main/docs/videos/ui.gif" />
53
+
54
+
55
+ ## Typed event handlers
56
+
57
+ Every known event has a typed convenience method. No manual casting needed.
58
+
59
+ ```python
60
+ import asyncio
61
+ from rlstatsapi import StatsClient, TypedEventMessage, GoalScoredPayload
62
+
63
+ async def on_goal(msg: TypedEventMessage[GoalScoredPayload]) -> None:
64
+ scorer = msg.data.get("Scorer", {})
65
+ speed = msg.data.get("GoalSpeed", 0.0)
66
+ print(f"Goal by {scorer.get('Name')} at {speed:.0f} km/h")
67
+
68
+ async def main() -> None:
69
+ async with StatsClient() as client:
70
+ client.on_goal_scored(on_goal)
71
+ await asyncio.Event().wait()
72
+
73
+ asyncio.run(main())
74
+ ```
75
+
76
+ The decorator form of `on()` is also supported:
77
+
78
+ ```python
79
+ @client.on("GoalScored")
80
+ async def on_goal(msg: TypedEventMessage[GoalScoredPayload]) -> None:
81
+ ...
82
+ ```
83
+
84
+ ## Connection events
85
+
86
+ ```python
87
+ client.on_connect(lambda: print("Connected"))
88
+ client.on_disconnect(lambda: print("Disconnected"))
89
+ ```
90
+
91
+ ## Error handling
92
+
93
+ ```python
94
+ def on_error(event_name: str, exc: Exception) -> None:
95
+ print(f"Handler error for {event_name}: {exc}")
96
+
97
+ client.on_handler_error(on_error)
98
+ ```
99
+
100
+ Without a registered error handler, exceptions log at `ERROR` level automatically.
101
+
102
+ ## Handler deregistration
103
+
104
+ ```python
105
+ client.off("GoalScored", my_handler)
106
+ client.off_any(my_handler)
107
+
108
+ # Fire once then auto-remove
109
+ client.once("MatchCreated", lambda msg: print("Match started"))
110
+ ```
111
+
112
+ ## Logging
113
+
114
+ Use the standard `logging` module, no library-specific flags needed:
115
+
116
+ ```python
117
+ import logging
118
+ logging.getLogger("rlstatsapi").setLevel(logging.DEBUG)
119
+ ```
120
+
121
+ ## `StatsClient` parameters
122
+
123
+ | Parameter | Default | Description |
124
+ |---|---|---|
125
+ | `host` | `"127.0.0.1"` | TCP host |
126
+ | `port` | `49123` | TCP port |
127
+ | `reconnect` | `True` | Auto-reconnect on drop |
128
+ | `reconnect_delay` | `0.5` | Initial reconnect delay (s) |
129
+ | `max_reconnect_delay` | `30.0` | Backoff cap (s) |
130
+ | `max_reconnect_attempts` | `None` | Max retries (`None` = infinite) |
131
+ | `connect_timeout` | `5.0` | TCP connect timeout (s) |
132
+ | `include_raw` | `False` | Include raw JSON string in `EventMessage.raw` |
133
+ | `queue_size` | `2048` | Internal event queue size |
134
+ | `overflow` | `"block"` | Queue-full policy: `"block"` / `"drop"` / `"raise"` |
135
+
136
+
137
+ ## `is_connected`
138
+
139
+ ```python
140
+ print(client.is_connected) # True once TCP is established
141
+ ```
142
+
143
+ ## Public API
144
+
145
+ **Registration:**
146
+ `on(event_name, handler)` · `on_any(handler)` · `on_<event>(handler)` · `on_connect(handler)` · `on_disconnect(handler)` · `on_handler_error(handler)`
147
+
148
+ **Deregistration:**
149
+ `off(event_name, handler)` · `off_any(handler)` · `once(event_name, handler)`
150
+
151
+ **Lifecycle:**
152
+ `connect()` · `disconnect()` · `async with StatsClient()`
153
+
154
+ **Async iteration:**
155
+ `events()` async iterator yielding `EventMessage`
156
+
157
+ **Types:**
158
+ `EventName` · `TypedEventMessage[T]` · `KnownEventMessage` · per-event payload types (`GoalScoredPayload`, `UpdateStatePayload`, …)
159
+
160
+ ## Notes
161
+
162
+ - Works for regular matches. Some fields like `MatchGuid` are only present in online/LAN contexts.
163
+ - In current builds this endpoint may behave as a plain TCP JSON stream instead of a WebSocket upgrade. This library handles the TCP stream format.
164
+
165
+ ## Disclaimer
166
+
167
+ This project is an independent, community-made library and is **not affiliated with, endorsed by, or sponsored by Psyonix or Epic Games**.
168
+
169
+ Rocket League and related trademarks are the property of their respective owners.
170
+ Use this library at your own risk and in compliance with Rocket League’s terms and policies.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rlstatsapi"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "Rocket League Stats API client"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -22,9 +22,21 @@ classifiers = [
22
22
 
23
23
  [project.urls]
24
24
  Homepage = "https://github.com/manucabral/RocketLeagueStatsAPI"
25
+ Repository = "https://github.com/manucabral/RocketLeagueStatsAPI"
26
+ "Bug Tracker" = "https://github.com/manucabral/RocketLeagueStatsAPI/issues"
27
+
28
+ [project.optional-dependencies]
29
+ dev = ["pytest>=8", "pytest-asyncio>=0.23"]
30
+
31
+ [tool.pytest.ini_options]
32
+ asyncio_mode = "auto"
33
+ testpaths = ["tests"]
25
34
 
26
35
  [tool.setuptools]
27
36
  package-dir = {"" = "src"}
28
37
 
29
38
  [tool.setuptools.packages.find]
30
39
  where = ["src"]
40
+
41
+ [tool.setuptools.package-data]
42
+ rlstatsapi = ["py.typed"]
@@ -0,0 +1,68 @@
1
+ """rlstatsapi public API."""
2
+
3
+ from importlib.metadata import PackageNotFoundError
4
+ from importlib.metadata import version as _pkg_version
5
+
6
+ from .client import StatsClient
7
+ from .events import KNOWN_EVENTS
8
+ from .models import EventMessage
9
+ from .types import (
10
+ BallHitPayload,
11
+ ClockUpdatedSecondsPayload,
12
+ CountdownBeginPayload,
13
+ CrossbarHitPayload,
14
+ EventName,
15
+ GoalReplayEndPayload,
16
+ GoalReplayStartPayload,
17
+ GoalReplayWillEndPayload,
18
+ GoalScoredPayload,
19
+ KnownEventMessage,
20
+ MatchCreatedPayload,
21
+ MatchDestroyedPayload,
22
+ MatchEndedPayload,
23
+ MatchInitializedPayload,
24
+ MatchPausedPayload,
25
+ MatchUnpausedPayload,
26
+ PodiumStartPayload,
27
+ ReplayCreatedPayload,
28
+ RoundStartedPayload,
29
+ StatfeedEventPayload,
30
+ TypedEventMessage,
31
+ UpdateStatePayload,
32
+ cast_event_data,
33
+ )
34
+
35
+ try:
36
+ __version__: str = _pkg_version("rlstatsapi")
37
+ except PackageNotFoundError:
38
+ __version__ = "unknown"
39
+
40
+ __all__ = [
41
+ "__version__",
42
+ "StatsClient",
43
+ "EventMessage",
44
+ "KNOWN_EVENTS",
45
+ "EventName",
46
+ "TypedEventMessage",
47
+ "KnownEventMessage",
48
+ "UpdateStatePayload",
49
+ "BallHitPayload",
50
+ "ClockUpdatedSecondsPayload",
51
+ "CountdownBeginPayload",
52
+ "CrossbarHitPayload",
53
+ "GoalReplayEndPayload",
54
+ "GoalReplayStartPayload",
55
+ "GoalReplayWillEndPayload",
56
+ "GoalScoredPayload",
57
+ "MatchCreatedPayload",
58
+ "MatchInitializedPayload",
59
+ "MatchDestroyedPayload",
60
+ "MatchEndedPayload",
61
+ "MatchPausedPayload",
62
+ "MatchUnpausedPayload",
63
+ "PodiumStartPayload",
64
+ "ReplayCreatedPayload",
65
+ "RoundStartedPayload",
66
+ "StatfeedEventPayload",
67
+ "cast_event_data",
68
+ ]