aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'README.md')
-rw-r--r--README.md121
1 files changed, 121 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0d1c280
--- /dev/null
+++ b/README.md
@@ -0,0 +1,121 @@
+# craftio-rs
+
+Version 0.1.0, by [Twister915](https://github.com/Twister915)!
+
+craftio-rs is a library which let's you read & write packets defined in [mcproto-rs](https://github.com/Twister915/mcproto-rs)
+to real Minecraft servers/clients.
+
+You can use this library to implement anything from a simple server status ping client, BungeeCord-like proxy, a bot
+to join your favorite server, or an entire Minecraft server or client implementation.
+
+The protocol definition is managed in a separate crate, mentioned above, called [mcproto-rs](https://github.com/Twister915/mcproto-rs)
+which defines a set of traits to support custom protocol implementations, and also defines all packets for a few of the
+versions of Minecraft.
+
+This crate optionally implements the following features:
+* `compression` (using the [flate2](https://crates.io/crates/flate2) crate)
+* `encryption` (using the [aes](https://crates.io/crates/aes) crate) with a fast implementation of CFB-8
+* `futures-io` enables reading/writing to implementors of the `AsyncRead`/`AsyncWrite` traits from the
+ [futures](https://crates.io/crates/futures) crate
+* `tokio-io` enables reading/writing to implementors of the `AsyncRead`/`AsyncWrite` traits from the
+ [tokio](https://crates.io/crates/tokio) crate
+
+# Usage
+
+```toml
+[dependencies]
+craftio-rs = "0.1"
+```
+
+This library can be used to connect to servers or host client connections. It implements all features of the Minecraft
+protocol, and these features can be disabled for simpler use-cases (such as hitting servers to gather status information).
+
+You can also use an async based I/O implementation, or a blocking I/O implementation.
+
+## Connecting to a Server
+
+To connect to a Minecraft server, you can write something like this:
+
+```rust
+let mut conn = CraftTokioConnection::connect_server_tokio("localhost:25565").await?;
+conn.write_packet_async(Packet578::Handshake(HandshakeSpec { ... })).await?;
+conn.set_state(State::Login);
+...
+```
+
+This `CraftTokioConnection` struct is actually a type alias for the more general `CraftConnection<R, W>` type which wraps
+any `R` (reader) and `W` (writer) type supported by `CraftReader` and `CraftWriter`. More detail on these types below.
+
+You can also connect using a blocking socket from `std::net` like this:
+
+```rust
+let mut conn = CraftTcpConnection::connect_server_std("localhost:25565")?;
+conn.write_packet(Packet578::Handshake(HandshakeSpec { ... }))?;
+conn.set_state(State::Login);
+...
+```
+
+## Serving Clients
+
+You can use `CraftConnection::from_std_with_state(your_client, PacketDirection::ServerBound, State::Handshaking)` to wrap
+a blocking `TcpStream`, and you can use `CraftConnection::from_async_with_state((client_read_half, client_write_half), PacketDirection::ServerBound, State::Handshaking)`
+to wrap an async `TcpStream`. In the async case you must split your connection into reader/writer halves before passing it to the
+`CraftConnection`.
+
+In all cases it is recommended to first wrap the reader in a buffering reader implementation of your choice. This is because
+this crate typically reads the packet length (first 5 bytes) as one call, then the entire packet body as another call. If
+you choose to not use a buffering implementation, these two calls could have an undesirable overhead, because both may actually
+require an operating system call.
+
+# Types
+
+There are two structs which implement the behavior of this crate: `CraftReader<R>` and `CraftWriter<W>`.
+
+They are defined to implement the `CraftAsyncReader`/`CraftSyncReader` and `CraftAsyncWriter`/`CraftSyncWriter` traits
+when wrapping `R`/`W` types which implement the `craftio_rs::AsyncReadExact`/`std::io::Read` and
+`craftio_rs::AsyncWriteExact`/`std::io::Write` traits respectively.
+
+This crate provides implementations of `craftio_rs::AsyncReadExact` and `craftio_rs::AsyncWriteExact` for implementors of
+the `tokio::io::AsyncRead`/`tokio::io::AsyncWrite` and `futures::AsyncRead`/`futures::AsyncWrite` traits when you enable
+the `tokio-io` and `futures-io` features respectively.
+
+## Performance
+
+A `CraftReader<R>` and `CraftWriter<W>` hold some buffers, both of which are lazily allocated `Vec<u8>`s:
+* `raw_buf` which is a buffer for packet bytes
+* `compress_buf`/`decompress_buf`. When compression is enabled (both as a crate-feature called `compression` and after
+ a call to `.set_compression_threshold` with a `Some(> 0)` value) this buffer is used to store a compressed packet
+ (in the case of a writer) or the decompressed packet (in the case of a reader).
+
+These buffers can be eagerly allocated using calls to `.ensure_buf_capacity(usize)` and `.ensure_compression_buf_capacity(usize)`,
+but they cannot yet be provided by the user.
+
+### Motivation
+
+This library was designed when I was working on these three projects: a replacement for BungeeCord, a bot client that can
+join servers for me, and a tool to ping a list of servers quickly and print their status. This crate tries to avoid dynamic
+allocation, but does have some buffers to make serialization/deserialization fast. These allocations are done lazily by
+default, but can be done eagerly (described below) if desired.
+
+When implementing something like a game server, or a proxy like BungeeCord, you are dealing with tens to hundreds of joins
+per second in the maximum case, so the dynamic allocation is not going to dramatically impact performance. Therefore,
+lazily allocation and growing of the buffers aren't going to impact your flame-graph.
+
+However, in the case of trying to ping servers, I really wanted to ensure we only allocate once per connection half. To
+that end, you can eagerly allocate a large-enough buffer and also limit the max packet size to prevent it from growing
+any further (call `.set_max_packet_size` and `.ensure_buf_capacity`).
+
+A great feature would be allowing the user to provide a `&mut Vec<u8>` which can be used by the wrapper types until the
+connection is closed. This way, in a many-worker model (like a ping tool), you can simply allocate a buffer for each worker,
+which you re-use for each subsequent connection. This does not exist yet.
+
+## Adapting to different I/O implementations
+
+To add your favorite I/O library, you can either implement the std I/O traits (`std::io::Read` and `std::io::Write`) or
+for an async implementation you can implement the traits provided by this crate (`AsyncReadExact` and `AsyncWriteExact`).
+
+# Todo
+
+* Allow user to provide buffers which they already allocated for `raw_buf`
+* See if we can stop managing the `Vec<u8>` ourselves and just use `BufReader` traits that already exist?
+* Extract the offset tracking from `CraftReader` struct. \ No newline at end of file