Skip to content
This repository has been archived by the owner on Jul 1, 2024. It is now read-only.

Procedural macros to make your Rust structs compatible with the Minecraft protocol.

Notifications You must be signed in to change notification settings

Mubelotix/minecraft-protocol-derive

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

minecraft-protocol-derive

Procedural macros to make your structs compatible with the Minecraft protocol.

This crate aims to make the development of Minecraft protocol libraries easier.
There is already a complete Minecraft protocol implementation using this crate, but you could also make your own.

Usage

This crate requires you to declare a MinecraftPacketPart trait (see tests for examples).
The name of the derive macros is the same and can be used to implement the trait automatically.
It can still be implemented manually for complex types.

#[derive(MinecraftPacketPart)]
struct Entity {
    entity_id: VarInt,
    x: f64,
    y: f64,
    z: f64,
}

You can also nest your different structures.

#[derive(MinecraftPacketPart)]
struct Entity {
    entity_id: VarInt,
    position: Position,
}

#[derive(MinecraftPacketPart)]
struct Position {
    x: f64,
    y: f64,
    z: f64,
}

Note that you need to implement the MinecraftPacketPart trait for all the primitive types. The VarInt type is a common signed integer type. See the wiki for help with the implementation.

Enums

Enums are supported as long as you use named fields.

#[derive(MinecraftPacketPart)]
enum Packet {
    Login {
        username: String,
    },
    MoveTo {
        x: f64,
        y: f64,
        z: f64,
    }
    Ping,
}

For enums exclusively composed of unit variants, using #[minecraft_enum] is recommended since its implementation is more lightweight and optimized.

Since numeric IDs represent enums in the protocol, each variant has an associated value (its corresponding ID). It can be specified explicitly or inferred. A variant with no specified ID will take the ID of the previous variant, incremented by 1. The first variant matches 0 if no ID is specified.

You can specify the type of the numeric ID in the macro parameters. If missing, VarInt will be used.

#[minecraft_enum(u8)]
enum EntityType {
    Player,     // = 0 (inferred)
    Villager,
    Animal = 3, // Specify the corresponding ID like this.
    Monster,    // = 4 (inferred, 3+1)
    Minecart,
}

It is also possible to set the type and value of the numeric IDs with the derive syntax.

The same inference rules are applied.

#[derive(MinecraftPacketPart)]
#[discriminant(u8)] // define the type of the numeric ID of the variants
enum Packet {
    Login {
        username: String,
    },
    #[value = 5] // define the ID corresponding to the MoveTo variant
    MoveTo {
        x: f64,
        y: f64,
        z: f64,
    }
    Ping,
}

Lifetimes

Lifetimes are supported everywhere. The only limitation is that you cannot have more than one lifetime.

It is easy to implement zero-copy deserialization by using references.

#[derive(MinecraftPacketPart)]
struct Player<'a> {
    username: &'a str,
    data: &'a [u8],
}

Releases

No releases published

Packages

No packages published

Languages