khanat-opennel-code/code/nel/samples/net/udp/simlag.cpp

201 lines
4.4 KiB
C++

// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// Includes
//
#include <string>
#include <queue>
#include <nel/misc/types_nl.h>
#include <nel/misc/debug.h>
#include <nel/net/udp_sock.h>
//
// Using
//
using namespace std;
using namespace NLMISC;
using namespace NLNET;
//
// Variables
//
static uint32 Lag = 0;
static uint8 PacketLoss = 0;
static uint8 PacketDuplication = 0;
static uint8 PacketDisordering = 0;
//
// Class
//
struct CBufferizedPacket
{
CBufferizedPacket (CUdpSock *client, const uint8 *packet, uint32 packetSize, uint32 delay, const CInetAddress *addr):
Client(client), PacketSize(packetSize), Time(CTime::getLocalTime()+delay)
{
nlassert (packetSize > 0);
nlassert (packet != NULL);
nlassert (client != NULL);
Packet = new uint8[packetSize];
memcpy (Packet, packet, packetSize);
if (addr != NULL)
{
Addr = new CInetAddress;
*Addr = *addr;
}
else
{
Addr = NULL;
}
}
~CBufferizedPacket ()
{
nlassert (Packet != NULL);
delete [] Packet;
Packet = NULL;
Client = NULL;
PacketSize = 0;
Time = 0;
if (Addr != NULL)
delete Addr;
}
CUdpSock *Client;
uint8 *Packet;
uint32 PacketSize;
TTime Time;
CInetAddress *Addr;
};
//
// Variables
//
static queue<CBufferizedPacket*> BufferizedPackets;
//
// Prototypes
//
void sendUDPNow (CUdpSock *client, const uint8 *packet, uint32 packetSize, const CInetAddress *addr);
//
// Functions
//
void updateBufferizedPackets ()
{
TTime ct = CTime::getLocalTime ();
while (!BufferizedPackets.empty())
{
CBufferizedPacket *bp = BufferizedPackets.front ();
if (bp->Time <= ct)
{
// time to send the message
sendUDPNow (bp->Client, bp->Packet, bp->PacketSize, bp->Addr);
delete bp;
BufferizedPackets.pop ();
}
else
{
break;
}
}
}
void setSimlagValues (sint32 lag, sint8 packetLoss, sint8 packetDuplication, sint8 packetDisordering)
{
if (lag != -1) Lag = lag;
if (packetLoss != -1) PacketLoss = packetLoss;
if (packetDuplication != -1) PacketDuplication = packetDuplication;
if (packetDisordering != -1) PacketDisordering = packetDisordering;
}
void sendUDPNow (CUdpSock *client, const uint8 *packet, uint32 packetSize, const CInetAddress *addr)
{
if (addr == NULL)
client->send (packet, packetSize);
else
client->sendTo (packet, packetSize, *addr);
uint32 packetNumber = *(uint32 *)packet;
// nlinfo ("time %"NL_I64"u sending now packet %5u", CTime::getLocalTime (), packetNumber);
}
void sendUDP (CUdpSock *client, const uint8 *packet, uint32 packetSize, const CInetAddress *addr)
{
nlassert (client != NULL);
nlassert (packet != NULL);
nlassert (packetSize > 0);
if ((float)rand()/(float)(RAND_MAX)*100.0f >= PacketLoss)
{
sint32 lag = Lag /*+ (rand()%40) - 20*/;// void disordering
if (lag > 100)
{
// send the packet later
CBufferizedPacket *bp = new CBufferizedPacket (client, packet, packetSize, lag, addr);
// duplicate the packet
if ((float)rand()/(float)(RAND_MAX)*100.0f < PacketDisordering && BufferizedPackets.size() > 0)
{
CBufferizedPacket *bp2 = BufferizedPackets.back();
// exange the time
TTime t = bp->Time;
bp->Time = bp2->Time;
bp2->Time = t;
// exange packet in the buffer
BufferizedPackets.back() = bp;
bp = bp2;
}
BufferizedPackets.push (bp);
// duplicate the packet
if ((float)rand()/(float)(RAND_MAX)*100.0f < PacketDuplication)
{
CBufferizedPacket *bp = new CBufferizedPacket (client, packet, packetSize, lag, addr);
BufferizedPackets.push (bp);
}
}
else
{
// send the packet NOW
sendUDPNow (client, packet, packetSize, addr);
// duplicate the packet
if ((float)rand()/(float)(RAND_MAX)*100.0f < PacketDuplication)
{
sendUDPNow (client, packet, packetSize, addr);
}
}
}
}