Skip to main content

Python bindings for bedrock-crustaceans/nethernet - Minecraft Bedrock WebRTC transport

Project description

py-bedrock

Python bindings for 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

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
pip install maturin

Development install

From py-bedrock/py-bedrock:

python -m maturin develop --release

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

Build a wheel

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

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

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

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

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

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

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

cd py-bedrock/py-bedrock
python examples/lan_server.py
python examples/lan_client.py
set MY_ID=12345678901234567890
set TOKEN=your_mctoken_here
python examples/xbl_server.py
set MY_ID=12345678901234567890
set PEER_ID=9876543210987654321
set TOKEN=your_mctoken_here
python examples/xbl_client.py

Tests

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

For integration tests:

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bedrock_nethernet-0.1.0-cp38-abi3-win_amd64.whl (3.8 MB view details)

Uploaded CPython 3.8+Windows x86-64

File details

Details for the file bedrock_nethernet-0.1.0-cp38-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for bedrock_nethernet-0.1.0-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 5fff0664b40f6a0594619c63932ac67a9f3aa28070c395c0358777c948af9962
MD5 e7ad072b445e0f29f7d8ce8243e0dcfe
BLAKE2b-256 2e4bc767064c345c38df46763a591f778bc92e871b3ec1c9eb7e9e8fa1c5396c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page