#Network Animator error

50 messages · Page 1 of 1 (latest)

desert vale
#

Unity version 2021.3.18f1
Fishnet version 3.11.15R pro

The error occurs randomly, but when it does it starts to occur every frame (on host). Once this happens, all the clients get disconnected, getting no errors or warnings on their side. On the side of the host, all objects that use DefaultObjectsPool to spawn/despawn start to behave weirdly (ignoring collisions and/or freezing), my colleague is going to attach a video below

Error:

NullReferenceException: Object reference not set to an instance of an object. FishNet.Component.Animating.NetworkAnimator.TimeManager_OnPreTick () (at <00000000000000000000000000000000>:0) FishNet.Managing.Timing.TimeManager.IncreaseTick () (at <00000000000000000000000000000000>:0) FishNet.Managing.Timing.TimeManager.TickUpdate () (at <00000000000000000000000000000000>:0)
warm viper
granite sorrel
#

Was this always an issue or new to 3.11.15

desert vale
#

Always an issue

desert vale
granite sorrel
#

Okay well those should have been in latest. Send me a DM with your package please so I can diff. @desert vale

granite sorrel
# warm viper 👋🏻

I checked the diff and the network animator is the same in the one you had prev vs new one. So the fixes have been in the latest releases.

#

I checked all files which might affect it which were different. servermanager, clientmanager, networkobject, so on

#

none of the changes should be a problem. Mostly just prediction 2 stuff which is wrapped in defines.

#

The only thing I see that could cause a NRE is perhaps the base.TimeManager call

        private void TimeManager_OnPreTick()
        {
            if (!_isAnimatorEnabled)
            {
                _fromServerBuffer.Clear();
                return;
            }
            //Disabled/cannot start.
            if (_startTick == 0)
                return;
            //Nothing in queue.
            if (_fromServerBuffer.Count == 0)
            {
                _startTick = 0;
                return;
            }
            //Not enough time has passed to start queue.
            if (base.TimeManager.LocalTick < _startTick)
                return;

            ReceivedServerData rd = _fromServerBuffer.Dequeue();
            ArraySegment<byte> segment = rd.GetArraySegment();
            ApplyParametersUpdated(ref segment);
            rd.Dispose();
        }```
#

_fromServerBuffer is a queue but it's initialized on the field so it cannot be that.

desert vale
#

Yep, base.TimeManager also relies on _cachedNetworkObject or something like that, which could be an issue

granite sorrel
#

unlikely.

#

that uses the root nob which should never go anywhere

#

and base.TimeManager exist so long as the object is initialized. If it were deinitialized the OnStopNetwork would unsub from the 'OnPreTick' event.

desert vale
#

I think we are dealing with something unlikely here though

granite sorrel
#

Unless the script is a child of the nob and you are moving the child object away from the nob then destroying the nob, that's not the case.

#

Plus when the nob is destroyed it calls stops on all it's NB, even if theyre no longer a child.

#

Id need a full stack trace to find out what part exactly is null, which prob means you running a dev build.

#

the only time the base managers are reset is AFTER the object is stored in the pool, which would occur after stop callbacks

#

Are you calling NetworkManager.StorePooledInstantiated by any chance?

#

@desert vale ^

desert vale
#

I'm looking it up

desert vale
granite sorrel
#

okay thats fine. that just puts them in the pool w/o spawning

desert vale
granite sorrel
#

Having a full stack trace will help but I can provide you with a maybe fix with what I know

#

Just put this at the top, but again, this is a guess with what info I have

#
        private void TimeManager_OnPreTick()
        {
            if (base.TimeManager == null)
                return;```
#

Also consider replacing this method with such..

#
        public void StorePooledInstantiated(NetworkObject instantiated, bool asServer)
        {
            if (instantiated.IsSpawned)
            {
                LogError($"NetworkObject {instantiated.ToString()} cannot be stored because it is still spawned. The object will be destroyed instead.");
                Destroy(instantiated);
                return;
            }

            _objectPool.StoreObject(instantiated, asServer);
        }```
#

can make it a warning instead I suppose

desert vale
#

Got it, we'll try it
Everyone's asleep now, so we'll share the results tomorrow, as well as the full stack trace

granite sorrel
#

the problem itself is a bit interesting though. as said the manager references dont go away until instantiated.ResetState(); is called, and that doesn't call until AFTER deinit.

#

It's called in the public override void StoreObject(NetworkObject instantiated, bool asServer) method.

#

And when you deinit, it unsubs from the timemanager, so OnPreTick should never invoke.

#

The only thing I suppose that might make sense is if the stop callbacks arent happening and then the object is going to the pull which clears the managers

#

@desert vale very last goto NetworkObject.cs and find ResetState, add this to the top like so

#
        public void ResetState()
        {
            //Was not deinitialized. ResetState should never call before deinitialization.
            if (!IsDeinitializing)
            {
                string err = $"NetworkObject {this.ToString()} is being reset prior to calling deinitialize. The object will be destroyed instead.";
                if (NetworkManager == null)
                    Debug.LogError(err);
                else
                    NetworkManager.LogError(err);

                Destroy(gameObject);
                return;
            }
#

I would expect at least one of those errors to pop, but if they do it should prevent other problems

desert vale
#

Lets say a gameobject with a network object is disabled first and despawned after that, would that cause this issue?

#

In other words, is it safe to despawn disabled objects?

granite sorrel
#

it shouldn't.

#
        private void OnDisable()
        {
            /* If deinitializing and an owner exist
             * then remove object from owner. */
            if (IsDeinitializing && Owner.IsValid)
                Owner.RemoveObject(this);
            /* If not nested then check to despawn this OnDisable.
             * A nob may become disabled without being despawned if it's
             * beneath another deinitializing nob. This can be true even while
             * not nested because users may move a nob under another at runtime.
             * 
             * This object must also be activeSelf, meaning that it became disabled
             * because a parent was. If not activeSelf then it's possible the
             * user simply deactivated the object themselves. */
            else if (IsServer && !IsNested && gameObject.activeSelf)
            {
                bool canDespawn = false;
                Transform nextParent = transform.parent;
                while (nextParent != null)
                {
                    if (nextParent.TryGetComponent(out NetworkObject pNob))
                    {
                        /* If pNob is not the same as ParentNetworkObject
                         * then that means this object was moved around. It could be
                         * that this was previously a child of something else
                         * or that was given a parent later on in it's life cycle.
                         ^
                         * When this occurs do not send a despawn for this object.
                         * Rather, let it destroy from unity callbacks which will force
                        * the proper destroy/stop cycle. */
                        if (pNob != ParentNetworkObject)
                            break;
                        //If nob is deinitialized then this one cannot exist.
                        if (pNob.IsDeinitializing)
                        {
                            canDespawn = true;
                            break;
                        }
                    }
                    nextParent = nextParent.parent;
                }

                if (canDespawn)
                    Despawn();
            }
        }```
#

Disabling would just SOMETIMES despawn it, if conditions are proper.

#

but despawning doesnt clear manager references, storing does.

#

this is under the assumption the error is in _networkObjectReference.TimeManager being null (base.TimeManager). Cannot really say with a full trace

#

So my advice currently is to add those changes in and run a dev build

#

@desert vale I'm going to give you a new object pool to try, but make a backup first of the old with the parenting commented. If the new one fails use the old but please give it a chance first.