aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-01-03 00:14:41 -0600
committermat <github@matdoes.dev>2022-01-03 00:14:41 -0600
commit96eba2b39a596dd19c29a93aaa3b5bb9b700ba62 (patch)
tree9a585864e81fd01da15bdc9ca5e4e3e7a69eb1f4
parent394f996df27bedc68be6c1f9e9764e8f78ba6282 (diff)
downloadazalea-drasl-96eba2b39a596dd19c29a93aaa3b5bb9b700ba62.tar.xz
difficulty packet
-rw-r--r--azalea-client/src/connect.rs3
-rw-r--r--azalea-core/src/difficulty.rs96
-rw-r--r--azalea-core/src/lib.rs10
-rw-r--r--azalea-protocol/src/mc_buf/read.rs38
-rw-r--r--azalea-protocol/src/mc_buf/write.rs19
-rw-r--r--azalea-protocol/src/packets/game/clientbound_change_difficulty_packet.rs8
-rw-r--r--azalea-protocol/src/packets/game/mod.rs15
7 files changed, 177 insertions, 12 deletions
diff --git a/azalea-client/src/connect.rs b/azalea-client/src/connect.rs
index 6ed25bff..7b1da525 100644
--- a/azalea-client/src/connect.rs
+++ b/azalea-client/src/connect.rs
@@ -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);
diff --git a/azalea-core/src/difficulty.rs b/azalea-core/src/difficulty.rs
new file mode 100644
index 00000000..21e980ba
--- /dev/null
+++ b/azalea-core/src/difficulty.rs
@@ -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());
+ }
+}
diff --git a/azalea-core/src/lib.rs b/azalea-core/src/lib.rs
index 887d1686..cdf07c43 100644
--- a/azalea-core/src/lib.rs
+++ b/azalea-core/src/lib.rs
@@ -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);
- }
-}
diff --git a/azalea-protocol/src/mc_buf/read.rs b/azalea-protocol/src/mc_buf/read.rs
index 5127860e..0fa1d099 100644
--- a/azalea-protocol/src/mc_buf/read.rs
+++ b/azalea-protocol/src/mc_buf/read.rs
@@ -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?))
+ }
+}
diff --git a/azalea-protocol/src/mc_buf/write.rs b/azalea-protocol/src/mc_buf/write.rs
index 6fbe6eab..fd9faeb4 100644
--- a/azalea-protocol/src/mc_buf/write.rs
+++ b/azalea-protocol/src/mc_buf/write.rs
@@ -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)
+ }
+}
diff --git a/azalea-protocol/src/packets/game/clientbound_change_difficulty_packet.rs b/azalea-protocol/src/packets/game/clientbound_change_difficulty_packet.rs
new file mode 100644
index 00000000..e12cfff3
--- /dev/null
+++ b/azalea-protocol/src/packets/game/clientbound_change_difficulty_packet.rs
@@ -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,
+}
diff --git a/azalea-protocol/src/packets/game/mod.rs b/azalea-protocol/src/packets/game/mod.rs
index 43b3ca3d..4efe72fb 100644
--- a/azalea-protocol/src/packets/game/mod.rs
+++ b/azalea-protocol/src/packets/game/mod.rs
@@ -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