02 Apr, 2009, Scandum wrote in the 61st comment:
Votes: 0
David Haley said:
I guess it's your turn to be friendly and charitable. If somebody says A is better than B because they're ignorant about B, there's not a lot of misinterpretation to have other than on the part of the person making the claim…

You take the words right out of my mouth there. I know relatively more about Lua than anyone here knows about mrmud's mobprogs, so yes, you're so ignorant you can't really say anything sensible, other than 'hahahahahahaha'. Elanthis is so clueless it's not even funny. I'm starting to doubt that he actually saw the source code, though it's cute if he tried to look at it just to have an opinion, and even cuter that you echo his opinion, it's like watching the seven dwarves march in line.

David Haley said:
I've found that mudprogs are actually quite difficult to extend, because the internals of the parsing are all icky.

Somehow I'm not surprised that part has you and elanthis stumped, but on the bright side, you can just hack in lua support which is a no brainer.
02 Apr, 2009, David Haley wrote in the 62nd comment:
Votes: 0
You're really being serious, aren't you, and not just insulting people to save face? You are completely seriously proposing that mudprogs are more powerful than Lua…?

Well, I didn't have much luck last time around, but I might as well ask again on the remote possibility that you actually have some clever observation to make: please provide backup for your claim. (No, restating your claim does not count as backing it up.)
02 Apr, 2009, elanthis wrote in the 63rd comment:
Votes: 0
Act like an adult or just drop it, dude. You're not even trying to make technical arguments anymore, you're just throwing around personal insults and vague hand-wavey claims. You're not fooling anybody, you're not making me magically believe that you're right, you're not magically making other people believe that you're right, and you're certainly not discrediting anyone but yourself with that kind of behavior. If you just want to insult people because they refuse to believe that your smelly crap is really gold nuggets, kindly go screw yourself and quit filling the boards with irrelevant trolling. This flame war crap between us is actively harming the site, and you and I both need to cut it out. I accept blame for starting this one, I'm sorry I needlessly made a crack about your design tastes, now let's please quit filling the Coding & Design board with this bullshit.

Of course I looked up mrmud mobprogs because of your comment on it. I enjoy language design and implementation, it's my second greatest intellectual passion after game design. I thought maybe it would be cool to check out since I've never actually looked at any mobprog implementation in detail before, and I figured that maybe if you pointed out that one in particular above all the others, it might be really good – I know you have a firm grasp on the core technical aspects of programming and tintin is decent so clearly you're not a complete crackpot. I looked at a copy of mrmud I found on ftp.game.org through Google (this code here – if that's not the code you're talking about, please provide a link, because that's all Google is showing for mrmud besides a bunch of non-MUD crap). I saw a bunch of spaghetti code barely cobbled together that looks like the kind of crap I wrote when I was 16, and I mean that very literally. I posted that to make it clear that mrmud's mobprogs are not in any meaningful way better than Lua, because it to me clearly just boils down to a novice-level implementation of a batch command language, which isn't at all useful… especially when the original poster asked about using Lua or a similar tool as a _replacement_ for mobprogs.

