public override bool Write(ref UdpBitStream bitstream, Frame frame) { // Base class does some forceUpdate checking, keep it around. bool forceUpdate = IsUpdateForced(frame); ElementFrame e = frames[frame.frameid]; e.compXform = Compress(); e.xform = Localized; CompressedElement newComp = e.compXform; if (rotationType == RotationType.Quaternion) { // For frames between forced updates, we need to first send a flag bit for if this element is being sent if (!forceUpdate) { bool hasChanged = newComp.quat != lastSentCompressed.quat && sendCullMask.OnChanges(); bitstream.WriteBool(hasChanged); // if no changes have occured we are done. if (!hasChanged) { return(false); } } bitstream.WriteULong(newComp.quat, totalBitsForQuat); lastSentCompressed.quat = newComp.quat; lastSentTransform = e.xform; return(true); } else { // For frames between forced updates, we need to first send a flag bit for if this element is being sent if (!forceUpdate) { bool hasChanged = !CompressedElement.Compare(newComp, lastSentCompressed) && sendCullMask.OnChanges(); bitstream.WriteBool(hasChanged); // if no changes have occured we are done. if (!hasChanged) { return(false); } } for (int axis = 0; axis < 3; axis++) { if (includedAxes.IsXYZ(axis)) { bitstream.WriteUInt(newComp[axis], axes[axis].bits); lastSentCompressed[axis] = newComp[axis]; } } return(true); } }
public static void Send(ref UdpBitStream bitstream, int updateCounter) { // If this is the server and it is due to ping... ping //TODO this hard coded 60 will likely go. //TODO this should probably be offset by 1 to keep frame zero from becoming massive with all the keyframes of NST if (MasterNetAdapter.ServerIsActive && updateCounter % 20 == 0 && updateCounter != 60) { svrPingInitiateTime = Time.time; bitstream.WriteBool(true); } // If this is a client, and it has rcvd a server ping, it needs to respond next tick. else if (clientNeedsToRespondToPing) { bitstream.WriteBool(true); // write how long the client waited to reply in ms (1023 ms max with 10 bits) bitstream.WriteInt((int)((Time.time - clntPingArriveTime) * 1000), 10); clientNeedsToRespondToPing = false; } // nothing happening this pass. else { bitstream.WriteBool(false); } }
public byte[] Pack() { var data = new byte[1200]; var stream = new UdpBitStream(data, data.Length); //stream.WriteInt(state.index, 32); UdpBitStreamExt.WriteVector3(ref stream, state.position); UdpBitStreamExt.WriteQuaternion(ref stream, state.rotation); UdpBitStreamExt.WriteVector3(ref stream, state.velocity); UdpBitStreamExt.WriteVector2(ref stream, movementInput); UdpBitStreamExt.WriteVector2(ref stream, lookInput); stream.WriteBool(jumpInput); stream.WriteBool(shootInput); return(data); }
public bool Write(ref UdpBitStream bitstream, Frame frame) { ElementFrame e = frames[frame.frameid]; e.compXform = Compress(); e.xform = Localized; CompressedElement newComp = e.compXform; bool forceUpdate = IsUpdateForced(frame); // For frames between forced updates, we need to first send a flag bit for if this element is being sent if (!forceUpdate) { bool hasChanged = !CompressedElement.Compare(newComp, lastSentCompressed) && sendCullMask.OnChanges(); bitstream.WriteBool(hasChanged); // if no changes have occured we are done. if (!hasChanged) { return(false); } } crusher.Write(e.compXform, bitstream.Data, ref bitstream.ptr); lastSentCompressed = newComp; lastSentTransform = e.xform; return(true); }
/// <summary> /// Ping all owned NSTs for any due updates. Passes the bitstream to that NST to write to. /// </summary> public static void PollAllForUpdates() { //Debug.Log("<b><color=green>Mstr Ping</color></b> " + (Time.time - tempMasterPollTime)); //tempMasterPollTime = Time.time; UdpBitStream bitstream = new UdpBitStream(bitstreamByteArray); UdpBitStream outstream = new UdpBitStream(); bool foundUpdate = false; for (int i = 0; i < NetworkSyncTransform.allNsts.Count; i++) { foundUpdate |= NetworkSyncTransform.allNsts[i].PollForUpdate(ref bitstream); } // No Updates, we are done. if (!foundUpdate) { return; } // Write the end of stream marker of 00 bitstream.WriteBool(false); mna.SendUpdate(ref bitstream, ref outstream); //Debug.Log("<b><color=blue>Mstr Snd</color></b> " + (Time.time - tempMasterSendTime)); //tempMasterSendTime = Time.time; }
public bool Write(ref UdpBitStream bitstream, Frame frame) { ElementFrame e = frames[frame.frameid]; CompressedElement compXform = e.compXform; Compress(compXform); e.xform = Decompress(compXform); // Localized; /// Experimental - Apply the outgoing lossy values to the GhostGO so owner/authority of object can use it to replicate lossy events like weapon fire. if (ghostGO) { Apply(e.xform, ghostGO); } if (!nstElement.Enabled) { bitstream.WriteBool(false); return(false); } bool forceUpdate = IsUpdateForced(frame); // For frames between forced updates, we need to first send a flag bit for if this element is being sent if (!forceUpdate) { bool hasChanged = !compXform.Equals(lastSentCompressed) && sendCullMask.OnChanges(); bitstream.WriteBool(hasChanged); // if no changes have occured we are done. if (!hasChanged) { return(false); } } else { bitstream.WriteBool(true); } crusher.Write(compXform, bitstream.Data, ref bitstream.ptr); lastSentCompressed.CopyFrom(compXform); lastSentTransform = e.xform; return(true); }
public void MirrorToClients(ref UdpBitStream outstream, Frame frame, bool hasChanged) { //// Write the used flag (if this is not a forced update) and determine if an update needs to be written. //if (WriteUpdateFlag(ref outstream, frame, hasChanged) == false) // return; outstream.WriteBool(hasChanged); if (!hasChanged) { return; } ElementFrame e = frames[frame.frameid]; crusher.Write(e.compXform, outstream.Data, ref outstream.ptr); }
/// <summary> /// Write the flag bool if this is not a forced update, and return true if the element should be written to the stream (the value of the flag). /// </summary> protected bool WriteUpdateFlag(ref UdpBitStream outstream, Frame frame, bool hasChanged) { bool forcedUpdate = IsUpdateForced(frame); // For non-forced updates we need to set the used flag. if (!forcedUpdate) { outstream.WriteBool(hasChanged); } // exit if we are not writing a compressed value. if (!hasChanged && !forcedUpdate) { return(false); } return(true); }
/// <summary> /// Ping all owned NSTs for any due updates (fires on network ticks, generated by the NSTMaster FixedUpdate()). Passes the bitstream to that NST. /// </summary> public static bool PollAllForNSTUpdates(ref UdpBitStream bitstream, List <NetworkSyncTransform> nsts, int updateCounter, bool isOfftick) { if (!MasterNetAdapter.ServerIsActive && !MasterNetAdapter.ClientIsActive) { return(false); } bool foundUpdate = false; int count = nsts.Count; for (int i = 0; i < count; ++i) { foundUpdate |= nsts[i].PollForUpdate(ref bitstream, updateCounter, isOfftick); } // Write the end of stream marker of 00 bitstream.WriteBool(false); IntegrityCheck.WriteCheck(ref bitstream); return(foundUpdate); }
public static void Rcv(ref UdpBitStream bitstream, ref UdpBitStream outstream, bool mirror, int clientId) { bool isPing = bitstream.ReadBool(); // if this is a ping from a client, a time delta should follow (mirror means this is the server, and this pass is the server pass) if (isPing && mirror && clientId != MasterNetAdapter.MasterClientId) { float clientHeldTime = .001f * bitstream.ReadInt(10); float rtt = (Time.time - svrPingInitiateTime) - clientHeldTime; if (RTT.ContainsKey(clientId)) { RTT[clientId] = RTT[clientId] * OLD_SAMP_WEIGHT + rtt * NEW_SAMP_WEIGHT; } else { RTT.Add(clientId, rtt); } //Debug.Log( DebugX.Log(!DebugX.logInfo ? null : "MasterRTT ping result " + clientId + " <b>" + RTT[clientId] + " </b> plus " + clientHeldTime + " of client waiting for next outgoing tick."); } // this is a dumb client and it just got a ping from server else if (isPing && !MasterNetAdapter.ServerIsActive) { clientNeedsToRespondToPing = true; clntPingArriveTime = Time.time; } // We don't mirror out pings. The conversation is strictly Server > Player > Server if (mirror) { outstream.WriteBool(false); } }
/// <summary> /// Reads update headers for each NST frame update in the incoming bitstream, and passes the bitstream to that NST to read out its /// update information. /// </summary> /// <param name="mirror">True if this is the server, and this is the incoming bitstream. Tells the server that the outstream /// needs to be populated for retransmission to all clients. Also false if this is the server running its own outgoing update.</param> public static void ReceiveUpdate(ref UdpBitStream bitstream, ref UdpBitStream outstream, bool mirror, int senderId) { // Create a new bitstream to ensure ptr is at 0. Same data as master though. bitstream.ptr = 0; int frameid = bitstream.ReadInt(6); if (mirror) { outstream.WriteInt(frameid, 6); } bool isOfftick = frameid == 60; // remove this safety once working //TEST int safety = 0; UpdateType updateType; do { safety++; BandwidthUsage.Start(ref bitstream, BandwidthLogType.UpdateRcv); //stop looking when header is EOS bool notEOS = bitstream.ReadBool(); int mirrorUpdateStartPtr = outstream.ptr; BandwidthUsage.AddUsage(ref bitstream, "NotEOS"); if (mirror) { outstream.WriteBool(notEOS); } if (!notEOS) { break; } // First three bits are the msgtype //TODO this might only need to be two updateType = (UpdateType)bitstream.ReadInt(3); BandwidthUsage.AddUsage(ref bitstream, "UpdateType"); int updateBitstreamPos = outstream.ptr; if (mirror) { outstream.WriteInt((int)updateType, 3); } // Next variable is the NstId - get it to know where to send the rest of the bitstream uint nstid = bitstream.ReadUInt(HeaderSettings.single.BitsForNstId); BandwidthUsage.AddUsage(ref bitstream, "NstId"); if (mirror) { outstream.WriteUInt(nstid, HeaderSettings.single.BitsForNstId); } lastNST = NSTTools.GetNstFromId(nstid); BandwidthUsage.SetName(lastNST); int updatelength = bitstream.ReadInt(UPDATELENGTH_BYTE_COUNT_SIZE); if (mirror) { outstream.WriteInt(updatelength, UPDATELENGTH_BYTE_COUNT_SIZE); } BandwidthUsage.AddUsage(ref bitstream, "DataLength"); //Note the starting pos in stream int bodyPtr = bitstream.ptr; // The start pos for modifying update lenght for mirror int mirrorBodyPtr = outstream.ptr; // This mising NST handler is NOT FULLY TESTED. Uses the updatelength value to jump ahead in the bitstream if the NST it is // addressed to doesn't exist for some reason. if (lastNST == null) { //DebugX.LogWarning(!DebugX.logWarnings ? null : DebugX.Log( ("Message for an NST Object " + nstid + " arrived but that object does not exist. (yet/anymore?) This is normal during startup and shutdown.")); // Forward to the next update start in the incoming stream. bitstream.ptr = bodyPtr + (updatelength << 3); // rewind to the EOS marker and pretend this arrival never occured for the outgoing mirror stream. outstream.ptr = mirrorUpdateStartPtr; continue; } // Tell this nst to read its mail. updateType may get modified by server receive for things like teleport. Frame frame = lastNST.ReadUpdate(ref bitstream, ref outstream, frameid, isOfftick, updateType, updatelength, mirror); updateType = frame.updateType; // overwrite the updateType of the server outgoing in case it has changed. if (mirror) { outstream.WriteIntAtPos((int)updateType, 3, updateBitstreamPos); } //Advance ptr to next update in stream by force, in case the last update wasn't read for any reason (such as the NST leaving the game) bitstream.ptr = bodyPtr + (updatelength << 3); // write the update byte length for the mirror (not the same value as the incoming due to server side adjustments) if (mirror) { int holdPos = outstream.ptr; outstream.ptr = mirrorBodyPtr - UPDATELENGTH_BYTE_COUNT_SIZE; // get the bytesused rounded up. int bytes = ((holdPos - mirrorBodyPtr) >> 3) + (((holdPos - mirrorBodyPtr) % 8 == 0) ? 0 : 1); outstream.WriteInt(bytes, UPDATELENGTH_BYTE_COUNT_SIZE); outstream.ptr = mirrorBodyPtr + (bytes << 3); } } while (safety < 100); /// NST updates are finished - any data to append to the master update can go here IntegrityCheck.ReadCheck(ref bitstream, ref outstream, "End of All Update Reads", mirror); MasterRTT.Rcv(ref bitstream, ref outstream, mirror, senderId); BandwidthUsage.AddUsage(ref bitstream, "RTT checks"); // Very last thing... report the bits that were used. This is conditional to the editor only BandwidthUsage.ReportMasterBits(ref bitstream, BandwidthLogType.MasterIn); }
public override void WriteToBitstream(ref UdpBitStream bitstream, MsgType msgType, bool forceUpdate, bool isKeyframe) { // Base class does some forceUpdate checking, keep it around. //forceUpdate = base.WriteToBitstream(ref bitstream, msgType, forceUpdate); //bool hasChanged = false; if (rotationType == XType.Quaternion) { ulong compressedQuat = QuatCompress.CompressQuatToBitsBuffer(Localized, totalBitsForQuat); // For frames between forced updates, we need to first send a flag bit for if this element is being sent if (!forceUpdate) { bool hasChanged = compressedQuat != lastSentCompressed; bitstream.WriteBool(hasChanged); // if no changes have occured we are done. if (!hasChanged) { return; } } bitstream.WriteULong(compressedQuat, totalBitsForQuat); lastSentCompressed = compressedQuat; return; } else { // Euler types... CompressedElement newValues = new CompressedElement(0, 0, 0); // populate the new compressed position, and test if any of the axes have changed. for (int axis = 0; axis < 3; axis++) { if (rotationType.IsXYZ(axis)) { newValues[axis] = CompressFloat(((Vector3)Localized)[axis], axis); } } // For frames between forced updates, we need to first send a flag bit for if this element is being sent if (!forceUpdate) { bool hasChanged = !CompressedElement.Compare(newValues, lastSentCompressed); bitstream.WriteBool(hasChanged); // if no changes have occured we are done. if (!hasChanged) { return; } } for (int axis = 0; axis < 3; axis++) { if (rotationType.IsXYZ(axis)) { bitstream.WriteUInt(newValues[axis], xyzBits[axis]); lastSentCompressed[axis] = newValues[axis]; } } } }
/// <summary> /// Reads update headers for each NST frame update in the incoming bitstream, and passes the bitstream to that NST to read out its /// update information. /// </summary> /// <param name="mirror">True if this is the server, and this is the incoming bitstream. Tells the server that the outstream /// needs to be populated for retransmission to all clients. Also false if this is the server running its own outgoing update.</param> public static void ReceiveUpdate(ref UdpBitStream bitstream, ref UdpBitStream outstream, bool mirror, int senderId) { // Create a new bitstream to ensure ptr is at 0. Same data as master though. bitstream.ptr = 0; int frameid = bitstream.ReadInt(6); if (mirror) { outstream.WriteInt(frameid, 6); } bool isOfftick = frameid == FRAME_COUNT; int sceneIndex = NSTSceneManager.Deserialize(ref bitstream, ref outstream, mirror); bool sceneOutOfSync = HeaderSettings.single.includeSceneIndex && sceneIndex != NSTSceneManager.CurrentSceneIndex; if (sceneOutOfSync) { Debug.LogWarning(frameid + " Out of sync " + sceneIndex + " " + NSTSceneManager.CurrentSceneIndex); } // remove this safety once working //TEST int safety = 0; UpdateType updateType; do { safety++; BandwidthUsage.Start(ref bitstream, BandwidthLogType.UpdateRcv); //stop looking when header is EOS bool notEOS = bitstream.ReadBool(); int mirrorUpdateStartPtr = outstream.ptr; BandwidthUsage.AddUsage(ref bitstream, "NotEOS"); if (mirror) { outstream.WriteBool(notEOS); } if (!notEOS) { break; } // First three bits are the msgtype //TODO this might only need to be two updateType = (UpdateType)bitstream.ReadInt(3); BandwidthUsage.AddUsage(ref bitstream, "UpdateType"); int updateBitstreamPos = outstream.ptr; if (mirror) { outstream.WriteInt((int)updateType, 3); } // Next variable is the NstId - get it to know where to send the rest of the bitstream uint nstid = bitstream.ReadUInt(HeaderSettings.single.BitsForNstId); BandwidthUsage.AddUsage(ref bitstream, "NstId"); if (mirror) { outstream.WriteUInt(nstid, HeaderSettings.single.BitsForNstId); } lastNST = NSTTools.GetNstFromId(nstid); BandwidthUsage.SetName(lastNST); int updatelength = bitstream.ReadInt(UPDATELENGTH_BYTE_COUNT_SIZE); if (mirror) { outstream.WriteInt(updatelength, UPDATELENGTH_BYTE_COUNT_SIZE); } BandwidthUsage.AddUsage(ref bitstream, "DataLength"); //Note the starting pos in stream int bodyPtr = bitstream.ptr; // The start pos for modifying update lenght for mirror int mirrorBodyPtr = outstream.ptr; XDebug.LogWarning(!XDebug.logWarnings ? null : ("Incoming Update for nstid: " + nstid + " was from a different scene. Ignoring update to avoid data corruption due to different compression settings."), sceneOutOfSync); XDebug.Log(!XDebug.logInfo ? null : //Debug.Log( ("Message for an NST Object " + nstid + " arrived but that object does not exist. (yet/anymore?) This is normal during startup and shutdown."), lastNST == null); /// Skip reading if the target NST doesn't exist, or if this we compressed with a different scene (codec mismatch likely) if (lastNST == null || sceneOutOfSync) { if (sceneOutOfSync) { Debug.LogWarning(frameid + " skipped entirely due to sceneID mismatch"); } // Forward to the next update start in the incoming stream. bitstream.ptr = bodyPtr + (updatelength << 3); // rewind to the EOS marker and pretend this arrival never occured for the outgoing mirror stream. if (mirror) { /// TODO : Rather than jump ahead, Server should bulk copy the ignored data to outstream in case other clients can use it. outstream.ptr = mirrorUpdateStartPtr; } continue; } // Tell this nst to read its mail. updateType may get modified by server receive for things like teleport. Frame frame = lastNST.ReadUpdate(ref bitstream, ref outstream, frameid, isOfftick, updateType, updatelength, sceneIndex, sceneOutOfSync, mirror); updateType = frame.updateType; // overwrite the updateType of the server outgoing in case it has changed. if (mirror) { outstream.WriteIntAtPos((int)updateType, 3, updateBitstreamPos); } //Advance ptr to next update in stream by force, in case the last update wasn't read for any reason (such as the NST leaving the game) bitstream.ptr = bodyPtr + (updatelength << 3); // write the update byte length for the mirror (not the same value as the incoming due to server side adjustments) if (mirror) { int holdPos = outstream.ptr; outstream.ptr = mirrorBodyPtr - UPDATELENGTH_BYTE_COUNT_SIZE; // get the bytesused rounded up. int bytes = ((holdPos - mirrorBodyPtr) >> 3) + (((holdPos - mirrorBodyPtr) % 8 == 0) ? 0 : 1); outstream.WriteInt(bytes, UPDATELENGTH_BYTE_COUNT_SIZE); outstream.ptr = mirrorBodyPtr + (bytes << 3); } } while (safety < 100); /// NST updates are finished - any data to append to the master update can go here IntegrityCheck.ReadCheck(ref bitstream, ref outstream, "End of All Update Reads", mirror); if (!isOfftick) { MasterRTT.Rcv(ref bitstream, ref outstream, mirror, senderId); } BandwidthUsage.AddUsage(ref bitstream, "RTT checks"); // Very last thing... report the bits that were used. This is conditional to the editor only BandwidthUsage.ReportMasterBits(ref bitstream, BandwidthLogType.MasterIn); }
/// <summary> /// Reads update headers for each NST frame update in the incoming bitstream, and passes the bitstream to that NST to read out its /// update information. /// </summary> /// <param name="mirror">True if this is the server, and this is the incoming bitstream. Tells the server that the outstream /// needs to be populated for retransmission to all clients. Also false if this is the server running its own outgoing update.</param> public static void ReceiveUpdate(ref UdpBitStream bitstream, ref UdpBitStream outstream, bool mirror) { // Create a new bitstream to ensure ptr is at 0. Same data as master though. bitstream.Ptr = 0; // remove this safety once working //TEST int safety = 0; UpdateType updateType; do { safety++; BandwidthUsage.Start(ref bitstream, BandwidthLogType.UpdateRcv); //stop looking when header is EOS bool notEOS = bitstream.ReadBool(); int mirrorUpdateStartPtr = outstream.Ptr; BandwidthUsage.AddUsage(ref bitstream, "NotEOS"); if (mirror) { outstream.WriteBool(notEOS); } if (!notEOS) { break; } // First three bits are the msgtype //TODO this might only need to be two updateType = (UpdateType)bitstream.ReadInt(3); BandwidthUsage.AddUsage(ref bitstream, "UpdateType"); int updateBitstreamPos = outstream.Ptr; if (mirror) { outstream.WriteInt((int)updateType, 3); } // Next variable is the NstId - get it to know where to send the rest of the bitstream uint nstid = bitstream.ReadUInt(NSTSettings.single.bitsForNstId); BandwidthUsage.AddUsage(ref bitstream, "NstId"); if (mirror) { outstream.WriteUInt(nstid, NSTSettings.single.bitsForNstId); } NetworkSyncTransform nst = NetworkSyncTransform.GetNstFromId(nstid); BandwidthUsage.SetName(nst); int updatelength = bitstream.ReadInt(UPDATELENGTH_BYTE_COUNT_SIZE); if (mirror) { outstream.WriteInt(updatelength, UPDATELENGTH_BYTE_COUNT_SIZE); } BandwidthUsage.AddUsage(ref bitstream, "DataLength"); //Note the starting pos in stream int bodyPtr = bitstream.Ptr; // The start pos for modifying update lenght for mirror int mirrorBodyPtr = outstream.Ptr; // This mising NST handler is NOT FULLY TESTED. Uses the updatelength value to jump ahead in the bitstream if the NST it is // addressed to doesn't exist for some reason. if (nst == null) { DebugX.LogWarning(!DebugX.logWarnings ? "" : ("Message for an NST Object arrived but that object does not exist.")); // Forward to the next update start in the incoming stream. bitstream.Ptr = bodyPtr + (updatelength << 3); // rewind to the EOS marker and pretend this arrival never occured for the outgoing mirror stream. outstream.Ptr = mirrorUpdateStartPtr; continue; } // Tell this nst to read its mail. updateType may get modified by server receive for things like teleport. updateType = nst.ReceieveGeneric(ref bitstream, ref outstream, updateType, updatelength, mirror); // overwrite the updateType of the server outgoing in case it has changed. if (mirror) { outstream.WriteIntAtPos((int)updateType, 3, updateBitstreamPos); } //Advance ptr to next update in stream by force, in case the last update wasn't read for any reason (such as the NST leaving the game) bitstream.Ptr = bodyPtr + (updatelength << 3); // write the update byte length for the mirror (not the same value as the incoming due to server side adjustments) if (mirror) { int holdPos = outstream.Ptr; outstream.Ptr = mirrorBodyPtr - UPDATELENGTH_BYTE_COUNT_SIZE; // get the bytesused rounded up. int bytes = ((holdPos - mirrorBodyPtr) >> 3) + (((holdPos - mirrorBodyPtr) % 8 == 0) ? 0 : 1); outstream.WriteInt(bytes, UPDATELENGTH_BYTE_COUNT_SIZE); outstream.Ptr = mirrorBodyPtr + (bytes << 3); } } while (safety < 100); }