mymcproto 0.1.0
Encode and Decode the DataType and Protocols of the Minecraft (Java Edition) version 1.21.8 (Protocol 772) in Python. 
Requires Python: >=3.12
Keywords: Minecraft, Protocols, Game

# MYMCProto V0.1.0
## Me2sY Minecraft Protocol
使用python语言实现的**Minecraft JE**通讯协议解析与构建。实现了V772版本的数据结构及全部通讯协议。
* 数据类型详见[Minecraft Wiki - DataTypes](https://minecraft.wiki/w/Java_Edition_protocol/Packets#Data_types)
* 通讯协议详见[Minecraft Wiki - Packets](https://minecraft.wiki/w/Java_Edition_protocol/Packets)

## 特点
* 实现 V772(1.21.8) 涉及的数据结构
* 实现 V772 全部通讯协议包
* 创建 V772 全部枚举类
* 结构简单，通过继承，可方便构建其他版本的通讯协议包
* 根据不同minecraft版本自动映射对应解析关系（目前仅772/768）

## 安装
```bash
pip install mymcproto
```

## 使用示例
### 前言
* 数据类型在 mymcproto.data_types中，对应Minecraft数据结构。[Minecraft Wiki - DataTypes](https://minecraft.wiki/w/Java_Edition_protocol/Packets#Data_types)
* 协议包为 mymcproto.protocol_packet.ProtocolPacket 类的继承类，主要负责协议包的组包和解包，面向实际功能
* 通讯数据包 为 mymcproto.data_packet.DataPacket 类，负责包裹协议包，面向通讯
* 协议包的全部实现包裹于 mymcproto.protocols.**[VERSION]**.Packets类中

DataPacket包裹ProtocolPacket，在未压缩阶段，组包规则为 Length + Packet ID + Data

> 通讯数据包结构详见 [数据包结构Wiki](https://minecraft.wiki/w/Java_Edition_protocol/Packets#Packet_format)

**!!! 数据包、结构及数据类型较多，目前未充分测试，欢迎提ISSUE !!!**

### HandShaking | 0x00 | intention
Client -> Server 创建一个握手协议并查询服务器状态信息

```python
# 引入数据类型，所有数据类型使用 .encode() 编码成 字节 DataTypeClass.decode(bytes) 解码成对应数据
from mymcproto.data_types.data_type import VarInt

# 引入 v772 版本协议包类
from mymcproto.protocols.v772 import Packets

# 引入常量值
from mymcproto.enums.v772 import Enums

# 1.创建协议包
# 详见 https://minecraft.wiki/w/Java_Edition_protocol/Packets#Handshake
intention = Packets.HSIntention(
    protocol_version=772,  # 协议号
    host='localhost',  # 地址，The vanilla server does not use this information.
    port=25565,  # 服务器端口号 The vanilla server does not use this information.
    intent=Enums.Status.STATUS  # 通讯意图，此处 STATUS 为查询
)

# 2.生成通讯字节
# 建议编写 编码/解码器 组成 data_packet，此处仅演示组包过程

# Data
protocol_packet_bytes = intention.encode()

# PacketID + Data
packet_data = VarInt.encode(intention.PACKET_ID_HEX) + protocol_packet_bytes

# (Length of PacketID + Data) + PacketID + Data
trans_bytes_0 = VarInt.encode(len(packet_data)) + packet_data
# 示例 trans_bytes_0 > b'\x10\x00\x84\x06\tlocalhostc\xde\x01'

# ===========================================================================================
# 在发送握手包后，客户端由 Handshaking 态 进入 Status 态，服务端在收到握手包后 进入 Status 态
# Client 向 Server 发送状态查询请求，此处构建协议请求包
# 3.发送状态查询请求
status_request = Packets.SSStatusRequest()      # status request 无参数

# 重复上述步骤
# Data
protocol_packet_bytes = status_request.encode()

# PacketID + Data
packet_data = VarInt.encode(status_request.PACKET_ID_HEX) + protocol_packet_bytes

# (Length of PacketID + Data) + PacketID + Data
trans_bytes_1 = VarInt.encode(len(packet_data)) + packet_data
# 示例 trans_bytes_1 > b'\x01\x00'

send_bytes = trans_bytes_0 + trans_bytes_1
# 示例 b'\x10\x00\x84\x06\tlocalhostc\xde\x01\x01\x00'
```

> 创建一个 TCP socket 连接 minecraft 1.21.8 原版服务器，发送 send_bytes。
> 正常的话，将会得到回包 status_response 的字节流。

trans_bytes_0示例数据解释: 
```
b'\x10\x00\x84\x06\tlocalhostc\xde\x01'
其中:

传输字节     DataType        描述                值
---- DataPacket 部分 ----
\x10        VarInt          数据包长度           16
\x00        VarInt          PacketID           0x00

---- Protocol Packet Data 部分 ----
\x84\x06    VarInt          protocol_version    772
\tlocalhost String          host                localhost
c\xde       UnsignedShort   port                25565
\x01        VarInt          intent              1
```

### Status | 0x00 | status_response
Server -> Client 服务器返回状态信息。在获取到服务器返回时，对数据进行解包。
```python
# 引入数据类型，所有数据类型使用 .encode() 编码成 字节 DataTypeClass.decode(bytes) 解码成对应数据
from mymcproto.data_types.data_type import VarInt, String

# 引入 v772 版本协议包类
from mymcproto.protocols.v772 import Packets

# 字节流
from io import BytesIO

# 此处为示例服务器回流字节
response_bytes = b'q\x00o{"version":{"name":"1.21.8","protocol":772},"description":"A Minecraft Server","players":{"max":20,"online":0}}'

# 以下过程仅为示例，实际建议编写 编码器/解码器 处理
# 创建字节流
bytes_io = BytesIO(response_bytes)

# 读取 DataPacket 长度
data_packet_length: int = VarInt.decode(bytes_io)

# 读取 PacketID
packet_id: int = VarInt.decode(bytes_io)

# 解析数据表内容
protocol_packet: Packets.SCStatusResponse = Packets.SCStatusResponse.decode(bytes_io)

# Do whatever you want
```

以上示例获得一个 `SCStatusResponse` 实例，该实例为 `dataclass`，包含内容为服务器查询响应Json字符串
具体见 [Wiki Status_Response](https://minecraft.wiki/w/Java_Edition_protocol/Packets#Status_Response)
> `SCStatusResponse` 中包含属性字段 `status_response`, 属性为 `str | String`。`str` 是 python属性类型，`String` 是 minecraft中定义的 DataType 类型。
> 在Cls.decode()解码中自动解析为python属性并生成实例。

实例如下：

> Packets.SCStatusResponse(status_response='{"version":{"name":"1.21.8","protocol":772},"description":"A Minecraft Server","players":{"max":20,"online":0}}')

## 声明

本项目供日常学习、AI训练等使用。同时需遵守 Minecraft 相关要求！

**请一定注意：本项目不可用于违法犯罪等使用**

**本人及本项目不对以上产生的相关后果负相关责任，请斟酌使用。**

## 许可
本项目遵循 Apache-2.0 许可