From 802a3f5376daee8aea887c9e1e9e665f4249d504 Mon Sep 17 00:00:00 2001 From: Franklin Date: Mon, 20 Nov 2023 17:48:27 -0400 Subject: [PATCH] Fixed weapon equip bug where changing firearm while in hands would not persist attachments --- Cargo.lock | 6 ++++-- Cargo.toml | 6 ++++++ src/comps/core/events/pickup_item.rs | 1 + src/comps/core/inventory/player_inventory.rs | 14 +++++++++++--- src/comps/core/items/guns/ak105.rs | 17 ++++++++++++----- src/comps/core/items/guns/glock17.rs | 15 +++++++++++---- src/comps/core/items/item.rs | 6 ++++++ src/comps/core/markers/proxy/weapons/firearm.rs | 14 +++++++++++++- src/comps/core/spawners/guns/ak105_spawner.rs | 5 +++-- src/comps/core/spawners/guns/glock17_spawner.rs | 5 +++-- src/comps/core/spawners/player.rs | 1 + src/comps/core/weapons/firearm.rs | 17 +---------------- src/logic/core/player/hands.rs | 10 ++++------ src/logic/core/player/inventory.rs | 1 - src/setup/equipment.rs | 9 +++++---- 15 files changed, 81 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 23dd768..00a96b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1918,6 +1918,7 @@ dependencies = [ "bevy_gltf_components", "bevy_hanabi", "bevy_rapier3d", + "uuid", ] [[package]] @@ -3990,11 +3991,12 @@ dependencies = [ [[package]] name = "uuid" -version = "1.4.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ "getrandom", + "rand", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 40cf3f5..0b43e9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,9 @@ bevy_rapier3d = { version = "0.23", features = ["debug-render-3d"] } bevy_hanabi = { version = "0.8", default-features = false, features = [ "3d" ] } bevy-trait-query = "0.4.0" bevy_gltf_components = "0.2.0" + + +uuid = { version = "1.6.1", features = [ + "v4", # Lets you generate random UUIDs + "fast-rng", # Use a faster (but still sufficiently random) RNG +] } \ No newline at end of file diff --git a/src/comps/core/events/pickup_item.rs b/src/comps/core/events/pickup_item.rs index 2924f28..752a000 100644 --- a/src/comps/core/events/pickup_item.rs +++ b/src/comps/core/events/pickup_item.rs @@ -13,6 +13,7 @@ impl ItemState { pub fn as_firearm_state(self) -> FirearmState { match self { ItemState::Weapon(firearm_state) => firearm_state, + #[allow(unreachable_patterns)] _ => panic!("Not a weapon ItemState variant...") } } diff --git a/src/comps/core/inventory/player_inventory.rs b/src/comps/core/inventory/player_inventory.rs index 3161368..5cf2cb0 100644 --- a/src/comps/core/inventory/player_inventory.rs +++ b/src/comps/core/inventory/player_inventory.rs @@ -57,7 +57,6 @@ impl PlayerInventory { _ => unimplemented!(), }; let Some(firearm) = item.get_firearm() else { return; }; - println!("Pickup item: {:?}", item.get_state()); inventory_slot.item = Some(item); } pub fn drop_item(&mut self, slot: PlayerInventorySlotType) { @@ -66,7 +65,17 @@ impl PlayerInventory { PlayerInventorySlotType::Secondary => self.secondary.item = None, _ => unimplemented!(), } - } + } + pub fn get_current_slot_item(&self) -> Option> { + match self.current_slot { + Some(current_slot) => match current_slot { + PlayerInventorySlotType::Primary => self.primary.item.clone(), + PlayerInventorySlotType::Secondary => self.secondary.item.clone(), + _ => unimplemented!(), + }, + None => None, + } + } } /// Drop item from a specific slot. @@ -108,7 +117,6 @@ pub fn drop_slot_in_game_world( FirearmType::Primary => { // Send equipment_changed_event if let Some(primary_item) = player_inventory.get_primary() { - println!("drop_slot_in_game_world {:?}", primary_item.get_state()); // Drop this one primary_item.spawn( commands, diff --git a/src/comps/core/items/guns/ak105.rs b/src/comps/core/items/guns/ak105.rs index 8bd24a6..a5dbaef 100644 --- a/src/comps/core/items/guns/ak105.rs +++ b/src/comps/core/items/guns/ak105.rs @@ -6,13 +6,15 @@ use bevy_rapier3d::{dynamics::{RigidBody, GravityScale, ExternalImpulse}, geomet use crate::{comps::core::{ grid::UGrid, - items::item::{Item, ItemType}, + items::item::{Item, ItemType, ItemId}, markers::{holdable::HoldableObjectType, interactable::Interactable}, inventory::slot::PlayerInventorySlotType, weapons::{firearm::Firearm, firearm_data::FirearmData}, events::pickup_item::ItemState, }, setup::assets::{GltfAssets, GltfAssetType}, utils}; -#[derive(Component)] -pub struct Ak105GunItem { - pub state: Mutex> +#[derive(Component, Clone)] +pub struct Ak105GunItem { + pub id: ItemId, + pub state: Mutex>, + } impl Item for Ak105GunItem { @@ -52,6 +54,10 @@ impl Item for Ak105GunItem { PlayerInventorySlotType::Primary } + fn id(&self) -> ItemId { + self.id.clone() + } + fn spawn( &self, commands: &mut Commands, @@ -121,7 +127,8 @@ impl Item for Ak105GunItem { impulse: with_impulse, ..Default::default() }, - Interactable::Item(Arc::new(Ak105GunItem { state: Mutex::new(item_state) })), + Interactable::Item(Arc::new(self.clone())), + self.id(), )) .push_children(&[firearm_asset_entity]); } diff --git a/src/comps/core/items/guns/glock17.rs b/src/comps/core/items/guns/glock17.rs index 2989ab7..9317bbf 100644 --- a/src/comps/core/items/guns/glock17.rs +++ b/src/comps/core/items/guns/glock17.rs @@ -5,12 +5,14 @@ use bevy_rapier3d::{geometry::{ColliderMassProperties, Collider}, dynamics::{Rig use crate::{comps::core::{ grid::UGrid, - items::item::{Item, ItemType}, + items::item::{Item, ItemType, ItemId}, markers::{holdable::HoldableObjectType, interactable::Interactable}, inventory::slot::PlayerInventorySlotType, weapons::{firearm::Firearm, firearm_data::FirearmData}, events::pickup_item::ItemState, }, setup::assets::{GltfAssets, GltfAssetType}, utils}; -#[derive(Component, Reflect)] -pub struct Glock17GunItem; +#[derive(Component, Reflect, Clone)] +pub struct Glock17GunItem { + pub id: ItemId, +} impl Item for Glock17GunItem { fn get_type(&self) -> ItemType { @@ -118,7 +120,8 @@ impl Item for Glock17GunItem { impulse: with_impulse, ..Default::default() }, - Interactable::Item(Arc::new(Glock17GunItem) ), + Interactable::Item(Arc::new(self.clone()) ), + self.id(), )) .push_children(&[firearm_asset_entity]); } @@ -132,5 +135,9 @@ impl Item for Glock17GunItem { fn set_state(&self, state: Option) { todo!() } + + fn id(&self) -> ItemId { + self.id.clone() + } } diff --git a/src/comps/core/items/item.rs b/src/comps/core/items/item.rs index e2702d2..611799f 100644 --- a/src/comps/core/items/item.rs +++ b/src/comps/core/items/item.rs @@ -8,6 +8,7 @@ use crate::{ }; use bevy::{gltf::Gltf, prelude::*}; use bevy_rapier3d::prelude::*; +use uuid::Uuid; #[allow(unused)] pub enum ItemType { @@ -16,6 +17,10 @@ pub enum ItemType { Consumable, } +#[derive(Component, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Reflect, Default)] +#[reflect(Component)] +pub struct ItemId(pub Uuid); + #[bevy_trait_query::queryable] pub trait Item: Sync + Send { fn get_type(&self) -> ItemType; @@ -28,6 +33,7 @@ pub trait Item: Sync + Send { fn inventory_description(&self) -> String; fn set_state(&self, state: Option); fn get_state(&self) -> Option; + fn id(&self) -> ItemId; /// Spawn an item on the game world. Every item should implement this /// The transform passed to this function should be a GlobalTransform.into() /// diff --git a/src/comps/core/markers/proxy/weapons/firearm.rs b/src/comps/core/markers/proxy/weapons/firearm.rs index b280a6d..57df19a 100644 --- a/src/comps/core/markers/proxy/weapons/firearm.rs +++ b/src/comps/core/markers/proxy/weapons/firearm.rs @@ -1,6 +1,6 @@ use bevy::{prelude::*, gltf::Gltf, ecs::system::SystemParam, scene::SceneInstance}; -use crate::{comps::core::{weapons::{firearm::Firearm, firearm_state::FirearmState, slot::slot::WeaponSlot, attachment_slot::AttachmentSlot, attachments::weapon_attachment::WeaponAttachment}, events::pickup_item::ItemState}, setup::assets::{GltfAssets, GltfAssetType}}; +use crate::{comps::core::{weapons::{firearm::Firearm, firearm_state::FirearmState, slot::slot::WeaponSlot, attachment_slot::AttachmentSlot, attachments::weapon_attachment::WeaponAttachment}, events::pickup_item::ItemState, markers::holdable::InPlayerHands, inventory::player_inventory::PlayerInventory, items::item::ItemId}, setup::assets::{GltfAssets, GltfAssetType}}; #[derive(SystemParam)] pub struct InsertFirearmStateIntoFirearmsParams<'w, 's> { @@ -8,6 +8,8 @@ pub struct InsertFirearmStateIntoFirearmsParams<'w, 's> { firearm_query: Query<'w, 's, (Entity, &'static Firearm, &'static Parent, Option<&'static FirearmState>), Or<(Without, Changed)>>, slots_query: Query<'w, 's, (Entity, &'static WeaponSlot, &'static Parent)>, attachments_query: Query<'w, 's, (Entity, &'static WeaponAttachment, &'static Parent)>, + in_player_hands_query: Query<'w, 's, &'static ItemId, With>, + player_inventories_query: Query<'w, 's, &'static PlayerInventory> } /// This query inserts FirearmState into firearms, updates firearm assets that already have a FirearmState, @@ -40,6 +42,16 @@ pub fn insert_firearm_state_to_firearms( Some(firearm_state) => { // Change the Slots spawn_attachments_in_firearm(&mut commands, firearm_entity, firearm_state, &queries.slots_query, &assets_gltf, &loaded_gltf_assets); + //TODO: Change firearm state inside inventory + for in_player_hands_item_id in queries.in_player_hands_query.iter() { + for player_inventory in queries.player_inventories_query.iter() { + if let Some(current_item) = player_inventory.get_current_slot_item() { + if ¤t_item.id() == in_player_hands_item_id { + current_item.set_state(Some(ItemState::Weapon(firearm_state.clone()))); + } + } + } + } }, None => { // Create the firearm_state diff --git a/src/comps/core/spawners/guns/ak105_spawner.rs b/src/comps/core/spawners/guns/ak105_spawner.rs index 42c5bf4..5834727 100644 --- a/src/comps/core/spawners/guns/ak105_spawner.rs +++ b/src/comps/core/spawners/guns/ak105_spawner.rs @@ -1,8 +1,9 @@ use bevy::prelude::*; use bevy_inspector_egui::egui::mutex::Mutex; +use uuid::Uuid; use crate::comps::core::{ - items::{guns::ak105::Ak105GunItem, item::Item}, + items::{guns::ak105::Ak105GunItem, item::{Item, ItemId}}, spawners::item::ItemSpawnPoint, }; @@ -17,6 +18,6 @@ impl ItemSpawnPoint for Ak105SpawnPoint { } fn get_item(&self) -> Box { - Box::new(Ak105GunItem { state: Mutex::new(None) }) + Box::new(Ak105GunItem { state: Mutex::new(None), id: ItemId(Uuid::new_v4()) }) } } diff --git a/src/comps/core/spawners/guns/glock17_spawner.rs b/src/comps/core/spawners/guns/glock17_spawner.rs index d9271ff..ed29e34 100644 --- a/src/comps/core/spawners/guns/glock17_spawner.rs +++ b/src/comps/core/spawners/guns/glock17_spawner.rs @@ -1,7 +1,8 @@ use bevy::prelude::*; +use uuid::Uuid; use crate::comps::core::{ - items::{guns::glock17::Glock17GunItem, item::Item}, + items::{guns::glock17::Glock17GunItem, item::{Item, ItemId}}, spawners::item::ItemSpawnPoint, }; @@ -16,6 +17,6 @@ impl ItemSpawnPoint for Glock17SpawnPoint { } fn get_item(&self) -> Box { - Box::new(Glock17GunItem) + Box::new(Glock17GunItem { id: ItemId(Uuid::new_v4()) }) } } diff --git a/src/comps/core/spawners/player.rs b/src/comps/core/spawners/player.rs index 15bc4d1..19b3d56 100644 --- a/src/comps/core/spawners/player.rs +++ b/src/comps/core/spawners/player.rs @@ -111,6 +111,7 @@ pub fn player_spawner( game_load_state.player_loaded = true; equipment_change_event_writer.send(EquipmentChangeEvent( player_spawn_point.player.0.equipment.clone(), + None )); commands.entity(player_spawn_point_entity).despawn(); } diff --git a/src/comps/core/weapons/firearm.rs b/src/comps/core/weapons/firearm.rs index 310ce86..cf11f42 100644 --- a/src/comps/core/weapons/firearm.rs +++ b/src/comps/core/weapons/firearm.rs @@ -1,4 +1,4 @@ -use std::sync::{Arc}; +use std::sync::Arc; use bevy::prelude::*; use bevy_inspector_egui::egui::mutex::Mutex; @@ -153,19 +153,4 @@ impl Firearm { } } - - pub fn get_item_arc(&self) -> Arc { - match self { - //Firearm::M4A1 => Arc::new(M4a1GunItem), - Firearm::Glock17 => Arc::new(Glock17GunItem), - Firearm::Ak105 => Arc::new(Ak105GunItem { state: Mutex::new(None) }), - } - } - pub fn get_item_box(&self) -> Box { - match self { - //Firearm::M4A1 => Box::new(M4a1GunItem), - Firearm::Glock17 => Box::new(Glock17GunItem), - Firearm::Ak105 => Box::new(Ak105GunItem { state: Mutex::new(None) }), - } - } } \ No newline at end of file diff --git a/src/logic/core/player/hands.rs b/src/logic/core/player/hands.rs index b897754..3316c9f 100644 --- a/src/logic/core/player/hands.rs +++ b/src/logic/core/player/hands.rs @@ -76,9 +76,8 @@ pub fn capture_hand_usage( if Equipment::Firearm(primary_firearm.clone(), primary_item.get_state().expect("No item state in an equipped Item.").as_firearm_state()) != player.0.equipment { - println!("CaptureHandUsage {:?}", primary_item.get_state().expect("No item state in an equipped Item.").as_firearm_state()); equipment_change_event_writer - .send(EquipmentChangeEvent(Equipment::Firearm(primary_firearm, primary_item.get_state().expect("No item state in an equipped Item.").as_firearm_state()))); + .send(EquipmentChangeEvent(Equipment::Firearm(primary_firearm, primary_item.get_state().expect("No item state in an equipped Item.").as_firearm_state()), Some(primary_item.id()))); player_inventory.current_slot = Some(PlayerInventorySlotType::Primary); } } @@ -90,14 +89,14 @@ pub fn capture_hand_usage( != player.0.equipment { equipment_change_event_writer - .send(EquipmentChangeEvent(Equipment::Firearm(secondary_firearm, secondary_item.get_state().expect("No item state in an equipped Item.").as_firearm_state()))); + .send(EquipmentChangeEvent(Equipment::Firearm(secondary_firearm, secondary_item.get_state().expect("No item state in an equipped Item.").as_firearm_state()), Some(secondary_item.id()))); player_inventory.current_slot = Some(PlayerInventorySlotType::Secondary); } } } } else if resources.keyboard_input.just_pressed(KeyCode::Key3) { if Equipment::Nothing != player.0.equipment { - equipment_change_event_writer.send(EquipmentChangeEvent(Equipment::Nothing)); + equipment_change_event_writer.send(EquipmentChangeEvent(Equipment::Nothing, None)); player_inventory.current_slot = None; } } else if resources.keyboard_input.just_pressed(KeyCode::G) { @@ -107,7 +106,7 @@ pub fn capture_hand_usage( for (firearm_entity, _, firearm_state, _) in firearms_query.iter() { if find_child_in_parent_children(&mut commands, in_player_hands_entity, firearm_entity, &children) { player_inventory::drop_slot_in_game_world(&mut commands, player_transform, &mut inventory_changed_events, &mut player_inventory, &resources.assets_gltf, &resources.loaded_gltf_assets, current_slot, Some(ItemState::Weapon(firearm_state.clone()))); - equipment_change_event_writer.send(EquipmentChangeEvent(Equipment::Nothing)); + equipment_change_event_writer.send(EquipmentChangeEvent(Equipment::Nothing, None)); player_inventory.current_slot = None; } } @@ -352,7 +351,6 @@ pub fn interact_action( item_state = Some(ItemState::Weapon(firearm_state.clone())); } } - println!("Setting item state: {:?}", item_state); item.set_state(item_state); pickup_item_event_writer.send(PickupItemEvent { diff --git a/src/logic/core/player/inventory.rs b/src/logic/core/player/inventory.rs index 3e80378..c9904c3 100644 --- a/src/logic/core/player/inventory.rs +++ b/src/logic/core/player/inventory.rs @@ -24,7 +24,6 @@ pub fn update_player_inventory_system( //player_inventory::drop_slot_in_game_world(&mut commands, player_transform, &mut inventory_changed_events, &mut player_inventory, &assets_gltf, &loaded_gltf_assets, event.item.get_item_slot(), event.item.get_state().clone()); player_inventory.pickup_item(event.item.clone(), event.item.get_item_slot()); inventory_changed_events.send(PlayerInventoryChangedEvent { item: Some(event.item.clone()), slot_type: event.item.get_item_slot() }); - println!("Inventory Changed Event sent"); } } } diff --git a/src/setup/equipment.rs b/src/setup/equipment.rs index 690e17a..28ae785 100644 --- a/src/setup/equipment.rs +++ b/src/setup/equipment.rs @@ -6,7 +6,7 @@ use crate::{ comps::core::{markers::{ holdable::InPlayerHands, player::Player, proxy::character::in_player_hands_parent::InPlayerHandsParent, - }, weapons::{firearm::Firearm, firearm_data::FirearmData, firearm_state::FirearmState}, events::pickup_item::ItemState}, + }, weapons::{firearm::Firearm, firearm_data::FirearmData, firearm_state::FirearmState}, events::pickup_item::ItemState, items::item::ItemId}, logic::core::guns::player_firing::PlayerFiringInfo, utils, }; @@ -14,7 +14,7 @@ use crate::{ use super::assets::{GltfAssetType, GltfAssets}; #[derive(Event)] -pub struct EquipmentChangeEvent(pub Equipment); +pub struct EquipmentChangeEvent(pub Equipment, pub Option); /// Foundation for inventory System. #[derive(Component, Clone, Default, Reflect, PartialEq, PartialOrd)] pub enum Equipment { @@ -42,10 +42,8 @@ pub fn change_equipment( let player_hands = player_hands_query.single_mut(); commands.entity(player_hands).despawn_descendants(); // TODO: Don't do this without keeping the state from the last mag - println!(""); if let Equipment::Firearm(new_firearm, firearm_state) = equipment_change_event.0.clone() { - println!("Equipping: {:?}", firearm_state); spawn_firearm_on_player_hands( &mut commands, player_firing_info, @@ -54,6 +52,7 @@ pub fn change_equipment( &loaded_gltf_assets, new_firearm, firearm_state, + equipment_change_event.1.clone().expect("Spawning firearm on player hands without an ItemId") ); } @@ -71,6 +70,7 @@ fn spawn_firearm_on_player_hands( loaded_gltf_assets: &Assets, firearm: Firearm, firearm_state: FirearmState, + item_id: ItemId, ) { if let Some(asset_handle) = assets_gltf .assets @@ -103,6 +103,7 @@ fn spawn_firearm_on_player_hands( .spawn(( firearm.holdable_object_data(), InPlayerHands, + item_id, Name::new("Firearm"), TransformBundle { local: Transform::from_xyz(0.0, 0.0, 0.0),