/// <summary>
    /// walks through the message queue and packs the messages together and sends them off.
    /// later we can add priority filtering to the messages we add to the message queue, as it's just sorting the queued messages in some way.
    /// any messages that don't fit in this packet we leave until next time around (and increase their priority)
    /// maybe we should keep two message queues, one for entity updates or something
    /// </summary>
    public void NetworkSend()
    {
        //Debug.Log("NetworkSend");
        UnityEngine.Profiling.Profiler.BeginSample("Network Send");
        foreach (SteamConnection sc in connections.Values)
        {
            if (sc.messageQueue.Count > 0)
            {
                //pack
                writeStream.Reset(packetSize);

                //grab the first message
                //check if it can fit in the stream
                //if it can, remove it from the queue and write it
                //continue until writeStream can't fit any other messages
                //or until the message queue is empty

                //we should loop through all the messages and calculate their priority.
                //store this message list in a new list, and sort it by priority (or maybe just sort the queue, since we don't really need the original order?

                for (int i = 0; i < sc.messageQueue.Count; i++)
                {
                    NetworkMessage m = sc.messageQueue[i];
                    if (MessagePriorityCalculators[m.msgCode] != null)
                    {
                        if (m.isEntityMsg)
                        {
                            if (m.entity == null)
                            {
                                m.priority = 0; //can't send this because our entity is GONE
                            }
                            else
                            {
                                m.priority = m.entity.Priority(sc.steamID);
                            }
                        }
                        else
                        {
                            //normal message
                            m.priority = MessagePriorityCalculators[m.msgCode](sc.steamID, m.args);
                        }
                    }
                    else
                    {
                        m.priority = 1f; //default priority for normal messages.  These will send *eventually* whenever there is space
                    }
                }

                //sort it by priority, with higher priority values first, lower last.
                sc.messageQueue = sc.messageQueue.OrderByDescending(p => p.priority + p.skipped).ToList();

                for (int i = 0; i < sc.messageQueue.Count; i++)
                {
                    //Debug.Log("queue count: " + sc.messageQueue.Count);
                    //Debug.Log("message: " + i);

                    NetworkMessage m = sc.messageQueue[i];
                    if (!writeStream.CanWrite())
                    {
                        m.skipped++;
                        //Debug.Log("!writeStream.CanWrite()");
                        continue; //continue because we need to mark the rest of the messages as skipped.
                        //break; //ZERO room left m
                    }
                    else
                    {
                        if (m.priority == 0f)            //if the message has a priority of 0 we dont want to send the message
                        {
                            sc.messageQueue.RemoveAt(i); //this will happen when we queue something to everyone, but
                            i--;                         //some players are too far away to care about the message (in a different map, etc)
                            continue;                    //so it just gets discarded.
                            //what happens if we discard a spawn request, and then move into the area
                            //the object should be in, and start receiving state updates from that spawn???
                            //maybe NEVER remove a spawn request (even with priority 0?)
                            //add it to a list and just buffer the message until we get into the area?
                            //that could work...
                        }

                        //get the total message size to check if it will fit
                        int msgSize = 8;                       //8 bits for the msgCode included before the data
                        if (MessagePeekers[m.msgCode] != null) //if it's null we don't have any data to send, just the msgCode (like for a keep alive)
                        {
                            msgSize += Core.net.MessagePeekers[m.msgCode](m.args);

                            if (IsEntityMsg(m.msgCode))
                            {
                                msgSize += m.entity.Peek(); //entity state msgSize
                                //Debug.Log("msgSize: ["+m.msgCode+"]: " + msgSize);
                            }
                        }
                        //Debug.Log("CanWrite: " + msgSize + " : " + writeStream.CanWrite(msgSize));
                        if (writeStream.CanWrite(msgSize))                            //will it fit?
                        {
                            SerializerUtils.WriteInt(writeStream, m.msgCode, 0, 255); //write the msgCode
                            if (MessageSerializers[m.msgCode] != null)
                            {
                                Core.net.MessageSerializers[m.msgCode](sc.steamID, writeStream, m.args); //write the rest of the data

                                if (IsEntityMsg(m.msgCode))
                                {
                                    m.entity.Serialize(writeStream);
                                }
                            }
                            //Debug.Log("Wrote: " + msgSize + " : new bit position: " + writeStream.Position);
                            //remove this message from the list.
                            sc.messageQueue.RemoveAt(i);
                            i--;
                        }
                        else
                        {
                            m.skipped++;
                            //Debug.Log("trying next message, can't fit..");
                            continue; //try the next message I guess? until the packet is full or we run out
                        }
                    }
                }

                //try and add a "StreamEmpty" message at the end if it fits
                //"there are no more messages" message. Stop trying to read any data after.
                //this isn't actually necessary, because since our Empty code is 00000000, and junk data after is 00000000
                //it picks up the empty automagically.  Since when we grab the message code, if it's junk data it's the empty msgCode!
                //if(writeStream.CanWrite() && writeStream.CanWrite(8)) {
                //    SerializerUtils.WriteInt(writeStream, GetMessageCode("Empty"), 0, 255);
                //}

                SendP2PData(sc.steamID, writeStream.Data, writeStream.Position, Networking.SendType.Reliable, 0);
                //send it!
            }
        }
        UnityEngine.Profiling.Profiler.EndSample();
    }
