Pumpkin-Docs/docs/pt/developer/networking/networking.md
Alexander Medvedev d219a313bc Better formatting
2025-08-11 22:42:58 +02:00

240 lines
6.7 KiB
Markdown

### Rede (Networking)
A maior parte do código de rede do Pumpkin pode ser encontrada na crate [pumpkin-protocol](https://github.com/Pumpkin-MC/Pumpkin/tree/master/pumpkin-protocol).
Serverbound: Cliente→Servidor
Clientbound: Servidor→Cliente
### Estrutura
Os pacotes no protocolo Pumpkin são organizados por funcionalidade e estado.
`server`: Contém definições para pacotes serverbound.
`client`: Contém definições para pacotes clientbound.
### Estados
**Handshake**: Sempre o primeiro pacote enviado pelo cliente. Isso também determina o próximo estado, geralmente indicando se o jogador deseja realizar uma solicitação de status, entrar no servidor ou ser transferido.
**Status**: Indica que o cliente deseja ver uma resposta de status (MOTD).
**Login**: A sequência de login. Indica que o cliente deseja entrar no servidor.
**Config**: Uma sequência de pacotes de configuração que são principalmente enviados do servidor para o cliente (recursos, pacotes de recursos, links do servidor, etc.).
**Play**: O estado final, que indica que o jogador está pronto para entrar, também é usado para lidar com todos os outros pacotes de gameplay.
### Protocolo Minecraft
Você pode encontrar todos os pacotes do Minecraft Java em [Minecraft Wiki](https://minecraft.wiki/w/Minecraft_Wiki:Projects/wiki.vg_merge/Protocol). Lá você também pode ver em qual [estado](#estados) eles estão. Você também pode ver todas as informações que os pacotes possuem, as quais podemos ler ou escrever, dependendo se são serverbound ou clientbound.
### Adicionando um Pacote
1. Adicionar um pacote é fácil. Primeiro, derive:
```rust
// Para pacotes clientbound:
#[derive(Serialize)]
// Para pacotes serverbound:
#[derive(Deserialize)]
```
2. Em seguida, você deve deixar claro que sua struct representa um pacote. Isso automaticamente obterá o ID do pacote do arquivo JSON de pacotes.
```rust
use pumpkin_data::packet::clientbound::PLAY_DISCONNECT;
#[packet(PLAY_DISCONNECT)]
```
3. Agora você pode criar a `struct`.
> [!IMPORTANT] IMPORTANTE
> Por favor, comece o nome do pacote com "C" ou "S" para "Clientbound" ou "Serverbound".
> Além disso, se for um pacote que pode ser enviado em múltiplos [estados](#estados), adicione o estado ao nome. Por exemplo, existem 3 pacotes de desconexão diferentes.
>
> - `CLoginDisconnect`
> - `CConfigDisconnect`
> - `CPlayDisconnect`
Crie campos dentro da sua estrutura de pacote para representar os dados que serão enviados.
> [!IMPORTANT] IMPORTANTE
> Use nomes de campos descritivos e tipos de dados apropriados.
Exemplos:
```rust
pub struct CPlayDisconnect {
reason: TextComponent,
// mais campos...
}
pub struct SPlayerPosition {
pub x: f64,
pub feet_y: f64,
pub z: f64,
pub ground: bool,
}
```
4. (Apenas pacotes clientbound) Implemente uma função `new` para que possamos realmente criá-los inserindo os valores.
```rust
impl CPlayDisconnect {
pub fn new(reason: TextComponent) -> Self {
Self { reason }
}
}
```
5. No final, tudo deve se juntar.
```rust
#[derive(Serialize)]
#[packet(PLAY_DISCONNECT)]
pub struct CPlayDisconnect {
reason: TextComponent,
}
impl CPlayDisconnect {
pub fn new(reason: TextComponent) -> Self {
Self { reason }
}
}
#[derive(Deserialize)]
#[packet(PLAY_MOVE_PLAYER_POS)]
pub struct SPlayerPosition {
pub x: f64,
pub feet_y: f64,
pub z: f64,
pub ground: bool,
}
```
6. Você também pode serializar/deserializar o pacote manualmente, o que pode ser útil se o pacote for mais complexo.
```diff
-#[derive(Serialize)]
+ impl ClientPacket for CPlayDisconnect {
+ fn write(&self, bytebuf: &mut BytesMut) {
+ bytebuf.put_slice(&self.reason.encode());
+ }
-#[derive(Deserialize)]
+ impl ServerPacket for SPlayerPosition {
+ fn read(bytebuf: &mut Bytes) -> Result<Self, ReadingError> {
+ Ok(Self {
+ x: bytebuf.try_get_f64()?,
+ feet_y: bytebuf.try_get_f64()?,
+ z: bytebuf.try_get_f64()?,
+ ground: bytebuf.try_get_bool()?,
+ })
+ }
```
7. Agora você pode enviar o pacote clientbound (veja [Enviando Pacotes](#enviando-pacotes)) ou ouvir o pacote serverbound (veja [Recebendo Pacotes](#recebendo-pacotes)).
### Cliente
Pumpkin categoriza `Client`s e `Player`s separadamente. Tudo o que não está no estado de jogo é um simples `Client`. Aqui estão as diferenças:
**Client**
- Só pode estar nos estados: Status, Login, Transfer, Config
- Não é uma entidade viva
- Consome poucos recursos
**Player**
- Só pode estar no estado Play
- É uma entidade viva no mundo
- Possui mais dados e consome mais recursos
#### Enviando Pacotes
Exemplo:
```rust
// Funciona apenas no estado Status
client.send_packet(&CStatusResponse::new("{ description: "A Description"}"));
```
#### Recebendo Pacotes
Para `Client`s:
`src/client/mod.rs`
```diff
// Coloque o pacote no estado correto
fn handle_mystate_packet(
&self,
server: &Arc<Server>,
packet: &mut RawPacket,
) -> Result<(), ReadingError> {
let bytebuf = &mut packet.bytebuf;
match packet.id.0 {
SStatusRequest::PACKET_ID => {
self.handle_status_request(server, SStatusRequest::read(bytebuf)?)
.await;
}
+ MyPacket::PACKET_ID => {
+ self.handle_my_packet(MyPacket::read(bytebuf)?)
+ .await;
}
_ => {
log::error!(
"Falha ao lidar com o pacote id {} enquanto no estado ...",
packet.id.0
);
}
};
Ok(())
}
```
Para `Player`s:
`src/entity/player.rs`
```diff
// Players só têm o estado Play
fn handle_play_packet(
&self,
server: &Arc<Server>,
packet: &mut RawPacket,
) -> Result<(), ReadingError> {
let bytebuf = &mut packet.bytebuf;
match packet.id.0 {
SChatMessage::PACKET_ID => {
self.handle_chat_message(SChatMessage::read(bytebuf)?).await;
}
MyPacket::PACKET_ID => {
+ self.handle_mypacket(server, MyPacket::read(bytebuf)?).await;
}
_ => {
log::error!(
"Falha ao lidar com o pacote id {} enquanto no estado ...",
packet.id.0
);
}
};
Ok(())
}
```
### Compressão
Os pacotes do Minecraft **podem** usar compressão ZLib para decodificação/encodificação. Normalmente, existe um limite quando a compressão é aplicada; isso afeta principalmente pacotes de chunks.
### Portabilidade
Para portar para uma nova versão do Minecraft, você pode comparar as diferenças no protocolo na [referência de protocolo minecraft.wiki](https://minecraft.wiki/w/Java_Edition_protocol).
Além disso, altere o `CURRENT_MC_PROTOCOL` em `src/lib.rs`.