internal void EnqueueOutgoingMessage(TimelineMessage message)
 {
     lock (_outgoingMessages)
     {
         _outgoingMessages.Enqueue(message);
     }
 }
        TimelineMessage CreateSetCachedMessageFromTemplate(TimelineMessage template, ushort remoteTimelineIndex)
        {
            byte[] cacheBytes = new byte[template.Data.Length];

            Buffer.BlockCopy(BitConverter.GetBytes(remoteTimelineIndex), 0, cacheBytes, 0, sizeof(ushort));
            Buffer.BlockCopy(template.Data, sizeof(ushort), cacheBytes, sizeof(ushort),
                             template.Data.Length - sizeof(ushort));

            TimelineMessage cacheMessage = new TimelineMessage(
                _relayToCacheMessageTypes[template.MessageType], cacheBytes, template.DeliveryMode);

            return(cacheMessage);
        }
Example #3
0
        public void OnNetworkReceive(NetPeer peer, NetDataReader reader)
        {
            try
            {
                var             type            = reader.GetByte();
                var             data            = reader.GetBytes();
                TimelineMessage timelineMessage = new TimelineMessage((TimelineMessageType)type, data);

                TimelineManager.Default.ProcessIncomingMessage(timelineMessage);
            }
            catch (Exception ex)
            {
                Console.WriteLine("[Client] Exception! " + ex.Message);
            }
        }
        /// <summary>
        /// Connect a peer to a timeline. For internal use only.
        /// </summary>
        /// <param name="peerInfo">The peer which wants to connect to a timeline.</param>
        /// <param name="remoteTimelineIndex">The index used by the peer to refer to the timeline.</param>
        /// <param name="timelineId">The unique ID of the timeline.</param>
        void ConnectPeerToTimeline(PeerInfo peerInfo, ushort remoteTimelineIndex, byte[] timelineId)
        {
            // Check if timeline exists first. If not, create it.
            TimelineInfo timelineInfo;

            if (_timelinesById.ContainsKey(timelineId))
            {
                timelineInfo = _timelinesById[timelineId];
                if (TimelineUpdated != null)
                {
                    TimelineUpdated(timelineInfo.ConnectedPeers.Count + 1, timelineId);
                }
            }
            else
            {
                timelineInfo    = new TimelineInfo();
                timelineInfo.ID = timelineId;
                _timelinesById.Add(timelineId, timelineInfo);

                if (TimelineCreated != null)
                {
                    TimelineCreated(timelineId);
                }
            }

            timelineInfo.ConnectedPeers[peerInfo]            = remoteTimelineIndex;
            peerInfo.ConnectedTimelines[remoteTimelineIndex] = timelineInfo;

            // Send cached messages if there are any

            foreach (TimelineMessage cachedMessage in timelineInfo.CachedEntries)
            {
                TimelineMessage relayMessage = CreateSetCachedMessageFromTemplate(
                    cachedMessage, remoteTimelineIndex);

                peerInfo.OutgoingMessages.Enqueue(relayMessage);
            }

            if (TimelineConnected != null)
            {
                TimelineConnected(peerInfo.Index, remoteTimelineIndex, timelineId);
            }
        }
        /// <summary>
        /// Connect a peer to the timeline synchronizer
        /// </summary>
        /// <param name="peerIndex">Index number for the peer that connected.</param>
        /// <param name="rtt">round trip time between the peer and the timeline synchronizer</param>
        public void ConnectPeer(ushort peerIndex, float rtt = 0f)
        {
            lock (_peerLock)
            {
                if (!_peersByIndex.ContainsKey(peerIndex))
                {
                    PeerInfo peerInfo = new PeerInfo()
                    {
                        Index = peerIndex,
                    };

                    _peersByIndex.Add(peerIndex, peerInfo);

                    // InitializePeer:
                    // 8 bytes - initial time
                    TimelineMessage initMessage = new TimelineMessage(
                        TimelineMessageType.InitializePeer, BitConverter.GetBytes(_now + rtt / 2));


                    peerInfo.OutgoingMessages.Enqueue(initMessage);

                    // do a quick ping

                    TimelineMessage pingMessage = new TimelineMessage(TimelineMessageType.ClockSyncPing,
                                                                      BitConverter.GetBytes(_now), DeliveryMode.Unreliable);

                    lock (_peerLock)
                    {
                        peerInfo.OutgoingMessages.Enqueue(pingMessage);
                    }

                    if (PeerConnected != null)
                    {
                        PeerConnected(peerIndex);
                    }
                }
            }
            return;
        }
        void PingPeers()
        {
            HashSet <PeerInfo> peerInfos;

            _pinging = true;

            lock (_peerLock)
            {
                peerInfos = new HashSet <PeerInfo>(_peersByIndex.Values);
            }

            foreach (PeerInfo peerInfo in peerInfos)
            {
                if (!_pinging)
                {
                    return;
                }

                /*if (peerInfo.Pinging)
                 *      continue;*/

                TimelineMessage pingMessage = new TimelineMessage(TimelineMessageType.ClockSyncPing,
                                                                  BitConverter.GetBytes(_now), DeliveryMode.Unreliable);

                lock (_peerLock)
                {
                    peerInfo.OutgoingMessages.Enqueue(pingMessage);
                    peerInfo.Pinging = true;
                }

                //Thread.Sleep(1);
            }

            _pinging    = false;
            _pingThread = null;
        }
