Jump to content

  • Log In with Google      Sign In   
  • Create Account


#Actualrpiller

Posted 17 January 2013 - 06:59 AM

I use RakNet with BitStream's as well, and I fire "events" with messages, but I just go raw BitStream & Packet handling instead of wrapping them up in a formal message object. There are so many messages in a game that making an object for each one I just felt wasn't worth it. I'd rather just have a function be mapped to a message and then read the BitStream directly in there. The Event.h file I use is below. I do this so 1 message gets mapped to 1 function and I don't have to worry about messing with some switch control. Instead it's always just 1 mapping line of code. 

 

Events are stored like:

 

 

map<MessageID, Event2<Packet&, BitStream&>> _events;

 

 

I have 1 area that captures packets coming in from the RakNet loop to dispatch to member functions that are registered to the message:

 

 

 

for(_packet = _peer->Receive(); _packet; _peer->DeallocatePacket(_packet), _packet = _peer->Receive())
{
RakNet::MessageID msg = _packet->data[0];


// make sure we mapped to the event
if(_events.find(msg) != _events.end())
{
// create bitstream and ignore the msg
RakNet::BitStream reader(_packet->data, _packet->length, false);
reader.IgnoreBytes(sizeof(RakNet::MessageID));


// raise the event
_events[msg].Raise((*_packet), reader);
}
}

 

And I register the functions like:

 

 

_events[(MessageID)ID_NEW_INCOMING_CONNECTION].Bind(this, &Server::OnNewIncomingConnection);

 

The function using the data would be defined as:

 

 

 

void Server::OnNewIncomingConnection(Packet& p, BitStream& reader)
{
    int age;


   reader.Read(age);


   _peer->Send(..., p.address);
}

 

To me the BitStream is basically the "message" object. It just isn't wrapped in a type. The plus is it doesn't get the overhead wrapping hit that a type does, if the message changes you don't have to go 2 places for that change (the message object, then in here to use new field), & you won't have potentially hundreds of little classes laying around (although if you have multiple people on a team this might help separate duties). The only negative is you don't get a pretty type that defines all the fields that the object has. You have to do that yourself. I'm not sure of the speed hit that would occur with the message object, but it'll be "slowER" than this, but it might not matter.

 

 

 

Event.h. This has EventX objects where X is 0 - 3 which is the number of parameters to the class function.

#pragma once
#include <list>


using namespace std;




class TFunctor0
{
public:
virtual void Call()=0;
};


template <class TClass>
class TSpecificFunctor0 : public TFunctor0
{
private:
void (TClass::*fpt)();
TClass* pt2Object;         
public:
TSpecificFunctor0(TClass* _pt2Object, void(TClass::*_fpt)())
{ 
pt2Object = _pt2Object;  
fpt=_fpt; 
}


virtual void Call()
{ (*pt2Object.*fpt)(); }
};


class Event0
{
public:
list<TFunctor0*>  mCaller;


template<class Target>
void Bind(Target* t, void (Target::*fnPtr)())
{ 
mCaller.push_back(new TSpecificFunctor0<Target>(t,fnPtr));
}


void Clear()
{ mCaller.clear(); }
       
void Raise()
{
list<TFunctor0*>::reverse_iterator iter;


for (iter = mCaller.rbegin(); iter!= mCaller.rend(); iter++)
{
(*iter)->Call();
}
}
};


//===============================================================================


template<class P>
class TFunctor1
{
public:
virtual void Call(P var1)=0;
};


template <class TClass, class param1>
class TSpecificFunctor1 : public TFunctor1<param1>
{
private:
void (TClass::*fpt)(param1);
TClass* pt2Object;         
public:
TSpecificFunctor1(TClass* _pt2Object, void(TClass::*_fpt)(param1))
{ pt2Object = _pt2Object;  fpt=_fpt; }


virtual void Call(param1 var1)
{ (*pt2Object.*fpt)(var1); }
};


template<class T1>
class Event1
{
public:
list<TFunctor1<T1>* >  mCaller;


template<class Target>
void Bind(Target* t, void (Target::*fnPtr)(T1))
{ mCaller.push_back(new TSpecificFunctor1<Target, T1>(t,fnPtr)); }
       
void Raise(T1 V1)
{
list<TFunctor1<T1>*>::reverse_iterator iter;




for (iter = mCaller.rbegin(); iter!= mCaller.rend(); iter++)
{
(*iter)->Call(V1);
}
}


void Clear()
{
mCaller.clear();
}
};


//===============================================================================


template<class P, class Q>
class TFunctor2
{
public:
virtual void Call(P var1, Q var2)=0;
};


template <class TClass, class param1, class param2>
class TSpecificFunctor2 : public TFunctor2<param1, param2>
{
private:
void (TClass::*fpt)(param1, param2);
TClass* pt2Object;         
public:
TSpecificFunctor2(TClass* _pt2Object, void(TClass::*_fpt)(param1, param2))
{ pt2Object = _pt2Object;  fpt=_fpt; }


virtual void Call(param1 var1, param2 var2)
{ (*pt2Object.*fpt)(var1, var2); }
};


template<class T1, class T2>
class Event2
{
public:
list<TFunctor2<T1, T2>* >  mCaller;


template<class Target>
Event2(Target* t, void (Target::*fnPtr)(T1, T2))
{ mCaller.push_back(new TSpecificFunctor2<Target, T1, T2>(t,fnPtr)); }


Event2(){}


template<class Target>
void Bind(Target* t, void (Target::*fnPtr)(T1, T2))
{ mCaller.push_back(new TSpecificFunctor2<Target, T1, T2>(t,fnPtr)); }
       
void Raise(T1 V1, T2 V2)
{
list<TFunctor2<T1, T2>*>::reverse_iterator iter;




for (iter = mCaller.rbegin(); iter!= mCaller.rend(); iter++)
{
(*iter)->Call(V1, V2);
}
}


void Clear()
{
mCaller.clear();
}
};




//===============================================================================


template<class P, class Q, class Y>
class TFunctor3
{
public:
virtual void Call(P var1, Q var2, Y var3)=0;
};


template <class TClass, class param1, class param2, class param3>
class TSpecificFunctor3 : public TFunctor3<param1, param2, param3>
{
private:
void (TClass::*fpt)(param1, param2, param3);
TClass* pt2Object;         
public:
TSpecificFunctor3(TClass* _pt2Object, void(TClass::*_fpt)(param1, param2, param3))
{ pt2Object = _pt2Object;  fpt=_fpt; }


virtual void Call(param1 var1, param2 var2, param3 var3)
{ (*pt2Object.*fpt)(var1, var2, var3); }
};


template<class T1, class T2, class T3>
class Event3
{
public:
list<TFunctor3<T1, T2, T3>* >  mCaller;


template<class Target>
void Bind(Target* t, void (Target::*fnPtr)(T1, T2, T3))
{ mCaller.push_back(new TSpecificFunctor3<Target, T1, T2, T3>(t,fnPtr)); }
       
void Raise(T1 V1, T2 V2, T3 V3)
{
list<TFunctor3<T1, T2, T3>*>::reverse_iterator iter;




for (iter = mCaller.rbegin(); iter!= mCaller.rend(); iter++)
{
(*iter)->Call(V1, V2, V3);
}
}


void Clear()
{
mCaller.clear();
}
};

#1rpiller

Posted 17 January 2013 - 06:48 AM

I use RakNet with BitStream's as well, and I fire "events" with messages, but I just go raw BitStream & Packet handling instead of wrapping them up in a formal message object. There are so many messages in a game that making an object for each one I just felt wasn't worth it. I'd rather just have a function be mapped to a message and then read the BitStream directly in there. The Event.h file I use is below. I do this so 1 message gets mapped to 1 function and I don't have to worry about messing with some switch control. Instead it's always just 1 mapping line of code. 

 

Events are stored like:

 

 

map<MessageID, Event2<Packet&, BitStream&>> _events;

 

 

I have 1 area that captures packets coming in from the RakNet loop to dispatch to member functions that are registered to the message:

 

 

 

for(_packet = _peer->Receive(); _packet; _peer->DeallocatePacket(_packet), _packet = _peer->Receive())
{
RakNet::MessageID msg = _packet->data[0];


// make sure we mapped to the event
if(_events.find(msg) != _events.end())
{
// create bitstream and ignore the msg
RakNet::BitStream reader(_packet->data, _packet->length, false);
reader.IgnoreBytes(sizeof(RakNet::MessageID));


// raise the event
_events[msg].Raise((*_packet), reader);
}
}

 

And I register the functions like:

 

 

_events[(MessageID)ID_NEW_INCOMING_CONNECTION].Bind(this, &Server::OnNewIncomingConnection);

 

 

 

 

 

Event.h. This has EventX objects where X is 0 - 3 which is the number of parameters to the class function.

#pragma once
#include <list>


using namespace std;




class TFunctor0
{
public:
virtual void Call()=0;
};


template <class TClass>
class TSpecificFunctor0 : public TFunctor0
{
private:
void (TClass::*fpt)();
TClass* pt2Object;         
public:
TSpecificFunctor0(TClass* _pt2Object, void(TClass::*_fpt)())
{ 
pt2Object = _pt2Object;  
fpt=_fpt; 
}


virtual void Call()
{ (*pt2Object.*fpt)(); }
};


