kojacoord-protocol 0.1.0

Minecraft protocol types, packet (de)serialization and version registry for the Kojacoord proxy.
Documentation
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ProtocolVersion {
    V1_6_4,

    V1_7_10,

    V1_8,

    V1_12_2,

    V1_16_5,

    V1_19_4,

    V1_20_4,

    V1_21,

    Unknown(u32),
}

impl ProtocolVersion {
    pub fn from_id(id: u32) -> Self {
        match id {
            5 => ProtocolVersion::V1_7_10,
            47 => ProtocolVersion::V1_8,
            78 => ProtocolVersion::V1_6_4,
            340 => ProtocolVersion::V1_12_2,
            754 => ProtocolVersion::V1_16_5,
            762 => ProtocolVersion::V1_19_4,
            765 => ProtocolVersion::V1_20_4,
            767 => ProtocolVersion::V1_21,
            x => ProtocolVersion::Unknown(x),
        }
    }

    pub fn id(&self) -> u32 {
        match self {
            ProtocolVersion::V1_6_4 => 78,
            ProtocolVersion::V1_7_10 => 5,
            ProtocolVersion::V1_8 => 47,
            ProtocolVersion::V1_12_2 => 340,
            ProtocolVersion::V1_16_5 => 754,
            ProtocolVersion::V1_19_4 => 762,
            ProtocolVersion::V1_20_4 => 765,
            ProtocolVersion::V1_21 => 767,
            ProtocolVersion::Unknown(x) => *x,
        }
    }

    pub fn is_supported(&self) -> bool {
        !matches!(self, ProtocolVersion::Unknown(_))
    }
}

pub struct VersionRegistry;

impl VersionRegistry {
    const SUPPORTED: &'static [u32] = &[5, 47, 78, 340, 754, 762, 765, 767];

    pub fn nearest(protocol_id: u32) -> ProtocolVersion {
        let exact = ProtocolVersion::from_id(protocol_id);
        if exact.is_supported() {
            return exact;
        }

        let best = Self::SUPPORTED
            .iter()
            .copied()
            .min_by_key(|&s| (s as i64 - protocol_id as i64).unsigned_abs())
            .unwrap_or(767);

        ProtocolVersion::from_id(best)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn known_versions_roundtrip() {
        for &id in VersionRegistry::SUPPORTED {
            let v = ProtocolVersion::from_id(id);
            assert!(v.is_supported());
            assert_eq!(v.id(), id);
        }
    }

    #[test]
    fn v1_7_10_recognized() {
        assert_eq!(ProtocolVersion::from_id(5), ProtocolVersion::V1_7_10);
    }

    #[test]
    fn v1_6_4_recognized() {
        assert_eq!(ProtocolVersion::from_id(78), ProtocolVersion::V1_6_4);
    }

    #[test]
    fn nearest_exact() {
        assert_eq!(VersionRegistry::nearest(47), ProtocolVersion::V1_8);
        assert_eq!(VersionRegistry::nearest(5), ProtocolVersion::V1_7_10);
    }

    #[test]
    fn nearest_between_versions() {
        let v = VersionRegistry::nearest(400);
        assert_eq!(v, ProtocolVersion::V1_12_2);
    }
}