If you want to actually debate the merits of mobprogs with something approaching an actual fact (e.g., "here's how easy it is to add new functionality to mobprogs, can anyone show me how easy it is to add that same functionality using Lua?") then by all means PLEASE DO SO! That is good stuff that everybody benefits from!! That's what the forum is for!!! Otherwise, there's nothing more to say on the topic.
02 Apr, 2009, Scandum wrote in the 64th comment:
Votes: 0
elanthis said:
I looked at a copy of mrmud I found on ftp.game.org through Google (this code here – if that's not the code you're talking about, please provide a link, because that's all Google is showing for mrmud besides a bunch of non-MUD crap). I saw a bunch of spaghetti code barely cobbled together that looks like the kind of crap I wrote when I was 16, and I mean that very literally. I posted that to make it clear that mrmud's mobprogs are not in any meaningful way better than Lua, because it to me clearly just boils down to a novice-level implementation of a batch command language, which isn't at all useful… especially when the original poster asked about using Lua or a similar tool as a _replacement_ for mobprogs.

I never said it was better than Lua, that'd be silly, just that it's better suited for developing mobile programs. Despite your odd claims it is tokenized, you'd have to look at merc22 to see the entirely string based implementation, and emud to see a more refined implementation of mrmud's mobprog engine.
02 Apr, 2009, flumpy wrote in the 65th comment:
Votes: 0
elanthis said:
Ah, didn't know Java had that. I definitely need to pay more attention to the Java world, I guess. :)

I would highly suggest avoiding using numeric levels for access control. One of my friends running an RO server on eAthena just bitched to high heaven last night about that very issue, because he can't mix-and-match permissions. It's fairly easy to just define a set of permission and either assign those to users individually or assign them to permission groups and attach a user to a group. e.g. the GM group might have the KICK, TELEPORT, SPAWN, SUMMON, and INSPECT rights; the Support Staff group though might just have KICK, INSPECT, and TELEPORT; and the Builder group might have TELEPORT, SPAWN, and INSPECT.


yea i think i put a value in there at one point so i could debug the comparator.. i couldnt work out how it was comparing the permissions to each other and i think it got left in!
02 Apr, 2009, elanthis wrote in the 66th comment:
Votes: 0
Scandum said:
I never said it was better than Lua, that'd be silly, just that it's better suited for developing mobile programs.


You said it was both faster and had better "variable support," which would be two potentially meaningful ways that they're better than Lua. I contend both claims with reasons given above, and some more explanation below.

I would still like an explanation of _why_ you think mobprog handles those better. Not because I think you can't prove it and I want to see you flail or anything; I just want to know what it is you're evaluating this on so that either I can learn where you're coming from (and maybe I will learn something useful) or to help you understand where I'm coming from (and maybe you will learn something useful).

If it's just an issue of syntax, I note that Lua makes it easy to get custom syntax – you can get a parser for a syntax equivalent to mobprog, in less lines of code (by writing the mobprog->Lua token filter in Lua), and that executes on top of the Lua runtime with all its advantages. Win-win.

Scandum said:
I never said it was better than Lua, that'd be silly, just that it's better suited for developing mobile programs. Despite your odd claims it is tokenized, you'd have to look at merc22 to see the entirely string based implementation, and emud to see a more refined implementation of mrmud's mobprog engine.


We are talking about the code at the same link, right? Looking at it, it definitely isn't tokenizing the input separate from just scanning the string as it parses (if you take tokenize to mean "finds delimiters" then sure, it's tokenizing, but that's like comparing strtok() to lex). The if-statement parser for example (around like 284) just scans ahead, finds delimiters, and passes the resulting text in to be evaluated. At no point is the code performing any kind of lexical analysis other than "where's the next break," and at no point is any kind of true grammar parsing going on (I can't think of the technical term to separate basic string lookahead parsing and something like a syntactical analysis engine, e.g. a recursive-descent parser). Most of the parsing code in mrmud could be replaced with a few regular expressions and it'd be smaller (possibly faster – would depend on the regex engine used and the quality of the regular expressions themselves, naturally).

The emud mogprog engine is _much_ better. You should've linked that one from the start instead of mrmud. :p

It still could use a real lexical analysis/tokenizer, though, for the same reasons I expressed for mrmud. For example, the if-statement check does the magic for parsing the $ variables. With a real tokenizer/lexer, you can find those symbols at any point, and parse/evaluate them at any point. It makes the grammar easier to extend, too, because then instead of needing a bunch of string parsing/comparison/searching in each statement's code you can instead rely on the token stream. It also makes it way easier to extend ifs to have full expression support (including more operators, parenthesized expressions, operator precedence, variable lookup, etc.).

It's just so much easier to read and extend when you can write a parser that looks like the pseudo-C below (it's an execute-as-it-parses engine, like mobprogs, that requires no AST or other intermediate form – slower by far, but much simpler).

void parse_statement(int eval_flag) {
// parse a simple if/if-else statement
if (accept(TOKEN_IF)) {
// if is always followed by an expression and then a newline
test_result = to_boolean(parse_expression());
expect(TOKEN_EOL);

// parse if body
parse_block(eval_flag && test_result);

// if there's an else clause, parse it, but only execute if first block is false
if (accept(TOKEN_ELSE)) {
expect(TOKEN_EOL);
parse_block(eval_flag && !test_result);
}

// follow up with an end
expect(TOKEN_END);
expect(TOKEN_EOL);

// not an if-statment, must be a command
} else {
expect(TOKEN_IDENTIFIER, &name);
while (!accept(TOKEN_EOL))
argv[argc++] = parse_expression();

if (eval_flag)
execute_command(name, argv);
}
}

// parse a set of one or more statements
void parse_block(int eval_flag) {
while (!peek(TOKEN_ELSE) && !peek(TOKEN_END))
parse_statement(eval_flag);
}

// main body of script
void parse_main() {
while (!accept(TOKEN_EOF))
parse_statement(true);
}


That's just a very simple example pulled out of my ass. Adding in a simple lexer is easy (implementing accept/expect/peek, all on top of a simple get_token), especially for simple grammars. I'll leave that as an exercise to the reader. :) Overall, the code ends up being more compact than the mobprog code, the grammar is easier to extend, and right out of the gate you can get a lot more power and features than mobprogs. And you can give it an identical syntax if you want, modifying what's there is pretty easy.

That's the kind of stuff David and I were referring to when we talked about extensibility. Adding a new variable to mobprog is easy, sure: add in a new if (strcasecmp(blah, "foo")) and the code block and you're done. Not really harder in Lua. The mobprog system makes extending the core grammar itself far harder though because any grammar extension requires an entire set of string chopping code, possibly a bunch of code duplication, etc. Extending a parser like Lua's (in terms of C) on the other hand is very easy because you usually don't even need to modify the tokenizer, and the grammar parser (while being fairly terse and ugly) is easy to extend with all new grammar rules, including (if you so want) rules that makes mobprog-like behavior easier… though I'd just write a token filter in Lua itself instead since that's even easier. :)

Extending grammars can be important for a domain language like this because some MUDs want some very specific behavior that is not expressible with a simple language like most mobprog languages. A general purpose language like Lua can express any kind of behavior, but it's entirely true that the syntax required may be more complicated than a domain language might require. If a mobprog engine were implemented using a complete lexical/semantic analysis engine (tokenizer and grammar parser) then you could easily extend them with whatever additional behavior a specific MUD might want.

The biggest advantage of using a full script engine (Lua or anything else) is that you have zero limitations, and you get a very high-performance runtime for almost zero effort. The second advantage – and this is what I believe kills any notion that mobprogs have a place here at all – is that a script language makes it easy to just develop a mobprog like syntax on top of the existing runtime. You could part the emud mobprog parser to Lua and cut its code size down to a fraction of what you have, for example, without losing any functionality.
02 Apr, 2009, Scandum wrote in the 67th comment:
Votes: 0
elanthis said:
You said it was both faster and had better "variable support," which would be two potentially meaningful ways that they're better than Lua. I contend both claims with reasons given above, and some more explanation below.

I would still like an explanation of _why_ you think mobprog handles those better. Not because I think you can't prove it and I want to see you flail or anything; I just want to know what it is you're evaluating this on so that either I can learn where you're coming from (and maybe I will learn something useful) or to help you understand where I'm coming from (and maybe you will learn something useful).

You'd probably want to see expand_line_mprog in db.c where basic tokenization and debugging takes place. Commands and socials are indexed so they directly point to the actual function and need no further lookup. While the if check body isn't tokenized it should still be parsed at pretty fast speeds. Overall it should be faster, but I'm not sure by how much. Variable support is embedded in the "quest" ifcheck and offers the best compromise between speed, memory usage, and flexibility I've seen to date.

