• Advertisement
Sign in to follow this  

problem with repeating code on client and server (MORPG)

This topic is 4844 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hi, ive been working on a multiplayer online RPG for the past 9 months. anyway, ive noticed a pattern and im wondering if there is anything i can do about it. the client and server are 2 seperate programs and 2 seperate workspaces (im not releasing the server; it will run on a dedicated machine). anyway, i notice that i am cut and pasting a lot of code. for example class interfaces / implementation. they are very similar on the client and server, except the server doesnt render anything. so, for example, on the client i will have a Bullet class.. the server needs this too, BUT, it does not need some of the members (GLuint texture for example). so, instead of putting the Bullet.h file in the "common" directory that both the client and server share, i have to cut and paste them, and put a slightly modified version on the server. i dont like this that much though, and im worried they might get out of sync and its just going to keep piling up untill its too much to handle. is there anything i could do about this? pre proccessor macros or something? thanks for any help.

Share this post


Link to post
Share on other sites
Advertisement
Guest Anonymous Poster
Couldn't you make a Bullet class which couldn't render itself and then make a RenderableBullet or something inhert from it, or if the server also need some special functions you could have the bullet class which had the things that both of them wanted and then make a ClientBullet and a ServerBullet which both inhert from the bullet class.

Share this post


Link to post
Share on other sites
Quote:
Original post by graveyard filla
so, for example, on the client i will have a Bullet class.. the server needs this too, BUT, it does not need some of the members (GLuint texture for example).


So what? So it will have an unused texture field. Big freaking deal.

Share this post


Link to post
Share on other sites
It seems reasonable to make the client and server reuse code, if at all possible.

In fact, they could even be the same program.

If you have an object which is renderable, you could potentially either:

- Subclass a base Bullet into a RenderableBullet and a non-renderable one (possibly using the factory pattern)
- Make a Bullet (or indeed anything) using composition, and have some displayable component which is null, empty, or has a dummy value if you're in the server context
- Have the rendering code in the bullet anyway, but just not render anything on the server side (for example, have a method render which takes a View & object, which it then calls View::renderModel or something on). The server-side would have a dummy View object on which renderModel was a no-op

Mark

Share this post


Link to post
Share on other sites
It's not as pretty but another you can do is to #define out unneeded stuff. e.g.


class Bullet
{
// common stuff

#ifdef _SERVER_
bool ExtraServerValidation(...);
// etc
#endif

#ifdef _CLIENT_
void Render();
// etc
#endif
};


Try to do the stuff markr suggested first but if all else fails you can force the issue like above.

Share this post


Link to post
Share on other sites
Quote:
i notice that i am cut and pasting a lot of code


BADNESS!!!

We run the exact same code on client and server. The object, when created on the server, finds that it doesn't have a SoundPlayer or Renderer to play with, and thus won't render itself. The object, when created on the client, finds that it doesn't have an AuthoritativeStateRecorder, and thus won't checkpoint its state. (Loosely, that's what goes on -- in implementation, it's of course more involved)

There are ways of structuring this that is more decomposed and includes less useless code in the server binaries, if you really want to. However, you shouldn't write the same code twice -- that's a receipe for maintainance disaster.

Worst case, you can have a Bullet.cpp, and it uses #ifdefs for SERVER and CLIENT, and then you compile the same file with two different project settings, defining the appropriate symbol. It's not pretty, but it's better than nothing.

Share this post


Link to post
Share on other sites
@hplus

the method you are talking about, is it what markr's second suggestion is? e.g., give a pointer to a specific class as a member of the class. for example, make a RenderInterface* member for Character. on the server this would stay as null, but on the client i would instantiate it. then, i could actually use the exact same code on the client and server, by just checking if its null, and then rendering if its not. is this what your talking about, and is this what you mean by "exact" same code?

my only concern is that a lot of stuff is done in the client thats not in the server, and vice versa. more then just rendering (things like collision detection are slightly different on the server so the server can detect when a player switches maps). how do you account for stuff like that? would i have to make a seperate function that is called from outside of the "shared" functions or something?

i kind of like the idea the AP and mark suggested of having a general Bullet class, with ClientBullet and ServerBullet being in the different projects. to me this is cleaner to look at, and easier to make logic (e.g., when looking at the code, you dont have to think "is this for the server or the client"?). my only concern is this might be harder to maintain. im leaning towards this solution though.

thanks for anymore help.

Share this post


Link to post
Share on other sites
I've met this problem too. I've not find a best way to solve it. I tought to use #ifdef _CLIENT_ and #ifdef _SERVER_ as someone has just said. I think it is better than using inheritance because you'll avoid to see an explosion of classes (2 more classes for each common class (ie: BulletBase, BulletServer and BulletClient instead of Bullet only); the system may become hard to understand in a very short time.

On the other and, I don't like very much #ifdef... #endif code (they make my source no more indented and so a little harder to maintain/read).

However I try always to avoid cut&paste of source (and so I agree with hplus0603): I don't like to debug the same mistakes n times (n = # of cut&paste) ;)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by graveyard filla
i kind of like the idea the AP and mark suggested of having a general Bullet class, with ClientBullet and ServerBullet being in the different projects. to me this is cleaner to look at, and easier to make logic (e.g., when looking at the code, you dont have to think "is this for the server or the client"?).


Yes. It is a modern concept known as "Object Oriented Programming". You should try looking it up, reading a few books - it's interesting stuff. Saves a lot of time and effort when writing code.

Sadly, lots of gits (including more than one university lecturer I've met) decide to teach imperative programming and call it OOP in order, presumably, to save their jobs. WHy the heck else woudl they bother to do this yet not actually teach OOP? Shrug.

Quote:
my only concern is this might be harder to maintain. im leaning towards this solution though.


Um, no. A million (approximately) times *easier* to maintain...

OK, I lied. Proably 5 times easier to maintain. There's things that will make it harder to maintain with OOP, but they're outweighed massively in simple cases like this and/or become vanishingly small, so overall it's definitely going to be a lot easier. Since you don't know OOP yet, I'd suggest not even worrying about it; when doing what you're doing now you have to get into some pretty complex / rare / niche program design to encounter the situations where OOP goes spectacularly wrong and starts costing more time than it saves.

redmilamber

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement