// calls OnPhotonSerializeView (through ExecuteOnSerialize) // the content created here is consumed by receivers in: ReadOnSerialize private Hashtable OnSerializeWrite(PhotonView view) { // each view creates a list of values that should be sent List<object> data = new List<object>(); // 1=Specific data if (view.observed is MonoBehaviour) { PhotonStream pStream = new PhotonStream(true, null); PhotonMessageInfo info = new PhotonMessageInfo(this.mLocalActor, this.ServerTimeInMilliSeconds, view); view.ExecuteOnSerialize(pStream, info); if (pStream.Count == 0) { // if an observed script didn't write any data, we don't send anything return null; } // we want to use the content of the stream (filled in by user scripts) data = pStream.data; } else if (view.observed is Transform) { Transform trans = (Transform)view.observed; if (view.onSerializeTransformOption == OnSerializeTransform.OnlyPosition || view.onSerializeTransformOption == OnSerializeTransform.PositionAndRotation || view.onSerializeTransformOption == OnSerializeTransform.All) data.Add(trans.localPosition); else data.Add(null); if (view.onSerializeTransformOption == OnSerializeTransform.OnlyRotation || view.onSerializeTransformOption == OnSerializeTransform.PositionAndRotation || view.onSerializeTransformOption == OnSerializeTransform.All) data.Add(trans.localRotation); else data.Add(null); if (view.onSerializeTransformOption == OnSerializeTransform.OnlyScale || view.onSerializeTransformOption == OnSerializeTransform.All) data.Add(trans.localScale); } else if (view.observed is Rigidbody) { Rigidbody rigidB = (Rigidbody)view.observed; if (view.onSerializeRigidBodyOption != OnSerializeRigidBody.OnlyAngularVelocity) data.Add(rigidB.velocity); else data.Add(null); if (view.onSerializeRigidBodyOption != OnSerializeRigidBody.OnlyVelocity) data.Add(rigidB.angularVelocity); } else { Debug.LogError("Observed type is not serializable: " + view.observed.GetType()); return null; } object[] dataArray = data.ToArray(); if (view.synchronization == ViewSynchronization.UnreliableOnChange) { if (AlmostEquals(dataArray, view.lastOnSerializeDataSent)) { if (view.mixedModeIsReliable) { return null; } view.mixedModeIsReliable = true; view.lastOnSerializeDataSent = dataArray; } else { view.mixedModeIsReliable = false; view.lastOnSerializeDataSent = dataArray; } } // EVDATA: // 0=View ID (an int, never compressed cause it's not in the data) // 1=data of observed type (different per type of observed object) // 2=compressed data (in this case, key 1 is empty) // 3=list of values that are actually null (if something was changed but actually IS null) Hashtable evData = new Hashtable(); evData[(byte)0] = (int)view.viewID; evData[(byte)1] = dataArray; // this is the actual data (script or observed object) if (view.synchronization == ViewSynchronization.ReliableDeltaCompressed) { // compress content of data set (by comparing to view.lastOnSerializeDataSent) // the "original" dataArray is NOT modified by DeltaCompressionWrite // if something was compressed, the evData key 2 and 3 are used (see above) bool somethingLeftToSend = this.DeltaCompressionWrite(view, evData); // buffer the full data set (for next compression) view.lastOnSerializeDataSent = dataArray; if (!somethingLeftToSend) { return null; } } return evData; }