Skip to content

Commit

Permalink
feat: add colored leather armor for team
Browse files Browse the repository at this point in the history
Add support for colored leather armor with a new `Color` struct and helper methods to visually distinguish teams. Simplifies player customization by using a single skin per rank with team-colored boots instead of team-specific skin files.

Example:
```rust
ItemBuilder::new(ItemKind::LeatherHelmet)
    .color(Color(255, 0, 0))
    .build()
```
  • Loading branch information
andrewgazelka committed Nov 18, 2024
1 parent ef000fb commit bb30c06
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 81 deletions.
38 changes: 38 additions & 0 deletions crates/hyperion-item/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ impl Attribute for MaxHealth {
}
}

#[derive(Copy, Clone, Debug)]
pub struct Color(pub u8, pub u8, pub u8);

impl ItemBuilder {
pub const fn new(kind: ItemKind) -> Self {
Self {
Expand All @@ -74,6 +77,41 @@ impl ItemBuilder {
}
}

/// Sets the color of a leather armor item
///
/// # Example
/// ```
/// // Create a red leather helmet
/// use hyperion::ItemKind;
/// use hyperion_item::builder::{Color, ItemBuilder};
/// let item = ItemBuilder::new(ItemKind::LeatherHelmet)
/// .color(Color(255, 0, 0))
/// .build();
/// ```
pub fn color(mut self, color: Color) -> Self {
let nbt = self.nbt.get_or_insert_with(nbt::Compound::new);

// Create or get existing display compound
let display = match nbt.remove("display") {
Some(Value::Compound(display)) => display,
_ => nbt::Compound::new(),
};

let r = color.0;
let g = color.1;
let b = color.2;

// Create a new display compound with the color
let mut new_display = display;
let color = (u32::from(r) << 16) | (u32::from(g) << 8) | u32::from(b);
let color = bytemuck::cast(color);
new_display.insert("color", Value::Int(color));

// Insert the updated display compound
nbt.insert("display", Value::Compound(new_display));
self
}

/// Sets a custom name for the item
pub fn name(mut self, name: impl Into<String>) -> Self {
let nbt = self.nbt.get_or_insert_with(nbt::Compound::new);
Expand Down
17 changes: 16 additions & 1 deletion crates/hyperion-rank-tree/src/inventory.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use flecs_ecs::core::{World, WorldGet};
use hyperion_inventory::PlayerInventory;
use hyperion_item::builder::{AttackDamage, ItemBuilder};
use hyperion_item::builder::{AttackDamage, Color, ItemBuilder};
use valence_protocol::ItemKind;

use crate::{Handles, Rank, Team};
Expand Down Expand Up @@ -30,6 +30,21 @@ impl Rank {

let upgrade_not_available = ItemBuilder::new(ItemKind::GrayDye);

inventory.clear();

let color = match team {
Team::Red => Color(255, 0, 0),
Team::Blue => Color(0, 0, 255),
Team::Green => Color(0, 255, 0),
Team::Yellow => Color(255, 255, 0),
};

let boots = ItemBuilder::new(ItemKind::LeatherBoots)
.color(color)
.build();

inventory.set_boots(boots);

let upgrades = ["Speed", "Vision", "Health", "Armor", "Damage"];

world.get::<&Handles>(|handles| {
Expand Down
103 changes: 26 additions & 77 deletions crates/hyperion-rank-tree/src/skin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,89 +2,38 @@ use std::sync::LazyLock;

use hyperion::simulation::skin::PlayerSkin;

use crate::{Rank, Team};

macro_rules! define_skins {
($($rank:ident => $file:literal),* $(,)?) => {
$(
define_team_skins!($rank => $file);
)*
use crate::Rank;

macro_rules! define_skin {
($name:ident, $path:literal) => {
static $name: LazyLock<PlayerSkin> = LazyLock::new(|| {
let skin = include_str!($path);
toml::from_str(skin).unwrap()
});
};
}

macro_rules! define_team_skins {
($rank:ident => $file:literal) => {
paste::paste! {
static [<RED_ $rank>]: LazyLock<PlayerSkin> = LazyLock::new(|| {
let skin = include_str!(concat!("skin/red/", $file, ".toml"));
toml::from_str(skin).unwrap()
});
static [<BLUE_ $rank>]: LazyLock<PlayerSkin> = LazyLock::new(|| {
let skin = include_str!(concat!("skin/blue/", $file, ".toml"));
toml::from_str(skin).unwrap()
});
static [<GREEN_ $rank>]: LazyLock<PlayerSkin> = LazyLock::new(|| {
let skin = include_str!(concat!("skin/green/", $file, ".toml"));
toml::from_str(skin).unwrap()
});
static [<YELLOW_ $rank>]: LazyLock<PlayerSkin> = LazyLock::new(|| {
let skin = include_str!(concat!("skin/yellow/", $file, ".toml"));
toml::from_str(skin).unwrap()
});
}
};
}

define_skins! {
// STICK_SKIN => "stick",
// SWORDSMAN_SKIN => "swordsman",
KNIGHT_SKIN => "knight",
// ARCHER_SKIN => "archer",
// MAGE_SKIN => "mage",
// BUILDER_SKIN => "builder",
// MINER_SKIN => "miner",
// EXCAVATOR_SKIN => "excavator"
}
define_skin!(STICK_SKIN, "skin/stick.toml");
define_skin!(SWORDSMAN_SKIN, "skin/swordsman.toml");
define_skin!(KNIGHT_SKIN, "skin/knight.toml");
define_skin!(ARCHER_SKIN, "skin/archer.toml");
define_skin!(MAGE_SKIN, "skin/mage.toml");
define_skin!(BUILDER_SKIN, "skin/builder.toml");
define_skin!(MINER_SKIN, "skin/miner.toml");
define_skin!(EXCAVATOR_SKIN, "skin/excavator.toml");

impl Rank {
#[must_use]
pub fn skin(&self, team: Team) -> &'static PlayerSkin {
match (team, self) {
// (Team::Red, Self::Stick) => &RED_STICK_SKIN,
// (Team::Red, Self::Sword) => &RED_SWORDSMAN_SKIN,
// (Team::Red, Self::Archer) => &RED_ARCHER_SKIN,
// (Team::Red, Self::Mage) => &RED_MAGE_SKIN,
// (Team::Red, Self::Builder) => &RED_BUILDER_SKIN,
// (Team::Red, Self::Miner) => &RED_MINER_SKIN,
// (Team::Red, Self::Excavator) => &RED_EXCAVATOR_SKIN,

// (Team::Blue, Self::Stick) => &BLUE_STICK_SKIN,
// (Team::Blue, Self::Sword) => &BLUE_SWORDSMAN_SKIN,
(Team::Blue, Self::Knight) => &BLUE_KNIGHT_SKIN,
// (Team::Blue, Self::Archer) => &BLUE_ARCHER_SKIN,
// (Team::Blue, Self::Mage) => &BLUE_MAGE_SKIN,
// (Team::Blue, Self::Builder) => &BLUE_BUILDER_SKIN,
// (Team::Blue, Self::Miner) => &BLUE_MINER_SKIN,
// (Team::Blue, Self::Excavator) => &BLUE_EXCAVATOR_SKIN,

// (Team::Green, Self::Stick) => &GREEN_STICK_SKIN,
// (Team::Green, Self::Sword) => &GREEN_SWORDSMAN_SKIN,
(Team::Green, Self::Knight) => &GREEN_KNIGHT_SKIN,
// (Team::Green, Self::Archer) => &GREEN_ARCHER_SKIN,
// (Team::Green, Self::Mage) => &GREEN_MAGE_SKIN,
// (Team::Green, Self::Builder) => &GREEN_BUILDER_SKIN,
// (Team::Green, Self::Miner) => &GREEN_MINER_SKIN,
// (Team::Green, Self::Excavator) => &GREEN_EXCAVATOR_SKIN,

// (Team::Yellow, Self::Stick) => &YELLOW_STICK_SKIN,
// (Team::Yellow, Self::Sword) => &YELLOW_SWORDSMAN_SKIN,
(Team::Yellow, Self::Knight) => &YELLOW_KNIGHT_SKIN,
// (Team::Yellow, Self::Archer) => &YELLOW_ARCHER_SKIN,
// (Team::Yellow, Self::Mage) => &YELLOW_MAGE_SKIN,
// (Team::Yellow, Self::Builder) => &YELLOW_BUILDER_SKIN,
// (Team::Yellow, Self::Miner) => &YELLOW_MINER_SKIN,
// (Team::Yellow, Self::Excavator) => &YELLOW_EXCAVATOR_SKIN,
_ => &RED_KNIGHT_SKIN, // Default fallback
pub fn skin(&self) -> &'static PlayerSkin {
match self {
Self::Stick => &STICK_SKIN,
Self::Sword => &SWORDSMAN_SKIN,
Self::Knight => &KNIGHT_SKIN,
Self::Archer => &ARCHER_SKIN,
Self::Mage => &MAGE_SKIN,
Self::Builder => &BUILDER_SKIN,
Self::Miner => &MINER_SKIN,
Self::Excavator => &EXCAVATOR_SKIN,
}
}
}
2 changes: 0 additions & 2 deletions crates/hyperion/src/simulation/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,6 @@ fn chat_command(mut data: &'static [u8], query: &PacketSwitchQuery<'_>) -> anyho
fn hand_swing(mut data: &[u8], query: &mut PacketSwitchQuery<'_>) -> anyhow::Result<()> {
let packet = play::HandSwingC2s::decode(&mut data)?;

println!("hand swing");

match packet.hand {
Hand::Main => {
query.animation.push(animation::Kind::SwingMainArm);
Expand Down
2 changes: 1 addition & 1 deletion events/proof-of-concept/src/command/rank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl MinecraftCommand for ClassCommand {
)
.unwrap();

let skin = rank.skin(team);
let skin = rank.skin();
let property = Property {
name: "textures".to_string(),
value: skin.textures.clone(),
Expand Down

0 comments on commit bb30c06

Please sign in to comment.