/// <summary> /// Deserializes a packet from the given buffer. Returns the amount of bytes consumed. /// </summary> private int DeserializePacket(IntPtr buffer) { PacketHeader packetHeader = (PacketHeader)Marshal.PtrToStructure(buffer, typeof(PacketHeader)); //Get the type for the packet sitting in the receive buffer Type packetType = PacketMap.GetTypeForPacketCode(packetHeader.OpCode); //If we can deserialize it... if (packetType != null) { try { //Block copy the buffer to a struct of the correct type IPacketBase packet = (IPacketBase)Marshal.PtrToStructure(buffer, packetType); //Throw the strongly-typed packet into the incoming queue m_incomingQueue.Enqueue(packet); return(packet.Header.SizeInBytes); } catch (Exception ex) { Console.Write("Deserialization error! " + ex); } } else { Console.WriteLine("Bad packet code: " + packetHeader.OpCode); } return(0); }
/// <summary> /// Updates this entity, flushes and handles any pending packets in the incoming queue. /// </summary> public void Update(TimeSpan dt) { //Handle all packets in the incoming queue IPacketBase packet = null; while (m_incomingQueue.TryDequeue(out packet)) { HandlePacket(packet); } //Send any packets that have been deferred foreach (CoalescedData p in m_deferredSendList) { SendPacket(p); } m_deferredSendList.Clear(); if (m_currentDeferredPacket.PacketCount > 0) { SendPacket(m_currentDeferredPacket); } //Reset the current deferred packet for next update m_currentDeferredPacket = PacketFactory.CreatePacket <CoalescedData>(); //Warn if any of the queues are getting swamped if (m_outgoingQueue.Count > 25) { Console.WriteLine("Outgoing queue swamped: " + m_outgoingQueue.Count); } if (m_incomingQueue.Count > 25) { Console.WriteLine("Incoming queue swamped: " + m_incomingQueue.Count); } }
/// <summary> /// Incoming packets are pushed here for handling. /// </summary> protected unsafe override void HandlePacket(IPacketBase packet) { base.HandlePacket(packet); //Update state from the client if (packet is PushState) { var state = (PushState)packet; //Push their state if it's the correct world ID if (state.WorldID == WorldID) { LastState = state.State; } } //Move the user in to a new zone else if (packet is RequestZoneTransfer) { var request = (RequestZoneTransfer)packet; mWorld.ZoneManager.RequestZoneTransfer(this, request.ZoneID); } //Resolve names else if (packet is WhoisRequest) { var request = (WhoisRequest)packet; var response = PacketFactory.CreatePacket <WhoisResponse>(); response.WorldID = request.WorldID; var name = mWorld.GetNameForWorldID(request.WorldID); TextHelpers.StringToBuffer(name, response.Name, name.Length); DeferredSendPacket(response); } }
/// <summary> /// Incoming packets are pushed here for handling. /// </summary> protected unsafe override void HandlePacket(IPacketBase packet) { base.HandlePacket(packet); //Update state from the client if (packet is PushState) { PushState state = (PushState)packet; //Push their state if it's the correct world ID if (state.WorldID == WorldID) { LastState = state.State; } } //Move the user in to a new zone else if (packet is RequestZoneTransfer) { RequestZoneTransfer request = (RequestZoneTransfer)packet; m_world.ZoneManager.RequestZoneTransfer(this, request.ZoneID); } //Resolve names else if (packet is WhoisRequest) { WhoisRequest request = (WhoisRequest)packet; WhoisResponse response = PacketFactory.CreatePacket<WhoisResponse>(); response.WorldID = request.WorldID; string name = m_world.GetNameForWorldID(request.WorldID); TextHelpers.StringToBuffer(name, response.Name, name.Length); DeferredSendPacket(response); } }
/// <summary> /// Serialize the given packet into the send buffer. /// </summary> protected void SerializePacket(IPacketBase packet) { try { Marshal.StructureToPtr(packet, mSendBufferPtr, false); } catch (Exception ex) { Console.WriteLine("Serialization error! " + ex); } }
/// <summary> /// Packet handler logic /// </summary> protected virtual void HandlePacket(IPacketBase packet) { //Send auth responses for an auth request if (packet is AuthRequest) { AuthResponse response = PacketFactory.CreatePacket <AuthResponse>(); //Tell them their world ID response.WorldID = WorldID; DeferredSendPacket(response); AuthState = EntityAuthState.Authorised; } //Update auth state and world ID else if (packet is AuthResponse) { AuthResponse response = (AuthResponse)packet; WorldID = response.WorldID; AuthState = EntityAuthState.Authorised; } //Unpack coalesced packets else if (packet is CoalescedData) { CoalescedData data = (CoalescedData)packet; unsafe { byte *ptr = data.DataBuffer; //Start deserializing packets from the buffer for (int i = 0; i < data.PacketCount; i++) { //Deserialize and advance pointer to next packet in the buffer ptr += DeserializePacket((IntPtr)ptr); } } } //Synchronise clocks else if (packet is ClockSyncResponse) { ClockSyncResponse response = (ClockSyncResponse)packet; int rtt = Environment.TickCount - m_clockSyncSendTime; m_roundTripTimes.Enqueue(rtt); if (m_roundTripTimes.Count > 10) { m_roundTripTimes.Dequeue(); } SyncClock(response.Time); m_awaitingClockSyncResponse = false; } else if (packet is ClockSyncRequest) { ClockSyncResponse response = PacketFactory.CreatePacket <ClockSyncResponse>(); response.Time = Environment.TickCount; SendPacket(response); } }
/// <summary> /// Queues a packet to be send on the next update. Will coalesce these packets together. /// </summary> public void DeferredSendPacket(IPacketBase packet) { if (!mCurrentDeferredPacket.TryAddPacket(packet)) { mDeferredSendList.Add(mCurrentDeferredPacket); mCurrentDeferredPacket = PacketFactory.CreatePacket <CoalescedData>(); mCurrentDeferredPacket.TryAddPacket(packet); } }
public bool Read( IPacketBase UnitPacket ) { // General Key if( false == UnitPacket.Read( out GeneralKey ) ) return false; // TODO: 로그인 성공했을 때 서버로부터 받는 키 값이 제대로 읽혀진 것인지 확인할 것 return true; }
public bool Write( IPacketBase UnitPacket ) { // General Key if( false == UnitPacket.Write( GeneralKey ) ) return false; // TODO: 로그인 성공했을 때 서버로부터 받는 키 값이 제대로 쓰여진 것인지 확인할 것 return true; }
/// <summary> /// Enqueue a packet for sending over the wire /// </summary> public void SendPacket(IPacketBase packet) { mOutgoingQueue.Enqueue(packet); //If we're not already sending, queue up a send on the task pool if (Interlocked.Read(ref mSending) == 0) { QueueSend(); } }
/// <summary> /// Incoming packets are pushed here for handling. /// </summary> protected unsafe override void HandlePacket(IPacketBase packet) { base.HandlePacket(packet); //Update state from the client if (packet is PushState) { var state = (PushState)packet; //Push their state if it's the correct world ID if (state.WorldID == WorldID) { LastState = state.State; } } }
/// <summary> /// Try to add a <paramref name="packet" /> into the buffer. Returns /// <see langword="true" /> if the <paramref name="packet" /> was /// successfully copied. /// </summary> public bool TryAddPacket(IPacketBase packet) { fixed (byte* buf = DataBuffer) { int packetSize = packet.Header.SizeInBytes; if (mUsedBytes + packetSize < BUFFER_SIZE) { //Copy packet into buffer Marshal.StructureToPtr(packet, (IntPtr)(buf + mUsedBytes), false); //Update used bytes and packet count mUsedBytes += (short)packetSize; mPacketCount++; //Update actual size mHeader.SizeInBytes = (short)(Marshal.SizeOf(this) - BUFFER_SIZE + mUsedBytes); return true; } } return false; }
/// <summary> /// Poll the outgoing queue and send any packets /// </summary> private void Send() { IPacketBase packet = null; //Grab a packet to send while (!m_outgoingQueue.TryDequeue(out packet)) { Thread.Sleep(0); } //Bail out if we lost connection if (!m_socket.Connected) { return; } //Serialize the packet into the send buffer SerializePacket(packet); try { //Send packet bytes over the wire m_sendArgs.SetBuffer(m_sendArgs.Offset, packet.Header.SizeInBytes); if (!m_socket.SendAsync(m_sendArgs)) { SendCompleted(m_socket, m_sendArgs); } } catch (SocketException) { //Client disconnect } catch (Exception ex) { Console.WriteLine("Send error! " + ex); } }
/// <summary> /// Try to add a packet into the buffer. Returns true if the packet was successfully copied. /// </summary> public bool TryAddPacket(IPacketBase packet) { fixed(byte *buf = DataBuffer) { int packetSize = packet.Header.SizeInBytes; if (m_usedBytes + packetSize < BUFFER_SIZE) { //Copy packet into buffer Marshal.StructureToPtr(packet, (IntPtr)(buf + m_usedBytes), false); //Update used bytes and packet count m_usedBytes += (short)packetSize; m_packetCount++; //Update actual size m_header.SizeInBytes = (short)(Marshal.SizeOf(this) - BUFFER_SIZE + m_usedBytes); return(true); } } return(false); }
/// <summary> /// Enqueue a packet for sending over the wire /// </summary> public void SendPacket(IPacketBase packet) { m_outgoingQueue.Enqueue(packet); //If we're not already sending, queue up a send on the task pool if (Interlocked.Read(ref sending) == 0) { QueueSend(); } }
public bool Read( IPacketBase UnitPacket ) { int Length = 0; char[] Temp = null; // ID UnitPacket.Read( out Length ); if( false == UnitPacket.Read( out Temp, Length ) ) return false; ID = new string( Temp ); Length = 0; Temp = null; // Password UnitPacket.Read( out Length ); if( false == UnitPacket.Read( out Temp, Length ) ) return false; Password = new string( Temp ); // TODO: ID, Password가 제대로 읽혀진 것인지 확인할 것 return true; }
public bool Write( IPacketBase UnitPacket ) { // ID if( false == UnitPacket.Write( ID.Length ) ) return false; if( false == UnitPacket.Write( ID.ToCharArray(), ID.Length ) ) return false; // Password if( false == UnitPacket.Write( Password.Length ) ) return false; if( false == UnitPacket.Write( Password.ToCharArray(), Password.Length ) ) return false; // TODO: ID, Password가 제대로 쓰여진 것인지 확인할 것 return true; }
/// <summary> /// Queues a packet to be send on the next update. Will coalesce these packets together. /// </summary> public void DeferredSendPacket(IPacketBase packet) { if (!m_currentDeferredPacket.TryAddPacket(packet)) { m_deferredSendList.Add(m_currentDeferredPacket); m_currentDeferredPacket = PacketFactory.CreatePacket<CoalescedData>(); m_currentDeferredPacket.TryAddPacket(packet); } }
/// <summary> /// Serialize the given packet into the send buffer. /// </summary> private void SerializePacket(IPacketBase packet) { try { Marshal.StructureToPtr(packet, m_sendBufferPtr, false); } catch (Exception ex) { Console.WriteLine("Serialization error! " + ex); } }
/// <summary> /// Packet handler logic /// </summary> protected virtual void HandlePacket(IPacketBase packet) { //Send auth responses for an auth request if (packet is AuthRequest) { AuthResponse response = PacketFactory.CreatePacket<AuthResponse>(); //Tell them their world ID response.WorldID = WorldID; DeferredSendPacket(response); AuthState = EntityAuthState.Authorised; } //Update auth state and world ID else if (packet is AuthResponse) { AuthResponse response = (AuthResponse)packet; WorldID = response.WorldID; AuthState = EntityAuthState.Authorised; } //Unpack coalesced packets else if (packet is CoalescedData) { CoalescedData data = (CoalescedData)packet; unsafe { byte* ptr = data.DataBuffer; //Start deserializing packets from the buffer for (int i = 0; i < data.PacketCount; i++) { //Deserialize and advance pointer to next packet in the buffer ptr += DeserializePacket((IntPtr)ptr); } } } //Synchronise clocks else if (packet is ClockSyncResponse) { ClockSyncResponse response = (ClockSyncResponse)packet; int rtt = Environment.TickCount - m_clockSyncSendTime; m_roundTripTimes.Enqueue(rtt); if (m_roundTripTimes.Count > 10) { m_roundTripTimes.Dequeue(); } SyncClock(response.Time); m_awaitingClockSyncResponse = false; } else if (packet is ClockSyncRequest) { ClockSyncResponse response = PacketFactory.CreatePacket<ClockSyncResponse>(); response.Time = Environment.TickCount; SendPacket(response); } }