difficulty packet

This commit is contained in:
mat 2022-01-03 00:14:41 -06:00
parent 394f996df2
commit 96eba2b39a
7 changed files with 177 additions and 12 deletions

View file

@ -70,6 +70,9 @@ pub async fn join_server(address: &ServerAddress) -> Result<(), String> {
GamePacket::ClientboundCustomPayloadPacket(p) => {
println!("Got custom payload packet {:?}", p);
}
GamePacket::ClientboundChangeDifficultyPacket(p) => {
println!("Got difficulty packet {:?}", p);
}
},
Err(e) => {
println!("Error: {:?}", e);

View file

@ -0,0 +1,96 @@
use std::fmt::{Debug, Error, Formatter};
#[derive(Hash, Clone, Debug, PartialEq)]
pub enum Difficulty {
PEACEFUL,
EASY,
NORMAL,
HARD,
}
pub enum Err {
InvalidDifficulty(String),
}
impl Debug for Err {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
match self {
Err::InvalidDifficulty(s) => write!(f, "Invalid difficulty: {}", s),
}
}
}
impl Difficulty {
pub fn name(&self) -> &'static str {
match self {
Difficulty::PEACEFUL => "peaceful",
Difficulty::EASY => "easy",
Difficulty::NORMAL => "normal",
Difficulty::HARD => "hard",
}
}
pub fn from_name(name: &str) -> Result<Difficulty, Err> {
match name {
"peaceful" => Ok(Difficulty::PEACEFUL),
"easy" => Ok(Difficulty::EASY),
"normal" => Ok(Difficulty::NORMAL),
"hard" => Ok(Difficulty::HARD),
_ => Err(Err::InvalidDifficulty(name.to_string())),
}
}
pub fn by_id(id: u8) -> Difficulty {
match id % 4 {
0 => Difficulty::PEACEFUL,
1 => Difficulty::EASY,
2 => Difficulty::NORMAL,
3 => Difficulty::HARD,
// this shouldn't be possible because of the modulo, so panicking is fine
_ => panic!("Unknown difficulty id: {}", id),
}
}
pub fn id(&self) -> u8 {
match self {
Difficulty::PEACEFUL => 0,
Difficulty::EASY => 1,
Difficulty::NORMAL => 2,
Difficulty::HARD => 3,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_difficulty_from_name() {
assert_eq!(
Difficulty::PEACEFUL,
Difficulty::from_name("peaceful").unwrap()
);
assert_eq!(Difficulty::EASY, Difficulty::from_name("easy").unwrap());
assert_eq!(Difficulty::NORMAL, Difficulty::from_name("normal").unwrap());
assert_eq!(Difficulty::HARD, Difficulty::from_name("hard").unwrap());
assert!(Difficulty::from_name("invalid").is_err());
}
#[test]
fn test_difficulty_id() {
assert_eq!(0, Difficulty::PEACEFUL.id());
assert_eq!(1, Difficulty::EASY.id());
assert_eq!(2, Difficulty::NORMAL.id());
assert_eq!(3, Difficulty::HARD.id());
assert_eq!(4, Difficulty::PEACEFUL.id());
}
#[test]
fn test_difficulty_name() {
assert_eq!("peaceful", Difficulty::PEACEFUL.name());
assert_eq!("easy", Difficulty::EASY.name());
assert_eq!("normal", Difficulty::NORMAL.name());
assert_eq!("hard", Difficulty::HARD.name());
}
}

View file

@ -1,14 +1,6 @@
//! Random miscellaneous things like UUIDs that don't deserve their own crate.
pub mod difficulty;
pub mod game_type;
pub mod resource_location;
pub mod serializable_uuid;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
}

View file