elanthis said:
That's just a very simple example pulled out of my ass. Adding in a simple lexer is easy (implementing accept/expect/peek, all on top of a simple get_token), especially for simple grammars. I'll leave that as an exercise to the reader. :) Overall, the code ends up being more compact than the mobprog code, the grammar is easier to extend, and right out of the gate you can get a lot more power and features than mobprogs. And you can give it an identical syntax if you want, modifying what's there is pretty easy.

Looks a lot like what emud does in execute_mob_prog, and it's easy to extend the core grammar if you understand the level based approach it uses.

Emud's if check and internal variable parsing is iffy, but it gets the job done.

I agree that ideally you'd want to implement a mobprog like engine in Lua, but if it doesn't precompile the code I'm worried about performance, and also the amount of effort involved in merging things properly. My MUD is running 80K lines of mprog, so a performance hit could be problem. It's hard to determine efficiency until you really put something to the test. Precompiled PCRE regular expressions for example are 2 times slower than tintin's (v1.99) regular expression parser, and 6 times slower uncompiled.

I think a Lua implementation would also need to add support for a O(1) or O(log n) lookup for commands, which can be tricky for C muds.
02 Apr, 2009, David Haley wrote in the 68th comment:
Votes: 0
Scandum said:
Overall it should be faster, but I'm not sure by how much.

Well, when discussing performance it's usually better to just profile instead of suppose, as suppositions are often wrong unfortunately. As you said later, performance claims are very hard to make and basically impossible to back up until something's actually put to the test.

Scandum said:
but if it doesn't precompile the code I'm worried about performance

It depends on what you mean by precompile. It gets compiled to byte code, in any case.

Scandum said:
My MUD is running 80K lines of mprog, so a performance hit could be problem.

Check out the benchmarks on Lua's performance. 80k lines is nothing, really, in terms of affecting performance, considering how utterly simple mudprogs are in terms of their logic.

Scandum said:
Precompiled PCRE regular expressions for example are 2 times slower than tintin's (v1.99) regular expression parser, and 6 times slower uncompiled.

Are apples being compared to apples here?

Scandum said:
I think a Lua implementation would also need to add support for a O(1) or O(log n) lookup for commands, which can be tricky for C muds.

Lua table lookup uses efficient hash tables, so it would certainly be in that range.
02 Apr, 2009, Lyanic wrote in the 69th comment:
Votes: 0
David Haley said:
Scandum said:
I think a Lua implementation would also need to add support for a O(1) or O(log n) lookup for commands, which can be tricky for C muds.

Lua table lookup uses efficient hash tables, so it would certainly be in that range.

It's average case constant time complexity (the forum refuses to display big-Theta), worst case of O(log n). All operations (lookup, insertion, deletion) on the tables are constant best case time complexity (forum won't display big-Omega). I'm not sure any lookup (or other table operation) can be worst case (big-Omicron) constant time complexity, though. Anyone feel free to correct me if I'm wrong…
02 Apr, 2009, elanthis wrote in the 70th comment:
Votes: 0
Scandum said:
I think a Lua implementation would also need to add support for a O(1) or O(log n) lookup for commands, which can be tricky for C muds.


Lua tables provide O(1) efficiency, and since Lua functions (include c-functions) are first-class values, you can just create a table full of functions that implement either commands or dynamic variables.

If you have O(1) lookup, what is all that massive if(strcasecmp()) else if (strcasecmp()) else if (strcasecmp()) stuff in the mrmud and emud code doing? That looks an awful lot like O(N) to me. (I'm at the cafe and I try not to download things on their net, so I'll have to wait until later this evening before I download and browse the emud code again to look up the other stuff you pointed out – sorry.)

Is emud storing the compiled program somehow that I'm not seeing? It looks to be an immediate execution engine, which means it's parsing the mobprog every time it runs, instead of storing compiled disgustingly-high-efficiency bytecode (literally the best in the industry; Lua was one of the first dynamic VMs to make use of register-based bytecode instead of a stack machine, and has proven it to be a superior model in performance – HUGE Lua scripts are used for very complex AI and game scripting in a number of commercial games, including on MMO servers).

