Shield ItemAction blocks attacks even tho weapon is holstered

Grannyboy

Active member
I've came across this what seems to be a bug when I attached a shield Item Action on my melee weapon Item Action item.

Please see this attached video describing my problem. I cannot replicate this in the demo scene, but that is because I dont have a blockable sorce nearby to try it out. This bug might be in demo scene as well im not sure.


Im sorry for my AI its really bad...

What we can see in the video attached is as follows:
I get attacked by my AI with weapon just picked up and holstered.
I equip my weapon and block a few attacks.
I toggle off my weapon to holster pos and it still blocks all incoming attacks.

Here is my shield settings on weapon as well:
1677518667593.png

Its basically set up same way as in Demo scene.
 
So turns out the ShiledCollider was not being disabled when the item is unequipped.
So I added some event listeners to check for item unequip/equip state and disable the shield collider if necessary.
I made it optional in case some people want to have a holstered shield protect the characters back.

Code:
/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------

namespace Opsive.UltimateCharacterController.Objects.ItemAssist
{
    using Opsive.Shared.Events;
    using Opsive.UltimateCharacterController.Items.Actions;
    using Opsive.UltimateCharacterController.Character;
    using Opsive.UltimateCharacterController.Items;
    using UnityEngine;
    using UnityEngine.Serialization;

    /// <summary>
    /// The ShieldCollider component specifies the object that acts as a collider for the shield.
    /// </summary>
    public class ShieldCollider : MonoBehaviour
    {
        [Tooltip("A reference to the Shield item action.")]
        [SerializeField] protected ShieldAction m_ShieldAction;
        [Tooltip("Should the shield collider be disabled when unequipped (for example in the holster?).")]
        [SerializeField] protected bool m_DisableOnUnequip = true;

        [Shared.Utility.NonSerialized] public ShieldAction ShieldAction { get { return m_ShieldAction; } set { m_ShieldAction = value; } }

        private bool m_FirstPersonPerspective;
        private Collider m_Collider;
        private GameObject m_Character;
        private UltimateCharacterLocomotion m_Locomotion;

        /// <summary>
        /// Initialize the default values.
        /// </summary>
        private void Start()
        {
            if (m_ShieldAction == null) {
                Debug.LogError("Error: The shield is not assigned. Ensure the shield is created from the Item Manager.", this);
                return;
            }
            
            var firstPersonPerspectiveItem = m_ShieldAction.CharacterItem.FirstPersonPerspectiveItem?.GetVisibleObject()?.transform;
            if (firstPersonPerspectiveItem != null && (transform == firstPersonPerspectiveItem || transform.IsChildOf(firstPersonPerspectiveItem))) {
                m_FirstPersonPerspective = true;
            } else {
                m_FirstPersonPerspective = false;
            }
            
            m_Locomotion = m_ShieldAction.gameObject.GetComponentInParent<UltimateCharacterLocomotion>();
            m_Character = m_Locomotion.gameObject;
            m_Collider = GetComponent<Collider>();
            m_Collider.enabled = m_Locomotion.FirstPersonPerspective == m_FirstPersonPerspective;

            EventHandler.RegisterEvent<bool>(m_Character, "OnCharacterChangePerspectives", OnChangePerspectives);
            EventHandler.RegisterEvent<CharacterItem, int>(m_Character, "OnInventoryUnequipItem", OnUnequipItem);
            EventHandler.RegisterEvent<CharacterItem, int>(m_Character, "OnInventoryEquipItem", OnEquipItem);
        }

        /// <summary>
        /// The camera perspective between first and third person has changed.
        /// </summary>
        /// <param name="firstPersonPerspective">Is the camera in a first person view?</param>
        private void OnChangePerspectives(bool firstPersonPerspective)
        {
            if(m_ShieldAction == null){ return; }
            // The collider should only be enabled for the corresponding perspective and if it is active.
            m_Collider.enabled = (m_FirstPersonPerspective == firstPersonPerspective);
            if (m_DisableOnUnequip && m_Collider.enabled) {
                m_Collider.enabled = m_ShieldAction.CharacterItem.IsActive();
            }
            
        }

        /// <summary>
        /// An item has been unequipped.
        /// </summary>
        /// <param name="characterItem">The item that was unequipped.</param>
        /// <param name="slotID">The slot that the item was unequipped from.</param>
        private void OnUnequipItem(CharacterItem characterItem, int slotID)
        {
            if(m_ShieldAction == null){ return; }
            
            if (characterItem != m_ShieldAction.CharacterItem) {
                return;
            }

            if (m_DisableOnUnequip) {
                m_Collider.enabled = false;
            }
        }
        
