Advertisement

new networker needs help.. lots of easy questions

Started by June 19, 2004 04:42 AM
9 comments, last by graveyard filla 20 years, 7 months ago
high, im working on a top down action / RPG w / c++, OpenGL, and SDL. anyway, im working with an experianced network programmer but he doesnt have much game programming experiance. he has finished writing the protocol for the game and the client and server... basically, hes boiled it down to me calling an Init() function, calling a Send() function whenever needed, and of course i customize the Receieve() function to do whatever i need to do with the data i receive... hes allowed me to create any structure i want and send it over the wire, as long as its under 64 k in size (no problem) now, the game is an RPG, but the multiplayer is more like a 2d action game. that is, there is only a single map allowed, NO NPC's, and a max of 8 players. this is to keep things as simple as possible, basically just making the multiplayer good for death-matches and FFA's. could someone PLEASE give me some guidance on how to start implementing this thing? heres my ideas so far, please tell me if i have the right idea and give me advise on what to look out for: i have a class called Player. (already made, represents the player). im going to make another class called Other_Player.. he will be like a "bare-bones" player... as in, just like a Player, only doesnt do things like collision detection (since collision detection will be handled on the client side, i will only need to know the coordinates of Other_Players, and its up to their clients to make sure no one gets through a wall or anything...). they would also have a char ID_Number; now, ill make a std::list of Other_Player. now, when i receieve a "player connected" message, ill push_back a new Other_Player. Ill assign this Other_Player the ID which i got from the server. Now, its just a matter of me updating for this player. ill make a struct like this:

struct player_data
{
   int x_position;
   int y_position;
   string weapon_type;
}
and this is how ill handle all recieving data...

receive_data(char message, char *data,char ID, int data_size)
{
   
  //if this message was PLAYER_DATA
  if(message == PLAYER_DATA)
  {
     ///copy our player data into a holder
     player_data this_guys_data;
     memcpy(this_guys_data, data, data_size);
     
     //for each other player we have in our list
    for(list<Other_Player>::iterator i = other_players.begin(); i != other_players.end(); i++)
    {
       // if this other player matches up to the one we are receiving data for
        if(i->ID_Number == ID)
        {
            //then set this other players data to the one we just receieved
            i->x_position = this_guys_data.x_position;
            i->y_position = this_guys_data.y_position;
           
           if(this_guys_data.current_weapon == FLAMETHROWER)
              i->current_weapon = Flamethrower;
         }
     }
   }
}
 
do you see what im doing? basically im keeping a local copy of all clients connected, and updating them accordingly? this example was for player coordinates, but there will be other messages like BULLET_FIRED, MAP_DATA, etc... is this how its done? am i on the right track? this will be my first time doing any network programming... i think i get it, and the protocol my partner has made is very nice and flexible, and does a lot of the work for me...the receive() function is in a thread and is called whenever there is data ready to be receieved... i just have to Send() data whenever its nessecary (please give advise on stuff like this, anything, things to look out for! i know this is a huge under taking , especially for a first time networking. if you think this is too much, please let me know and ill network my pong game first. im actually confident i could do this, but i dont want to start something i cant finish. im sure there are many things im not expecting. is my design totally wrong? thanks for any help!!! [Edited by - graveyard filla on June 19, 2004 6:02:16 PM]
FTA, my 2D futuristic action MMORPG
I suggest you get on google and search a bit, I bet there are A LOT of articles explaining how to do multiplayer games.
If you have the money, you could get a book too. Any book bought is not a waste. Except for schoolbooks.

As for your code, it's the best to try it out. Everyone has his own style, and programming is about using your own ideas (at first), comparing them to others ideas (later), and construct an über solution.

Good luck!
Advertisement
couple things.

in your player_data struct, is your weapon type a fixed size string like a char weapon_type[32] or is it an std::string or some other dynamic structure?

if it is dynamic you arent really going to be able to just memcpy over it, nor are you going to be able to just send &player_data, sizeof(player_data). In order to do that the easiest you should change your string to a fixed size character array.

secondly, and this is purely a recommendation for efficiency, instead of using an std::list, you might consider using an std::map, as it will allow much faster lookups of characters by their unique ID. something like this

std::map<int, Other_Player *> playerList;

then when someone joins and you create a new player you add them do the map like

Other_Player *pNewPlayer = new Other_Player;
// fill in the struct here...
// add it to the map.
playerList[thisguysID] = pNewPlayer;


then in your recieve_data function instead of searching through the list like you do now, you can do

std::map<int, Other_Player *>::iterator it;
it = playerList.find(ID);
if(it != playerList.end())
{
Other_Player *pThisPlayer = it->second;
// update the stored struct with the data from the network message
}

you can still iterate through the map like a linked list to call your update functions and stuff, and the map will give you better performance looking up your objects by their ID.

Your idea seems good and so seems your network programmer.

As far as the player position updation is concerned yours should work well.I would suggest you go ahead and try it out without any bullets or anything ,just people moving around.If you get that right your major troubles are over.

An idea for bullets.Let your player class have linked list to hold bullets (I am hoping you already have one) and when the server sends a BULLET_FIRED message add a bullet to the player object (according to the ID) and keep updating it.Now also the server can send updates to the client (about the bullet) or the client can do it with time based movement.This way the server will only have to send a update when the bullet is to be destroyed but which method is better is yours to decide.
______________________________________________________________________________________________________
[AirBash.com]
thanks you all for your comments!!! i just wanted to make sure i was on the right track before i started coding..

so this is how it works? i make a local copy of any players in the world, and update them as needed? doesnt seem THAT bad... anything else i should look out for?? thanks for all your guys help!!!

FTA, my 2D futuristic action MMORPG
I would use the same player class for local/remote players. Then I'd hook up separate "input" providers for them, where the "input" from the remote players arrives over network, whereas "input" from local players arrives over keyboard/mouse. That way, there is less split code, and thus fewer bugs.
enum Bool { True, False, FileNotFound };
Advertisement
how would you use the same exact class ? i mean, how could you make the player instances which were not the local player take input differently ? i just cant see how you can use the same class but do different code somewhere... the only way i can think of off the top of my head is to make some sort of Input class, and derive Player_Input and NPC_Input classes from that... then have the Player class have a pointer to an Input class, and allocate the one which was apropriate... is this the kind of thing your suggesting ? and why would using seperate classes for the 2 cause more bugs ? thanks for your help !!

another thing is, my Player class has things that are un-nessacary for non local clients... things like, collision detection for example. collision detection wont be performed by non-local players. this is because collison is the responsibility of the local client, and i just send my coordinates. its up to me to make sure im not inside a wall or anything... when i receive data from other players, i assume that their collision detection is working... is this bad or something ? thanks again
FTA, my 2D futuristic action MMORPG
Hello graveyard filla,

Looks like you have a good system, and as hplus0603 stated it could be even better.

You asked him how to make both local and remote use the same interface.
Several ways.

1) make them all use the same input class/struct.
2) create overload input functions, one for local input other for buffer passed to it.
3) create virtual input functions, were you have a base player class, and then local and extern player classes inherit for this and was there own virtual functions.

I would prefer the #1. reason it has the focus that local and extern player are the same class and use the same input interface.
Input struct would have key info, mouse info etc, than you just pass this in and it get processed.

Have the input/class have methods to be set by local user input and by a buffer passed to it.
That way only the input class needs different set methods not the player class.
You could then add NPC that use the same player class and control by a AI thread that passes in a input classes to control it.

Added:
The reason that having two classes almost doing the same thing might introduce bugs is you can have twice as many files, If you fix a bug in one you need to check if it there in the other.

It is fine to have your remote be the same class as the local player is. If you don't do collision detection on remote then don't do collision detection. Since remote only get update by a message they should not be in the same input update code of your local player.

Lord Bart :)
Lord Brat, thanks for your reply.

im having a hard time imagining this in my head. maybe i havent thought about it enough, but i just cant see how i could use the same class to represent the local player / non-local player.

maybe its because of the way my engine works? basically, i have a parent class called World_Update. this class has a virtual bool Update().

now, any class which needs updating (basically almost all my classes) will inherit from World Update. then, inside each class, i customize how they update themselves. then i can manage all of my objects from a "master list", calling Update() when needed, and deleting the object when his Update() call returns false. (this could be when an enemy dies, a particle's life ends, whatever..). another thing i should tell you, is that i DONT manage my Other_Players from this master list. DrEvil gave a really great suggestion that im using, and my Other_Player's are going to be stored in a std::map, instead of registering them with my Update engine, and updating them as a part of the master list, i will just loop through my map and call Update(). i guess i COULD register them with the update engine AND store them in a std::map, but this brings up other issues which i dont like, such as different list's storing the same pointers, and having to let one let the other one know when an object is no longer valid...


so, since everything is called from inside of Update(). how could i go about changing my Update() function to be different on non-local clients? heres a ruff psuedo code of what my player class's update looks like:

bool Player::Update(){   Take_Input();   Do_Collision();   Do_Other_Stuff_Only_A_Local_Player_Would_Do();}


do you see the problem here? i mean, the only way i could see this working, is if i have some sort of bool is_local flag, and then if is_local == true, then do this, if not, do that...

but thats ugly!

anyway, im hoping im missing something thats obvious, it seems like the only choice that i have, is your #3. i make a general "player" class, then have "local_player" and "remote_player" derive from it. then, i can customize how their Update() function works (the local one would take input and such, while the remote one would do much less stuff...)

what do you think? also, i dont really like the fact that a class will have members which it will never use, like the remote player having Collision() functions which he nevers uses. IMO this is worse then data duplication, but im thinking maybe this case could be an exeption?

thanks for anymore help!!!
FTA, my 2D futuristic action MMORPG
Hello graveyard filla,

virtual bool Update(), that great.

so what you do is this

your local player is created just like you want.

then you do is this.

Class RemotePlayer : public Player
{
public:
// note should have a flag to say if local or remote in Player
RemotePlayer(); // should only set a flag that it is remote
virtaul bool Update();
};

then your RemotePlayer Update is

virtual bool Update()
{
Take_Input();
}

So what you have here is RemotePlayer is the same as Player except for one virtual Update() method.

Now the next major step is getting the Input.
Questions to ask your self.
How fast do you get input?
Do you care if you get 5 remote message for same remote player the process all of them or only the lastest one and throw away the old messages?

Want I would do is have a Input thread that handle queuing up input messages for each Player(local and remotes).
Then when your call your update process each Player object goes and gets back it queue form this input thread. The input thread creates a new queue for new incoming message.
Then each Player Take_Input uses the it queue for it player and process the input.

Do you get what I trying to say :).

You could have an input thread for each player that controls getting input and creating/added to it que.

Later if you wanted to add NPC each could gets it own AI/input thread. And form your code it all the same player
The main process thread doesn’t know or care what the player object is (local, remote or NPC).

Lord Bart :)

[Edited by - Lord Bart on June 22, 2004 8:37:26 AM]

This topic is closed to new replies.

Advertisement