#minecraft #mc #mcmodern

ozelot

Handles everything network related to MCMODERN

8 breaking releases

Uses old Rust 2015

0.9.0 Apr 23, 2020
0.8.0 Nov 28, 2018
0.7.0 May 9, 2018
0.5.0 Sep 20, 2017
0.3.0 Jun 10, 2017

#250 in Games

24 downloads per month

CC0 license

175KB
3.5K SLoC

Rust 2.5K SLoC // 0.0% comments Clojure 1K SLoC // 0.0% comments

Ozelot

Ozelot (spelling intentional) is a Rust library which goal is to handle everything network related to MCMODERN. To avoid duplication, the readme here is kept very basic, read the rustdocs for more information.


lib.rs:

(Link to repository page.)

This is a library made for interacting with the Minecraft protocol (MCMODERN only, not MCPE.)

It is mostly a low-level library, its goals are to handle everything network related, but nothing beyond that. For example this library does not support any types beyond ones found in standard Rust, this results in certain packets that contain compound datatypes not having their complex fields serialized by this library, but instead handing the raw binary data to consumers of this library to parse however they wish. One example of this is packets that contain NBT data, the packets are read but the NBT data is not in any way parsed by this library. You'll probably want to see what the meanings of each of the packets are, which is documented on wiki.vg. The protocol documentation in particular is likely to be a necessary companion to using this library.

Currently the library is entirely synchronous, requiring consumers to handle concurrency however they wish. It would be cool to add an asynchronous API though, maybe using mio.

The library nominally supports every packet used in MCMODERN, but the goal is still to add lots more helper functions and other useful things. There are still many errors and inconvenient things in the library, where changes or helper functions would be good to add. If you find any errors or suggestions for improvement, no matter how trivial, then post it on the bugtracker.

The library does not yet have any stable releases, not because it may contain bugs (which it certainly does,) but because the API may be significantly restructured without warning.

Examples

Connecting to a remote server as an authenticated user, printing all chat messages, and then echoing back messages that appear not to be written by us (else we'd get into an infinite loop echoing our own messages.)

(See the textclient example for a comprehensive version.)

use std::thread;
use std::time::Duration;
use ozelot::{mojang, Client, serverbound, utils};
use ozelot::clientbound::ClientboundPacket;

let auth = mojang::Authenticate::new("my_email@example.com".to_string(),
                                     "my_password".to_string())
    .perform().unwrap();


/* By using connect_authenticated, auto_handle will be true and thus ozelot
 * will respond to keepalives automatically */
let mut client = Client::connect_authenticated("minecraft.example.com",
                                               25565, &auth).unwrap();

let username = auth.selectedProfile.name;

'main: loop {
    let packets = client.read().unwrap();
    for packet in packets {
        match packet {
        ClientboundPacket::PlayDisconnect(ref p) => {
            println!("Disconnected, reason: {}",
                     utils::chat_to_str(p.get_reason()).unwrap());
            break 'main;
        },
        ClientboundPacket::ChatMessage(ref p) => {
            let msg = utils::chat_to_str(p.get_chat()).unwrap();
            println!("{}", msg);
            if !msg.contains(&username) {
                /* Since we don't want an infinite loop, we don't echo back
                 * our own messages. We say that a received message wasn't
                 * written by us if it doesn't contain our username
                 *
                 * Note that this echoes back the raw chat message, that is
                 * playername and everything, and also non-chat messages. */
                let response = serverbound::ChatMessage::new(msg);
                let _: usize = client.send(response).unwrap();
            }
        },
        /* We throw away all other packets */
        _ => (),
        }
    }
    /* Make sure we don't consume the entire CPU trying to check if new packets have arrived */
    thread::sleep(Duration::from_millis(50));
}

Dependencies

~19–29MB
~459K SLoC