7
\$\begingroup\$

I am working on a MUD engine and I want to do it a little differently then all the MUD games I played. I find a "cycle" system very boring. One of the idea I had is to make every clients socket working in their own Thread. I am aware that it wont end with hundreds of player but I would like to know if there are problems creating "alot" of thread in a single process.

Or, what other strategy I could use if I want to make it (eg. combats) in "real-time".

I hope you guys understand the question.

Thank you.

\$\endgroup\$

4 Answers 4

14
\$\begingroup\$

MUD cycles are generally not there because the server has trouble processing everything within the available time or serving network requests fast enough. They are there because spamming commands as fast as possible should not be a valid tactic.

Simply have a cooldown / charge-up timer associated with each ability. Depending on your social design this might also include "move" and "speak", or not.

Generally, having more than one thread per core for network processing in a game is pointless. If you are packet-processing-bound, then a thread per core will be maxing out your system - more threads would just starve the others of CPU time they need. If you are not packet-processing-bound, a thread per core is small enough that it won't affect the rest of the system via too many context switches.

\$\endgroup\$
5
  • \$\begingroup\$ Exactly what this person said :) \$\endgroup\$
    – speeder
    Commented Oct 8, 2010 at 0:38
  • 3
    \$\begingroup\$ Damn enter thing... Anyway, I saw once a MUD without cycle, and it sucked, because some players would make some wierd macros on their client, and when you went to PvP with them, they would easily pummel you do death by sheer command flooding, even if they were weaker, they sometimes would hit you several times before you had the chance to even read what was going on. \$\endgroup\$
    – speeder
    Commented Oct 8, 2010 at 0:40
  • \$\begingroup\$ Hmm I see the point there but adding different commands an inner lag (combat command 3s, movement lets say 2s, and socials 1s) I believe it would fix that problem. The other battles texts will constantly display. Some players will hit more / faster depending of their stats. Thats my thought of what I would like to do \$\endgroup\$
    – Cybrix
    Commented Oct 9, 2010 at 14:16
  • \$\begingroup\$ that was the idea behind the whole thing. I just can't figure it out if it all runs in the same single thread. It looks like a big loop to me to see if any player have a command buffered and then execute it. But what about the regular attacks commands (similar to "white damage" in WoW)? \$\endgroup\$
    – Cybrix
    Commented Oct 9, 2010 at 14:20
  • \$\begingroup\$ Run your game logic update at some fixed FPS, e.g. 30. Damage that occurs every 2 seconds occurs every 60 frames. It's just a normal game loop, but without the render() call. \$\endgroup\$
    – user744
    Commented Oct 9, 2010 at 15:22
5
\$\begingroup\$

Sorry about thread necromancy, but this problem is my FAVORITE pet-project for learning and teaching concurrency models and frameworks!

Running every client/mob in their own thread does give a natural division, but as several have noted threads are expensive when you use more of them than you have CPU cores. If this isn't a compelling reason not to use it in your MUD, it's still a good reason to learn a better way.

Running all clients in a single fixed-time game-loop, with actions taking some number of loops, is a familiar method from the world of graphical games. It does bind everything in the world to the same time-cycle, although making the loops sufficiently fine-grained can mask that. The main drawback of this method, as I see it, is that it is not inherently parallelizable. Someone noted that you can create threads to offload constructing/parsing/transceiving I/O, running AI and so on to other threads, but getting the main game logic parallelized requires a fundamental change and a lot of work to keep things thread-safe.

If you did all of that work, you'd probably end up with something akin to my current favorite, the Actor model (http://en.wikipedia.org/wiki/Actor_model). The Actor model is a time-sharing strategy that ends up working out pretty close to what you were proposing with the one-thread-per-client idea. Using it, you code your "Actors" like they're standalone threads, with a few restrictions: they must be event-driven, and they can only communicate with the rest of the system by passing messages (which is different but simple). The event-driven bit makes room for your truly-independent-timing, by scheduling Actor-specific events to fire at particular times, e.g. when an action is completed or at some client-specific frequency.

Under the hood the implementation uses a queue (or queues) of messages being generated by all the actors, and a pool of threads matching your # of CPU cores. The threads pull messages off of the queues and the invoke the recipient Actor's message-handling methods to handle them, running in the context of that Actor until the message is "handled". From your point of view, each Actor gets its very own thread whenever it is actually running, but from the system's point of view there are only as many threads as there are CPUs to run them.

There are some great Actor frameworks out there, namely Erlang/OTP and Akka, but the basic idea is simple enough that you could implement it in any language without the additional fuss of a framework.

For completeness, the Actor model is really just the combination of message-passing for thread safety, event-driven programming for concurrency, and a thread dispatching mechanism. If you were to remove the thread-dispatch bits, you'd be left with a "reactive" system, which is very in vogue for scalability in general right now (see http://www.reactivemanifesto.org/). You could then map execution to multiple machines in a cloud or whatever... you get the idea... which is all to say that your MUD programming project may be teaching you marketable programming skills. Hooray!

\$\endgroup\$
2
\$\begingroup\$

You could allow combat commands as they come in and then add a time delay after commands based on how long they would take to execute.

Dragonrealms uses this method for combat as well as many other actions, it is called Roundtime there. Heavier weapons get a greater time and you can reduce it, but not eliminate it with strength and agility.

\$\endgroup\$
2
  • \$\begingroup\$ That is exactly my idea behind. But I thought I would drive it with multi-threaded clients. But now I hear its not a good suggestion suggestion :P \$\endgroup\$
    – Cybrix
    Commented Oct 9, 2010 at 14:18
  • \$\begingroup\$ why use threads beyond what you may use for sockets/communication? \$\endgroup\$
    – lathomas64
    Commented Oct 9, 2010 at 16:11
0
\$\begingroup\$

Networking is serial in nature anyway (at least until you get into multi-Tbps fibre-optic lines). Having one thread for network I/O separate from game logic and maybe some autonomous agent threads makes sense. Everything else is overkill.

\$\endgroup\$
1
  • \$\begingroup\$ If you've got multicore machines I would recommend more than one network thread (up to one per core); while each socket is network-limited, reading the client requests and constructing the game-state / RPC-response packets to shove back into the sockets is almost perfectly parallelizable. \$\endgroup\$
    – user744
    Commented Oct 7, 2010 at 17:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .