Skip to main content
gamedev.net
🔒 Locked

(MM)ORPG server structure

Started by Antriel Feb 25, 2009 at 1:04 PM 11 replies 3.3k views
Original Post
Antriel
Antriel
Well.. time has come to point that making a small mmorpg is probably best next step I can do.. I know I need to be very careful.. I don't want to rewrite thousand lines of code just for finding that tcp packets can be merged during transport.. I want to test my skills by writing small online rpg. It would be tile-based, with small maps, no big features and simple combat system. Now first thing to do is to make a good server structure. The problem I wasn't able to solve myself is how would I manage monsters in game. Movements will be direction (key) based, not point&click. So I need to fire a function for each monster on map every xx ms where xx depend on monster speed. For this I would need thread for each monster (which is unimaginable) or some big thread that will group monsters according their speed and fire a function for all of them.. but.. I don't think that's a good approach.. since I found nothing like a mmo server structure on internet and I don't have time to read thousands of lines of open-source mmos out there... I hope for someone to discuss the best approach to basic (very basic) server structure.
Palidine
Palidine
Think of a server like a local client game. It knows about all the monsters in the world, where they are, and what they're doing.

However, if you send that info to every client out there, you'll die in a sea of overused bandwidth. So you do local updates for each client only. Each client's character gets updates on mob positions/behaviors only for mobs within a certain radius.

So you've got a couple different update cycles. One option:
1) iterate & update all mobs
2) iterate each client and send them only relevant mob positions

do 1 & 2 on a period that makes sense. Client can help out a lot or a little depending on the determinism of your mob behaviors. If the behaviors are completely deterministic you could just tell the client when behaviors change and it will locally simulate them with only occasional periodic updates to correct position/orientation.

And incidentally, i have no idea why you're talking about threads. It's completely orthogonal to the issue you're trying to solve.

-me
folcojp
folcojp

You can try Sun's project DarkStar ( open source ). It makes the server coding a little easier.

You implement the server in java. But the client can run in C, Java, whatever.
Antriel
Antriel
Palidine:
I will explain.
I know what I need to send.. the problem is server calculations (leave the network part behind.. maybe I chose wrong section but it is about multiplayer).
I will have some thread pool for connected players. Some threads for every active map.. but what about monsters? Iterating each one in map thread and sending appropriate info to players on that map.. but how to when monsters have different speeds. Map thread can't just all time check all monsters about if they are willing to make another move or not.
I mean how to organize threads so everything can work in parallel. Like if there is an NPC and Monsters on map and some player make a request for NPC.. map thread will be the one resolving it and what would happen when monsters are on the move? I can't have player to wait for it even if we are talking just about few ms. How would I design such thread?

while(true){
checkPlayersRequest();//will check if some player on this map wants something
moveMonsters();//will check if some monster on map finished move and want to move again...
}

I'm just looking for best approach.

folcojp: since this is more like learning project than trying to do something real... I would like to write everything from scratch.
hplus0603
hplus0603
Typically, you will use a priority queue that maps from "time" to "action."

Each monster would add itself into the queue when created, telling the queue that "at time now plus 3 seconds, call my "maybeDoSomething" function."

Inside maybeDoSomething, the monster will check whether it needs to do something, and if so, set itself up for doing that. If not, then the monster simply re-adds itself to the event queue for another 3 seconds.

Adjust the value "3 seconds" to whatever works best for your system.

In the main loop, you'd simply do something like:

  while (true) {    poll_network();    now = current_time();    eventqueue->run_events_until_time(now);  }


enum Bool { True, False, FileNotFound };
Antriel
Antriel
That sound logically.. and if I make extra thread(s) for lower priority actions that can take more time to calculate.. it would not affect high priority ones.. well now just to find some time and make some diagrams.. thanks :)
hplus0603
hplus0603
Quote:
if I make extra thread(s) for lower priority actions that can take more time to calculate.. it would not affect high priority ones


Only if you have a multi-core CPU. Even a lower-priority thread will typically run out its scheduling quanta once scheduled -- and that quanta might be as big as 100 milliseconds, even if the pre-emption interval is much faster.

Also, if you have a low-priority thread that grabs some lock to safely access some shared data, and then gets pre-empted, then the higher-priority thread, if it needs that same lock, will stall waiting on the lower thread until it gets re-scheduled and can finish what it's doing and relinquish the lock (known as priority inversion).

You have to be quite experienced and skilled with threading to create a threaded system that actually leads to higher performance, lower latency, and better user experience than a single-threaded system when it comes to highly coupled systems like an ORPG server. I think the idea of "work items" and a shared work queue with multiple worker items is much more likely to lead to reasonable scalability and performance.

In fact, your task queue could be the work item queue for the threads. You may want to enqueue the network I/O task for a known interval (say, 50 times a second), and/or let networking be done as an "idle" task that gets executed when nothing is currently due in the queue.
enum Bool { True, False, FileNotFound };
Antriel
Antriel
I'm used to java blocking tcp so I need to use threads... I need to create a diagram to find all of dependency for synchronization... but for now I see it as infinite tasks loop... thread pool for connections..
the idea about thread for lower priority jobs was not about making another low priority thread.. but the same thread that will only do jobs that take longer to calculate.. so I can do a few quick tasks while not waiting for long task.
I need to finish reading my java threads book.. I know using threads is hard.. and sometimes it is better to use one thread programs but if I'm afraid of threads.. I can never learn them.
Kylotan
Kylotan
So wouldn't it make sense to learn non-blocking sockets at this point instead?
Antheus
Antheus
Quote:
Original post by Antriel
I'm used to java blocking tcp so I need to use threads... I need to create a diagram to find all of dependency for synchronization... but for now I see it as infinite tasks loop... thread pool for connections..


There are considerably bigger problems with Java's 1.0 networking than blocking. For example, you cannot determine how much you have written to the socket, which is a fairly common task.

The lack of this option alone is enough to cause server to wait indefinitely, causing the client to time out.

Either use UDP, or NIO. Default java sockets are only useful for blocking RPC, and that design is simply inadequate at best, and downright catastrophic on unreliable connections (not LAN).
Antriel
Antriel
I briefly looked at java.nio and it really seems that using it will be better. Thanks.
I hate that for any new project I start I need to read couple of books.. but somehow I like that feeling that I always have something new to learn.
hplus0603
hplus0603
Quote:
I hate that for any new project I start I need to read couple of books


Welcome to life as a programmmer! I've sold software for 25 years, and still have that "problem." (I actually like it!)
enum Bool { True, False, FileNotFound };
Antriel
Antriel
Yeah.. I like it too.. the only problem with it is time. I'm in school alt-tabing between word and some pdf.. I come to home and read.. read... sleep... I somehow fail to find time to actually use skills I already have :) Then after couple of dreamless nights I came to point which I call total exhaustion or burn-out.. at that time I don't even want to do favourite part of my work.. playing games..
But that's a little off topic..

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.