npc missions used to get a ServerErrorMessage back. now StartMission builds a LogicGameMode snapshot off the arena tilemap and answers 21903. towers come from assets/locations/*.csv the way initDefaultSector does it: tile coordinates times 500, leader index decided by which half of the map the tower sits in. the two king towers must be there, the client dereferences them without a null check. they live in buildings.csv, not characters.csv. LogicCharacter puts the base object fields fourth, not first. the buff component writes a fixed array sized by the character_buffs row count even with no buffs. training_arena parses to 2 kings, 4 princess towers, 36x64 subtiles. snapshot is 602 bytes over 6 objects. the real client has not seen it yet.
52 lines
1.7 KiB
Rust
52 lines
1.7 KiB
Rust
use std::fmt;
|
|
pub type Result<T> = std::result::Result<T, Error>;
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum Error {
|
|
#[error("unexpected end of stream: wanted {wanted} byte(s) at offset {offset}, {available} available")]
|
|
Eof {
|
|
offset: usize,
|
|
wanted: usize,
|
|
available: usize,
|
|
},
|
|
#[error("string length {length} exceeds the {limit} byte limit")]
|
|
StringTooLong { length: usize, limit: usize },
|
|
#[error("negative length {0}")]
|
|
NegativeLength(i32),
|
|
#[error("invalid utf-8 payload: {0}")]
|
|
Utf8(#[from] std::str::Utf8Error),
|
|
#[error("payload of {actual} byte(s) exceeds the {limit} byte frame limit")]
|
|
FrameTooLarge { actual: usize, limit: usize },
|
|
#[error("collection of {actual} item(s) exceeds the {limit} item limit")]
|
|
CollectionTooLarge { actual: usize, limit: usize },
|
|
#[error("expected exactly {expected} item(s), got {actual}")]
|
|
ArityMismatch { expected: usize, actual: usize },
|
|
#[error("unknown message type {0}")]
|
|
UnknownMessageType(u16),
|
|
#[error("unknown command type {0}")]
|
|
UnknownCommandType(i32),
|
|
#[error("trailing {0} unread byte(s)")]
|
|
TrailingBytes(usize),
|
|
#[error("{0}")]
|
|
Unsupported(&'static str),
|
|
#[error("io: {0}")]
|
|
Io(#[from] std::io::Error),
|
|
}
|
|
impl Error {
|
|
pub fn eof(offset: usize, wanted: usize, available: usize) -> Self {
|
|
Error::Eof {
|
|
offset,
|
|
wanted,
|
|
available,
|
|
}
|
|
}
|
|
}
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub struct DecodeContext {
|
|
pub message_type: u16,
|
|
pub offset: usize,
|
|
}
|
|
impl fmt::Display for DecodeContext {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "message {} at offset {}", self.message_type, self.offset)
|
|
}
|
|
}
|