From 8eb940555c9fa9240bb754a6fae8f72156b87deb Mon Sep 17 00:00:00 2001 From: NotThatRqd <67846317+NotThatRqd@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:00:22 -0700 Subject: [PATCH 01/10] Add utility function for player head texture value --- crates/valence_protocol/src/item.rs | 31 ++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/crates/valence_protocol/src/item.rs b/crates/valence_protocol/src/item.rs index 1080abca7..527ff1601 100644 --- a/crates/valence_protocol/src/item.rs +++ b/crates/valence_protocol/src/item.rs @@ -1,7 +1,8 @@ use std::io::Write; pub use valence_generated::item::ItemKind; -use valence_nbt::Compound; +use valence_nbt::{Compound, compound, List}; +use uuid::Uuid; use crate::{Decode, Encode}; @@ -43,6 +44,34 @@ impl ItemStack { self } + #[must_use] + pub fn with_playerhead_texture_value(mut self, texture_value: impl Into) -> Result { + if self.item != ItemKind::PlayerHead { + return Err(()); + } + + let new_nbt = compound! { + "SkullOwner" => compound! { + "Id" => Uuid::default(), + "Properties" => compound! { + "textures" => List::Compound(vec![ + compound! { + "Value" => texture_value.into() + } + ]) + } + } + }; + + if let Some(nbt) = &mut self.nbt { + nbt.merge(new_nbt); + } else { + self.nbt = Some(new_nbt); + } + + Ok(self) + } + pub const fn is_empty(&self) -> bool { matches!(self.item, ItemKind::Air) || self.count <= 0 } From d32d7122bf7a3aa8881bebf0c56eb52f9a1e212f Mon Sep 17 00:00:00 2001 From: NotThatRqd <67846317+NotThatRqd@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:00:46 -0700 Subject: [PATCH 02/10] format --- crates/valence_protocol/src/item.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/valence_protocol/src/item.rs b/crates/valence_protocol/src/item.rs index 527ff1601..90fbf3310 100644 --- a/crates/valence_protocol/src/item.rs +++ b/crates/valence_protocol/src/item.rs @@ -1,8 +1,8 @@ use std::io::Write; -pub use valence_generated::item::ItemKind; -use valence_nbt::{Compound, compound, List}; use uuid::Uuid; +pub use valence_generated::item::ItemKind; +use valence_nbt::{compound, Compound, List}; use crate::{Decode, Encode}; @@ -45,7 +45,10 @@ impl ItemStack { } #[must_use] - pub fn with_playerhead_texture_value(mut self, texture_value: impl Into) -> Result { + pub fn with_playerhead_texture_value( + mut self, + texture_value: impl Into, + ) -> Result { if self.item != ItemKind::PlayerHead { return Err(()); } From 82084fc7bceb83beb3f227dc66de3819546ff238 Mon Sep 17 00:00:00 2001 From: NotThatRqd <67846317+NotThatRqd@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:08:20 -0700 Subject: [PATCH 03/10] add documentation --- crates/valence_protocol/src/item.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/crates/valence_protocol/src/item.rs b/crates/valence_protocol/src/item.rs index 90fbf3310..9e72e049e 100644 --- a/crates/valence_protocol/src/item.rs +++ b/crates/valence_protocol/src/item.rs @@ -44,6 +44,12 @@ impl ItemStack { self } + /// This function takes the "Value" of the skin you want to apply to a PlayerHead. + /// The "Value" is a Base64-encoded JSON object that is usually provided by websites. + /// To learn more: https://minecraft.wiki/w/Item_format#Player_Heads + /// + /// # Errors + /// This function returns an error if the [ItemStack] you call it on isn't a PlayerHead #[must_use] pub fn with_playerhead_texture_value( mut self, From e78bfdb235bea6ebc29e29a8cef630871e0d16f9 Mon Sep 17 00:00:00 2001 From: NotThatRqd <67846317+NotThatRqd@users.noreply.github.com> Date: Tue, 4 Jun 2024 15:24:22 -0700 Subject: [PATCH 04/10] fix formatting --- crates/valence_protocol/src/item.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/valence_protocol/src/item.rs b/crates/valence_protocol/src/item.rs index 9e72e049e..bd88da9a0 100644 --- a/crates/valence_protocol/src/item.rs +++ b/crates/valence_protocol/src/item.rs @@ -46,8 +46,8 @@ impl ItemStack { /// This function takes the "Value" of the skin you want to apply to a PlayerHead. /// The "Value" is a Base64-encoded JSON object that is usually provided by websites. - /// To learn more: https://minecraft.wiki/w/Item_format#Player_Heads - /// + /// To learn more: + /// /// # Errors /// This function returns an error if the [ItemStack] you call it on isn't a PlayerHead #[must_use] From 45291561d4bc225c7dc228a095233c3d0c171ad7 Mon Sep 17 00:00:00 2001 From: NotThatRqd <67846317+NotThatRqd@users.noreply.github.com> Date: Tue, 4 Jun 2024 16:51:06 -0700 Subject: [PATCH 05/10] better documentation --- crates/valence_protocol/src/item.rs | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/crates/valence_protocol/src/item.rs b/crates/valence_protocol/src/item.rs index bd88da9a0..95aca2221 100644 --- a/crates/valence_protocol/src/item.rs +++ b/crates/valence_protocol/src/item.rs @@ -50,6 +50,57 @@ impl ItemStack { /// /// # Errors /// This function returns an error if the [ItemStack] you call it on isn't a PlayerHead + /// + /// # Examples + /// ``` + /// // Value provided by https://minecraft-heads.com/ + /// let value = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzlmOWRkOGQ5MjQ0NTg0NWIwODM1MmZjMmY0OTRjYTE4OGJmNWMzNzFmM2JmOWQwMWJiNzRkOGVlNTk3YmM1YSJ9fX0="; + /// let head = ItemStack::new(ItemKind::PlayerHead, 1, None).with_playerhead_texture_value(value).unwrap(); + /// ``` + /// + /// Simple head command + /// ``` + /// fn command_handler( + /// mut command_events: EventReader, + /// mut clients_query: Query<(&mut Client, &Username, &Properties, &mut Inventory)>, + /// ) { + /// for event in command_events.read() { + /// if !event.command.starts_with("head") { + /// continue; + /// } + /// + /// let target_username = event.command.split(' ').nth(1); + /// let target = if let Some(target_username) = target_username { + /// clients_query + /// .iter() + /// .find(|(_, username, _, _)| username.0 == target_username) + /// } else { + /// Some(clients_query.get(event.executor).unwrap()) + /// }; + /// + /// if let Some(target) = target { + /// let properties = target.2; + /// let textures = properties.textures().unwrap(); + /// + /// // Construct a PlayerHead using `with_playerhead_texture_value` + /// let head = ItemStack::new( + /// ItemKind::PlayerHead, + /// 1, + /// None, + /// ).with_playerhead_texture_value(textures.value.clone()).unwrap(); + /// + /// let (_, _, _, mut inventory) = clients_query.get_mut(event.executor).unwrap(); + /// inventory.set_slot(36, head); + /// } else { + /// let (mut client, _, _, _) = clients_query.get_mut(event.executor).unwrap(); + /// client.send_chat_message( + /// "No player with that username found on the server".color(Color::RED), + /// ); + /// continue; + /// } + /// } + /// } + /// ``` #[must_use] pub fn with_playerhead_texture_value( mut self, From fbac53cbc56d80d74aa00999c4bb37049ea8939f Mon Sep 17 00:00:00 2001 From: NotThatRqd <67846317+NotThatRqd@users.noreply.github.com> Date: Tue, 4 Jun 2024 16:56:56 -0700 Subject: [PATCH 06/10] format --- crates/valence_protocol/src/item.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/valence_protocol/src/item.rs b/crates/valence_protocol/src/item.rs index 95aca2221..a30e2d819 100644 --- a/crates/valence_protocol/src/item.rs +++ b/crates/valence_protocol/src/item.rs @@ -57,7 +57,7 @@ impl ItemStack { /// let value = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzlmOWRkOGQ5MjQ0NTg0NWIwODM1MmZjMmY0OTRjYTE4OGJmNWMzNzFmM2JmOWQwMWJiNzRkOGVlNTk3YmM1YSJ9fX0="; /// let head = ItemStack::new(ItemKind::PlayerHead, 1, None).with_playerhead_texture_value(value).unwrap(); /// ``` - /// + /// /// Simple head command /// ``` /// fn command_handler( @@ -81,14 +81,14 @@ impl ItemStack { /// if let Some(target) = target { /// let properties = target.2; /// let textures = properties.textures().unwrap(); - /// + /// /// // Construct a PlayerHead using `with_playerhead_texture_value` /// let head = ItemStack::new( /// ItemKind::PlayerHead, /// 1, /// None, /// ).with_playerhead_texture_value(textures.value.clone()).unwrap(); - /// + /// /// let (_, _, _, mut inventory) = clients_query.get_mut(event.executor).unwrap(); /// inventory.set_slot(36, head); /// } else { From 01ff0f05163cd3fe43f1d9bc232c7241ed430672 Mon Sep 17 00:00:00 2001 From: NotThatRqd <67846317+NotThatRqd@users.noreply.github.com> Date: Wed, 5 Jun 2024 19:23:28 -0700 Subject: [PATCH 07/10] update example to use better command system --- crates/valence_protocol/src/item.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/crates/valence_protocol/src/item.rs b/crates/valence_protocol/src/item.rs index a30e2d819..765066420 100644 --- a/crates/valence_protocol/src/item.rs +++ b/crates/valence_protocol/src/item.rs @@ -58,22 +58,25 @@ impl ItemStack { /// let head = ItemStack::new(ItemKind::PlayerHead, 1, None).with_playerhead_texture_value(value).unwrap(); /// ``` /// - /// Simple head command + /// Simple head command. More examples of Valence's command system: /// ``` + /// #[derive(Command)] + /// #[paths("head {username}")] + /// struct HeadCommand { + /// username: String, + /// } + /// /// fn command_handler( - /// mut command_events: EventReader, + /// mut command_events: EventReader>, /// mut clients_query: Query<(&mut Client, &Username, &Properties, &mut Inventory)>, /// ) { /// for event in command_events.read() { - /// if !event.command.starts_with("head") { - /// continue; - /// } - /// - /// let target_username = event.command.split(' ').nth(1); - /// let target = if let Some(target_username) = target_username { + /// let target_username = &event.result.username; + /// + /// let target = if !target_username.is_empty() { /// clients_query /// .iter() - /// .find(|(_, username, _, _)| username.0 == target_username) + /// .find(|(_, username, _, _)| username.0 == *target_username) /// } else { /// Some(clients_query.get(event.executor).unwrap()) /// }; @@ -96,7 +99,6 @@ impl ItemStack { /// client.send_chat_message( /// "No player with that username found on the server".color(Color::RED), /// ); - /// continue; /// } /// } /// } From f1bbec3f2cd950de7d0483be5dd437ca806a8ff8 Mon Sep 17 00:00:00 2001 From: NotThatRqd <67846317+NotThatRqd@users.noreply.github.com> Date: Wed, 5 Jun 2024 19:24:10 -0700 Subject: [PATCH 08/10] formatting --- crates/valence_protocol/src/item.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/valence_protocol/src/item.rs b/crates/valence_protocol/src/item.rs index 765066420..e345c50b0 100644 --- a/crates/valence_protocol/src/item.rs +++ b/crates/valence_protocol/src/item.rs @@ -65,14 +65,14 @@ impl ItemStack { /// struct HeadCommand { /// username: String, /// } - /// + /// /// fn command_handler( /// mut command_events: EventReader>, /// mut clients_query: Query<(&mut Client, &Username, &Properties, &mut Inventory)>, /// ) { /// for event in command_events.read() { /// let target_username = &event.result.username; - /// + /// /// let target = if !target_username.is_empty() { /// clients_query /// .iter() From 245c2c79f5e97f4d819a3d1ea7bde8c394985f41 Mon Sep 17 00:00:00 2001 From: NotThatRqd <67846317+NotThatRqd@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:33:49 -0700 Subject: [PATCH 09/10] formatting please --- crates/valence_protocol/src/item.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/valence_protocol/src/item.rs b/crates/valence_protocol/src/item.rs index e345c50b0..2b7e4170c 100644 --- a/crates/valence_protocol/src/item.rs +++ b/crates/valence_protocol/src/item.rs @@ -44,9 +44,9 @@ impl ItemStack { self } - /// This function takes the "Value" of the skin you want to apply to a PlayerHead. - /// The "Value" is a Base64-encoded JSON object that is usually provided by websites. - /// To learn more: + /// This function takes the "Value" of the skin you want to apply to a + /// PlayerHead. The "Value" is a Base64-encoded JSON object that is + /// usually provided by websites. To learn more: /// /// # Errors /// This function returns an error if the [ItemStack] you call it on isn't a PlayerHead @@ -86,11 +86,9 @@ impl ItemStack { /// let textures = properties.textures().unwrap(); /// /// // Construct a PlayerHead using `with_playerhead_texture_value` - /// let head = ItemStack::new( - /// ItemKind::PlayerHead, - /// 1, - /// None, - /// ).with_playerhead_texture_value(textures.value.clone()).unwrap(); + /// let head = ItemStack::new(ItemKind::PlayerHead, 1, None) + /// .with_playerhead_texture_value(textures.value.clone()) + /// .unwrap(); /// /// let (_, _, _, mut inventory) = clients_query.get_mut(event.executor).unwrap(); /// inventory.set_slot(36, head); From 6ba8c0a108880e65723eb31262269af55acd1b16 Mon Sep 17 00:00:00 2001 From: NotThatRqd <67846317+NotThatRqd@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:37:01 -0700 Subject: [PATCH 10/10] please format --- crates/valence_protocol/src/item.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/valence_protocol/src/item.rs b/crates/valence_protocol/src/item.rs index 2b7e4170c..3fac674a0 100644 --- a/crates/valence_protocol/src/item.rs +++ b/crates/valence_protocol/src/item.rs @@ -46,10 +46,11 @@ impl ItemStack { /// This function takes the "Value" of the skin you want to apply to a /// PlayerHead. The "Value" is a Base64-encoded JSON object that is - /// usually provided by websites. To learn more: + /// usually provided by websites. To learn more: /// /// # Errors - /// This function returns an error if the [ItemStack] you call it on isn't a PlayerHead + /// This function returns an error if the [ItemStack] you call it on isn't a + /// PlayerHead /// /// # Examples /// ```