-
-
Notifications
You must be signed in to change notification settings - Fork 144
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
# Objective - make valence work with entity equipment (armor, main/off hand items) # Solution adds the crate `valence_equipment` that exposes the Equipment Plugin. every `LivingEntity` will have a `Equipment` Component. The Equipment plugin will NOT be compatible with the inventory by default (thats intended, as that makes it possible to use the equipment feature without the inventory feature + I do think there are probably use cases where you want to make players appear as having armor, although they dont have it in their inventory) This PR would add Events when entities are (un)loaded by a player (used for sending equipment once the player loads an entity). I do believe this might also be a useful feature outside of the equipment feature. used #254 as reference + stole example idea fixes #662 Opening as a draft for now (might refactor the updating/event emitting system). Let me know what you think of the Entity Load/Unload events.
- Loading branch information
1 parent
daaa682
commit c57193a
Showing
12 changed files
with
1,392 additions
and
177 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[package] | ||
name = "valence_equipment" | ||
description = "Equipment support for Valence" | ||
readme = "README.md" | ||
version.workspace = true | ||
edition.workspace = true | ||
repository.workspace = true | ||
documentation.workspace = true | ||
license.workspace = true | ||
|
||
[lints] | ||
workspace = true | ||
|
||
[dependencies] | ||
bevy_app.workspace = true | ||
bevy_ecs.workspace = true | ||
derive_more.workspace = true | ||
tracing.workspace = true | ||
valence_server.workspace = true | ||
valence_inventory.workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# `valence_equipment` | ||
Manages Minecraft's entity equipment (armor, held items) via the `Equipment` component. | ||
By default this is separated from an entities `Inventory` (which means that changes are only visible to other players), but it can be synced by attaching the `EquipmentInventorySync` | ||
component to a entity (currently only Players). | ||
|
||
## Example | ||
|
||
```rust | ||
use bevy_ecs::prelude::*; | ||
use valence_equipment::*; | ||
use valence_server::{ | ||
ItemStack, ItemKind, | ||
entity::player::PlayerEntity, | ||
}; | ||
// Add equipment to players when they are added to the world. | ||
fn init_equipment( | ||
mut clients: Query< | ||
&mut Equipment, | ||
( | ||
Added<Equipment>, | ||
With<PlayerEntity>, | ||
), | ||
>, | ||
) { | ||
for mut equipment in &mut clients | ||
{ | ||
equipment.set_main_hand(ItemStack::new(ItemKind::DiamondSword, 1, None)); | ||
equipment.set_off_hand(ItemStack::new(ItemKind::Shield, 1, None)); | ||
equipment.set_feet(ItemStack::new(ItemKind::DiamondBoots, 1, None)); | ||
equipment.set_legs(ItemStack::new(ItemKind::DiamondLeggings, 1, None)); | ||
equipment.set_chest(ItemStack::new(ItemKind::DiamondChestplate, 1, None)); | ||
equipment.set_head(ItemStack::new(ItemKind::DiamondHelmet, 1, None)); | ||
} | ||
} | ||
``` | ||
|
||
### See also | ||
|
||
Examples related to inventories in the `valence/examples/` directory: | ||
- `equipment` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
use valence_inventory::player_inventory::PlayerInventory; | ||
use valence_inventory::{HeldItem, Inventory, UpdateSelectedSlotEvent}; | ||
use valence_server::entity::player::PlayerEntity; | ||
|
||
use super::*; | ||
|
||
/// This component will sync a player's [`Equipment`], which is visible to other | ||
/// players, with the player [`Inventory`]. | ||
#[derive(Debug, Default, Clone, Component)] | ||
pub struct EquipmentInventorySync; | ||
|
||
/// Syncs the player [`Equipment`] with the [`Inventory`]. | ||
/// If a change in the player's inventory and in the equipment occurs in the | ||
/// same tick, the equipment change has priority. | ||
/// Note: This system only handles direct changes to the held item (not actual | ||
/// changes from the client) see [`equipment_held_item_sync_from_client`] | ||
pub(crate) fn equipment_inventory_sync( | ||
mut clients: Query< | ||
(&mut Equipment, &mut Inventory, &mut HeldItem), | ||
( | ||
Or<(Changed<Equipment>, Changed<Inventory>, Changed<HeldItem>)>, | ||
With<EquipmentInventorySync>, | ||
With<PlayerEntity>, | ||
), | ||
>, | ||
) { | ||
for (mut equipment, mut inventory, held_item) in &mut clients { | ||
// Equipment change has priority over held item changes | ||
if equipment.changed & (1 << Equipment::MAIN_HAND_IDX) != 0 { | ||
let item = equipment.main_hand().clone(); | ||
inventory.set_slot(held_item.slot(), item); | ||
} else { | ||
// If we change the inventory (e.g by pickung up an item) | ||
// then the HeldItem slot wont be changed | ||
|
||
// This will only be called if we change the held item from valence, | ||
// the client change is handled in `equipment_held_item_sync_from_client` | ||
let item = inventory.slot(held_item.slot()).clone(); | ||
equipment.set_main_hand(item); | ||
} | ||
|
||
let slots = [ | ||
(Equipment::OFF_HAND_IDX, PlayerInventory::SLOT_OFFHAND), | ||
(Equipment::HEAD_IDX, PlayerInventory::SLOT_HEAD), | ||
(Equipment::CHEST_IDX, PlayerInventory::SLOT_CHEST), | ||
(Equipment::LEGS_IDX, PlayerInventory::SLOT_LEGS), | ||
(Equipment::FEET_IDX, PlayerInventory::SLOT_FEET), | ||
]; | ||
|
||
// We cant rely on the changed bitfield of inventory here | ||
// because that gets reset when the client changes the inventory | ||
|
||
for (equipment_slot, inventory_slot) in slots { | ||
// Equipment has priority over inventory changes | ||
if equipment.changed & (1 << equipment_slot) != 0 { | ||
let item = equipment.slot(equipment_slot).clone(); | ||
inventory.set_slot(inventory_slot, item); | ||
} else if inventory.is_changed() { | ||
let item = inventory.slot(inventory_slot).clone(); | ||
equipment.set_slot(equipment_slot, item); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// Handles the case where the client changes the slot (the bevy change is | ||
/// suppressed for this) | ||
pub(crate) fn equipment_held_item_sync_from_client( | ||
mut clients: Query<(&HeldItem, &Inventory, &mut Equipment), With<EquipmentInventorySync>>, | ||
mut events: EventReader<UpdateSelectedSlotEvent>, | ||
) { | ||
for event in events.read() { | ||
let Ok((held_item, inventory, mut equipment)) = clients.get_mut(event.client) else { | ||
continue; | ||
}; | ||
|
||
let item = inventory.slot(held_item.slot()).clone(); | ||
equipment.set_main_hand(item); | ||
} | ||
} | ||
|
||
pub(crate) fn on_attach_inventory_sync( | ||
entities: Query<Option<&PlayerEntity>, (Added<EquipmentInventorySync>, With<Inventory>)>, | ||
) { | ||
for entity in &entities { | ||
if entity.is_none() { | ||
tracing::warn!( | ||
"EquipmentInventorySync attached to non-player entity, this will have no effect" | ||
); | ||
} | ||
} | ||
} |
Oops, something went wrong.