class Event0
{
public:
list<TFunctor0*>  mCaller;


template<class Target>
void Bind(Target* t, void (Target::*fnPtr)())
{ 
mCaller.push_back(new TSpecificFunctor0<Target>(t,fnPtr));
}


void Clear()
{ mCaller.clear(); }
       
void Raise()
{
list<TFunctor0*>::reverse_iterator iter;


for (iter = mCaller.rbegin(); iter!= mCaller.rend(); iter++)
{
(*iter)->Call();
}
}
};


//===============================================================================


template<class P>
class TFunctor1
{
public:
virtual void Call(P var1)=0;
};


template <class TClass, class param1>
class TSpecificFunctor1 : public TFunctor1<param1>
{
private:
void (TClass::*fpt)(param1);
TClass* pt2Object;         
public:
TSpecificFunctor1(TClass* _pt2Object, void(TClass::*_fpt)(param1))
{ pt2Object = _pt2Object;  fpt=_fpt; }


virtual void Call(param1 var1)
{ (*pt2Object.*fpt)(var1); }
};


template<class T1>
class Event1
{
public:
list<TFunctor1<T1>* >  mCaller;


template<class Target>
void Bind(Target* t, void (Target::*fnPtr)(T1))
{ mCaller.push_back(new TSpecificFunctor1<Target, T1>(t,fnPtr)); }
       
void Raise(T1 V1)
{
list<TFunctor1<T1>*>::reverse_iterator iter;




for (iter = mCaller.rbegin(); iter!= mCaller.rend(); iter++)
{
(*iter)->Call(V1);
}
}


void Clear()
{
mCaller.clear();
}
};


//===============================================================================


template<class P, class Q>
class TFunctor2
{
public:
virtual void Call(P var1, Q var2)=0;
};


template <class TClass, class param1, class param2>
class TSpecificFunctor2 : public TFunctor2<param1, param2>
{
private:
void (TClass::*fpt)(param1, param2);
TClass* pt2Object;         
public:
TSpecificFunctor2(TClass* _pt2Object, void(TClass::*_fpt)(param1, param2))
{ pt2Object = _pt2Object;  fpt=_fpt; }


virtual void Call(param1 var1, param2 var2)
{ (*pt2Object.*fpt)(var1, var2); }
};


template<class T1, class T2>
class Event2
{
public:
list<TFunctor2<T1, T2>* >  mCaller;


template<class Target>
Event2(Target* t, void (Target::*fnPtr)(T1, T2))
{ mCaller.push_back(new TSpecificFunctor2<Target, T1, T2>(t,fnPtr)); }


Event2(){}


template<class Target>
void Bind(Target* t, void (Target::*fnPtr)(T1, T2))
{ mCaller.push_back(new TSpecificFunctor2<Target, T1, T2>(t,fnPtr)); }
       
void Raise(T1 V1, T2 V2)
{
list<TFunctor2<T1, T2>*>::reverse_iterator iter;




for (iter = mCaller.rbegin(); iter!= mCaller.rend(); iter++)
{
(*iter)->Call(V1, V2);
}
}


void Clear()
{
mCaller.clear();
}
};




//===============================================================================


template<class P, class Q, class Y>
class TFunctor3
{
public:
virtual void Call(P var1, Q var2, Y var3)=0;
};


template <class TClass, class param1, class param2, class param3>
class TSpecificFunctor3 : public TFunctor3<param1, param2, param3>
{
private:
void (TClass::*fpt)(param1, param2, param3);
TClass* pt2Object;         
public:
TSpecificFunctor3(TClass* _pt2Object, void(TClass::*_fpt)(param1, param2, param3))
{ pt2Object = _pt2Object;  fpt=_fpt; }


virtual void Call(param1 var1, param2 var2, param3 var3)
{ (*pt2Object.*fpt)(var1, var2, var3); }
};


template<class T1, class T2, class T3>
class Event3
{
public:
list<TFunctor3<T1, T2, T3>* >  mCaller;


template<class Target>
void Bind(Target* t, void (Target::*fnPtr)(T1, T2, T3))
{ mCaller.push_back(new TSpecificFunctor3<Target, T1, T2, T3>(t,fnPtr)); }
       
void Raise(T1 V1, T2 V2, T3 V3)
{
list<TFunctor3<T1, T2, T3>*>::reverse_iterator iter;




for (iter = mCaller.rbegin(); iter!= mCaller.rend(); iter++)
{
(*iter)->Call(V1, V2, V3);
}
}


void Clear()
{
mCaller.clear();
}
};

PARTNERS