Metadata-Version: 2.4
Name: craftcord
Version: 0.1.1
Summary: Async Python SDK for connecting Discord bots and automation to Minecraft servers through a CraftCord plugin API.
Project-URL: Homepage, https://github.com/example/craftcord
Project-URL: Documentation, https://github.com/example/craftcord/tree/main/docs
Project-URL: Repository, https://github.com/example/craftcord
Project-URL: Issues, https://github.com/example/craftcord/issues
Author: CraftCord Contributors
License: MIT
Keywords: asyncio,automation,discord,minecraft,sdk,websocket
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.12
Requires-Dist: aiohttp<4.0,>=3.10
Requires-Dist: websockets<14,>=13
Provides-Extra: dev
Requires-Dist: coverage[toml]<8.0,>=7.6; extra == 'dev'
Requires-Dist: pytest-asyncio<0.25,>=0.24; extra == 'dev'
Requires-Dist: pytest<9.0,>=8.3; extra == 'dev'
Requires-Dist: ruff<0.7,>=0.6; extra == 'dev'
Provides-Extra: discord
Requires-Dist: discord-py<3.0,>=2.4; extra == 'discord'
Description-Content-Type: text/markdown

# CraftCord

CraftCord is a Python SDK for Discord bot developers who want to connect their bot to Minecraft.
It is to be used with Craftcord plugin, you can find it in https://github.com/rytisltu09/CraftcordPlugin

If you are new, the fastest way to understand CraftCord is:

1. Run the example bot.
2. Use `!mc_online` in Discord.
3. See Minecraft player data in your Discord channel.

## Who This Is For

CraftCord is a good fit if you want to:

- build a Discord bot in Python
- read Minecraft server events
- run Minecraft actions from Discord commands
- keep bot logic clean and reusable

## What You Get

- async Python client (`Client`)
- two transport options: WebSocket or HTTP
- typed Minecraft events and models
- CraftCord command system (`@client.command`)
- Discord adapter for `discord.py` (`DiscordPyAdapter`)
- plugin system (`client.plugins.load(...)`)

## Beginner 5-Minute Setup

### 1. Install Dependencies

From your virtual environment
```bash
pip install craftcord
```

### 2. Configure Environment Variables

Set these before running `examples/basic_bot.py`:

- `DISCORD_TOKEN` (required)
- `CRAFTCORD_HOST` (default: `127.0.0.1`)
- `CRAFTCORD_PORT` (default: `8080`)
- `CRAFTCORD_TOKEN` (default: `secret`)
- `CRAFTCORD_TRANSPORT` (`ws` or `http`, default: `ws`)
- `CRAFTCORD_DEFAULT_CHANNEL` (optional Discord channel id)

Example:

```bash
export DISCORD_TOKEN="your-discord-bot-token"
export CRAFTCORD_HOST="127.0.0.1"
export CRAFTCORD_PORT="8080"
export CRAFTCORD_TOKEN="secret"
export CRAFTCORD_TRANSPORT="ws"
```

### 3. Start The Bot

```bash
python examples/basic_bot.py
```

### 4. Test It In Discord

In a channel where your bot can read and send messages, run:

```text
!mc_online
```

If everything is connected, the bot responds with online player names.

## How Commands Work (Simple Mental Model)

- `@bot.command` is Discord-facing.
- `@client.command` is CraftCord-facing shared logic.

Typical flow:

1. User types a Discord command like `!mc_online`.
2. Discord handler calls `await client.invoke_command("online")`.
3. CraftCord command runs and returns data.
4. Discord handler sends the result back to chat.

This is why you avoid duplicating business logic.

## Minimal Example

```python
import asyncio

from craftcord import Client


async def main() -> None:
    client = Client(host="127.0.0.1", port=8080, token="secret")

    @client.command("online")
    async def online_players() -> list[str]:
        players = await client.minecraft.players()
        return [player.username for player in players]

    await client.start()


asyncio.run(main())
```

## Minecraft Features Available

From `client.minecraft`:

- `players()` / `get_players()`
- `server_info()` / `get_server_info()`
- `send_message(message, target=None)`
- `execute(command)`
- `kick(username, reason=None)`
- `ban(username, reason=None)`

## Events You Can Listen To

Typed built-in events include:

- `player_join`
- `player_leave`
- `player_chat`
- `player_death`
- `server_start`
- `server_stop`

Unknown event names arrive as `GenericEvent`.

## Transport Choice

- Use `ws` for real-time events and long-running bot sessions.
- Use `http` for simple request/response integrations.

Set with:

```bash
export CRAFTCORD_TRANSPORT="ws"
```

or

```bash
export CRAFTCORD_TRANSPORT="http"
```

## Troubleshooting

### Bot starts but keeps retrying WebSocket

Cause: CraftCord API endpoint is not reachable.

Check:

1. Is your Java-side CraftCord plugin/API running?
2. Do `CRAFTCORD_HOST`, `CRAFTCORD_PORT`, and `CRAFTCORD_TOKEN` match?
3. If your server only supports HTTP, set `CRAFTCORD_TRANSPORT=http`.

### Discord command does not trigger

Check:

1. Message Content Intent is enabled in Discord Developer Portal.
2. Bot has permission to read and send in that channel.
3. You are using the right prefix (`!`) and command (`!mc_online`).

### Import or dataclass errors on Python 3.14

Use the latest code in this repository. Recent updates include Python 3.14 compatibility fixes for event dataclasses.

## Plugin System

Extensions are classes with `setup(client)` and optional `teardown(client)`.

```python
class GreetingExtension:
    async def setup(self, client) -> None:
        @client.on("player_join")
        async def greet(event) -> None:
            await client.minecraft.send_message(f"Welcome {event.player.username}!")


await client.plugins.load(GreetingExtension())
```

## Protocol Contract (For Java Plugin Authors)

Expected API behavior:

- Bearer token auth for HTTP and WebSocket
- WebSocket action: `auth.validate`
- HTTP endpoint: `GET /api/v1/auth/validate`
- HTTP endpoint: `POST /api/v1/rpc`
- WebSocket event envelope support

Request envelope:

```json
{
  "type": "request",
  "id": "uuid",
  "action": "minecraft.get_players",
  "payload": {}
}
```

Response envelope:

```json
{
  "type": "response",
  "id": "uuid",
  "status": "ok",
  "data": {}
}
```

Event envelope:

```json
{
  "type": "event",
  "event": "player_join",
  "data": {
    "player": {
      "uuid": "3b5e4f2d-8e34-4ad1-848f-b9d66fd07a4f",
      "username": "Alex",
      "health": 20.0,
      "world": "world",
      "location": {"x": 0.0, "y": 64.0, "z": 0.0}
    }
  }
}
```

## Development

Run tests:

```bash
pytest
```

Run lint:

```bash
ruff check .
```

## Repository Layout

```text
craftcord/
docs/
examples/
tests/
```
