/// <summary> /// Write/Pack all of the values we want to network into a bitstream /// </summary> /// <param name="bitstream"></param> public void SerializeValuesToBitstream(byte[] bitstream, ref int writepos) { /// Write the NetId of the player this update belongs to. bitstream.Write((ulong)NetId, ref writepos, 32); /// Compress this objects current transform to the CompressedMatrix. sharedCrusher.Crusher.Compress(compMatrix, transform); /// For this example we compare the new CompressedMatrix with the previously sent one to see if anything has changed. /// If the compressed value has not changed, we will not send a compressed transform this tick. The == operator is overloaded /// for CompressedElement and CompressedMatrix, so == actually is running a.Equals(b) behind the scenes letting you compare the /// classes as if they were structs. if (compMatrix != sentCompMatrix) { /// Single true bit flag to indicate a compressed transform follows bitstream.WriteBool(true, ref writepos); /// Pass the bitstream to the TransformCrusher to serialize in the value of compMatrix. sharedCrusher.Crusher.Write(compMatrix, bitstream, ref writepos); /// Copy the values of of cm for comparison next tick. sentCompMatrix.CopyFrom(compMatrix); } else { /// Single false bit flag to indicate a compressed transform doesn't follow bitstream.WriteBool(false, ref writepos); } }
public override void CopyFrom(FrameBase sourceFrame) { base.CopyFrom(sourceFrame); Frame src = sourceFrame as Frame; /// When copying a teleport frame, we use the tele values. if (src.hasTeleported) { m.CopyFrom(src.telem); cm.CopyFrom(src.telecm); } else { m.CopyFrom(src.m); cm.CopyFrom(src.cm); } hasTeleported = false; // src.hasTeleported; parentHash = src.parentHash; }
private void FixedUpdate() { if (!IsMine) { return; } fixedCount++; /// For this example we are sending every X fixed update to produce a lower net tick rate. if (((fixedCount % SEND_EVERY) != 0) && ((fixedCount % KEY_EVERY) != 0)) { return; } // We compress the transform, which returns a CompressedMatrix. sharedCrusher.Crusher.Compress(compMatrix, transform); /// For this example, we are testing to see if the new CompressedMatrix value has changed from the last. /// Only send if there has been a change, or if this is a keyframe. if (compMatrix != sentCompMatrix || fixedCount % KEY_EVERY == 0) { /// The largest primitive we can send with most RPCs is a 64 bit ulong, so we need to break the CompressedMatrix /// (Which is a collection of compressed floats and possibly a compressed quaternion) into serializable primitives. /// Our total bits for this example is 72, so we send 64 of those bits as the first argument from our first fragment. /// The second fragment of the contains the remaining 8 bits and that becomes the second argument. /// Rather than sending the whole 64 bit second fragment, we can instead just cast down to (byte), /// since the upper/left bits of the second fragment will always be zeros. /// 00000000-00000000-00000000-XXXXXXXX /// Casting a CompressedMatrix to ULong lets us break the compressed object into primitives for use as Syncvars or RPC arguments. /// We only need to make use of the first two returned array elements here. /// CompressedMatrix and CompressedElements implicitly can be cast to arrays as shown below. ulong[] fragments = (ulong[])compMatrix; /// Send the RPC from the owner /// PUN can't serialize most unsigned types (ushort, uint, ulong) for some strange reason - so we are using ByteConverter here serialize our ulong as long /// We will use ByteConverter again after deserialization to convert the long back to a ulong. #if PUN_2_OR_NEWER photonView.RPC("RpcClientRPC", RpcTarget.Others, (long)(ByteConverter)fragments[0], (byte)fragments[1]); #else CmdServerRPC((ByteConverter)fragments[0], (byte)fragments[1]); #endif /// We can Store the CompressedMatrix we just sent for comparison on next fixed update, to check for changes sentCompMatrix.CopyFrom(compMatrix); } }