#Borrow checker &mut self not mutating self

9 messages · Page 1 of 1 (latest)

thorny sandal
#

which is called like this:

fn try_equip_equipment_system(
    mut events: EventReader<SelectedEquipmentSlot>,
    mut held_item_query: Query<(
        Entity,
        &mut SelectedItem,
        &mut EquipmentSlots,
        &mut Stats,
    )>,
    mut item_query: Query<(
        &EquipmentItem, 
        &StatStick,
        &mut EquippedTo,
    )>,
) {
    for event in events.read() {
        for (
            equipping_entity,
            mut selected_item, 
            mut equipment_slots, 
            mut stats,
        ) in held_item_query.iter_mut() {
            if let Some(held_item_entity) = selected_item.0 {
                let equipment_in_slot = equipment_slots.0.get(event.0).and_then(|slot| slot.entity);
                if equipment_slots.try_equip_item(
                    event.0,
                    held_item_entity,
                    equipping_entity,
                    &mut stats,
                    &mut item_query,
                ) {
                    //equipment_slots.0[event.0].entity = Some(held_item_entity);
                    selected_item.0 = equipment_in_slot;
                } else {
                    println!("Failed to equip item {:?}.", held_item_entity);
                }
            } else {
                let Some(slot_data) = equipment_slots.0.get(event.0) else {
                    println!("Invalid equipment slot");
                    continue;
                };
                
                let Some(equipped_entity) = slot_data.entity else {
                    println!("Equipment slot is empty");
                    continue;
                };
                
                selected_item.0 = Some(equipped_entity);
                equipment_slots.unequip_item(
                    event.0, 
                    equipped_entity,
                    equipping_entity,
                    &mut stats,
                    &mut item_query.transmute_lens::<(&StatStick, &mut EquippedTo)>().query(),
                );
            }
        }
    }
}

My problem is that the line slot.entity = Some(new_item_entity); in my EquipmentSlots struct does not actually set slot.entity. If I put debug statements before and after, the slot appears to change. However, in order to actually set it I have to uncomment this line in try_equip_equipment_system: equipment_slots.0[event.0].entity = Some(held_item_entity);

It's like the mutable reference to the slot is getting messed up somewhere, but I don't understand rust well enough to know why this might happen.

karmic edge
#

What is the structure of EquipmentSlots

thorny sandal
#
#[derive(Debug)]
pub struct EquipmentSlot {
    pub slot_type: SlotType,
    pub entity: Option<Entity>,
    pub is_dead: bool,
}

impl EquipmentSlot {
    pub fn new(slot_type: SlotType) -> EquipmentSlot {
        EquipmentSlot {
            slot_type,
            entity: None,
            is_dead: false,
        }
    }
}


#[derive(Component, Debug)]
pub struct EquipmentSlots(pub Vec::<EquipmentSlot>);
#

@karmic edge here you are

karmic edge
#

Nothing particularly screams out to me

#

The only thing I can think is that perhaps unequipping the old item messes with this somehow - try moving that bit to before the rest of the equip logic

thorny sandal
#

That doesn't seem to have done it

#
    pub fn try_equip_item(
        &mut self,
        index: usize,
        new_item_entity: Entity,
        character_entity: Entity,
        character_stats: &mut Stats,
        item_query: &mut Query<(&EquipmentItem, &StatStick, &mut EquippedTo)>,
    ) -> bool {
        let changed_slot = {
            let Some(slot) = self.0.get_mut(index) else {
                return false;
            };
    
            let Ok((new_equipment_item, new_stat_stick, equipped_to)) = item_query.get(new_item_entity) else {
                println!("Item not found");
                return false;
            };
    
            if equipped_to.0 == Some(character_entity) {
                println!("Item already equipped");
                return false;
            }
    
            if !new_equipment_item.valid_slots.contains(&slot.slot_type) {
                println!("Invalid slot type");
                return false;
            }
    
            if !new_stat_stick.requirements_met(&character_stats) {
                println!("Requirements not met");
                return false;
            }
    
            if slot.is_dead {
                println!("Slot is dead");
                return false;
            }

            let mut slot_clone = slot.clone();
            slot_clone.entity = Some(new_item_entity);
    
            let old_item_entity = slot.entity;
    
            // Equip new item
            let Ok((_, new_stat_stick, mut new_equipped_to)) = item_query.get_mut(new_item_entity) else {
                println!("Item not found");
                return false;
            };
    
            new_equipped_to.0 = Some(character_entity);
            slot.entity = Some(new_item_entity); // This should now work
            character_stats.equip(&new_stat_stick.grants);
    
            // Unequip old item if it exists
            if let Some(old_entity) = old_item_entity {
                self.unequip_item(index, old_entity, character_entity, character_stats, &mut item_query.transmute_lens::<(&StatStick, &mut EquippedTo)>().query());
            }
            Some(slot_clone)
        };
        
        if let Some(slot) = changed_slot {
            self.0[index] = slot.clone();
        }

        return true;
    }

this does work tho. Basically just manually setting the slot at the end if it changed.

#

Feels like a hack. Like I should have a better way of doing this. But this works so I do not care.