[Bug] Projectiles not reliably destroyed over the network

Found a working solution. If there is a duplicate, I assign a random view id to the inactive game object. If it is active, I destroy the object beforehand. This seems to be the only way to stay consistent with the photon view list. The only problem is that I get an exception in the shootable weapon as I destroy the object already in the PunObjectPool.

Code:
var obj = ObjectPool.Instantiate(original, (Vector3)data[1], (Quaternion)data[2]);
                var photonView = obj.GetCachedComponent<PhotonView>();
                var targetViewID = (int)data[3];
                // Check if an object with the target viewID already exists
                var existingPhotonView = PhotonNetwork.GetPhotonView(targetViewID);


                if(existingPhotonView != null)  // There is an existing photon view with identical viewID
                {
                    if(existingPhotonView.gameObject.activeInHierarchy)
                    {
                        if(existingPhotonView.gameObject != obj)
                        {
                            // Bad case. An active game object exists in the scene, but it is not the object received from object pool.
                            // Probably a race condition. The object has been destroyed on server, but not yet on client.
                            if (ObjectPool.InstantiatedWithPool(existingPhotonView.gameObject))
                            {
                                DestroyInternal(existingPhotonView.gameObject);
                                ReassignPhotonView(existingPhotonView);
                            }
                        }
                    }
                    else
                    {
                        // Bad case. There is an inactive game object in the pool with the target viewID.
                        ReassignPhotonView(existingPhotonView);
                    }
                }
                PhotonNetwork.LocalCleanPhotonView(photonView);
                photonView.ViewID = 0;
                photonView.ViewID = targetViewID;

Code:
        private void ReassignPhotonView(PhotonView photonView)
        {
            bool run = true;
            int newID = 0;
            while(run)
            {
                newID = Random.Range(300, 400);
                if(PhotonNetwork.GetPhotonView(newID) == null) run = false;
            }
            PhotonNetwork.LocalCleanPhotonView(photonView);
            photonView.ViewID = 0;
            photonView.ViewID = newID;
        }

And here is the exception (on the client). Seems I am destroying an object that anyway should not be there ...

Code:
Unable to pool BubbleGunProjectilePUN(Clone) (instance -374776): the GameObject was not instantiated with ObjectPool.Instantiate.
UnityEngine.Debug:LogError (object)
Opsive.Shared.Game.ObjectPoolBase:DestroyInternal (UnityEngine.GameObject)
Opsive.Shared.Game.ObjectPoolBase:Destroy (UnityEngine.GameObject)
Opsive.UltimateCharacterController.Items.Actions.ShootableWeapon:ProjectileFire (single) (at Assets/Opsive/UltimateCharacterController/Scripts/Items/Actions/ShootableWeapon.cs:793)
Opsive.UltimateCharacterController.Items.Actions.ShootableWeapon:Fire (single) (at Assets/Opsive/UltimateCharacterController/Scripts/Items/Actions/ShootableWeapon.cs:774)
Opsive.UltimateCharacterController.Items.Actions.ShootableWeapon:UseItem () (at Assets/Opsive/UltimateCharacterController/Scripts/Items/Actions/ShootableWeapon.cs:694)
Opsive.UltimateCharacterController.Character.Abilities.Items.Use:LateUpdate () (at Assets/Opsive/UltimateCharacterController/Scripts/Character/Abilities/Items/Use.cs:638)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotion:LateUpdateActiveAbilities (Opsive.UltimateCharacterController.Character.Abilities.Ability[],int&) (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotion.cs:1042)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotion:LateUpdateUltimateLocomotion () (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotion.cs:1028)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotion:UpdatePositionAndRotation () (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotion.cs:843)
Opsive.UltimateCharacterController.Character.CharacterLocomotion:UpdatePositionAndRotation (bool) (at Assets/Opsive/UltimateCharacterController/Scripts/Character/CharacterLocomotion.cs:517)
Opsive.UltimateCharacterController.Character.CharacterLocomotion:OnAnimatorMove () (at Assets/Opsive/UltimateCharacterController/Scripts/Character/CharacterLocomotion.cs:1453)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotion:OnAnimatorMove () (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotion.cs:1772)
 
BTW. I now understand, that most of the collisions of identical photon views with active objects are not from race conditions. If the projectile is set to "always visible" you instantiate a local object on the client just for being visible, but the object is not synced across the network. It is destroyed and replaced when the projectile is fired and synced by the server. The problem is that the local instance that's only used for visibility still has a photon view attached.
 
Thank you for the in depth analysis and fix. I will take a close look at this and have it fixed for the next update. Ideally I'd like to not use LocalCleanPhotonView since that seems like a hack now that I have an understanding of the problem.
 
Top