예제 #2
0
    /// <summary>
    /// walks through the message queue and packs the messages together and sends them off.
    /// later we can add priority filtering to the messages we add to the message queue, as it's just sorting the queued messages in some way.
    /// any messages that don't fit in this packet we leave until next time around (and increase their priority)
    /// maybe we should keep two message queues, one for entity updates or something
    /// </summary>
    public void NetworkSend()
    {
        //Debug.Log("NetworkSend");
        UnityEngine.Profiling.Profiler.BeginSample("Network Send");



        if (NetworkSendEvent != null)
        {
            NetworkSendEvent();
        }

        foreach (SteamConnection sc in connections.Values)
        {
            //walk the entities and say "hey, we're sending this frame" so we can update the state?
            //or, let entities subscribe to an event?  Wonder how much faster it would be vs walking the entire entity list.
            //if we had 4096 entites (max) things would break down anyways.  Probably don't want to just
            //add state update messages willy-nilly.  Should check priority or somethings?

            if (sc.messageQueue.Count > 0)
            {
                //pack
                writeStream.Reset(packetSize);

                //grab the first message
                //check if it can fit in the stream
                //if it can, remove it from the queue and write it
                //continue until writeStream can't fit any other messages
                //or until the message queue is empty

                //we should loop through all the messages and calculate their priority.
                //store this message list in a new list, and sort it by priority (or maybe just sort the queue, since we don't really need the original order?

                for (int i = 0; i < sc.messageQueue.Count; i++)
                {
                    NetworkMessage m = sc.messageQueue[i];
                    if (MessagePriorityCalculators[m.msgCode] != null)
                    {
                        if (m.isEntityMsg)
                        {
                            if (m.entity == null)
                            {
                                m.priority = 0; //can't send this because our entity is GONE
                            }
                            else
                            {
                                //this checks the priority to whoever we are sending to
                                //via distance check around their player
                                //what if the entity we want to send is too far away from US for us to care about the entity
                                //anymore and we want to destroy it locally?
                                //do we do a separate check somewhere for that too?
                                m.priority = m.entity.PriorityCaller(sc.steamID, true);
                            }
                        }
                        else
                        {
                            //normal message
                            m.priority = MessagePriorityCalculators[m.msgCode](sc.steamID, m.args);
                        }
                    }
                    else
                    {
                        m.priority = 1f; //default priority for normal messages.  These will send *eventually* whenever there is space
                    }
                }

                //sort it by priority, with higher priority values first, lower last.
                sc.messageQueue = sc.messageQueue.OrderByDescending(p => p.priority + p.skipped).ToList();
                for (int i = 0; i < sc.messageQueue.Count; i++)
                {
                    //Debug.Log("queue count: " + sc.messageQueue.Count);
                    //Debug.Log("message: " + i);

                    NetworkMessage m = sc.messageQueue[i];
                    if (!writeStream.CanWrite())
                    {
                        m.skipped++;
                        //Debug.Log("!writeStream.CanWrite()");
                        continue; //continue because we need to mark the rest of the messages as skipped.
                        //break; //ZERO room left m
                    }
                    else
                    {
                        if (m.priority == 0f)
                        {
                            if (m.isEntityMsg)
                            {
                                m.entity.queuedMessage[sc.steamID] = null;
                            }

                            //if the message has a priority of 0 we dont want to send the message
                            sc.messageQueue.RemoveAt(i); //this will happen when we queue something to everyone, but
                            i--;                         //some players are too far away to care about the message (in a different map, etc)
                            continue;                    //so it just gets discarded.
                            //what happens if we discard a spawn request, and then move into the area
                            //the object should be in, and start receiving state updates from that spawn???
                            //maybe NEVER remove a spawn request (even with priority 0?)
                            //add it to a list and just buffer the message until we get into the area?
                            //that could work...
                        }

                        //get the total message size to check if it will fit
                        int msgSize = SerializerUtils.RequiredBitsInt(0, maxMessageTypes); //8 bits for the msgCode included before the data
                        if (MessagePeekers[m.msgCode] != null)                             //if it's null we don't have any data to send, just the msgCode (like for a keep alive)
                        {
                            msgSize += Core.net.MessagePeekers[m.msgCode](m.args);

                            if (m.msgCode == GetMessageCode("EntityUpdate"))
                            {
                                int entityDataSize = m.entity.Peek();
                                msgSize += entityDataSize; //entity state msgSize
                                //Debug.Log("msgSize: ["+m.msgCode+"]: " + msgSize);
                                //if size is zero, we should just NOT send the message
                                if (entityDataSize == 0)
                                {
                                    //just don't send it, no point wasting 8 bits with an empty message code.
                                    //Debug.Log("removed");
                                    m.entity.queuedMessage[sc.steamID] = null;
                                    sc.messageQueue.RemoveAt(i);
                                    i--;
                                    continue;
                                }
                            }
                        }
                        //Debug.Log("CanWrite: " + msgSize + " : " + writeStream.CanWrite(msgSize));
                        if (writeStream.CanWrite(msgSize))  //will it fit?
                        //Debug.Log("write message");
                        {
                            SerializerUtils.WriteInt(writeStream, m.msgCode, 0, maxMessageTypes); //write the msgCode
                            if (MessageSerializers[m.msgCode] != null)
                            {
                                Core.net.MessageSerializers[m.msgCode](sc.steamID, writeStream, m.args); //write the rest of the data

                                if (m.msgCode == GetMessageCode("EntityUpdate"))
                                {
                                    m.entity.queuedMessage[sc.steamID] = null; //clear this so they can queue the next message
                                    m.entity.Serialize(writeStream);
                                }
                                else if (m.msgCode == GetMessageCode("EntityDestroy"))
                                {
                                    m.entity.queuedMessage[sc.steamID] = null;
                                    m.entity.TryDestroyInternal(); //we can only destroy the entity after the message has been sent.
                                                                   //If we try to destroy it earlier, the entity is already null when trying to send and things fail
                                }
                            }
                            //Debug.Log("Wrote: " + msgSize + " : new bit position: " + writeStream.Position);
                            //remove this message from the list.
                            sc.messageQueue.RemoveAt(i);
                            i--;
                            continue;
                        }
                        else
                        {
                            m.skipped++;
                            //Debug.Log("trying next message, can't fit..");
                            continue; //try the next message I guess? until the packet is full or we run out
                        }
                    }
                }

                //try and add a "StreamEmpty" message at the end if it fits
                //"there are no more messages" message. Stop trying to read any data after.
                //this isn't actually necessary, because since our Empty code is 00000000, and junk data after is 00000000
                //it picks up the empty automagically.  Since when we grab the message code, if it's junk data it's the empty msgCode!
                //if(writeStream.CanWrite() && writeStream.CanWrite(8)) {
                //    SerializerUtils.WriteInt(writeStream, GetMessageCode("Empty"), 0, 255);
                //}

                SendP2PData(sc.steamID, writeStream.Data, writeStream.Position, Networking.SendType.Reliable, 0);
                //send it!
            }
        }
        UnityEngine.Profiling.Profiler.EndSample();
    }