|
|
@ -1,3 +1,5 @@ |
|
|
|
|
|
|
|
//! Implements writer that sends data to UE2 game server.
|
|
|
|
|
|
|
|
|
|
|
|
use std::cmp::{max, min}; |
|
|
|
use std::cmp::{max, min}; |
|
|
|
use std::collections::VecDeque; |
|
|
|
use std::collections::VecDeque; |
|
|
|
use std::convert::TryFrom; |
|
|
|
use std::convert::TryFrom; |
|
|
@ -10,30 +12,42 @@ const UE_INPUT_BUFFER: usize = 4095; |
|
|
|
// Minimal payload size (in bytes) to send, unless there is not enough data left
|
|
|
|
// Minimal payload size (in bytes) to send, unless there is not enough data left
|
|
|
|
const MIN_PAYLOAD_SIZE: usize = 50; |
|
|
|
const MIN_PAYLOAD_SIZE: usize = 50; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// For converting byte stream that is expected from the ue-server into actual messages.
|
|
|
|
|
|
|
|
/// Conversion process has two steps:
|
|
|
|
|
|
|
|
/// 1. Every string message is converted into it's utf8 representation and is pre-pended with
|
|
|
|
|
|
|
|
/// it's own length in format:
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// | Data | Length |
|
|
|
|
|
|
|
|
/// |---------|---------|
|
|
|
|
|
|
|
|
/// | Message `LENGTH` | 4 bytes: u32 BE |
|
|
|
|
|
|
|
|
/// | UTF8-encoded string | `LENGTH` bytes|
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Resulting byte sequences from all the messages then concatenated, in order, into
|
|
|
|
|
|
|
|
/// a single data stream.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// 2. Resulting data stream is then separated into "chunks" that can be accepted by
|
|
|
|
|
|
|
|
/// the ue-server (each no longer than `UE_INPUT_BUFFER` in total) and are sent in a format:
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// | Data | Length |
|
|
|
|
|
|
|
|
/// |---------|---------|
|
|
|
|
|
|
|
|
/// | Chunk `LENGTH` | 2 bytes: u16 BE |
|
|
|
|
|
|
|
|
/// | UTF8-encoded string | `LENGTH` bytes|
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Use `push()` to input string messages and `try_pop()` to retrieve next chunk, if ue-server
|
|
|
|
|
|
|
|
/// can accept it.
|
|
|
|
|
|
|
|
/// NOTE: `try_pop()` can return `None` even if not all message data has been transferred,
|
|
|
|
|
|
|
|
/// in case ue-server's buffer does not have enough space.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Call `update_ue_received_bytes()` to update `MessageWriter`'s information about
|
|
|
|
|
|
|
|
/// how many bytes ue-server has received so far.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Use `is_empty()` call to check for whether `MessageWriter` has depleted all it's data.
|
|
|
|
pub struct MessageWriter { |
|
|
|
pub struct MessageWriter { |
|
|
|
sent_bytes: u64, |
|
|
|
sent_bytes: u64, |
|
|
|
ue_received_bytes: u64, |
|
|
|
ue_received_bytes: u64, |
|
|
|
pending_data: VecDeque<u8>, |
|
|
|
pending_data: VecDeque<u8>, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// For converting byte stream that is expected from the ue-server into actual messages.
|
|
|
|
|
|
|
|
/// Conversion process has two steps:
|
|
|
|
|
|
|
|
/// 1. Every string message is converted into it's utf8 representation and is pre-pended with
|
|
|
|
|
|
|
|
/// it's own length in format:
|
|
|
|
|
|
|
|
/// [MESSAGE_LENGTH: length of the message in utf8 encoding | 4 bytes: u32 BE]
|
|
|
|
|
|
|
|
/// [MESSAGE: utf8-encoded string | `MESSAGE_LENGTH` bytes]
|
|
|
|
|
|
|
|
/// Resulting byte sequences from all the messages then concatenated, in order, into
|
|
|
|
|
|
|
|
/// a single data stream.
|
|
|
|
|
|
|
|
/// 2. Resulting data stream is then separated into "chunks" that can be accepted by
|
|
|
|
|
|
|
|
/// the ue-server (each no longer than `UE_INPUT_BUFFER` in total) and are sent in a format:
|
|
|
|
|
|
|
|
/// [LENGTH: length of the chunk | 2 bytes: u16 BE]
|
|
|
|
|
|
|
|
/// [PAYLOAD: utf8-encoded string | `LENGTH` bytes]
|
|
|
|
|
|
|
|
/// Use `push()` to input string messages and `try_pop()` to retrieve next chunk, if ue-server
|
|
|
|
|
|
|
|
/// can accept it. Call `update_ue_received_bytes()` to update `MessageWriter`'s information about
|
|
|
|
|
|
|
|
/// how many bytes ue-server has received so far.
|
|
|
|
|
|
|
|
/// NOTE: `try_pop()` can return `None` even if not all message data has been transferred,
|
|
|
|
|
|
|
|
/// in case ue-server's buffer does not have enough space. Use `is_empty()` call to check for
|
|
|
|
|
|
|
|
/// whether `MessageWriter` has depleted all it's data.
|
|
|
|
|
|
|
|
impl MessageWriter { |
|
|
|
impl MessageWriter { |
|
|
|
pub fn new() -> MessageWriter { |
|
|
|
pub fn new() -> MessageWriter { |
|
|
|
MessageWriter { |
|
|
|
MessageWriter { |
|
|
|