@ -1,5 +1,8 @@
use async_trait::async_trait;
use azalea_core::{game_type::GameType, resource_location::ResourceLocation};
use azalea_core::{
difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation,
};
use num_traits::FromPrimitive;
use tokio::io::{AsyncRead, AsyncReadExt};
use super::MAX_STRING_LENGTH;
@ -338,6 +341,28 @@ impl McBufReadable for bool {
}
}
// u8
#[async_trait]
impl McBufReadable for u8 {
async fn read_into<R>(buf: &mut R) -> Result<Self, String>
where
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_byte().await
}
}
// i8
#[async_trait]
impl McBufReadable for i8 {
async fn read_into<R>(buf: &mut R) -> Result<Self, String>
where
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
buf.read_byte().await.map(|i| i as i8)
}
}
// GameType
#[async_trait]
impl McBufReadable for GameType {
@ -386,3 +411,14 @@ impl McBufReadable for azalea_nbt::Tag {
buf.read_nbt().await
}
}
// Difficulty
#[async_trait]
impl McBufReadable for Difficulty {
async fn read_into<R>(buf: &mut R) -> Result<Self, String>
where
R: AsyncRead + std::marker::Unpin + std::marker::Send,
{
Ok(Difficulty::by_id(u8::read_into(buf).await?))
}
}

View file

@ -1,6 +1,9 @@
use async_trait::async_trait;
use azalea_core::{game_type::GameType, resource_location::ResourceLocation};
use azalea_core::{
difficulty::Difficulty, game_type::GameType, resource_location::ResourceLocation,
};
use byteorder::{BigEndian, WriteBytesExt};
use num_traits::FromPrimitive;
use std::io::Write;
use super::MAX_STRING_LENGTH;
@ -255,6 +258,13 @@ impl McBufWritable for bool {
}
}
// i8
impl McBufWritable for i8 {
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
buf.write_byte(*self as u8)
}
}
// GameType
impl McBufWritable for GameType {
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
@ -284,3 +294,10 @@ impl McBufWritable for azalea_nbt::Tag {
buf.write_nbt(self)
}
}
// Difficulty
impl McBufWritable for Difficulty {
fn write_into(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
u8::write_into(&self.id(), buf)
}
}

View file

@ -0,0 +1,8 @@
use azalea_core::difficulty::Difficulty;
use packet_macros::GamePacket;
#[derive(Clone, Debug, GamePacket)]
pub struct ClientboundChangeDifficultyPacket {
pub difficulty: Difficulty,
pub locked: bool,
}

View file

@ -1,3 +1,4 @@
pub mod clientbound_change_difficulty_packet;
pub mod clientbound_custom_payload_packet;
pub mod clientbound_login_packet;
pub mod clientbound_update_view_distance_packet;
@ -18,12 +19,16 @@ where
ClientboundCustomPayloadPacket(
clientbound_custom_payload_packet::ClientboundCustomPayloadPacket,
),
ClientboundChangeDifficultyPacket(
clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket,
),
}
#[async_trait]
impl ProtocolPacket for GamePacket {
fn id(&self) -> u32 {
match self {
GamePacket::ClientboundChangeDifficultyPacket(_packet) => 0x0e,
GamePacket::ClientboundCustomPayloadPacket(_packet) => 0x18,
GamePacket::ClientboundLoginPacket(_packet) => 0x26,
GamePacket::ClientboundUpdateViewDistancePacket(_packet) => 0x4a,
@ -31,7 +36,12 @@ impl ProtocolPacket for GamePacket {
}
fn write(&self, buf: &mut Vec<u8>) -> Result<(), std::io::Error> {
Ok(())
match self {
GamePacket::ClientboundChangeDifficultyPacket(packet) => packet.write(buf),
GamePacket::ClientboundCustomPayloadPacket(packet) => packet.write(buf),
GamePacket::ClientboundLoginPacket(packet) => packet.write(buf),
GamePacket::ClientboundUpdateViewDistancePacket(packet) => packet.write(buf),
}
}
/// Read a packet by its id, ConnectionProtocol, and flow
@ -45,6 +55,9 @@ impl ProtocolPacket for GamePacket {
{
Ok(match flow {
PacketFlow::ServerToClient => match id {
0x0e => clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket
::read(buf)
.await?,
0x18 => clientbound_custom_payload_packet::ClientboundCustomPayloadPacket::read(buf).await?,
0x26 => clientbound_login_packet::ClientboundLoginPacket::read(buf).await?,
0x4a => clientbound_update_view_distance_packet::ClientboundUpdateViewDistancePacket