Metadata-Version: 2.4
Name: bedrock-nethernet
Version: 0.1.0
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Games/Entertainment
Classifier: Topic :: Software Development :: Libraries
Requires-Dist: maturin>=1.5 ; extra == 'dev'
Requires-Dist: pytest>=8 ; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
Requires-Dist: mypy>=1.10 ; extra == 'dev'
Provides-Extra: dev
Summary: Python bindings for bedrock-crustaceans/nethernet - Minecraft Bedrock WebRTC transport
Keywords: minecraft,bedrock,nethernet,webrtc,raknet
License: Apache-2.0
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM

# py-bedrock

Python bindings for
[bedrock-crustaceans/nethernet](https://github.com/bedrock-crustaceans/nethernet),
bringing Minecraft Bedrock's NetherNet WebRTC transport into Python using
PyO3.

## What is py-bedrock?

`py-bedrock` exposes a thin Python wrapper around the Rust `nethernet` crate.
It gives Python applications access to:

- LAN discovery and signalling via `DiscoveryServer` and `DiscoveryClient`
- Xbox Live WebRTC signalling via `NetherNetClient` and `NetherNetServer`
- Reliable and unreliable packet send/receive via `Connection`
- Native Rust performance for crypto, packet framing, and WebRTC state machines
- Async integration with Python's `asyncio`

## Why use py-bedrock?

| Concern | Pure Python | py-bedrock |
|---|---|---|
| WebRTC / ICE / DTLS / SCTP | Hard to implement correctly in Python | Uses battle-tested Rust crates with the real NetherNet implementation |
| LAN discovery crypto | Requires extra C extension dependencies | Handled completely in Rust |
| Packet fragmentation | Manual implementation required | Native Rust packet segmentation |
| Async | `asyncio` only | `asyncio` coroutine bridge via `pyo3-asyncio` |
| Performance | Slow for heavy crypto/buffer work | Native Rust speed |
| Maintenance | Two separate stacks | One Rust implementation + small Python wrapper |

## Architecture

```text
Python application (asyncio)
        |
        |  async/await
        ▼
py-bedrock Python extension
   DiscoveryServer ──▶ nethernet::signaling::lan::LanSignaling
   DiscoveryClient ──▶ nethernet::signaling::lan::LanSignaling
   NetherNetClient ──▶ nethernet::NethernetStream
   NetherNetServer ──▶ nethernet::NethernetListener
   Connection ───────▶ nethernet::Session
        |
        |  Tokio runtime
        ▼
nethernet crate
   WebRTC ICE · DTLS · SCTP · LAN discovery · Xbox Live signalling
```

## Installation

### Prerequisites

- Rust toolchain (stable)
- Python 3.8+
- `maturin`

```bash
pip install maturin
```

### Development install

From `py-bedrock/py-bedrock`:

```bash
python -m maturin develop --release
```

This builds the extension and installs it into the current Python environment.

### Build a wheel

```bash
python -m maturin build --release
pip install target/wheels/py_bedrock-*.whl
```

## Example scripts

See `examples/README.md` for runnable example scripts and step-by-step usage patterns.

## Quick start

```python
import asyncio
import py_bedrock as nethernet

async def main():
    client = nethernet.NetherNetClient(
        network_id=12345678901234567890,
        xbl_token="YOUR_MCTOKEN",
    )

    conn = await client.connect(remote_id=9876543210987654321)
    await conn.send(b"hello from Python")
    data = await conn.recv()
    print("received", data)
    await conn.close()

asyncio.run(main())
```

## API overview

### `py_bedrock.__version__`

Returns the package version string.

### `Connection`

- `remote_id() -> int`
- `send(data: bytes)`
- `send_unreliable(data: bytes)`
- `recv() -> bytes | None`
- `close()`

### `NetherNetClient`

- `NetherNetClient(network_id: int, xbl_token: str)`
- `connect(remote_id: int) -> Connection`

### `NetherNetServer`

- `NetherNetServer(network_id: int, xbl_token: str)`
- `listen() -> None`
- `accept() -> Connection`

### `DiscoveryServer`

- `DiscoveryServer(sender_id: int)`
- `broadcast(server_name, level_name, game_type=0, player_count=0, max_players=20, editor_world=False)`
- `recv_message() -> dict`
- `send_message(recipient_id: int, data: str) -> None`

### `DiscoveryClient`

- `DiscoveryClient(sender_id: int)`
- `discover(timeout: float = 3.0) -> list[dict]`

## Real-world examples

### LAN discovery server

```python
import asyncio
import random
import py_bedrock as nethernet

async def main() -> None:
    sender_id = random.getrandbits(64)
    disc = nethernet.DiscoveryServer(sender_id=sender_id)

    await disc.broadcast(
        server_name="My LAN Server",
        level_name="Test World",
        game_type=0,
        player_count=0,
        max_players=10,
    )

    print("Broadcasting discovery; waiting for incoming messages...")
    while True:
        msg = await disc.recv_message()
        print("received discovery message", msg)
        if msg["data"].startswith("CONNECTREQUEST"):
            print("Peer is attempting to connect; your server should now accept it.")
            break

asyncio.run(main())
```

### LAN discovery client

```python
import asyncio
import random
import py_bedrock as nethernet

async def main() -> None:
    sender_id = random.getrandbits(64)
    client = nethernet.DiscoveryClient(sender_id=sender_id)

    servers = await client.discover(timeout=3.0)
    for server in servers:
        print(server)

asyncio.run(main())
```

### Xbox Live client

```python
import asyncio
import py_bedrock as nethernet

async def main() -> None:
    client = nethernet.NetherNetClient(
        network_id=12345678901234567890,
        xbl_token="YOUR_MCTOKEN",
    )

    conn = await client.connect(remote_id=9876543210987654321)
    await conn.send(b"Hello world")
    data = await conn.recv()
    print("received", data)
    await conn.close()

asyncio.run(main())
```

### Xbox Live server

```python
import asyncio
import py_bedrock as nethernet

async def main() -> None:
    server = nethernet.NetherNetServer(
        network_id=12345678901234567890,
        xbl_token="YOUR_MCTOKEN",
    )

    await server.listen()
    print("listening for incoming connection...")

    conn = await server.accept()
    print("accepted connection from", conn.remote_id())

    pkt = await conn.recv()
    print("received", pkt)
    await conn.send(pkt)
    await conn.close()

asyncio.run(main())
```

### Full server pattern

```python
import asyncio
import random
import py_bedrock as nethernet

async def handle_connection(conn):
    try:
        while True:
            pkt = await conn.recv()
            if pkt is None:
                break
            await conn.send(pkt)
    finally:
        await conn.close()

async def main() -> None:
    sender_id = random.getrandbits(64)
    disc = nethernet.DiscoveryServer(sender_id=sender_id)
    server = nethernet.NetherNetServer(
        network_id=sender_id,
        xbl_token="YOUR_MCTOKEN",
    )

    await disc.broadcast(server_name="My Server", level_name="World")
    await server.listen()

    while True:
        conn = await server.accept()
        asyncio.create_task(handle_connection(conn))

asyncio.run(main())
```

## Running examples

```bash
cd py-bedrock/py-bedrock
python examples/lan_server.py
python examples/lan_client.py
```

```bash
set MY_ID=12345678901234567890
set TOKEN=your_mctoken_here
python examples/xbl_server.py
```

```bash
set MY_ID=12345678901234567890
set PEER_ID=9876543210987654321
set TOKEN=your_mctoken_here
python examples/xbl_client.py
```

## Tests

```bash
pip install -e ".[dev]"
python -m maturin develop --release
pytest tests/
```

For integration tests:

```bash
set NETHERNET_INTEGRATION=1
pytest tests/
```

## Additional notes

- Type stubs are available in `python/py_bedrock/__init__.pyi`.
- All wrapper methods are async coroutines and should be awaited.
- Example scripts live in `examples/` and demonstrate LAN discovery and
  Xbox Live WebRTC flows.

## License

Apache-2.0

## Note

All README.md files have been written by AI because I was too exhausted to do it myself atp.
