16 Dec, 2011, agesira wrote in the 1st comment:
Votes: 0
Hello. First of all, I'd like to apologize ahead of time if any of this has been answered before (I'm sure it has, but I probably missed a lot in my searches), or if this is in the wrong board.

Now, I suppose I should actually ask the questions. Databases - relational or flatfile? Or perhaps some kind of hybrid (such as player files in files, everything else in databases)? What decisions did you make, why, and have things you have come across reinforced your decision, or made you want to try something else? If flatfile, did you use/do you recommend JSON, XML, or line-by-line reading? If relational, would you use/recommend something embedded (sqlite), or one handled by its own server requiring a connection (mysql/postgresql)?

Now, somebody has suggested to me the idea of procedurally generating my rooms using terrain/heightmaps (reading them in, generating from there). Would you consider this idea? What would be any forseeable issues with this?

What are some major obstacles you had to overcome while creating your MUD, or pitfalls you/others you know have hit? How, if at all, did you overcome them?

EDIT1: Multithreading: should I even attempt it? What things would you run on a separate thread (assuming all sockets share the same thread)?

I'm sure I'll have more questions fairly soon. I again apologize for asking what I'm sure has been answered just short of a thousand times already, and thank you for any responses.

(Oh, just in case anybody has any advice/responses for my setup, or wishes to know for whatever reason, C++, heavy use of Boost (mainly due to ASIO), extended with Lua (class bindings with LuaBind))
16 Dec, 2011, Rarva.Riendf wrote in the 2nd comment:
Votes: 0
database: worth it, ease your life for some stuff, but it is not something the player care about. but dont mix flat files and database, it makes no sense. (you want to revert to a date, will you keep all flat files corresponding to the database history ?…not to mention any synchronising (so a bad idea)
and dont bother using xml/json in flat files if you already have a working parsing system. Those format are to make the data somehow portable, or easier to communicate through different programs. If you do not need it it is a waste of time.

multithreading:definitely no, unless you really really reallly need it. (and that is very unlikely with a text game)

For the rest, your questions are way too context specific. And why creating yet another mud, instead of contribute for one ?
16 Dec, 2011, agesira wrote in the 3rd comment:
Votes: 0
Quote
database: worth it, ease your life for some stuff, but it is not something the player care about. but dont mix flat files and database, it makes no sense. (you want to revert to a date, will you keep all flat files corresponding to the database history ?…not to mention any synchronising (so a bad idea)
and dont bother using xml/json in flat files if you already have a working parsing system. Those format are to make the data somehow portable, or easier to communicate through different programs. If you do not need it it is a waste of time.

multithreading:definitely no, unless you really really reallly need it. (and that is very unlikely with a text game)

For the rest, your questions are way too context specific. And why creating yet another mud, instead of contribute for one ?


Thank you for your response. The database thing does make sense. It's rare that any kind of portability is needed.

And yes, I do suppose a lot of questions were context-specific, but I had attempted to phrase them to learn about other people's experiences to learn from those, as opposed to have people tell me what to do. Different people have different situations, and people often have ingenious solutions and can provide more insight on different situations.

To answer your question, there's a few reasons, honestly. I coded for another MUD for a time (Lithmeria), and enjoyed it enough to try starting my own. I've been MUDding since I was a teen, and have several years of skill (Yes, I do realize it's likely a bad idea to paper-test skills) and lore plans, and I would like to see them see the light of day (or the black of a terminal/client, as the case may be). It's also a bit of an experiment, as I will have players giving input throughout the process.
16 Dec, 2011, Runter wrote in the 4th comment:
Votes: 0
Code translating into actual gameplay concepts isn't a criteria for something being a good idea… You said it yourself. "worth it, ease your life". There you go.

Just forget flat files and use a real database pl0x. The advantages are innumerable, and frankly, it's just easier to develop and maintain than some flatfile solution. Yeah, for really simple problems just dumping a yaml file might make sense, but muds deal in a lot of data with complex relationships. The underlying issues that databases solve are not trivial to solve correctly in flat files. For example, how do you constrain uniqueness across a set of data? It means having to do some type of query independent of your storage technology. Like opening the file name Playersname to see if it exists.

As for the specific database technology, people will tell you to avoid sqlite for a lot of technical reasons, but if the two options are sqlite or a roll-your-own file format… lol, I think that's a whole new magnitude of bad. In other words, I think just about any proper database will work just fine.

Play with multithreading academically, but understand you probably don't need or want the complexity for this project.

My overall advice as it relates to pitfalls is do what's simple and maintainable first. Do profile and gather real data on bottlenecks. Go out of your way to surprise yourself at how something you thought wouldn't be efficient enough was just fine. Once you start understanding the relationship between your needs and the power of modern computing, you'll start taking a hard look at a lot of the code you write and effort you put into maintaining the complexity for machine efficiency gains.
17 Dec, 2011, Nich wrote in the 5th comment:
Votes: 0
If you're not expecting many players (<100) concurrently, then a thread for each socket is a pretty natural feeling way to code a MUD. Client actions are inherently asynchronous, so if the overhead of threads isn't a big problem, you can gain some simplicity from matching that in your code. The main advantage is that you don't need to worry (as much) about one client's actions blocking everyone from acting.

If you're assuming one thread for client processing, I say don't bother.
17 Dec, 2011, David Haley wrote in the 6th comment:
Votes: 0
Nich said:
If you're not expecting many players (<100) concurrently, then a thread for each socket is a pretty natural feeling way to code a MUD. Client actions are inherently asynchronous, so if the overhead of threads isn't a big problem, you can gain some simplicity from matching that in your code. The main advantage is that you don't need to worry (as much) about one client's actions blocking everyone from acting.

Multithreading the way you describe it won't solve the actions problem. It solves the output blocking problem.

Whatever your players do needs to be processed somewhere on shared data. Either you have a master thread somewhere that represents 'the world', or each player thread is responsible for manipulating shared data, or something like that. Regardless, you will have to deal with managing this concurrent access, which means locks – which means that you still have contention over shared data.

Multithreading is great for things like DNS lookup that involves separate processes and blocking and so forth – you don't want the game to hang on something like that. It's also great if you have to use blocking I/O on the network for some reason.

Now, multithreading does provide a more natural feeling of coding in some cases, as you indicated. It makes a lot more sense to look at a main loop from the perspective of a single agent than it does one massive loop handling all input at the same time. But IMHO that's a small gain for the considerable costs and headaches you will incur.
18 Dec, 2011, Nich wrote in the 7th comment:
Votes: 0
Ah yeah, my bad. Operations on shared data will still block, of course. But at least the blocks will only affect a small portion of your population, not the entire MUD (If you're only blocking things that a given player can access, not blocking the entire DB).
19 Dec, 2011, Tyche wrote in the 8th comment:
Votes: 0
agesira said:
Databases - relational or flatfile?


Databases - Object or hash? ;-)

What is it you plan to store the state of? Configuration, players, other things, everything?
Do you plan on editing that state outside of the mud?

agesira said:
EDIT1: Multithreading: should I even attempt it? What things would you run on a separate thread (assuming all sockets share the same thread)?


I would only use it on operations that would block. One could also multi-processing instead of multi-threading.
Multi-tasking or non-preemptive threads are an option for long running tasks.
For example, if you are implementing a scripting engine, what happens if the scripts loop forever, or for many seconds?
19 Dec, 2011, donky wrote in the 9th comment:
Votes: 0
Tyche said:
I would only use it on operations that would block. One could also multi-processing instead of multi-threading.
Multi-tasking or non-preemptive threads are an option for long running tasks.
For example, if you are implementing a scripting engine, what happens if the scripts loop forever, or for many seconds?

They could be time-sliced, or killed. I am not convinced this is a real problem.
19 Dec, 2011, oenone wrote in the 10th comment:
Votes: 0
If you use a Database, use Transactions for write access! Will save your life, if something strange happens while updating it.
19 Dec, 2011, plamzi wrote in the 11th comment:
Votes: 0
oenone said:
If you use a Database, use Transactions for write access! Will save your life, if something strange happens while updating it.


Transactions are nice, but they're by no means a necessity or a substitute for regular database backups.
19 Dec, 2011, Runter wrote in the 12th comment:
Votes: 0
plamzi said:
oenone said:
If you use a Database, use Transactions for write access! Will save your life, if something strange happens while updating it.


Transactions are nice, but they're by no means a necessity or a substitute for regular database backups.


That's what I was thinking, too. Transactions are significant overhead. I'd almost say they're only a necessity when sane backup automation isn't available, or data just cannot be lost. (Think financial transactions). Then again, the overhead is likely to not be that crippling for something with few users. I could go either way with it.

Regardless, if you're not going to use transactions (and even if you are) it's wise to ensure backups. Preferably off-site.
19 Dec, 2011, Tyche wrote in the 13th comment:
Votes: 0
donky said:
Tyche said:
I would only use it on operations that would block. One could also multi-processing instead of multi-threading.
Multi-tasking or non-preemptive threads are an option for long running tasks.
For example, if you are implementing a scripting engine, what happens if the scripts loop forever, or for many seconds?

They could be time-sliced, or killed. I am not convinced this is a real problem.


task inflation(p):
for obj in world
obj.value = obj.value * p

Killing such a task leaves the world in an awkward state.
Time-slicing might leave obj.value open to race conditions.
And disallowing such a task severely limits the utility of embedding the language.

I don't know what you mean when you say "real problem".
19 Dec, 2011, David Haley wrote in the 14th comment:
Votes: 0
If you:
a) want to have scripts that need to run that cannot be interrupted
b) want to turn off scripts that are running too long
then you need some kind of admin-privilege mode where a script can be allowed to run for long.

That said, a good model in this kind of scenario is to never let scripts run for long, and instead give scripts an API to register long-running operations. You could still have a privileged mode to only allow certain scripts to make such a request.
But in such a case, you would want the long-running scripts to run in a separate thread, or at the least, only run in chunks.

For instance, you wouldn't do something like what Tyche wrote. You might do something like:

for obj in world
if we're at the 100th iteration, release control for now
otherwise, do_operation()

Whether or not you rely on the script to do that or force it upon scripts is a separate question. Forcing it upon scripts means that you need to give scripts a locking API so that they can mark data as unavailable for other threads. Letting the script manage it means trusting the script (author) to not do stupid things. Which is the lesser evil? :wink:
20 Dec, 2011, Deimos wrote in the 15th comment:
Votes: 0
The purpose of transactions is data integrity, not data backup. Essentially, the primary use case for them in almost all contexts is to wrap multiple interdependent actions into one action. For example, consider the canonical example: a bank transfer. It consists of two different actions - debiting money from one account and crediting it to another. If either of those UPDATE queries fails, your data is borked, since you're left with either too much money in the system (if the debit failed) or too little (if the credit failed). Wrapping these actions in a transaction means you can rollback changes in the case one of them fails, or commit them if everything went okay.

Anywho, transactions are A Good Idea™ for almost every application, used wisely. If you go with MySQL, make sure you use the InnoDB engine for your tables. It's been awhile since I used MySQL, but I think it defaults to MyISAM. If you go with Postgres, Oracle, or SQL Server, they all support transactions.
0.0/15