kojacoord_protocol/versions/v1_8/status/
mod.rs1use bytes::{Buf, BufMut, Bytes, BytesMut};
2
3use crate::codec::{Decode, Encode, PacketId};
4use crate::error::ProtocolError;
5use crate::types::VarInt;
6
7pub use clientbound::{ClientboundPongResponse, ClientboundStatusResponse};
8pub use serverbound::{ServerboundPingRequest, ServerboundStatusRequest};
9
10pub const PROTOCOL_VERSION: u32 = 47;
11
12mod serverbound {
13 use super::*;
14
15 #[derive(Debug, Clone, PartialEq)]
16 pub struct ServerboundStatusRequest;
17
18 impl PacketId for ServerboundStatusRequest {
19 fn packet_id(_ver: u32) -> u8 {
20 0x00
21 }
22 }
23
24 impl Encode for ServerboundStatusRequest {
25 fn encode(&self, _dst: &mut BytesMut) -> Result<(), ProtocolError> {
26 Ok(())
27 }
28 }
29
30 impl Decode for ServerboundStatusRequest {
31 fn decode(_src: &mut Bytes) -> Result<Self, ProtocolError> {
32 Ok(Self)
33 }
34 }
35
36 #[derive(Debug, Clone, PartialEq)]
37 pub struct ServerboundPingRequest {
38 pub payload: i64,
39 }
40
41 impl PacketId for ServerboundPingRequest {
42 fn packet_id(_ver: u32) -> u8 {
43 0x01
44 }
45 }
46
47 impl Encode for ServerboundPingRequest {
48 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
49 dst.put_i64(self.payload);
50 Ok(())
51 }
52 }
53
54 impl Decode for ServerboundPingRequest {
55 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
56 Ok(Self {
57 payload: src.get_i64(),
58 })
59 }
60 }
61}
62
63mod clientbound {
64 use super::*;
65
66 #[derive(Debug, Clone, PartialEq)]
67 pub struct ClientboundStatusResponse {
68 pub json_response: String,
69 }
70
71 impl PacketId for ClientboundStatusResponse {
72 fn packet_id(_ver: u32) -> u8 {
73 0x00
74 }
75 }
76
77 impl Encode for ClientboundStatusResponse {
78 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
79 let json_bytes = self.json_response.as_bytes();
80 VarInt(json_bytes.len() as i32).encode(dst)?;
81 dst.put_slice(json_bytes);
82 Ok(())
83 }
84 }
85
86 impl Decode for ClientboundStatusResponse {
87 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
88 let json_len = VarInt::decode(src)?.0 as usize;
89
90 if src.remaining() < json_len {
91 return Err(ProtocolError::Io(std::io::Error::new(
92 std::io::ErrorKind::UnexpectedEof,
93 "Missing bytes while reading ClientboundStatusResponse JSON payload",
94 )));
95 }
96
97 let mut json_bytes = vec![0u8; json_len];
98 src.copy_to_slice(&mut json_bytes);
99
100 let json_response = String::from_utf8(json_bytes).map_err(|_| {
101 ProtocolError::Io(std::io::Error::new(
102 std::io::ErrorKind::InvalidData,
103 "Invalid UTF-8 string in ClientboundStatusResponse",
104 ))
105 })?;
106
107 Ok(Self { json_response })
108 }
109 }
110
111 #[derive(Debug, Clone, PartialEq)]
112 pub struct ClientboundPongResponse {
113 pub payload: i64,
114 }
115
116 impl PacketId for ClientboundPongResponse {
117 fn packet_id(_ver: u32) -> u8 {
118 0x01
119 }
120 }
121
122 impl Encode for ClientboundPongResponse {
123 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
124 dst.put_i64(self.payload);
125 Ok(())
126 }
127 }
128
129 impl Decode for ClientboundPongResponse {
130 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
131 if src.remaining() < 8 {
132 return Err(ProtocolError::Io(std::io::Error::new(
133 std::io::ErrorKind::UnexpectedEof,
134 "Missing bytes for ClientboundPongResponse payload",
135 )));
136 }
137 Ok(Self {
138 payload: src.get_i64(),
139 })
140 }
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147
148 #[test]
149 fn status_request_roundtrip() {
150 let mut buf = BytesMut::new();
151 ServerboundStatusRequest.encode(&mut buf).unwrap();
152 let mut bytes = buf.freeze();
153 let _ = ServerboundStatusRequest::decode(&mut bytes).unwrap();
154 }
155
156 #[test]
157 fn status_response_roundtrip() {
158 let p = ClientboundStatusResponse {
159 json_response: r#"{"version":{"name":"1.8","protocol":47},"players":{"max":20,"online":0},"description":{"text":"A Minecraft 1.8 server"}}"#.to_string(),
160 };
161 let mut buf = BytesMut::new();
162 p.encode(&mut buf).unwrap();
163 let mut bytes = buf.freeze();
164 assert_eq!(ClientboundStatusResponse::decode(&mut bytes).unwrap(), p);
165 }
166
167 #[test]
168 fn ping_roundtrip() {
169 let p = ServerboundPingRequest { payload: 123456789 };
170 let mut buf = BytesMut::new();
171 p.encode(&mut buf).unwrap();
172 let mut bytes = buf.freeze();
173 assert_eq!(ServerboundPingRequest::decode(&mut bytes).unwrap(), p);
174 }
175
176 #[test]
177 fn pong_roundtrip() {
178 let p = ClientboundPongResponse { payload: -99 };
179 let mut buf = BytesMut::new();
180 p.encode(&mut buf).unwrap();
181 let mut bytes = buf.freeze();
182 assert_eq!(ClientboundPongResponse::decode(&mut bytes).unwrap(), p);
183 }
184
185 #[test]
186 fn packet_ids_are_correct_for_1_8() {
187 assert_eq!(ServerboundStatusRequest::packet_id(PROTOCOL_VERSION), 0x00);
188 assert_eq!(ServerboundPingRequest::packet_id(PROTOCOL_VERSION), 0x01);
189 assert_eq!(ClientboundStatusResponse::packet_id(PROTOCOL_VERSION), 0x00);
190 assert_eq!(ClientboundPongResponse::packet_id(PROTOCOL_VERSION), 0x01);
191 }
192}