public void Read(NetPacketReader reader, int frame, bool discardOutOfOrderPackets) { NetDebug.Log($"Receiving packet with remote frame <b>{frame}</b> at local frame <b>{world.Frame}</b>", LogType.Packet); if (!arbiter) { world.Frame = frame; int inputLength = reader.GetInt(); int statefulsLength = reader.GetInt(); int fieldsLength = reader.GetInt(); ReadInput(reader, inputLength); ReadStateful(reader, statefulsLength, frame, discardOutOfOrderPackets); ReadFields(reader, fieldsLength, frame, discardOutOfOrderPackets); } else { int inputLength = reader.GetInt(); ReadInput(reader, inputLength); } if (!reader.EndOfData) { NetDebug.LogError($"ReadState method did not read all bytes from the NetPacketReader; it is intended to always consume all bytes, regardless of whether the data is applied to the StatefulWorld."); } }
protected override void OnReceiveNonStatePacket(PacketType packetType, NetPeer peer, NetPacketReader reader, DeliveryMethod deliveryMethod) { base.OnReceiveNonStatePacket(packetType, peer, reader, deliveryMethod); if (packetType == PacketType.Join) { jitterBuffersByPeerId[peer.Id + 1] = new JitterBuffer(settings.JitterBufferDelayFrames); int remoteID = reader.GetInt(); int frame = reader.GetInt(); StatefulWorld.Instance.Frame = frame; NetDebug.Log($"Local client assigned id <b>{remoteID}</b>", LogType.Connection); } else if (packetType == PacketType.Ownership) { int id = reader.GetInt(); if (role == Role.ListenClient) { StatefulWorld.Instance.statefulObjects[id].GetComponent <IInputController>().SetEnabled(true, true); } else { Remote.ClaimOwnership(id); } NetDebug.Log($"Local client assigned ownership of object id <b>{id}</b>", LogType.Ownership); } }
public IEnumerable <Packet> StepBuffer() { DecrementBufferFrames(); outputPackets.Clear(); // If the buffer is too large, it is better to flush multiple packets all at once // to catch up to the sender. This will cause popping, but is preferable to perpetually // lagging behind. // If this is happening too frequently, the buffer delayFrames should be increased. while (buffer.Count > delayFrames) { Packet output = buffer[buffer.Count - 1]; outputPackets.Add(output); NetDebug.Log($"Buffer is size {buffer.Count}; <b><color=orange>Flushing</color></b> packet with remote frame <b>{output.StatePacket.Frame}</b>. " + $"<i>(Buffer is now size {buffer.Count - 1}.)</i>", LogType.JitterBuffer); buffer.RemoveAt(buffer.Count - 1); DecrementBufferFrames(); } if (buffer.Count > 0 && buffer[buffer.Count - 1].BufferFramesRemaining <= 0) { Packet output = buffer[buffer.Count - 1]; outputPackets.Add(output); buffer.RemoveAt(buffer.Count - 1); NetDebug.Log($"<b><color=cyan>Removing</color></b> packet with remote frame <b>{output.StatePacket.Frame}</b> from jitter buffer. " + $"<i>(Buffer is now size {buffer.Count}.)</i>", LogType.JitterBuffer); } return(outputPackets); }
public void Insert(Peer.StatePacket statePacket) { Packet packet = new Packet() { StatePacket = statePacket, BufferFramesRemaining = buffer.Count > 0 ? buffer[0].BufferFramesRemaining + 1 : delayFrames }; // Iterate through the buffer to determine where the new packet should be placed. for (int i = 0; i < buffer.Count + 1; i++) { // If the packet has arrived in order with respect to all elements in the buffer, its // remote frame should be larger than all other elements in the buffer, and it will // be inserted at the front of the buffer. if (i == buffer.Count || packet.StatePacket.Frame > buffer[i].StatePacket.Frame) { buffer.Insert(i, packet); break; } // If the packet arrived out of order with respect to the next packet in the buffer, // swap arrival frames with the next packet. This allows the buffer to more accurately represent // the cadence that the packets were sent. else { int tempArrivalFrame = packet.BufferFramesRemaining; packet.BufferFramesRemaining = buffer[i].BufferFramesRemaining; buffer[i].BufferFramesRemaining = tempArrivalFrame; } } NetDebug.Log($"<color=yellow><b>Inserting</b></color> packet with remote frame <b>{packet.StatePacket.Frame}</b> into jitter buffer. " + $"<i>(Buffer is now size {buffer.Count}.)</i>", LogType.JitterBuffer); }
private void Listener_PeerDisconnectedEvent(NetPeer peer, DisconnectInfo disconnectInfo) { int id = peer.Id + 1; jitterBuffersByPeerId.Remove(id); NetDebug.Log($"Peer index <b>{peer.Id}</b> global ID {id} disconnected. Reason: {disconnectInfo.Reason}", LogType.Connection); OnPeerDisconnected?.Invoke(id); }
public void WriteStateFields(NetDataWriter writer, bool writeEvenIfNotDirty = false) { bool objectHeaderWritten, behaviourHeaderWritten; objectHeaderWritten = false; for (int i = 0; i < stateFieldsByMonoBehaviour.Count; i++) { behaviourHeaderWritten = false; var kvp = stateFieldsByMonoBehaviour[i]; for (int j = 0; j < kvp.Value.Count; j++) { PropertyInfo info = kvp.Value[j]; IStateField field = (IStateField)info.GetValue(kvp.Key); if (field.IsDirty || writeEvenIfNotDirty) { // If this is the first field written for this object, // we need to write in this object's ID. if (!objectHeaderWritten) { writer.Put((byte)DataType.Object); writer.Put(ID); writer.Put(Identity.GUID); objectHeaderWritten = true; } // Same as above, but per-behaviour. if (!behaviourHeaderWritten) { writer.Put((byte)DataType.Behaviour); writer.Put(i); behaviourHeaderWritten = true; } writer.Put((byte)DataType.Field); writer.Put(j); field.Write(writer); field.IsDirty = false; NetDebug.Log($"Writing IStateField <b>{info.Name}</b>.", ID, LogType.Property); } } } }
private void Listener_PeerConnectedEvent(NetPeer peer) { int id = peer.Id + 1; jitterBuffersByPeerId[id] = new JitterBuffer(settings.JitterBufferDelayFrames); NetDataWriter writer = new NetDataWriter(); writer.Put((byte)PacketType.Join); writer.Put(id); writer.Put(StatefulWorld.Instance.Frame); peer.Send(writer, DeliveryMethod.ReliableOrdered); writer.Reset(); Remote.SynchronizeAll(); NetDebug.Log($"Peer index <b>{peer.Id}</b> connected. Assigned global ID {id}.", LogType.Connection); OnPeerConnected?.Invoke(id); }
private void Listener_ConnectionRequestEvent(ConnectionRequest request) { request.Accept(); NetDebug.Log($"Connection requested", LogType.Connection); }