        /// <summary>
        /// An item has been equipped.
        /// </summary>
        /// <param name="characterItem">The equipped item.</param>
        /// <param name="slotID">The slot that the item now occupies.</param>
        private void OnEquipItem(CharacterItem characterItem, int slotID)
        {
            if(m_ShieldAction == null){ return; }
            
            if (characterItem != m_ShieldAction.CharacterItem) {
                return;
            }

            
            if (m_DisableOnUnequip) {
                // Re-enable the collider only if the perspective is correct.
                m_Collider.enabled = m_Locomotion.FirstPersonPerspective == m_FirstPersonPerspective;
            }
        }

        /// <summary>
        /// The object has been destroyed.
        /// </summary>
        private void OnDestroy()
        {
            if (m_Character == null) {
                return;
            }

            EventHandler.UnregisterEvent<bool>(m_Character, "OnCharacterChangePerspectives", OnChangePerspectives);
            EventHandler.UnregisterEvent<CharacterItem, int>(m_Character, "OnInventoryUnequipItem", OnUnequipItem);
            EventHandler.UnregisterEvent<CharacterItem, int>(m_Character, "OnInventoryEquipItem", OnEquipItem);
        }
    }
}

Let me know if that works for you :)
 
Hi @Sangemdoko!

Thank you for looking into my issue! Unfortionatly this didnt solve my problem and it stays exactly the same. I was supposed to just replace the ShieldCollider script with your pasted code right?
 
That's odd I was convinced it would work. I'll look into again and let you know if I find something
 
I can't replicate your issue, so there must be something else that's causing your problem.
Here is a video showcasing my setup, hopefully it helps to compare



If you can't figure out the issue, I would recommend trying to debug you impact by adding a DebugImpactContent on the enemies weapon.
1678275276036.png
That should log all information about the impact, and might give you some context on what is being hit and why it thinks it is a shield
 
Thank you for this answer and video, I really appreciate it! I've been looking at your settings and copied everything exactly. I did some debug with the Debug Impact Context which shows some very interesting things.

This first log message is when hit normally, without ever blocking a single attack:
  1. Hit that damaged the player:
  2. Impact Callback Context:
  3. Character Item Action: (null)
  4. Impact Data:
  5. Source ID: 0
  6. IMPACT
  7. RaycastHit: UnityEngine.RaycastHit
  8. Impact Position: (-1.33, 0.34, -36.90)
  9. Impact GameObject: Character_Dummy_Male_02 (UnityEngine.GameObject)
  10. Impact Rigidbody: Character_Dummy_Male_02 (UnityEngine.Rigidbody)
  11. Impact Collider: CapsuleCollider (UnityEngine.CapsuleCollider)
  12. Impact Direction: (0.16, 0.15, 0.98)
  13. Impact Strength: 1
  14. DetectLayers: UnityEngine.LayerMask
  15. HitCount: 2
  16. HitColliders: List Content:
  17. i: 0 -> Plane (1) (UnityEngine.MeshCollider)
  18. i: 1 -> CapsuleCollider (UnityEngine.CapsuleCollider)
  19. SurfaceImpact:
  20. DamageTarget: Character_Dummy_Male_02 (Opsive.UltimateCharacterController.Traits.CharacterHealth)
  21. SOURCE
  22. Source Component: SM_Wep_PigButcher_601 (Opsive.UltimateCharacterController.Items.Actions.MeleeAction) [0]'Melee 1'
  23. Originator: SM_Wep_PigButcher_601 (UnityEngine.GameObject)
  24. Character Locomotion Initiator: Character_BR_MutantGuy_01 (Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotion)
  25. Item Action Initiator: SM_Wep_PigButcher_601 (Opsive.UltimateCharacterController.Items.Actions.MeleeAction) [0]'Melee 1'
  26. DamageOriginator: SM_Wep_PigButcher_601 (Opsive.UltimateCharacterController.Items.Actions.MeleeAction) [0]'Melee 1'
  27. Damage Data: Impact Damage Data:
  28. Layer Mask: UnityEngine.LayerMask
  29. Damage Processor: (Opsive.UltimateCharacterController.Traits.Damage.DamageProcessor)
  30. Damage Amount: 20
  31. Impact Force: 10
  32. Impact Force Frames: 15
  33. Impact Radius: 1
  34. Impact State Name:
  35. Impact State Disable Timer: 10
  36. Surface Impact:

This next message is when blocking the attack:
Impact Callback Context:
Character Item Action: (null)
Impact Data:
Source ID: 0

IMPACT
RaycastHit: UnityEngine.RaycastHit
Impact Position: (1.46, 0.30, -40.95)
Impact GameObject: Character_Dummy_Male_02 (UnityEngine.GameObject)
Impact Rigidbody: Character_Dummy_Male_02 (UnityEngine.Rigidbody)
Impact Collider: ThirdPersonSM_Wep_Sword_Large_01 (UnityEngine.BoxCollider)
Impact Direction: (-0.35, 0.26, 0.90)
Impact Strength: 1
DetectLayers: UnityEngine.LayerMask
HitCount: 3
HitColliders: List Content:
i: 0 -> Plane (1) (UnityEngine.MeshCollider)
i: 1 -> CapsuleCollider (UnityEngine.CapsuleCollider)
i: 2 -> ThirdPersonSM_Wep_Sword_Large_01 (UnityEngine.BoxCollider) //My weapons "shield collider"

SurfaceImpact:
DamageTarget: Character_Dummy_Male_02 (Opsive.UltimateCharacterController.Traits.CharacterHealth)

SOURCE
Source Component: SM_Wep_PigButcher_601 (Opsive.UltimateCharacterController.Items.Actions.MeleeAction) [0]'Melee 1'
Originator: SM_Wep_PigButcher_601 (UnityEngine.GameObject)
Character Locomotion Initiator: Character_BR_MutantGuy_01 (Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotion)
Item Action Initiator: SM_Wep_PigButcher_601 (Opsive.UltimateCharacterController.Items.Actions.MeleeAction) [0]'Melee 1'
DamageOriginator: SM_Wep_PigButcher_601 (Opsive.UltimateCharacterController.Items.Actions.MeleeAction) [0]'Melee 1'

Damage Data: Impact Damage Data:
Layer Mask: UnityEngine.LayerMask
Damage Processor:
Damage Amount: 0
Impact Force: 10
Impact Force Frames: 15
Impact Radius: 1
Impact State Name:
Impact State Disable Timer: 10
Surface Impact:


This next log message is when the AI hits my player again, without my player blocking (aiming) the attack. It hits my enemy, not the shield collider but it deals 0 damage:

  1. Hit that didnt damage the player:
  2. Impact Callback Context:
  3. Character Item Action: (null)
  4. Impact Data:
  5. Source ID: 0
  6. IMPACT
  7. RaycastHit: UnityEngine.RaycastHit
  8. Impact Position: (0.64, 0.33, -40.96)
  9. Impact GameObject: Character_Dummy_Male_02 (UnityEngine.GameObject)
  10. Impact Rigidbody: Character_Dummy_Male_02 (UnityEngine.Rigidbody)
  11. Impact Collider: CapsuleCollider (UnityEngine.CapsuleCollider)
  12. Impact Direction: (-0.03, 0.18, -0.98)
  13. Impact Strength: 1
  14. DetectLayers: UnityEngine.LayerMask
  15. HitCount: 2
  16. HitColliders: List Content:
  17. i: 0 -> Plane (1) (UnityEngine.MeshCollider)
  18. i: 1 -> CapsuleCollider (UnityEngine.CapsuleCollider)
  19. SurfaceImpact:
  20. DamageTarget: Character_Dummy_Male_02 (Opsive.UltimateCharacterController.Traits.CharacterHealth)
  21. SOURCE
  22. Source Component: SM_Wep_PigButcher_601 (Opsive.UltimateCharacterController.Items.Actions.MeleeAction) [0]'Melee 1'
  23. Originator: SM_Wep_PigButcher_601 (UnityEngine.GameObject)
  24. Character Locomotion Initiator: Character_BR_MutantGuy_01 (Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotion)
  25. Item Action Initiator: SM_Wep_PigButcher_601 (Opsive.UltimateCharacterController.Items.Actions.MeleeAction) [0]'Melee 1'
  26. DamageOriginator: SM_Wep_PigButcher_601 (Opsive.UltimateCharacterController.Items.Actions.MeleeAction) [0]'Melee 1'
  27. Damage Data: Impact Damage Data:
  28. Layer Mask: UnityEngine.LayerMask
  29. Damage Processor:
  30. Damage Amount: 0
  31. Impact Force: 10
  32. Impact Force Frames: 15
  33. Impact Radius: 1
  34. Impact State Name:
  35. Impact State Disable Timer: 10
  36. Surface Impact:

To me it seems that the colliders is acting acordingly. It gets disabled when not aiming as it should, but the AI still dosent deal any damage to my player.

I will try and record a video as well to describe it better!
 

In this pasted video the following is happening:
1. the AI hits my character after I picked up the weapon. I have never blocked with it once, just picked it up.
2. The second hit is a block. And it blocks all incoming damage which is correct.
3. The third attack and all attacks after is on the character when the weapon is holstered. This is where my character gets hit and not the shield collider, but the AI deals 0 damage. See attached log files above.

For some reason the AI's damage is still 0 even tho it dosent register a hit with the shield collider.

Here you can see the collider on the weapon:
1678379868218.png

And here is the Shield Action + Holster target:
1678379920397.png
 
I believe I found the issue! And for future reference here is my solution:
On my AI's weapon i had the following two checkboxes checked
1678380337880.png

Im not entierly sure what they do, but when I un ticked them everything seems to work as it does in your video @Sangemdoko !

Thank you very much for your patience and hopefully this is useful in the future for someone else!
 
Interesting I'll take note of that, because that should be the case
This option is supposed to set the damage impact data, such that the actions below can have the "updated" damage amount in case something like a shield reduces the damage amount to 0. But it should affect the damage it does by itself.
 
Top