Issue with Aim ItemAbility

amrita

New member
I have a character with a custom ILookSource (a clone of LocalLookSource). When I spawn the character, the ILookSource raise a "OnCharacterAttachLookSource" event and the aim ability correctly get the ILookSource (in the "OnAttachLookSource" event handler). The problem is that when i start the aim ability (I start it calling TryStartAbility method) the aim's "UpdateRotation" method is called but the ILookSource reference is null!
I logged the hash code and it seems that the aim object instance has changed: when the m_LookSource is setted by the OnAttachLookSource method the calling object has a certain hash code, when the UpdateRotation method is called the hash code is different (during all this, the hash code of the parent UltimateCharacterLocomotion object never change).
So, are the ItemAbility instantiated somewhere at runtime? What could be happening?
 
are the ItemAbility instantiated somewhere at runtime?
No - for this I would place a breakpoint within the abilities OnAttachLookSource to see if it's being hit. If it's not being hit you are likely assigning the look source before the aim ability initializes.
 
I already did that. The breakpoint is hitted and the look source is correctly setted. But when the UpdateRotation is called, the look source is null, even if the OnAttachLookSource is never hitted again. It seems that the awake (and so the event registration) is called on an instance of the Aim class, while UpdateRotation is called on another instance...
One more thing: I added some code to reassign the look source (when null) inside the UpdateRotation. With this workaround it works, the character correctly aim, but in the inspector, next to the aim ability, the "(active)" label does not appear.
 
You'll want to make sure you assign the look source within start because all of the deserialization happens within awake. Beyond that if you only have one aim ability then the instances will match.
 
The assignment is done within the start. I cloned the LocalLookSource file, only changing the target property (using a Vector3 instead on a Transform). Everything else is exactly as in the LocalLookSource file (initialization, event raise and so on).
I placed breakpoint in the deserialization method as well as in the OnAttachLookSource and UpdateRotation methods. The flow goes as it should go (deserialization is called first, OnAttachLookSource follow and UpdateRotation as last). Everything seems to work as expected.

Here a little more info about the scene, if it could help:
I have a character controlled by the player. When the character reach a certain position, a new character is spawned. This new character is controlled "by the game". It receive the position from the player's character in order to follow him. When the player's character aim, the other character should aim as well in the same direction, so I created a MyLookSource attached to the second character where I can set the direction (this is the LookSource that isn't working).
This second character is created with the character manager, as AI character (but without the navmesh part), attached the MyLookSource and stored as prefab.
 
Finally found what was causing the issue.
The problem is that the ItemAbilities property's getter (within the UltimateCharacterLocomotion class) calls the DeserializeItemAbilities. So if you instantiate a UltimateCharacterLocomotion object and access the ItemAbilities property, all the item abilities are created, but as soon as the object's awake is called all the item abilities are replaced.
Is there a reason why that getter instantiate the array? I would expect that when that array is null, if I try to access it I get a null value instead of calling something that silently instantiate the backing field...
At least the DeserializeItemAbilities method should check if the ItemAbilities has already been populated...

Anyway, the solution is to access the ItemAbilities property (and Abilities as well) only from within start and not before.

Just a tip from my OOP experience: never do logic/state manipulation in getters, but use it only to filter/translate (The only case when make sense to instantiate something within the getter is in singletons for the instance property).
 
Top