Debugging invalid cast

I recently ran in to a problem where I get an invalid cast exception but I can't figure out what is causing it or how to troubleshoot it. It appears only on client and I think it might be a PhotonView that's causing the problem after the GameObject is being isntantiated but that's just a guess and I could really use some help on how to proceed with this.
InvalidCastException: Cannot cast from source type to destination type.
NetworkingPeer.OnSerializeRead (ExitGames.Client.Photon.Hashtable data, .PhotonPlayer sender, Int32 networkTime, Int16 correctPrefix) (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs:3389)
NetworkingPeer.OnEvent (ExitGames.Client.Photon.EventData photonEvent) (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/NetworkingPeer.cs:1758)
ExitGames.Client.Photon.PeerBase.DeserializeMessageAndCallback (System.Byte[] inBuff)
ExitGames.Client.Photon.EnetPeer.DispatchIncomingCommands ()
ExitGames.Client.Photon.PhotonPeer.DispatchIncomingCommands ()
PhotonHandler.Update () (at Assets/Photon Unity Networking/Plugins/PhotonNetwork/PhotonHandler.cs:83)

Comments

  • I never ran into this issue, so we need some help what you actually do.

    Can you narrow down which Object is causing this error and then send me what you are sending in OnPhotonSerializeView()?
    Check your implementation of OnPhotonSerializeView(), too. In worst case, wrap the whole content of the method in a "try catch" block.
  • This is the function which I believe is causing the problem, I haven't mange to single out which object(s) is causing the problem.

    In NetworkingPeers.cs it's this line that's throwing the exception.
    3389:  trans.localRotation = (Quaternion)contents[1];
    

    Could the problem be that an object is instantiated and this function gets called before the transform.rotation has been set resulting in it sending a null? This doesn't seem to be it, tried to catch any nulls but didn't get any.
    void OnPhotonSerializeView (PhotonStream stream, PhotonMessageInfo info)
    	{
    		// Send data to server
    		if (stream.isWriting) {
    			Vector3 pos = transform.position;
    			Quaternion rot = transform.rotation;
    			Vector3 velocity = transform.position - prevPosition;
    			prevPosition = transform.position;
    			Vector3 angularVelocity = rig.angularVelocity;
    
    			stream.Serialize (ref pos);
    			stream.Serialize (ref velocity);
    			stream.Serialize (ref rot);
    			stream.Serialize (ref angularVelocity);
    			// Read data from remote client
    		} else {
    			Vector3 pos = Vector3.zero;
    			Vector3 velocity = Vector3.zero;
    			Quaternion rot = Quaternion.identity;
    			Vector3 angularVelocity = Vector3.zero;
    			stream.Serialize (ref pos);
    			stream.Serialize (ref velocity);
    			stream.Serialize (ref rot);
    			stream.Serialize (ref angularVelocity);
    
    			// Shift the buffer sideways, deleting state 20
    			for (int i = m_BufferedState.Length - 1; i >= 1; i--) {
    				m_BufferedState[i] = m_BufferedState[i - 1];
    			}
    
    			// Record current state in slot 0
    			State state;
    			state.timestamp = info.timestamp;
    			state.pos = pos;
    			state.velocity = velocity;
    			state.rot = rot;
    			state.angularVelocity = angularVelocity;
    			m_BufferedState[0] = state;
    
    			// Update used slot count, however never exceed the buffer size
    			// Slots aren't actually freed so this just makes sure the buffer is
    			// filled up and that uninitalized slots aren't used.
    			m_TimestampCount = Mathf.Min (m_TimestampCount + 1, m_BufferedState.Length);
    
    			// Check if states are in order, if it is inconsistent you could reshuffel or 
    			// drop the out-of-order state. Nothing is done here
    			for (int i = 0; i < m_TimestampCount - 1; i++) {
    				if (m_BufferedState[i].timestamp < m_BufferedState[i + 1].timestamp)
    					Debug.Log ("State inconsistent");
    			}
    		}
    	}
    
  • Do you change the PhotonView's Observe value in code maybe? This is not synchronized. If one client changes it, the others won't notice and still try to read what they expect (transform synchronization). If you begin to send something else, you can break this part.

    Could that be the case?
  • talothman
    talothman
    edited August 2018
    Hi @Tobias ,

    I've had the same issue. What I do mainly is that I sync the transform (position, rotation, scale) of all the children gameobjects under the gameobject that has a photonview. I loop through them.

    One thing that's interesting is that this issue doesn't appear when I have a smaller list of children gameobjects. I'm attempting to sync about a larger list (400+) and this causes a number of InvalidCastExceptions followed by the client getting kicked out of the room.

    My assumption is that when attempting to sync the long list of transforms, update messages go through but it takes the client too long to update the transforms through that long list so the client hangs and eventually gets kicked out of the room because they're not responsive.

    My question is if we send data through writing to the stream, to reduce the number of updates we send across, should we also check if that value has changes from the previous message?