Designing Multiplayer Game Engines?
"Lag is not really critical, but I still want things to be responsive and it must scale up well with the
number of clients. The size of the map data, the complexity of the
objects and bandwidth constraints rule out sending the complete game
state, so only incremental updates will work. The situation is further
complicated by the need to limit updates to just the areas of the map
that are visible to a given player/team - this is clearly necessary to prevent client-side hacks such as gaining full map
knowledge.
I understand the theory well enough, but I'm interested in practical
advice on how to implement a solid architecture. What should the
object model look like? How do I propagate events that are only
partly within a client's field of view? Are there any novel features
in C# that might make my life easier? How can I make the networking code
as transparent as possible so I don't have to write SendUpdate()
after every assignment?"
Your comments, insights, hints and flames are eagerly awaited."
Holy Mac has the transparent networking architecture in a C# framework. It should work well for what you're trying.
worldforge
the mudd developer mailing list is an excellent source of information on exactly this sort of topic... although not specifically regarding the STRATEGY portion of online gaming... most of the issues you have spoken of have already been resolved... take a look at the archives publicly available at https://www.kanga.nu/lists/listinfo/mud-dev
This is why there are companies like There.com. Their job is to create multiplayer game engines solving such networking issues. They do not create the graphics or the game logic, just the multiplayer/networking part that you can then use as a drop-in solution to your game or other application.
Especially considering that, say, Python already has MP libraries. A research paper from UO, another fellow who's trod this path before, several MUD/MOO/MP libraries and games, Merchant Empire, Twisted, Eve, and so on.
Using Python would allow this fellow to achieve his goal of learning a new language, fast. He can then properly focus on the important things: program structure and gameplay.
--
Don't like it? Respond with words, not karma.
Here is the website Terrarium
that's stupid, no it's not! Slower, perhaps, than say, straight C, but who cares?
On a celery 400mhz, limewire, for example, runs fast enough to not feel slow.
If the original poster who posted the question decides not to use java, then at least I would hope he wouldn't use c#. Does c# have features so vastly cool and ahead of other languages, that it would be chosen knowing the limited platforms available?
What's that, most desktops, you say?? Well, when handhelds and other devices become more widespread, wouldn't it be cool to have the game on them as well, with minimal fuss? What about consoles, which seem to be trending towards online-ness, really really this time - only one out of the bunch supports microsoft...this is potentially a bigger market than desktops. Handhelds seem to be comming out left and right, some with their own OS, some with Linux, some with Microsoft...point is on these 'other' types of computers, microsoft does not a monopoly have.
Think about it! Oh yeah, and all the stuff about making deals with the devil, the monopoly stuff, yadah yadah yadah, etc.
The important thing is that I really like the The WorldForge Project (in fact, it's one of my favourite projects (if not the favourite project), promoting the idea of free software to broader audience.
They're doing amazing work and I simply can't imagine what will they achieve in few years, but I'm sure all of current proprietary games won't even compare with those developed as a part of The WorldForge Project
So yes, I think promoring WorldForge is worth losing all of my karma.
Now back on topic...
You may want to announce your plans on the cpptraining at worldforge.org mailing list. It's originally meant to learn C++, not C#, but it's read by people who want to learn how to write MMORPGs, and those who want to and really can learn, like Bryce Harrington, so it's a good place to find people who can help with your project.
Also check out the other WorldForge mailing lists, especially Protocols, Server, Client and General.
Read the Development Area on WWW. Read about servers and clients. Use WorldForge protocols and libraries. Download games and read the source. You'll find there everything you need.
~shiny
WILL HACK FOR $$$
Stuff like "How can I make the networking code as transparent as possible so I don't have to write SendUpdate() after every assignment?" we can't answer. I mean, it's all events, and there are hundreds of ways to write this. There are countless examples. GUIs are event driven, for example.
A long time ago I wrote a multi-user game. It wasn't anything fancy, but it did the basics of what you are trying to do. It turned out that calling SendUpdate() wasn't the problem -- that's easily done with proper design (inheritance, etc). Heck, you can encapsulate the whole message in a class and let the constructor/destructor take care of it, if you want... The main problem was scheduling time to clients, especially when one client was slower than another. For example, it would be unfair for a fast client to send 10 move messages in the same time that a slow client would send one.
Another distinction you need to figure out is what needs to be real-time and what doesn't. For example, if the program supports inter-user messaging, you can implement "soon-enough" delivery rather than "just-in-time" delivery. It all depends what it is used for. That can be done with a MQ type setup rather than a real-time connection, and it can be sent from client directly to another client.
I wish I could work on such a project again.. open sourced, closed source, I don't care, just not commercial. But the internet is littered with the graves of abandoned open sourced programs, which tells me a little about how much commitment people are willing to put into these things.
I made a 3d game engine and in my cleverness, I figured I'd reduce load on the server by offloading the physics asynchronously onto the clients. I learned the hard way that THIS WONT WORK. The reason is that different floating point processors get slightly different answers in some instances. Indeed, if all processors are the same stepping of the same intel processor, you'll be fine, however for example an Athlon might in some rare circumstance be different by the very last decimal point from an Intel. The butterfly effect will eventually catch up to you and the Athlon machine will for example detect a collision where the intels didn't.
Using emulation or fixed point is either too slow or too inaccurate, so I ended up just doing all the work on the server and doing continual sychronization.
To be more precise, in order to smooth out 'lag' time, the clients would do their own emulation, but would resychronize all decisions on the 'heartbeat'. Using interpolation, this worked out to have great apparent lag response, even lag times of 3 seconds were smoothed out. The only problem then was when a client's lag was unstable, fluctuating a lot. I smoothed this out by emulating a 1 second lag in all circumstance, so everyone has a smoothed out lag response which isn't too bad to play. Only unstable lag of 2 seconds or more caused a problem, where that client would see his character jump around everytime synchronization kicked in.
Basically, I've broken it down into 5 objects: Game, Map, Sector, Player and Item. The ownership relationships are as follows: Game owns one or more Maps, and zero or more Players. Map owns one or more Sectors. Player owns zero or more Items.
There are three subclasses of items so far: Trivial (like swords and onions), Units (like tanks and horses), and Charactors [sic] (like Mario or Frodo). There are also interfaces for the items such as Movable and Jumpable.
Check out Metagame-Sector if this model interests you.
The only remaining issue is what we call "who is right?" If one game claims that a ship blew up because it was hit by shot, and another game claims that the ship dodged at the last minute, who is right? If the game is client-server, the answer is easy: the server is always right. In fact, clients shouldn't even display "big" events like a ship blowing up until it has confirmation from the server that that is what really happened. (Sometimes it's a good idea to use "hint" animations - if the client expects that a ship has been hit and is going to explode, but hasn't received confirmation from the server yet, you might want to show a shower of sparks. Then, if the confirmation is received a moment later, the explosition doesn't seem to be delayed quite so much.)
In peer-to-peer, things get much tougher. In some cases one of the peers simply declares itself a server, in which case you have the situation above. In true peer-to-peer, it's simply up to the game designers. The most obvious choice is to make each machine responisble for its own position as well as the position of the objects its has created. So the player controlling a given ship has the last say on where that ship was at any given moment.
In some cases, you may find that certain game elements (especially if it is an action game) don't work very well when you have to deal with 100ms or more of delay on network traffic. In that case you may want to remove or change those elements. You should pick a number where represents your "maximum" allowable delay, based on whether your target audience is modem users or not.
Having used and tested the performance of RMI I would immediately vote against it. It would definitely make your life easier, as it simplifies interface development. It also reduces the work load of interface modification. However, and this is a big however for a multiplayer game, the delays are generaly 50-100% longer than with pure sockets. Considering that you're using a centralized server, which slows the process down even further. I would say that RMI is a plausible but not practical solution.
You might like to investigate Unreal's network architecture for ideas.
"The fact is that up to now, hardware, the OS software and, for the most part, games have been a pay-once/play forever deal. "
Obviously you haven't been paying attention over the past several years.
Ultima Online
Everquest
Asheron's Call
Many many numerous others, I know I paid $10/month for a bit to play Allegiance. Going back in history we have examples at Compuserve and so forth.
Ongoing charges has been a factor of life for multiplayer gaming since almost it's beginning some 20 years ago.
Take your FUD elsewhere, troll. If people find enjoyment with the game and the value of paying per month exists they will do so. Otherwise the game will fail.
In the case of the XBox what I see as viable is for them to have a one time charge to access a large farm of hosted servers that grants access to many different multiplayer games. As things stand right now each different game asks for a seperate $10/month fee. Most people I know do not get addicted to just one game, they may play several, or go months at a time without ever touching one particular game.
~shiny
WILL HACK FOR $$$
He's using broadcast in the more generic sense, not the literal techincal sense.
Not exactly true.
Java has a lot of overhead. But that overhead is there for a reason. Java code gets faster over time as it runs (both due to optimizations done at run-time and the fact that class loading is still an expensive operation). However, in the case of a massively multiplayer environment, Java may be (and probably is) the best choice for the server environment. In a controlled environment where the application is expected to run for a significant amount of time, Java can actually perform as well or better than natively compiled code.
The "Java is slow" argument is soooo tired. Sure, there are many instances where Java is slower than other languages (even C#). But if you're going to knock Java's performance, explain why or shut the f@#* up.
"Don't blame me, I voted for Kodos!"
And Java is like C# in many areas except supporting reflection and other good ideas, unlike C#.
I don't quite understand your sentence, but if you're implying that C# doesn't support reflection then you're wrong. C# has FULL reflection support and goes beyond java (like C# attributes).
Look for the reflection classes under the System.Reflection namespace.
I won't cover the networking problems, because that's not my forte, but rather the issues of physical proximity of players. You have to assume that a player has a limited range of sight and effect to cull the amount of data sent to a player in real-time. Assuming a perfect 56K connection, you can only send about 600-700 bytes per 100msec frame, so (BOE) you can really only send position updates for about 20-50 other players, depending on compression techniques, etc.
Spatial Data Structures (Hanan Samet) describes a set of aglorithms such as quadtrees (2 - 2.5D), and octrees (3D) which can be used to solve the proximity problem in log time in multidimensions, i.e. you can find the N players within a reasonable distance in a pretty short period of time. In fact, you only have to traverse down once, then traverse back up until you're out of range. Insertions are log N as well, so the server should be limited on network bandwidth, not processing power. You can also give priority (send this packet first) to the player that you're looking directly at (or who's looking at you), with diminishing interest in other players (if his back's to me, and mine to him, I don't care quite as much as if I'm looking directly at him),
The second part is "what happens if I don't get a packet for an assigned player in time", a typical UDP problem. In a flight/driving sim game, you can "guesstimate" with an area of probability where the player's going to be, and if you're shooting at him, give the probability of a hit. Sometimes you'll miss when you should have hit, and vice versa, but you have to do something.
Do the canonical system first, with objects in 3-D space which can manueuver and shoot to tune your algorithms on the server, then you can refine the game. Doing a simple "space shooter" should be relatively easy. You can make robo-clients with scripts to test out your weights and probabilities. Once you have the empty space shooter, you can add a world with static objects, which should be replicated on each client. Dynamic worlds (walls falling down, etc.) are much more complicated, where you have to set the before and after on each client, and kick it off with a trigger. Dynamic interactions get a tad too complicated even in single player games.
If you're doing a game with animated players, it's easiest to have pre-programmed positions (running, shooting, slashing with the sword, kicking), so only a code for the target of the action has to be sent down. You can't ship down full animation information, it's too expensive. Unfortunately, it makes fighting unrealistic, because there's no reaction to the pre-programmed code. Doing interactions between figures is an N^2 problem (I block his kick), which while doable, requires a lot of hand-animation work. Full inverse kinematics is computationally prohibitive (AFAIK), but there are approximations that are quite realistic.
Keep your hopes up. There's a lot of stuff out there that's not very good because it was put together in a hurry.
For the networking stuff, try some tuning of packet sizes and rates for different scenarios (modem, DSL, high ping times) to figure out what's most efficient in terms of accuracy and percentage of arrived packets. You should be able to figure out your optimal packet size and rate for each scenario.
Actually, our site doesn't even have ads. Webwasher is blocked because an earlier version of it sent thousands of requests with every pageview, DOSing the server.
--Elefth
Cuiusvis hominis est errare, nullius nisi insipientis in errore perseverare
I've never had to count spaces with python -- and it's been my primary application language for years.
It's a fine point to try to debate with, until you try to actually use the thing and realize it never comes out at all (as opposed to counting curly braces in other languages, which really has happened to me).
Further, Python too can be run in a JVM or converted to C.