public void ReceiveNotifications(List <bool> notifications)
        {
            foreach (bool dropped in notifications)
            {
                ReplicationSystemTransmission transmission = _transmissions.Dequeue();

                if (!dropped)
                {
                    continue;
                }

                foreach (ReplicatedObjectTransmissionRecord tr in transmission.Records)
                {
                    // Since this packet was lost we know that the client hasn't synced the state
                    // represented in the state mask for this object so we want to set those bits
                    // in the objects state mask again so that those pieces of state are transmitted this iteration
                    ReplicatedObjectTransmissionRecord nextTransmission = tr.NextTransmission;
                    while (nextTransmission != null)
                    {
                        // We want to exclude any bits that were set in transmissions that came after the one we are being notified about
                        tr.StateMask    ^= tr.StateMask & nextTransmission.StateMask;
                        tr.Status       ^= tr.Status & nextTransmission.Status;
                        nextTransmission = nextTransmission.NextTransmission;
                    }

                    // The state mask in tr.StateMask now only contains bits that weren't
                    // set set in subsequent transmissions so we want to make sure all those bits
                    // are set for the next transmission
                    tr.RepRecord.StateMask |= tr.StateMask;
                    tr.RepRecord.Status    |= tr.Status;
                }
            }
        }
        public void WriteToPacketStream(NetDataWriter stream)
        {
            ReplicationSystemTransmission transmission = new ReplicationSystemTransmission();

            // sort by state change and then priority once it exists
            // TODO: flow control
            // how know if we overflow the buffer before hand or keep an index
            // for each write that doesn't overflow and then clear up to that index
            // as soon as we go over. Can keep the max that rep system is allowed to write still within
            // the actual buffer size
            foreach (ReplicationRecord r in ReplicatedObjects.Values)
            {
                if (r.StateMask == 0 && r.Status == ReplicationRecord.ReplicationSystemStatus.None)
                {
                    continue;
                }

                Log.Debug($"Writing ghost: {r.Id}");
                // Write the Id of the object that is referenced by the remote ReplicationSystem
                stream.Put(r.Id);
                // Write the state of the replicated object (need bitpacker so that this takes at most 2 bits)
                if (r.Status == ReplicationRecord.ReplicationSystemStatus.None)
                {
                    Log.Debug("No status change");
                    stream.Put((byte)0);
                }
                else
                {
                    stream.Put((byte)1);
                    if (r.Status == ReplicationRecord.ReplicationSystemStatus.Added)
                    {
                        stream.Put((byte)1);
                        // Write persistent object id for obj
                        stream.Put(r.Entity.ObjectRep.Id);
                        Log.Debug($"Status: ADDED. Writing object rep id: {r.Entity.ObjectRep.Id}");
                    }
                    else
                    {
                        Log.Debug("Status: REMOVED");
                        // removed
                        stream.Put((byte)0);
                    }
                }

                Log.Debug($"Serializing object into stream. Bytes before: {stream.Length}");
                // Write the object into the stream using the state mask for this rep system
                r.Entity.Serialize(stream, r.StateMask);
                Log.Debug($"After serializing size: {stream.Length}");


                // Write state and status to transmission record
                ReplicatedObjectTransmissionRecord tr = new ReplicatedObjectTransmissionRecord
                {
                    StateMask = r.StateMask,
                    Status    = r.Status,
                    RepRecord = r // not loving this
                };

                // This is the easiest way I could think of to reference the latest transmission
                if (r.LastTransmission != null)
                {
                    r.LastTransmission.NextTransmission = tr;
                }
                r.LastTransmission = tr;

                transmission.Records.Add(tr);

                // Clear masks
                r.Status    = ReplicationRecord.ReplicationSystemStatus.None;
                r.StateMask = 0;
            }

            // Write 0 which isn't a valid id so the remote stream will know that's the end of the data
            stream.Put((ushort)0);

            _transmissions.Enqueue(transmission);
        }