I'm using RakNet to create a program which involves networking. I however don't know how to define a typedef for a Packet. The function I am trying to get it working for is:
void UDP_ClientDisconnected(Packet *pPacket);
Packet needs to be a typedef for this function obviously, however I don't know how to do this? Thanks to anyone who offers a solution.
Edit:
void Connections::UpdateRakNetwork()
{
for(Packet = Peer ->Receive(); Packet; Peer ->DeallocatePacket(Packet), Packet = Peer ->Recieve())
{
PacketID = GetPacketIdentifier(Pacekt);
switch(PacketID)
{
case ID_DISCONNECTION_NOTIFICATION:
UDP_ClientDisconnected(Packet);
break;
}
Peer ->DeallocatePacket(Packet);
}
}
Information is passed from this Packet sorting also in Connections.cpp, to the .h file in order to allow me to access these features from other elements of the game. Therefore allowing me to call UDP_ClientDisconnected(..); from another file.
As of yet there is no errors with this part of the file but the .h declaration, with the "Packet is not a Type name" error. As the guy below suggested it might be the fact that I named something else packet therefore I renamed it RakPacket and gain the same error.
It seems that it is the solution :
void Connections::UpdateRakNetwork()
{
RakNet::Packet *RakPacket = NULL;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
for(RakPacket = Peer->Receive(); NULL != RakPacket; Peer->DeallocatePacket(RakPacket), RakPacket = Peer->Recieve())
// ^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^
{
RakNet::PacketID pID = GetPacketIdentifier(RakPacket);
// ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^
switch(pID)
{
case ID_DISCONNECTION_NOTIFICATION:
UDP_ClientDisconnected(RakPacket);
// ^^^^^^^^^
break;
}
Peer->DeallocatePacket(RakPacket);
// ^^^^^^^^^
}
}
I'm not helping you by giving you that. Again try to understand RakNet::Packet *RakPacket = NULL; and why we are not using the classname as a parameter of a function but the pointer to an object...
EDIT :
In response of the first comment :
In C++, an object is a region of storage with associated semantics. In the context of the object model of C++, the term object refers to an instance of a class. A class defines the characteristics of its instances in terms of members: data members (state) and member functions (methods or operations), and the visibility of these members to other classes. C++ is statically typed.
In this explanation you can replace the word class by struct. The only difference between both is the default access right to their members (private for class and public for struct) : What are the differences between struct and class in C++?.
You can this easily by writing:
typedef Packet * pPacket;
After that you can create a pointer to a Packet object via:
pPacket somePacket(NULL);
somePacket = new Packet(...);
//etc...
Typedef's are great, but hiding pointers makes it unreadable. So if you really want to do that, you better have a good reason for this.
EDIT:
"Connections::Packet" is not a type name.
Make sure that you include the correct classes and libraries. Is that your only compiler error?
Related
I have a file_manager class that tracks the files in a given directory. I use it as the model for a file UI similar to Windows Explorer or macOS Finder. The file_manager has various find() methods to allow clients to ask for handles to files, and those methods return an optional which will be empty if no files matched that search criteria.
Since files can be deleted from the directory at any time without our knowledge, there's a comment on the find() methods saying that you shouldn't retain the pointers they give you. Instead, you should just query the file_manager again later (e.g., once per frame/once per UI update/etc.). This rule helps prevent having to wrap every future use of the file_handle in something like an is_still_on_disk() check.
Here's what the code currently looks like:
struct file_handle {
std::string path;
std::string contents;
// Other metadata here
};
class file_manager {
public:
file_manager(std::string directory_to_manage);
// Clients shouldn't retain this pointer, because the file could
// disappear from disk at any time.
// Empty if we were unable to find a file with this name.
optional<const file_handle *> find_file_by_name(std::string file_name) const;
optional<const file_handle *> find_file_modified_before(time_t time) const;
// other find_xxx() methods here
// Examines the disk to add/remove from all_known_files to match the
// current state of the directory.
// Only called at well-defined times, from the same thread that uses
// the "find" methods.
void update();
private:
std::list<file_handle> all_known_files;
}
Is there any way to codify this "do not retain" rule such that you'd get a compile error (or failing that, a runtime assertion failure) if you stored the return value of the "find" method as a member variable? (Preventing it from being a static variable would be nice too, if possible.)
That is, I'd like to be able to have the file_manager::find_xxx() methods instead return an optional "un-retainable" wrapper... something like this:
class file_manager {
. . .
optional<cant_retain_me<file_handle>> find_file_by_name(std::string file_name) const;
. . .
}
...where the cant_retain_me wrapper would allow this code to work:
void do_stuff() {
auto optional_file = my_file_manager.find_file_by_name("foo.txt");
if(optional_file.has_value()) {
cant_retain_me<file_handle> handle = *optional_file;
// use handle as though it were a normal file_handle or file_handle *
}
}
...but would break this code:
class client {
client() {
auto optional_file = my_file_manager.find_file_by_name("foo.txt");
if(optional_file.has_value()) {
my_handle = *optional_file;
} else { /* use some fallback value */ }
}
void do_stuff() {
// Try to use my_handle as though it were a normal file_handle or file_handle *
}
cant_retain_me<file_handle> my_handle;
}
Two ideas I had considered for the wrapper:
Prevent the wrapper class from being instantiated on the heap. This would help a little (it's better than nothing!), but doesn't prevent the use shown in client above.
Make the wrapper class move-only (delete the copy constructor). I think this would work, in that it would at least force clients to write some very awkward code to store the handle as a member... but I don't write much code with explicit moves, so I'm not entirely sure if this would have the desired effect.
I realize in a language with memcpy() there's never going to be a way to fully prohibit clients from bad behavior, but I'd like to make it misusing the API as obvious a code smell as possible.
I have a strange question. I have started implementing simple game engine in c++/ SFML.
I implemented a message and message queue system so that modules to be decoupled and avoid any confusing dependencies. Also I implemented a class Entity, which represents an object in the game ( contains its position, sprite,...etc ).
each entity has a function called " on_message ", which is invoked by the message queue when a specified entity should receive a message. ( Ex: if entity P1 is the destination of a message coming from P2, msg_queue will invoke p1.on_message passing the msg_type "say damage" to it to do something.
My question, all entities ( objects from class entity ) have now the same implementation of the function on_message. However, this function should differ from an entity to another ( so the player behave different from enemy when "say" space is pressed )
One idea I got is to use inheritance but I think it is not the right as if the game have 100 entity should I make 100 class !?
Is there any efficient ideas that can solve this problem ?
Thanks in advance
One idea I got is to use inheritance but I think it is not the right as if the game have 100 entity should I make 100 class !?
This is actually entirely possible, and it may even the "right thing" for entities that are well-defined enough to have their own class. If, besides the behavior on message receive, you start to need data members or other custom functions packaging everything together in a class is a good idea.
On the other hand, if you have a lot of very similar entities with just some difference in behavior when receiving some message, you may have a common superclass which provides a customization point using e.g. an assignable std::function. Something like this:
struct Entity {
...
virtual ret on_message(msg_type msg) = 0;
};
...
struct LightweightCustomEntity : public Entity {
std::function<ret(msg_type)> custom_on_message;
virtual ret on_message(msg_type msg) override {
if(!custom_on_message) return ret();
return custom_on_message(msg);
}
};
// ...
// in reality this would be a smart pointer or whatever
Entity *e = new LightweightCustomEntity;
e->custom_on_message = [](msg_type msg) {
if(msg.type == SAY_DAMAGE) {
return ret(42);
}
return ret();
};
This allows some more runtime flexibility, but notice that you don't really gain much in compactness - especially since C++11 where we can inherit constructors, defining a new class inheriting from Entity and overriding on_message takes more or less the same code.
I have a question about hierarchy, references and pointers... The question comes to my mind when I had tried to do the following stuff:
class packet {
public:
int address;
int command; /**< Command select the type of Payload that I must decode */
Payload p; /**< Generic payload, first question:
Payload p or Payload * p or Payload &p ?
I have a background in C, for this reason I prefer
Payload p but I know that this is not recommended for C++ */
private:
/** All getter and setter for attributes */
/** Second question: What is the best way to implement a getter
and setter for Payload?... I prefer something
similar to Java if this is possible */
}
Now imagine that I have a lot of types of Payload, all these payloads are children of the super class (generic) Payload.
I want to read the header and switch o the command. For example, if command is 1 I create a PayloadReset : Payload and fill in all of its attributes, then I want to set on my packet this payload (up-casting). In other part of the program I want to read my current packet and then read the command field and down-cast to the appropriate type depending on the command field.
When I tried to do this, I could do the up-casting without problems but the problem comes when I tried to do the downcasting to the specific Payload, in our example PayloadReset.
To answer the first question (which was buried inside the comments in your first code example:
Payload *p;
The first thing you need to learn as part of your transition from Java to C++ is what pointers are and how they work. What will be confusing to you, for some time, is the fact that all objects in Java are really pointers. You never needed to know that, when working with Java. But you must know that now, in order to understand C++. So, declaring a C++ class as
Payload p;
Is not the same thing as making a similar declaration in Java. There is no equivalent to this declaration in Java. In Java you really have a pointer here, and you have to instantiate it using the new keyword. That part Java originally aped from C++. This is the same process as C++, except that you have to explicitly declare it as a pointer.
Payload *p;
Then, somewhere else, using your example of a PayloadReset subclass:
class PayloadReset : public Payload { /* Class declaration */ };
PayloadReset *r = new PayloadReset( /* Constructor argument */ };
p=r;
And the second thing you need to learn as part of your transaction from Java to C++ is when, and how, to delete all instantiated objects. You don't have Java's garbage collector here. This becomes your job, now.
Tagging onto Sam's answer.
Before you go any further, learn the difference between stack and heap allocation. In the example you posted, you're allocating your Payload p; object on the stack - implying that the size of the object is known at this point and said size will be allocated on the stack. If you wanted to assign an derived object to p, it wouldn't work, because said object will likely be of different size. This is why you instead declare a pointer to the object (8 bytes on 64-bit architecture, 4 bytes on 32 bit), and then when you know which type of derived object you want to allocate, you do it using the new operator, as such:
Payload *p;
p = new PayloadReset(...);
The above method would require manually managing memory, i.e. calling delete on the new allocated pointer. As of C++11, the recommendation is to use smart pointers from the <memory> header. These are essentially reference counted pointers that automatically call delete for you.
std::shared_ptr<Payload> p;
p = std::make_shared<PayloadReset>(...);
Your question is somewhat related to Java syntax, but mostly about Object Oriented Programming.
First of all, you should take a moment to get familiar with Java naming conventions. There are commonly used recommendations that you can find all over the web. Here is one example of Java Naming Conventions. I brought this up because single variable names is generally not a good idea and having descriptive variables names pays dividends as the program grows in size and especially if there are more than one person on a team. So, instead of Payload p use Payload payload.
Secondly, in OO (Object Oriented), it is best to always keep your Class instance variables private, not public. Give access to these variables only if necessary and shield access to them by providing public methods. So, in your example of class Packet, your public/private is backwards. Your class should look more like:
public class Packet{
//private fields
private int address;
private int command;
private Payload payload;
//Maybe provide a nice constructor to take in expected
//properties on instantiation
public Packet(Payload pay){
}
//public methods - as needed
public void getPayload(){
return this.payload;
}
public void setAddress(int addy){
this.address = addy;
}
public int getCommand(){
return this.command;
}
}
Also, to answer more of your question about the naming of Payload. Like i said earlier..use descriptive names. Java does not have pointer references like C and generally handles memory management for you, so the & is not required or supported.
Your last question/topic is really again about OO and Class heirarchy.
It seems that Payload would be a generic base class and you may have multiple, specific 'Payload types', like ResetPayload. If that is the case, you would then define Payload and create the ResetPayload class that extends Payload. I'm not sure exactly what you are trying to do, but think of Classes/objects ad nouns and methods as verbs. Also think about the 'is-a' and 'has-a' concept. From what I see, maybe all Payloads 'has-acommand and an address. Also, maybe eachPayloadalso has multiplePackets, whatever. Just as an example, you would then define yourPayload` class like this:
public class Payload{
private int address;
private int command;
private List<Packet> packets = new ArrayList<>();
public Payload(int addy, int comm){
this.address = addy;
this.command = comm;
}
public void addPacket(Packet p){
packets.add(p);
}
public List<Packet> getPackets(){
return this.packets;
}
public int getCommand(){
return this.command;
}
public int getAddress(){
return this.address;
}
}
Then if you had a type of Payload that is more specific, like Reset, you would create the class, extends Payload and provide the additional properties/operations specific to this type, something this like:
public class ResetPayload extends Payload{
public ResetPayload(int addy, int comm){
super(addy, comm);
}
public void reset(){
//Do stuff here to reset the payload
}
}
Hopefully, that answers your questions and moves you along further. Good luck.
Here is my take on the general problem, it extends the tagged union idea. Advantages are 1.) no inheritance/dynamic_cast 2.) no shared ptr 3.) POD 4.) rtti is used to generate unique tags:
using cleanup_fun_t = void(*)(msg*);
class msg
{
public:
template<typename T, typename... Args>
static msg make(Args&&... args);
private:
std::type_index tag_;
mutable std::atomic<cleanup_fun_t> del_fn_; // hell is waiting for me,
uint64_t meta_;
uint64_t data_;
};
Please fill in all the nice member functions. This class is move only. You are creating messages with payload by the static member function make:
template<typename T, typename... Args>
msg msg::make(Args&&... args)
{
msg m;
m.tag_ = typeid(T);
m.del_fn_ = nullptr;
if (!(std::is_empty<T>::value))
{
auto ptr = std::make_unique<T>(std::forward<Args>(args)...);
m.data_ = (uint64_t)ptr.release();
m.del_fn_ = &details::cleanup_t<T>::fun; // deleter template not shown
}
return m;
}
// creation:
msg m = msg::make<Payload>(params passed to payload constructor);
// using
if (m.tag() == typeid(Payload))
{
Payload* ptr = (Payload*)m.data;
ptr-> ...
}
Just check the tag if it contains your expected data (type) and cast the data to a pointer type.
Disclaimer: It is not the complete class. Some access member function are missing here.
Let us assume the following class:
class FileManipulator
{
static InputTypeOne * const fileone;
InputTypeTwo *filetwo;
public:
FileManipulator( InputTypeTwo *filetwo )
{
this->filetwo = filetwo;
}
int getResult();
};
FileManipulator uses data from both files to obtain output from getResult(). This means multiple iterations over filetwo and multiple constructions of FileManipulators via iterations for different InputTypeTwo objects. Inputs are, let us say, some .csv databases. InputTypeOne remains the same for the whole task.
The program itself is multi-modular and the operation above is only its small unit.
My question is how can I handle that static field in accordance with the object-oriented paradigm and encapsulation. The field must be initialized somehow since it is not a fixed value over different program executions. As far as I understand C++ rules I cannot create a method for setting the field, but making it public and initializing it outside of any class (FileManipulator or a befriended class) seems to me at odds with the encapsulation.
What can I do then? The only thing that comes to my mind is to do it in a C manner, namely initialize it in an isolated enough compilation unit. Is it really all I can do? How would that be solved in a professional manner?
edit
I corrected pointer to constant to constant pointer, which was my initial intention.
You can write a public static method of FileManipulator that would initialize the field for you:
static void init()
{
fileone = something();
}
And then call it from main() or some place where your program is being initialized.
One way of doing this which comes to mind is:
In the .cpp file
FileManipulator::fileone = NULL;
Then modify constructor to do the following:
FileManipulator( InputTypeTwo *filetwo, InputTypeOne *initValue = NULL)
{
if(fileone == NULL)
{
fileone = initValue;
}
this->filetwo = filetwo;
}
Or you could also define an init function and make sure to call it before using the class and after the CTOR. the init function will include the logic of how to init fileone.
I have, for my game, a Packet class, which represents network packet and consists basically of an array of data, and some pure virtual functions
I would then like to have classes deriving from Packet, for example: StatePacket, PauseRequestPacket, etc. Each one of these sub-classes would implement the virtual functions, Handle(), which would be called by the networking engine when one of these packets is received so that it can do it's job, several get/set functions which would read and set fields in the array of data.
So I have two problems:
The (abstract) Packet class would need to be copyable and assignable, but without slicing, keeping all the fields of the derived class. It may even be possible that the derived class will have no extra fields, only function, which would work with the array on the base class. How can I achieve that?
When serializing, I would give each sub-class an unique numeric ID, and then write it to the stream before the sub-class' own serialization. But for unserialization, how would I map the read ID to the appropriate sub-class to instanciate it?
If anyone want's any clarifications, just ask.
-- Thank you
Edit: I'm not quite happy with it, but that's what I managed:
Packet.h: http://pastebin.com/f512e52f1
Packet.cpp: http://pastebin.com/f5d535d19
PacketFactory.h: http://pastebin.com/f29b7d637
PacketFactory.cpp: http://pastebin.com/f689edd9b
PacketAcknowledge.h: http://pastebin.com/f50f13d6f
PacketAcknowledge.cpp: http://pastebin.com/f62d34eef
If someone has the time to look at it and suggest any improvements, I'd be thankful.
Yes, I'm aware of the factory pattern, but how would I code it to construct each class? A giant switch statement? That would also duplicade the ID for each class (once in the factory and one in the serializator), which I'd like to avoid.
For copying you need to write a clone function, since a constructor cannot be virtual:
virtual Packet * clone() const = 0;
Which each Packet implementation implement like this:
virtual Packet * clone() const {
return new StatePacket(*this);
}
for example for StatePacket. Packet classes should be immutable. Once a packet is received, its data can either be copied out, or thrown away. So a assignment operator is not required. Make the assignment operator private and don't define it, which will effectively forbid assigning packages.
For de-serialization, you use the factory pattern: create a class which creates the right message type given the message id. For this, you can either use a switch statement over the known message IDs, or a map like this:
struct MessageFactory {
std::map<Packet::IdType, Packet (*)()> map;
MessageFactory() {
map[StatePacket::Id] = &StatePacket::createInstance;
// ... all other
}
Packet * createInstance(Packet::IdType id) {
return map[id]();
}
} globalMessageFactory;
Indeed, you should add check like whether the id is really known and such stuff. That's only the rough idea.
You need to look up the Factory Pattern.
The factory looks at the incomming data and created an object of the correct class for you.
To have a Factory class that does not know about all the types ahead of time you need to provide a singleton where each class registers itself. I always get the syntax for defining static members of a template class wrong, so do not just cut&paste this:
class Packet { ... };
typedef Packet* (*packet_creator)();
class Factory {
public:
bool add_type(int id, packet_creator) {
map_[id] = packet_creator; return true;
}
};
template<typename T>
class register_with_factory {
public:
static Packet * create() { return new T; }
static bool registered;
};
template<typename T>
bool register_with_factory<T>::registered = Factory::add_type(T::id(), create);
class MyPacket : private register_with_factory<MyPacket>, public Packet {
//... your stuff here...
static int id() { return /* some number that you decide */; }
};
Why do we, myself included, always make such simple problems so complicated?
Perhaps I'm off base here. But I have to wonder: Is this really the best design for your needs?
By and large, function-only inheritance can be better achieved through function/method pointers, or aggregation/delegation and the passing around of data objects, than through polymorphism.
Polymorphism is a very powerful and useful tool. But it's only one of many tools available to us.
It looks like each subclass of Packet will need its own Marshalling and Unmarshalling code. Perhaps inheriting Packet's Marshalling/Unmarshalling code? Perhaps extending it? All on top of handle() and whatever else is required.
That's a lot of code.
While substantially more kludgey, it might be shorter & faster to implement Packet's data as a struct/union attribute of the Packet class.
Marshalling and Unmarshalling would then be centralized.
Depending on your architecture, it could be as simple as write(&data). Assuming there are no big/little-endian issues between your client/server systems, and no padding issues. (E.g. sizeof(data) is the same on both systems.)
Write(&data)/read(&data) is a bug-prone technique. But it's often a very fast way to write the first draft. Later on, when time permits, you can replace it with individual per-attribute type-based Marshalling/Unmarshalling code.
Also: I've taken to storing data that's being sent/received as a struct. You can bitwise copy a struct with operator=(), which at times has been VERY helpful! Though perhaps not so much in this case.
Ultimately, you are going to have a switch statement somewhere on that subclass-id type. The factory technique (which is quite powerful and useful in its own right) does this switch for you, looking up the necessary clone() or copy() method/object.
OR you could do it yourself in Packet. You could just use something as simple as:
( getHandlerPointer( id ) ) ( this )
Another advantage to an approach this kludgey (function pointers), aside from the rapid development time, is that you don't need to constantly allocate and delete a new object for each packet. You can re-use a single packet object over and over again. Or a vector of packets if you wanted to queue them. (Mind you, I'd clear the Packet object before invoking read() again! Just to be safe...)
Depending on your game's network traffic density, allocation/deallocation could get expensive. Then again, premature optimization is the root of all evil. And you could always just roll your own new/delete operators. (Yet more coding overhead...)
What you lose (with function pointers) is the clean segregation of each packet type. Specifically the ability to add new packet types without altering pre-existing code/files.
Example code:
class Packet
{
public:
enum PACKET_TYPES
{
STATE_PACKET = 0,
PAUSE_REQUEST_PACKET,
MAXIMUM_PACKET_TYPES,
FIRST_PACKET_TYPE = STATE_PACKET
};
typedef bool ( * HandlerType ) ( const Packet & );
protected:
/* Note: Initialize handlers to NULL when declared! */
static HandlerType handlers [ MAXIMUM_PACKET_TYPES ];
static HandlerType getHandler( int thePacketType )
{ // My own assert macro...
UASSERT( thePacketType, >=, FIRST_PACKET_TYPE );
UASSERT( thePacketType, <, MAXIMUM_PACKET_TYPES );
UASSERT( handlers [ thePacketType ], !=, HandlerType(NULL) );
return handlers [ thePacketType ];
}
protected:
struct Data
{
// Common data to all packets.
int number;
int type;
union
{
struct
{
int foo;
} statePacket;
struct
{
int bar;
} pauseRequestPacket;
} u;
} data;
public:
//...
bool readFromSocket() { /*read(&data); */ } // Unmarshal
bool writeToSocket() { /*write(&data);*/ } // Marshal
bool handle() { return ( getHandler( data.type ) ) ( * this ); }
}; /* class Packet */
PS: You might dig around with google and grab down cdecl/c++decl. They are very useful programs. Especially when playing around with function pointers.
E.g.:
c++decl> declare foo as function(int) returning pointer to function returning void
void (*foo(int ))()
c++decl> explain void (* getHandler( int ))( const int & );
declare getHandler as function (int) returning pointer to function (reference to const int) returning void