/// <summary> /// Packs all elements of an enumerable up to a given size. /// Max 255 elements. /// </summary> public byte PackToSize <T>( int maxTotalBytes, int maxIndividualBytes, IEnumerable <T> elements, Action <T> encode, Action <T> packed = null) { const int MAX_SIZE = 255; const int SIZE_BITS = 8; maxTotalBytes -= 1; // Sentinel bit can blow this up byte count = 0; // Reserve: [Count] int countWritePos = this.writePos; this.Write(SIZE_BITS, 0); // Write: [Elements] foreach (T val in elements) { if (count == MAX_SIZE) { break; } int rollback = this.writePos; int startByteSize = this.ByteSize; encode.Invoke(val); int endByteSize = this.ByteSize; int writeByteSize = (endByteSize - startByteSize); if (writeByteSize > maxIndividualBytes) { this.writePos = rollback; RailDebug.LogWarning( "Skipping " + val + " (" + writeByteSize + "B)"); } else if (endByteSize > maxTotalBytes) { this.writePos = rollback; break; } else { if (packed != null) { packed.Invoke(val); } count++; } } // Deferred Write: [Count] this.Insert(countWritePos, SIZE_BITS, count); return(count); }
/// <summary> /// Selects outgoing events to send. /// </summary> private IEnumerable <RailEvent> FilterOutgoingEvents() { // The receiving client can only store SequenceWindow.HISTORY_LENGTH // events in its received buffer, and will skip any events older than // its latest received minus that history length, including reliable // events. In order to make sure we don't force the client to skip a // reliable event, we will throttle the outgoing events if we've been // sending them too fast. For example, if we have a reliable event // with ID 3 pending, the highest ID we can send would be ID 67. If we // send an event with ID 68, then the client may ignore ID 3 when it // comes in for being too old, even though it's reliable. // // In practice this shouldn't be a problem unless we're sending way // more events than is reasonable(/possible) in a single packet, or // something is wrong with reliable event acking. SequenceId firstReliable = SequenceId.INVALID; foreach (RailEvent evnt in this.outgoingEvents) { if (evnt.IsReliable) { if (firstReliable.IsValid == false) { firstReliable = evnt.EventId; } RailDebug.Assert(firstReliable <= evnt.EventId); } if (firstReliable.IsValid) { if (SequenceWindow.AreInRange(firstReliable, evnt.EventId) == false) { string current = "Throttling events due to unacked reliable\n"; foreach (RailEvent evnt2 in this.outgoingEvents) { current += evnt2.EventId + " "; } RailDebug.LogWarning(current); break; } } if (evnt.CanSend) { yield return(evnt); } } }
internal static Tick Subtract(Tick a, int b, bool warnClamp = false) { RailDebug.Assert(b >= 0); long result = (long)a.tickValue - b; if (result < 1) { if (warnClamp) { RailDebug.LogWarning("Clamping tick subtraction"); } result = 1; } return(new Tick((uint)result)); }