Remember that the Lua parser is designed _specifically_ for chewing through massive amounts of text as fast as can possibly go. Its original design was as a data file format for geological databases, so it had to process very huge (especially at the time) files full of structured data. The scripting capabilities grew on from that as developers were using the Lua data file parser for some data-as-code purposes and needed basic evaluation. The features grew from there, until Lua introduced the (literally) revolutionary high-performance VM it has today… all without sacrificing the speed of the parser. Lua's only weakness in terms of performance is that – since it lacks an intermediate representation between the source and executable bytecode – it can't perform high-level aggressive optimizations (which mobprogs certainly are not doing either, of course – almost no script languages do, honestly). That is a conscious design decision by the developers, though, again because they need to parse those huge files without any kind of optimizer overhead either in terms of memory or CPU.

Note also that Lua includes a very high performance expression engine that is not based on PCRE (which is pretty big, and an utter mess internally – I tried submitting some patches for performance to that a year or so ago and gave up on it after realizing I'd have to rewrite over half the internal functions to get the memory optimization I wanted in place) and which will work just fine for most source->source translations.

Just to be clear, the idea of a token filter is that you transform the source language (mobprog) into Lua source, and then compile that into executable bytecode, which you keep around. So doing mobprogs on Lua will incur no runtime overhead, only a tiny bit of extra overhead on first compilation (and if you can even notice the different, either your machine you're running on is literally ancient, or your Lua token filters are doing something crazy).

As a final note, there are at least two Lua JIT-machine-code engines available, which means you can get scripts that compile directly into machine code. Zoom zoom!

(Note that most of this is not really Lua-specific. The same is true for Ruby, JavaScript/SpiderMonkey, Python, and so on. I just stick to Lua because the C API is the best embeddinig API for any general purpose script language I have ever seen, period.)
02 Apr, 2009, David Haley wrote in the 71st comment:
Votes: 0
Lyanic said:
I'm not sure any lookup (or other table operation) can be worst case (big-Omicron) constant time complexity, though. Anyone feel free to correct me if I'm wrong…

Sure you can, if you know something about the values you're storing, and can design a hash function to distribute hash codes based on those values. But it's also worth noting that the theoretical worst case is almost irrelevant in this case.
02 Apr, 2009, Lyanic wrote in the 72nd comment:
Votes: 0
David Haley said:
Lyanic said:
I'm not sure any lookup (or other table operation) can be worst case (big-Omicron) constant time complexity, though. Anyone feel free to correct me if I'm wrong…

Sure you can, if you know something about the values you're storing, and can design a hash function to distribute hash codes based on those values. But it's also worth noting that the theoretical worst case is almost irrelevant in this case.

I suppose. Now that I think about it, I can imagine an example where it's just basic arithmetic operations to calculate a memory address on the lookup, thus constant time. And yes, the worst case is irrelevant.
02 Apr, 2009, David Haley wrote in the 73rd comment:
Votes: 0
Constant-time lookup performance is a factor of distribution in the buckets, not the cost of the hash function (which is kindasorta supposed to always be constant-time w.r.t. the hash table size).
02 Apr, 2009, elanthis wrote in the 74th comment:
Votes: 0
Hash table with a perfect hash function and a load of 1 is O(1). While perfect hash functions don't actually exist, hash functions that are close enough for all practical purposes for specific domains (e.g. short alpha-numeric strings, like identifier names) are in common use. Combine that with a rebalancing hash table implementation (which can make table insertion O(N) in the worst case, but still O(1) in the common case) that keeps the bucket load low, and you essentially have O(1) lookup.
02 Apr, 2009, Scandum wrote in the 75th comment:
Votes: 0
elanthis said:
If you have O(1) lookup, what is all that massive if(strcasecmp()) else if (strcasecmp()) else if (strcasecmp()) stuff in the mrmud and emud code doing? That looks an awful lot like O(N) to me. (I'm at the cafe and I try not to download things on their net, so I'll have to wait until later this evening before I download and browse the emud code again to look up the other stuff you pointed out – sorry.)

Is emud storing the compiled program somehow that I'm not seeing?

The if body parser is only a small part of the engine and is admittedly O(n) though it has some optimizations and could easily be changed to be O(1), mud commands and socials are O(1).

The tokenization structure:
struct mob_prog_token
{
NPC_TOKEN * next;
NPC_TOKEN * prev;
bool type;
char * string;
sh_int value; /* value of command/social table */
void * function; /* Which do_fun to use */
bool level; /* Nesting level */
};


If, or, else, switch, case, endswitch, endif are indexed, including their nesting level. Mob progs are primarily evaluated based on their nesting level, the Obj progs are actually converted into a binary tree but the interface is horrible.

If I understand the concept of Lua's bytecode right it should be pretty fast. I'm doubtful if O(1) mud command access is possible in Lua (due to API limitations) without using a pre-parsing hack, then again that may work well: converting mob progs to lua rather than have lua emulate mob progs.
03 Apr, 2009, elanthis wrote in the 76th comment:
Votes: 0
Which API limitations are you referring to? It really is as easy as just storing them in a table and looking up the command by identifier. If you are pre-analyzing the command names during parsing like you do in mobprog, you can store them in a numerically indexed table (which is optimized to function identically to an array in any other language) and definitely get true O(1) best/worst case lookup. Nothing stops you from implementing the core mobprog commands in a C function that just uses a switch statement (and the optimizations GCC uses for switch statements with singly-incremented case statements) if you have reason to believe your C code is faster for that particular case.
03 Apr, 2009, JohnnyStarr wrote in the 77th comment:
Votes: 0
Hey, i know you guys are on a specific topic within the thread, but i had a question and didnt want to start another similar thread for it…

I know allot has been said about embedding Lua or using Mobprogs. But i'm looking into doing something similar, basically i want to have scripts for my rooms but because i'm using ruby i dont know if it would be better to write my own very basic scripting commands / language. or just write pure ruby and run it on the fly?

any ideas?
03 Apr, 2009, Grimble wrote in the 78th comment:
Votes: 0
staryavsky said:
…because i'm using ruby i dont know if it would be better to write my own very basic scripting commands / language. or just write pure ruby and run it on the fly?

I think one of the criteria for deciding was touched on earlier, and deals with security and how much you trust the scripts to play nicely. Rolling your own language will allow you to decide which MUD and host resources the scripts have access to and under which conditions (generally referred to as sandboxing). Existing script languages may allow this to varying degrees as well (e.g., Lua does, but I have no clue about Ruby). So if your scripts are generated by builders only, and you review them before they go live, security probably isn't a concern and you could opt for whatever is easiest.
03 Apr, 2009, elanthis wrote in the 79th comment:
Votes: 0
Ruby, iirc, has sandboxing support. I haven't played with the embedding API since 1.6 or 1.7 though, so I don't really recall how complete it was. You want to look up 'tainting' i believe, as well the support for const data.

If you're using Ruby and you want a simple macro language, it would be easy to roll one. It's pretty similar to what Scandum and I are discussing: do you want to use the Ruby syntax for your room stuff or do you want something that better handles the domain you're working on (e.g., room descriptions) ?

Given that template languages are in common use for PHP, Ruby, Python, and so on, I think it's fairly commonly accepted that code expressed in a general-purpose language does not always best fit the problem being solved, so if you feel that you're better off with a macro language, you're totally justified in implementing one. I wouldn't be surprised if there's already some Ruby examples or libs out there that come close to what you want, too.
03 Apr, 2009, JohnnyStarr wrote in the 80th comment:
Votes: 0
Cool, thanks elan, thats exactly what i wanted to know. :lol:
60.0/82