Advertisement

Implementing multiplayer in MOBA-like game

Started by June 28, 2015 09:11 PM
14 comments, last by hplus0603 9 years, 4 months ago

Hey,
To begin with I read the FAQ but I did not get all the answers I was looking for, so please do not send me back there :)
I'm developing a game in OpenGL in C++ that is intended to be a multiplayer one. I have a few questions about the approach that I should take when implementing the multiplayer.
I have experience writing client/server applications in Java, never did it in C++.

Below is how I imagine doing it, and I'd like you to correct me if anything I think is wrong.

I want to write the server in Java. It would create a separate thread for each player. The clients would only send the server their inputs, for example a click made by the player so that the character moves, or information that a spell has been cast. The server would calculate the positions of every dynamic object and send it to all players. It would also take care of collisions etc.

Since I'm not familiar with C++ networking, I was wondering if it was possible to somehow make client side also in java and communicate with the game program somehow? I don't think so, but I'll ask anyway :)

There is nothing preventing you from writing the whole thing in Java if you want. There are OpenGL wrappers for Java that you can use for that.

However, if I understand correctly, you would like to have some sort of networking layer on the client, written in java, which would mediate between the server and the client front-end (written in C++ or something else)? Sure, that is possible but then you have three parties involved instead of two and that might not make it that much easier.

In fact, in my engine, the level editor front-end is written in C# and the main engine is C++, and I actually use the network to have the different parts talk to each other even though they both run on the same machine. I find this more elegant than marshalling memory back and forth, and while it makes everything asynchronous it has not been a problem for me.

If you just wrote your whole client in C++ and have it talk to the Java server you would be in the same situation where you just send bytes over the network and have the receiver do something with them, regardless of what language it happens to be written in. I don't really know what you mean by "C++ networking" since it is all about sending and receiving bytes, but there are a number of good networking libraries for C++ that can help you if you don't want to be writing pure socket code.

Advertisement
The cool thing with networking is that one end doesn't know what language/tool/whatever was used to implement the other end.
Only bits on the wire matter.
That being said, if you use complex systems like Java remoting or serialization, then you will have more trouble trying to match that on the C++ side. Simple packets made of bytes in well-defined order are much easier to get robust cross-platform and cross-language.

Thread-per-client is an anti-pattern. Sometimes, you have to do it (such as on older versions of the JDK) but you really should be using Java NIO. Even if you don't, then the threads should only be used to read the sockets; the actual world/game simulation should most likely be on a single thread, unless your system is really, really, special, and you have extensive distributed simulation experience.

Also, sending only inputs to the server means that the server and the client will have to agree on what happens when the client presses "forward" and then keeps it down for 0.28 seconds. How many simulation ticks are those? How is collision detected? Building the same physics engine in both Java and C++ is a big task (unless your simulation is trivial.)

Now, if you really really want to build the networking side of the client in Java, but the rest of the client in C++, this can be done. You'd have to build the "main" of the project in Java, and then expose your C++ code through a JNI interface. Have the Java application run the main loop, run the socket/s, and communicate to the C++ code using JNI each frame. A bunch of games on Android works a bit like this, because the UI is generally in Java, but portable games are generally written in C++, so it can be done. It wouldn't be the simplest way to do it, though. And, if your'e not familiar with Java NIO, and want to create threads-per-socket, then you probably aren't gaining much from using Java anyway.

I'm not saying what you want to do can't be done. I'm just saying that you're not choosing the simplest possible way to build a multiplayer game.
Good luck with your project!
enum Bool { True, False, FileNotFound };
Greyshack, hey feel free to check out my open source engine here to get started. https://github.com/Sivx/Sivx-3DDesktop I'm working on a c# engine so I decided to give out what I did when I was younger. Here's the video for that
">
. As far as networking, I would start looking at Sockets and object serialization until you get comfortable passing objects back and forth and then upgrade to passing only significant bytes back and forth. I would keep the front and back end the same because you can reuse the same game loop just have it recognize its a server so it doesn't load client models. I can create a new open source project with the networking and client code in which I've done before.

As far as networking, I would start looking at Sockets and object serialization until you get comfortable passing objects back and forth and then upgrade to passing only significant bytes back and forth.


While everyone is entitled to offer their own advice, I would disagree with this advice. If you're getting started with networking, possibly across different languages, simple binary blobs-of-bytes, or even just text strings with delimiters, are a much better place to start.
Object serialization is a very different concept, very poorly matched to real-time gaming data, and comes with its own special set of terror related to versioning, security, and compatibility. Can be great in certain situations -- I don't think this is one of them.
enum Bool { True, False, FileNotFound };

@Sivx
The point is that I want my own game engine and my own server etc., I'm doing this because I want to see if I can and apart from that because I enjoy it a lot.

And it's not like I'm only starting, I have the engine working already, animated models and so on. I decided to write the client in C++ and the server in Java after I read that it's not recommended to send the whole structures over the network so it's not like making the server in C++ had that many advantages(and I prefer Java over C++).

So now I am focusing on making the server and there are many things I'm unsure about, since it is my first time. Basically I've decided that positions and collisions will be calculated by server and the client will only receive updates as well as notifications in case his character gets hit etc. And the client will notify the server when the player want to go to a certain position or has casted a spell.

I've just read that in many games such "packets" of data from the server are send something like 20 times per second, and the client somehow interpolates in between to get the smooth gameplay. Do you think its necessary to do this even if there is an 8 player limit ? Because what I intended to do was to have the loop on the server running at 60 FPS and send updates every game update on the server.


@hplus0603
Yeah I have zero knowledge of Java NIO, but actually I'm only using multiple thread to listen to the client sockets. There is only one thread doing the updates of the game state. And since the game isn't very complicated I think I am able to port the engine mechanics to Java without much problems.
And I'm sending only the most important data parsed in JSON strings over the network.

Advertisement

packets" of data from the server are send something like 20 times per second, and the client somehow interpolates in between to get the smooth gameplay. Do you think its necessary to do this even if there is an 8 player limit


And I'm sending only the most important data parsed in JSON strings over the network.


How much JSON? 200 bytes per player? Times 8 players? Times 60 packets per second?
With 40 bytes overhead per packet (assuming TCP, as you use multiple sockets,) you will see about 6.4 Mbps of upstream bandwidth from the server, and 800 kbps downstream for each client.

Can this be done? Yes! Would this be a good idea in a commercial situation? Not really.
enum Bool { True, False, FileNotFound };

20 packets per second, about 100 bytes per player.

What is the best commercial situation? Server in c++ I assume. How to send the data then? As pure bytes in some kind of sequence that I set myself?
Like for example first 4 bytes are player x etc?

I've made the server and everything works and over 300km there is a slight delay, my friend tells me. So I'll be trying to reduce it as much as it is possible.

Is a ping-pong delay test every second a good idea? To take it into account on the server side when calculating.


How to send the data then? As pure bytes in some kind of sequence that I set myself?
Like for example first 4 bytes are player x etc?

Try Google Protocol Buffers: https://developers.google.com/protocol-buffers/

Protocol buffers are alright -- they given you good rigor for data formats, yet some amount of flexibility.
However, they are bigger than the payload needs to be for a game, if you can assume that all players/clients/servers use the same version.

Game networking is built around "only send what you need, no more" and "when sending, only send the precision you need, no more."
For example, if the coordinate of a user is between -4000m and +4000m, and you need centimeter precision, that means you have about 800,000 distinct values.
Twenty bits will allow you to send 1024*1024 values, so a range from -5242.88 to 5242.87 would let you send one value in 20 bits instead of one value in 32 bits, for a cool 37.5% size savings!
Keep applying this thinking to each piece of data, and either don't send it (if you can calculate it) or trim bits if you don't need the full precision, and you will make for much smaller packets.

Note: If there are 8 players, each of which has 100 bytes of data, that's 800 bytes in a single outgoing packet to a single player for a single tick (because that's the updating state for each other player, plus the sync state that lets the player know what the server thinks he's doing.)
Savings there matter. However, because of the overhead of IP (20 bytes,) UDP (8 bytes,) and/or TCP (20 bytes) protocols, and the packetization of underlying networks, there exists a minimum below which you really don't gain much.

If we assume that the underlying network uses ATM, with 48 byte payloads, and IP + UDP (28 bytes of overhead,) then the minimum effective size is 20 bytes of payload (a single cell); the next iteration is 68 bytes of payload (two cells); etc. Other framing systems have different specific grouping rules. A rule of thumb is that if you're sending less than 100 bytes, further savings are better had by sending less frequently, rather than by making the packet smaller. Another rule of thumb is that it's always better to send 1 packet with data A and B to the same destination, rather than splitting it into two packets, one with data A and one with data B -- until some upper limit. For UDP on the internet, that upper limit is at least 1200 bytes, and sometimes a bit more. Various magic constants include Ethernet frame size, IPv6 minimum MTU, WiFi payload size, and 4G mobile data packet size. The often-quoted 576 byte MTU value for dial-up internet is largely a thing of the past, though (luckily :-)
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement