// Ryzom - MMORPG Framework
// 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 .
#ifndef NL_IMPULSE_ENCODER_H
#define NL_IMPULSE_ENCODER_H
#include
#include
#include "nel/misc/types_nl.h"
#include "nel/misc/bit_mem_stream.h"
#include "nel/misc/debug.h"
#include "nel/misc/time_nl.h"
//#include "../common/action.h"
#include "game_share/action_factory.h"
extern bool verboseImpulsions;
#ifdef NL_RELEASE
#define LOG_IMPULSION_INFO ;
#define LOG_IMPULSION_DEBUG ;
#else
#define LOG_IMPULSION_INFO if (!verboseImpulsions) {} else nlinfo
#define LOG_IMPULSION_DEBUG if (!verboseImpulsions) {} else nldebug
#endif
class CClientHost;
namespace CLFECOMMON
{
class CAction;
}
typedef void (*TImpulseReceivedCallback)(CClientHost *, CLFECOMMON::CAction *);
// CActionFactory header + CActionGeneric header + 1/8 (the follow bit)
const sint IMPULSE_ACTION_HEADER_BITSIZE = 4*8 + 4*8 + 1;
extern uint MaxImpulseBitSizes [3];
class CClientImpulseStat
{
public:
};
const uint IMPULSE_STAT_MEAN_TIME = 30; // seconds
const double IMPULSE_STAT_SMOOTH = 2.0;
class CTimedSize
{
public:
CTimedSize() {}
CTimedSize(NLMISC::TTime t, uint32 s) : Time(t), Size(s) {}
NLMISC::TTime Time;
uint32 Size;
void serial(NLMISC::IStream& s);
};
typedef std::deque TSendRateQueue;
/**
* An Impulse Queue
* \author Benjamin Legros
* \author Nevrax France
* \date 2001
*/
class CImpulseQueue
{
public:
typedef std::deque TActionQueue;
TActionQueue Queue;
/// \name Stat Part
// @{
TSendRateQueue SendRateQueue;
uint64 SentData;
uint32 FlushTimes;
// @}
uint32 MaxBitSize;
uint TotalBitsInImpulseQueue;
uint FirstSent;
uint32 Level, Channel;
public:
CImpulseQueue() : TotalBitsInImpulseQueue(0), FirstSent(0), SentData(0), FlushTimes(0) {}
/// Destructor
~CImpulseQueue();
void setup(uint maxBitSize, uint level, uint channel) { MaxBitSize = maxBitSize; Level = level; Channel = channel; }
void add(CLFECOMMON::CActionImpulsion *action) { Queue.push_back(action); }
void flush(uint packet, CClientHost *client, std::vector &impcounts);
uint32 send(TActionQueue& sourceQueue, uint32 packet, NLMISC::CBitMemStream &outbox, uint32 &sentActions);
void reinit() { FirstSent = 0; }
void reset()
{
reinit();
uint i;
for (i=0; iremove(Queue[i]);
}
Queue.clear();
TotalBitsInImpulseQueue = 0;
SentData = 0;
}
void removeReferences(CLFECOMMON::TCLEntityId id)
{
TActionQueue::iterator it;
for (it=Queue.begin(); itSlot == id)
{
CLFECOMMON::CActionFactory::getInstance()->remove(*it);
it = Queue.erase(it);
}
else
{
++it;
}
}
/// \name Stat Part
// @{
/// Count next effective sent
void countEffectiveSent(uint bitSent)
{
NLMISC::TTime ctime = NLMISC::CTime::getLocalTime();
flushSendRateQueue(ctime);
if (bitSent == 0)
return;
//nlinfo("sent effectively %d bits in level %d, channel %d", bitSent, Level, Channel);
SendRateQueue.push_back(CTimedSize(ctime, bitSent));
SentData += bitSent;
}
/// Flush SendRateQueue
void flushSendRateQueue(NLMISC::TTime ctime)
{
while (!SendRateQueue.empty() && ctime > SendRateQueue.front().Time+(IMPULSE_STAT_MEAN_TIME*1000))
SendRateQueue.pop_front();
}
/// Get Current Effective Send Rate (based on flush rate) (in bits per second)
uint effectiveSendRate();
/// Total send data in this queue (based on flush rate) (in bits per second)
uint64 totalSentData();
/// Dump queue to xml stream
void dump(NLMISC::IStream& s);
// @}
};
/**
* The impulse encoder, used to post important actions the client must receive.
* \author Benjamin Legros
* \author Nevrax France
* \date 2001
*/
class CImpulseEncoder
{
private:
/*
* Warning: the numbers of queues by channels is hardcoded in the acknowledgement system
*/
CImpulseQueue _Level0[1];
CImpulseQueue _Level1[2];
CImpulseQueue _Level2[4];
CClientHost *_ClientHost;
//uint _MaxBitSizes[4];
std::vector _QueuedImpulses;
typedef std::deque TActionQueue;
TActionQueue _MainQueues[3];
uint32 _TotalPackets;
protected:
friend class CImpulseQueue;
static TImpulseReceivedCallback _Callbacks[256];
TSendRateQueue _AddRateQueues[3];
public:
/// Constructor
CImpulseEncoder();
/// Destructor
~CImpulseEncoder();
/// Return the number of bits that the specified level can manage (biggest action it can manage) (no bound check)
static uint maxBitSize( uint level ) { return MaxImpulseBitSizes[level]; }
/// Return the number of bits that can be sent at most using all levels
static uint maxBitSizeTotal() { return MaxImpulseBitSizes[0]+MaxImpulseBitSizes[1]+MaxImpulseBitSizes[2] - - (IMPULSE_ACTION_HEADER_BITSIZE*3/8); }
///
void setClientHost(CClientHost *clientHost) { _ClientHost = clientHost; }
/// Adds an action at a given level of priority.
void add(CLFECOMMON::CActionImpulsion *action, uint level);
/// Packs/sends impulse on the given outbox, using the previously added actions
uint32 send(uint32 packet, NLMISC::CBitMemStream &outbox, uint32 &sentActions);
/// Acknowledges a message and flushes involved queues (only positive acks).
void ack(uint32 packet);
/// Reinits the whole queues
void reset();
/// Unmarks all queues (act as if the awaiting actions were cleared up and readded at once)
void unmarkAll();
/// Gets the total number of messages still to be sent
uint queueSize() const;
/// Gets the number of messages still to be sent at a given level
uint queueSize(uint level) const;
/// Sets a callback for a specific type of action (-1 for all types of action)
static void setReceivedCallback(TImpulseReceivedCallback cb, sint actionCode = -1);
/// Gets the maximum bit size that can be sent through a channel (specific for a given level)
//uint getMaxBitSize(uint level) const { return _MaxBitSizes[level]; }
/// Returns true if the encoder has actions referencing a given entity (by its client entity id)
bool hasEntityReferences(CLFECOMMON::TCLEntityId id) const
{
return (_QueuedImpulses[id] != 0);
}
/// Removes all actions referencing a given entity (if there are some)
void removeEntityReferences(CLFECOMMON::TCLEntityId id);
/// \name Stats part
// @{
/// Get Enqueued actions size in bits for a specified level
uint getEnqueuedSize(uint level) const;
/// Dump stats to XML stream
void dump(NLMISC::IStream& s);
/// Count Added action
void countAddedAction(CLFECOMMON::CActionImpulsion *action, uint level);
/// Effective Add Rate
uint effectiveAddRate(uint level);
/// Effective Send Rate (cumulated send of each channel)
uint effectiveSendRate(uint level);
/// Efficiency Ratio
float efficiencyRatio(uint level);
/// Get least efficiency
float leastEfficiencyRatio();
/// Get biggest queue size
uint biggestQueueSize();
// @}
};
#endif // NL_IMPULSE_ENCODER_H
/* End of impulse_encoder.h */