Example #7
0
        public void OnNetworkReceive(NetPeer peer, NetDataReader reader)
        {
            //echo
            //peer.Send(reader.Data, SendOptions.ReliableUnordered);

            Console.WriteLine("[Server] NetworkReceive: ");

            try
            {
                ushort peerIndx = 0;
                foreach (var peerConection in TimelineServer._peerConnections)
                {
                    if (peerConection.Value.ConnectId == peer.ConnectId)
                    {
                        peerIndx = peerConection.Key;
                    }
                }

                var type = reader.GetByte();
                var data = reader.GetBytes();

                TimelineMessage timelineMessage = new TimelineMessage((TimelineMessageType)type, data);
                TimelineServer.TimelineSynchronizer.ProcessIncomingMessage(peerIndx, timelineMessage);
                TimelineManager.Default.ProcessIncomingMessage(timelineMessage);
            }
            catch (Exception ex)
            {
                Console.WriteLine("[Server] Exception! " + ex.Message);
            }

            //fragment log
            if (reader.AvailableBytes == 13218)
            {
                Console.WriteLine("[Server] TestFrag: {0}, {1}", reader.Data[0], reader.Data[13217]);
            }
        }
        /// <summary>
        /// Process incoming messages depending upon the message type
        /// </summary>
        public void ProcessIncomingMessage(TimelineMessage message)
        {
            if (message.MessageType == TimelineMessageType.SetAbsolute ||
                message.MessageType == TimelineMessageType.SetCachedAbsolute)
            {
                // message format:
                //     2 bytes (ushort) TimelineIndex
                //     8 bytes (double) time
                //     n bytes (byte[]) timelineData
                ushort timelineIndex = BitConverter.ToUInt16(message.Data, 0);

                lock (_timelineLock)
                {
                    if (_timelinesByIndex.ContainsKey(timelineIndex))
                    {
                        double time             = BitConverter.ToDouble(message.Data, sizeof(ushort));
                        int    valueBytesLength = message.Data.Length - sizeof(ushort) - sizeof(double);
                        byte[] valueBytes       = new byte[valueBytesLength];
                        Array.Copy(message.Data, sizeof(ushort) + sizeof(double), valueBytes, 0, valueBytesLength);

                        _timelinesByIndex[timelineIndex].RemoteSet(time, valueBytes, true,
                                                                   message.MessageType == TimelineMessageType.SetCachedAbsolute);
                    }
                }
            }
            else if (message.MessageType == TimelineMessageType.InitializePeer)
            {
                // message format:
                //     8 bytes (double) time

                // initial synchronizing of time to the synchronizer

                _now = BitConverter.ToDouble(message.Data, 0);

                lock (_timelineLock)
                {
                    foreach (var timeline in _timelinesByIndex.Values)
                    {
                        timeline._now = _now;
                    }
                }
            }
            else if (message.MessageType == TimelineMessageType.ClockSyncPing)
            {
                // message from synchronizer with current time on synchonizer
                // message format 8 bytes (double)
                // need to reply with synchronizer time and current local time (16 bytes)

                byte[]       data   = new byte[sizeof(double) + sizeof(double)];
                BinaryWriter writer = new BinaryWriter(new MemoryStream(data));
                writer.Write(message._data);
                writer.Write(_now - _timeOffset);
                writer.Close();

                EnqueueOutgoingMessage(new TimelineMessage(
                                           TimelineMessageType.ClockSyncPong, data, DeliveryMode.Unreliable));
            }
            else if (message.MessageType == TimelineMessageType.ClockSyncCorrection)
            {
                // message from synchronizer with adjustment to current time
                // message format 4 bytes (float)
                _targetOffset = BitConverter.ToSingle(message.Data, 0);
            }
        }
        /// <summary>
        /// Process a message from one of the peers
        /// </summary>
        /// <param name="peerIndex">Index number for the peer.</param>
        /// <param name="message">The message to be processed.</param>
        public void ProcessIncomingMessage(ushort peerIndex, TimelineMessage message)
        {
            lock (_peerLock)
            {
                lock (_timelineLock)
                {
                    PeerInfo peerInfo = null;

                    if (!_peersByIndex.TryGetValue(peerIndex, out peerInfo))
                    {
                        return;
                    }

                    peerInfo.BytesToTLS += message.Data.Length;

                    // Be sure to arrange the message types in descending order of frequency.
                    // For example, sets are most frequent, so they are checked first.

                    if (message.MessageType == TimelineMessageType.RelayAbsolute)
                    {
                        BinaryReader reader = new BinaryReader(new MemoryStream(message.Data));
                        // We only need to read the timeline index, since we are only relaying, not receiving.
                        ushort timelineIndex = reader.ReadUInt16();
                        reader.Close();

                        // Get the timeline this message was intended for.
                        TimelineInfo timelineInfo = null;

                        if (!peerInfo.ConnectedTimelines.TryGetValue(timelineIndex, out timelineInfo))
                        {
                            return;
                        }

                        // Add message to cache queue
                        timelineInfo.CachedEntries.Add(message);

                        if (TimelineSet != null)
                        {
                            TimelineSet(timelineIndex, timelineInfo.ID);
                        }

                        while (timelineInfo.CachedEntries.Count > timelineInfo.EntryCacheSize)
                        {
                            timelineInfo.CachedEntries.RemoveAt(0);
                        }

                        // Loop through all the subscribers except for the sender...
                        foreach (var otherPeer in timelineInfo.ConnectedPeers)
                        {
                            if (peerInfo == otherPeer.Key)
                            {
                                continue;
                            }

                            // Create a new message to relay.
                            TimelineMessage relayMessage = CreateRelayMessageFromTemplate(message, otherPeer.Value);
                            otherPeer.Key.OutgoingMessages.Enqueue(relayMessage);
                        }
                    }
                    else if (message.MessageType == TimelineMessageType.ClockSyncPong)
                    {
                        BinaryReader reader         = new BinaryReader(new MemoryStream(message.Data));
                        double       localPingTime  = reader.ReadDouble();
                        double       remotePongTime = reader.ReadDouble();
                        double       localPongTime  = (localPingTime + _now) / 2;
                        reader.Close();

                        ClockSyncData newData = new ClockSyncData()
                        {
                            RTT    = (float)(_now - localPingTime),
                            Offset = (float)(localPongTime - remotePongTime)
                        };

                        AddClockSyncData(peerInfo, newData);
                        float correction = GetClockSyncCorrection(peerInfo);

                        TimelineMessage correctionMessage = new TimelineMessage(TimelineMessageType.ClockSyncCorrection,
                                                                                BitConverter.GetBytes(correction), DeliveryMode.Unreliable);

                        peerInfo.OutgoingMessages.Enqueue(correctionMessage);
                        peerInfo.Pinging = false;
                    }
                    else if (message.MessageType == TimelineMessageType.ConnectTimeline)
                    {
                        // Message format:
                        // 2 bytes (ushort) remote timeline index
                        // byte array (byte[]) timeline id

                        BinaryReader reader = new BinaryReader(new MemoryStream(message.Data));
                        ushort       remoteTimelineIndex = reader.ReadUInt16();
                        byte[]       timelineId          = reader.ReadBytes(message.Data.Length - sizeof(ushort));
                        reader.Close();

                        ConnectPeerToTimeline(peerInfo, remoteTimelineIndex, timelineId);
                    }
                    else if (message.MessageType == TimelineMessageType.DisconnectTimeline)
                    {
                        // Call disconnect method
                        BinaryReader reader = new BinaryReader(new MemoryStream(message.Data));
                        ushort       remoteTimelineIndex = reader.ReadUInt16();
                        reader.Close();

                        TimelineInfo timelineInfo;

                        if (peerInfo.ConnectedTimelines.TryGetValue(remoteTimelineIndex, out timelineInfo))
                        {
                            DisconnectPeerFromTimeline(peerInfo, timelineInfo);
                        }
                    }
                    else if (message.MessageType == TimelineMessageType.CacheSize)
                    {
                        BinaryReader reader = new BinaryReader(new MemoryStream(message.Data));
                        ushort       remoteTimelineIndex = reader.ReadUInt16();
                        ushort       cacheSize           = reader.ReadUInt16();
                        reader.Close();

                        TimelineInfo timelineInfo;

                        if (peerInfo.ConnectedTimelines.TryGetValue(remoteTimelineIndex, out timelineInfo))
                        {
                            timelineInfo.EntryCacheSize = cacheSize;

                            while (timelineInfo.CachedEntries.Count > cacheSize)
                            {
                                timelineInfo.CachedEntries.RemoveAt(0);
                            }
                        }
                    }
                }
            }
        }