07 Oct, 2008, Vassi wrote in the 1st comment:
Votes: 0
So one system I hadn't really given much time to is help systems.

How important is it that they be editable online? (I.E. by OLC) Is that the norm, or are they usually handled via a directory structure organization. Are the contents of the whole system loaded into memory upon load, or would it make more sense simply to draw out a tree based on all the subfolders (categories) and hold references to all the files inside for on-demand display.

I.E. if my Help folder contains files for attack and climb I would investigate the directory, build a display menu for that tells you your options are 'attack' and 'climb' and then hold attack and climb as keysand their full drive path as values. When you type help climb, then I pull up all the text from said file and display it. The alternative would be to store the entire contents of each file as the value, rather than just the path.

Lastly, assuming each game command is a class, would it make sense to require a Category and HelpText property to be 'hardwired' for auto-generation of a help menu? I'm kind of leaning away from it, if only because a help menu (the good ones) are usually slightly more helpful than a simple display of categories and command names.
07 Oct, 2008, David Haley wrote in the 2nd comment:
Votes: 0
Good questions… Depending on the number of help files, it might make sense to load them into memory upon use, and then leave them around for a few minutes (e.g. 30?) unless they're used again. Or keep 'x' in memory, and when you need to insert x+1, kick out the help file that was accessed last. Chances are that the common help files will stay in memory most of the time, and the least common ones will be loaded when needed. Of course, all of this might be total overkill depending on how many help files you actually have. For me, if I only have ~1mb worth of files, I'd just leave them in memory all the time.

Same for building the directory; I would probably just do it once and be done with it.

I'm building some degree of help into my new command system. By that I mean that you supply the help for a command in the same location that you register the command. I haven't worked out how exactly that will work, but I want help to be tagged on to the command object itself, not the name of the command. That way, if for instance a command name changes, the help file moves with it.

One nice feature of having a tree-based system is that it automatically generates see-also lists that are relevant. A disadvantage of a tree-based structure is that some commands would have more than one parent. In that case, using a category system (implemented with e.g. a graph) would be better.

Even if you have categories and automatically generated lists, I think that a main help screen should be written by a human in order to provide information that is most important to somebody who has no clue what is going on. When I type "help", I should understand what is being told. It doesn't really help me to be told that category mumbo-jumbo has help over there, if I don't understand what mumbo-jumbo is in the first place. The front page should motivate the sections to some extent, and make clear what the links mean.

Finally, I'm a very strong believer in using hyperlinks (via MXP or even just visual highlights) for better help browsing. It should be pretty obvious what things I can learn more about.
07 Oct, 2008, Vassi wrote in the 3rd comment:
Votes: 0
DavidHaley said:
I'm building some degree of help into my new command system. By that I mean that you supply the help for a command in the same location that you register the command. I haven't worked out how exactly that will work, but I want help to be tagged on to the command object itself, not the name of the command. That way, if for instance a command name changes, the help file moves with it.


That was what I meant, more or less, by "hardwiring" the text to the command. The problem for me there, though, is that the way my command structure works is that a command can arbitrarily match to what it wants. In order to find out if there is a match the Library queries the command (IsMatch(arg)) which lets each command match on it's 'main' name or partial match or do aliases, etc. This makes it harder to associate the text with the command because the command could arbitrarily have n number of aliases, or not.

I'm also leery of hard wiring anything. I staffed for and eventually ran a commercial MUD for five or six years where we had 0 programmer support. 0. Despite that, the classes\races\everything was templated and the OLC was very good so we could do 98% of all tasks. Because of that I'm very keen on providing a template-like engine that can still be quite customizeable without ever touching the code, even once. If we wanted class X to have skill Y we could set the class template to include skill Y (by index) in the training. Our guilds had intervals at which it gave gifts of an item, ability, and or skill; spells lived in index slots where all the numbers\descriptions were editable and functioned depending on what the FNN (function name) as, such as BOLT, SHIELD, etc. The only things we could not change were the above mentioned FNNs, the actual skills themselves, the abilities, etc - which one could argue were the best part, but at the same time you can make them truly modular so that adding them is trivial and does not involve having to mess with your code's guts all the time. The settings on a spell meant different things depending on the FNN, etc.

Anyway, I'm far afield, but my point is that I don't think it's a good idea to allocate help files to the coder. Superstars like you and I (=x) can communicate with code and word, but a lot of programmers should not be allowed to write things the public can see most of the time, and it's counter productive to have someone write something well and then copy and paste it into source code.

In the end, I think I like your 'caching' approach as it resembles what I'll be doing with blocks and I think it's a reasonable one-size-fits-all solution that could be optimized, but if it isn't then it still works fairly well.

P.S. I'm not sure templated is the right word at all but it was the first thing I came up with. The concept is simple though, everything conforms to a mold\template and we have x number of slots for each mold type. Everything was then created based on a set of tables. For instance, mob templates were referenced in a Mob Index table (which was its own template and we had a couple thousand of) and then this mob index table was referenced on a room (land\area whatever you want to call it) and given an interval. Whenever the interval struck, a random mob from the table was popped out. Mobs, in turn, had a Loot Index so when they died an item popped out, etc.
07 Oct, 2008, David Haley wrote in the 4th comment:
Votes: 0
Well, I have command objects, and then a mapping from names to those objects. You can do prefix matching on the mapping. Aliases would simply be a new mapping to the same object. The help file would in all cases follow the object.

The hard-wiring I'm talking about is in Lua, so it's essentially treated like a data file. The problem is that you'd need to go into the shell to modify it – in my current implementation. I've been thinking about how to change that. I'm finding that when your data is code, you need to be a little careful when you separate the two.

I agree that in the end of the day, the actual code should never need changing when you're doing things like assigning skills to classes or changing a description. I'm not sure that precludes treating data as code, though. Here's how I define the "showquest" command in Lua – note that the full help is not provided, and so defaults to "TODO":

cmds.makeCommand {
name = "showquest",

usage = "(all | list) | <quest name>",

brief = [[Shows the detail for a quest, or lists all quests.]],

code = cmd_showquest,

checks = {cmdchks.isPc, cmdchks.isBuilder, },
}

cmd_showquest is a reference to the function that implements the command.

cmds.makeCommand is a function that takes the supplied key/val map and inserts the appropriate entry into the command table.

So, if I wanted to save a command definition, there are many approaches I could take. I could save the entire function call above, or I could save the command table itself. I think that if I save the function call, that lets me keep command definitions lying around semantically, in the sense that I am not tied to any one particular command table representation. So, if somebody were to edit the associated help or brief, or even the 'checks' above (which I won't go into now), I'd need to write out the new command definition to a file somewhere.

I haven't played around with this a lot in practice so I'm not sure how well it would really work. It's the kind of thing that's pretty hard to reason about theoretically and only from a coder's perspective. I have no qualms going into the Lua code, modifying things, and then having the server reload that code on the fly. In some cases it's even easier than doing it with OLC. But that's totally unacceptable as a long-term solution because it's far too technical.
07 Oct, 2008, Vassi wrote in the 5th comment:
Votes: 0
DavidHaley said:
Well, I have command objects, and then a mapping from names to those objects. You can do prefix matching on the mapping. Aliases would simply be a new mapping to the same object. The help file would in all cases follow the object.


This isn't really about Help systems, but this is also an interesting topic for me, do you handle partial command matching or is the table strictly for exact matches only? I like the idea of checks, I think I get how it works, is there one for fullMatch only? For instance, on most of my staff commands (isBuilder, for instance) are exact match only so they can't 'fish' for commands. A previous approach I had was to have a static function to check for common things, like for most commands there's a cadre of things you check for like IsConscious, IsAlive, for movement it was like IsStanding, IsConscious, IsAlive, IsNotParalyzed, IsNotTired, blah blah. =\ It was the pits, though, because if I added a new status I would have to change every command that could be affected, the Checks idea is pretty elegant, but do you have flags for isNotPC as well as isPC?

Also, since this is LUA, do you 'drop' these declarations in a folder and then iterate through a folder at runtime \ on command to build the k\v table?

Quote
The hard-wiring I'm talking about is in Lua, so it's essentially treated like a data file. The problem is that you'd need to go into the shell to modify it – in my current implementation. I've been thinking about how to change that. I'm finding that when your data is code, you need to be a little careful when you separate the two.


Absolutely, Lua\Python stuff is meant to be reinterpreted so I would not consider that hardwiring. Essentially I want to limit the amount of things that require a server reboot to 0 for 99.9% of all issues - whether it's C# or Python.

Quote
I agree that in the end of the day, the actual code should never need changing when you're doing things like assigning skills to classes or changing a description. I'm not sure that precludes treating data as code, though. Here's how I define the "showquest" command in Lua – note that the full help is not provided, and so defaults to "TODO":

cmds.makeCommand {
name = "showquest",

usage = "(all | list) | <quest name>",

brief = [[Shows the detail for a quest, or lists all quests.]],

code = cmd_showquest,

checks = {cmdchks.isPc, cmdchks.isBuilder, },
}

cmd_showquest is a reference to the function that implements the command.

cmds.makeCommand is a function that takes the supplied key/val map and inserts the appropriate entry into the command table.

So, if I wanted to save a command definition, there are many approaches I could take. I could save the entire function call above, or I could save the command table itself. I think that if I save the function call, that lets me keep command definitions lying around semantically, in the sense that I am not tied to any one particular command table representation. So, if somebody were to edit the associated help or brief, or even the 'checks' above (which I won't go into now), I'd need to write out the new command definition to a file somewhere.

I haven't played around with this a lot in practice so I'm not sure how well it would really work. It's the kind of thing that's pretty hard to reason about theoretically and only from a coder's perspective. I have no qualms going into the Lua code, modifying things, and then having the server reload that code on the fly. In some cases it's even easier than doing it with OLC. But that's totally unacceptable as a long-term solution because it's far too technical.


I don't know, though I've noticed that I tend to approach situations from a slightly different perspective than most MUD builders, again perhaps because I worked for\with a commercial MUD. In any event, I don't think it's necessarily a bad thing to require going into LUA code and physically placing it somewhere and then flipping a recompile switch. At least not in the context of quest\script\command code - which is generally a highly technical endeavor - if you want a working quest, that is.

In a perfect world, of course, you'd have your creative types working with a technical type to create the script to specs and then put it where it needs to be, you'd have area builders designing and writing areas but 'ordering' mobs from those more versed in balance issues who can weigh the settings vs the rest of the game, but of course most MUDs are not that well staffed. Despite that, I think you can have a handful that can 'master' some quest\command tweaking and uploading. If all else fails maybe an FTP server could be setup specifically into the script directory to allow them access or something.

Honestly, I'm facing the same issue myself. We used to have a system called EPARMS that was seriously demented. Each eparm was essentially one instruction, such as MOVE or DELETEMOB or CreateItem, and you had to chain these things together to do anything. The nice thing, though, was that like everything else they existed in slots and were editable online. Now that Python is so tightly integrated into everything and i've exposed all those hooks to the game I'm facing the problem of getting the scripts to where the server can use them. One option I considered is having an editing dialog (like mushclient's notepad) and then sending that through the wire - but I can only get away with it because I have a custom client, which prevents me from really going "basic telnet" some day and prevents me from releasing the codebase for general use, too.
07 Oct, 2008, KaVir wrote in the 6th comment:
Votes: 0
DavidHaley said:
Good questions… Depending on the number of help files, it might make sense to load them into memory upon use, and then leave them around for a few minutes (e.g. 30?) unless they're used again. Or keep 'x' in memory, and when you need to insert x+1, kick out the help file that was accessed last. Chances are that the common help files will stay in memory most of the time, and the least common ones will be loaded when needed. Of course, all of this might be total overkill depending on how many help files you actually have. For me, if I only have ~1mb worth of files, I'd just leave them in memory all the time.


That's the approach I use, and it works fine - it's extremely simple, but does the job perfectly well, and allows me to use whatever text editor I like (I've yet to find an in-mud text editor that I felt comfortable with). I also added a command for flushing all help files from memory, so that a help file can be changed without requiring something silly like a reboot.

Vassi said:
Anyway, I'm far afield, but my point is that I don't think it's a good idea to allocate help files to the coder. Superstars like you and I (=x) can communicate with code and word, but a lot of programmers should not be allowed to write things the public can see most of the time, and it's counter productive to have someone write something well and then copy and paste it into source code.


Programming is a skill, and writing documentation is a skill, but the two are not mutually exclusive - in some cases they may even have considerable crossover. Not everyone is a one trick pony, and when working in a small team it is often essential for each member to possess a range of different skills.
07 Oct, 2008, Vassi wrote in the 7th comment:
Votes: 0
Quote
Programming is a skill, and writing documentation is a skill, but the two are not mutually exclusive - in some cases they may even have considerable crossover. Not everyone is a one trick pony, and when working in a small team it is often essential for each member to possess a range of different skills.


I'm fairly sure that's what I meant, I hope it didn't sound otherwise. The superstars quip was a bit of sarcasm, which I hoped the smiley would convey =\ I'm a technical writer for a bank so I'm kind of used to writing documentation, but not everybody is, nor should they be. I agree that one-man-shops are impressive but much more outside the norm than one would think, I feel a lot of would-be MUD owners get discouraged when they find out they can't do everything themselves - my advice is, and always will be, find others who are like-minded (usually someone who MUDs with you) and forge on together. Even if the second (or more) person isn't doing anything tangible, having someone to bounce ideas off of is a tremendous boon. To close that thought, a friend of mine asked me why I was devoting so much free time to making a text-based MUD, I told him it was simple: I can't draw.

To cycle back to the original topic, I'm fairly sure now that loading the files on-demand and holding on to them for a while is probably the best way to go. I'm not convinced that linking the command classes to the helpfile is necessarily the best, yet, but I would be interested in something like Circle\tbaMUD's helpcheck command so you can cross-reference which commands need some Help love.
07 Oct, 2008, David Haley wrote in the 8th comment:
Votes: 0
Vassi said:
This isn't really about Help systems, but this is also an interesting topic for me, do you handle partial command matching or is the table strictly for exact matches only?

At the moment, it does prefix match through a table. If there are multiple prefix matches, it asks you which one you meant, up to some reasonable limit (I think it's currently 5). I'm not sure I'll keep it this way forever, but that's the current implementation.

Vassi said:
I like the idea of checks, I think I get how it works, is there one for fullMatch only? For instance, on most of my staff commands (isBuilder, for instance) are exact match only so they can't 'fish' for commands.

Not at the moment but it sounds like an interesting idea. The checks are run by the command interpreter once it found the command you entered. So, when you try to run 'showquest', first it checks if isPc returns true, and then it checks that isBuilder returns true.

I'm not sure how much I like the fact that, at the moment, all (Lua-implemented) commands are available up-front and you get told that you can't go through with a given one.

Vassi said:
A previous approach I had was to have a static function to check for common things, like for most commands there's a cadre of things you check for like IsConscious, IsAlive, for movement it was like IsStanding, IsConscious, IsAlive, IsNotParalyzed, IsNotTired, blah blah. =\ It was the pits, though, because if I added a new status I would have to change every command that could be affected, the Checks idea is pretty elegant, but do you have flags for isNotPC as well as isPC?

Sure, for common things. Actually, what you saw were function references, and so you could in theory put in arbitrary code in place of the check. I provide a "negate" function that takes a function and negates its result. So you could refer to isNpc in two ways:

cmdchks.isNpc
or
negate(cmdchks.isPc)

which would be implemented as:
function negate(fun)
return function(x)
return not fun(x)
end
end


Of course, for common things it's a lot simpler to just provide the straight-up function…

Vassi said:
Also, since this is LUA, do you 'drop' these declarations in a folder and then iterate through a folder at runtime \ on command to build the k\v table?

At the moment, I have them intermingled with the actual code because I haven't fully worked out how to separate the code and data in a way that I like. For example, that trick I mentioned about 'negate' above wouldn't work so well when data is separated, because once the function declaration is loaded into the system, it's hard to write it out again in a human-readable format. But maybe it's not so bad to not allow arbitrary code there.

But the solution I'm currently leaning toward is indeed more or less what you described. I would do it once at startup, though, not on demand. (For commands, at least.)

Vassi said:
Absolutely, Lua\Python stuff is meant to be reinterpreted so I would not consider that hardwiring. Essentially I want to limit the amount of things that require a server reboot to 0 for 99.9% of all issues - whether it's C# or Python.

I definitely agree with that sentiment! :smile:

Vassi said:
I don't know, though I've noticed that I tend to approach situations from a slightly different perspective than most MUD builders, again perhaps because I worked for\with a commercial MUD. In any event, I don't think it's necessarily a bad thing to require going into LUA code and physically placing it somewhere and then flipping a recompile switch. At least not in the context of quest\script\command code - which is generally a highly technical endeavor - if you want a working quest, that is.

Well, I tend to be of that opinion. But it means that you need several people with access to the shell, and you might not always want your builders, even the relatively senior ones, poking around in a shell environment – or at least, the "production" shell environment. It's not so much a question of data security as it is hoping they don't break something.

Vassi said:
In a perfect world, of course, you'd have your creative types working with a technical type to create the script to specs and then put it where it needs to be, you'd have area builders designing and writing areas but 'ordering' mobs from those more versed in balance issues who can weigh the settings vs the rest of the game, but of course most MUDs are not that well staffed. Despite that, I think you can have a handful that can 'master' some quest\command tweaking and uploading. If all else fails maybe an FTP server could be setup specifically into the script directory to allow them access or something.

I'm becoming a very strong believer of that "catalog ordering" you mentioned. When you look at some very successful games such as Morrowind or Oblivion, the number of variation in objects or mobs is frankly quite small. I don't think that every area in a MUD really needs to redefine what a long sword is. It only causes trouble, IMO. If you want to have your own "skin" of a long sword, but keep all stats intact, that should be its own mechanism; you shouldn't have to recreate the entire object. But I digress…

I agree that this approach is better; the only catch is, as you say, that you need the staff to support it.

Vassi said:
Honestly, I'm facing the same issue myself. We used to have a system called EPARMS that was seriously demented. Each eparm was essentially one instruction, such as MOVE or DELETEMOB or CreateItem, and you had to chain these things together to do anything. The nice thing, though, was that like everything else they existed in slots and were editable online. Now that Python is so tightly integrated into everything and i've exposed all those hooks to the game I'm facing the problem of getting the scripts to where the server can use them. One option I considered is having an editing dialog (like mushclient's notepad) and then sending that through the wire - but I can only get away with it because I have a custom client, which prevents me from really going "basic telnet" some day and prevents me from releasing the codebase for general use, too.

Couldn't you in principle use an editor-buffer approach like what most OLCs currently do? It's not nearly as nice, but it works…

I'm also having this same problem. But then I think that I don't want that many people touching the fundamental Lua scripts, and those who do can be told they have to learn some version control system to move the files around.
08 Oct, 2008, Vassi wrote in the 9th comment:
Votes: 0
Quote
Sure, for common things. Actually, what you saw where function references, and so you could in theory put in arbitrary code in place of the check. I provide a "negate" function that takes a function and negates its result. So you could refer to isNpc in two ways:

cmdchks.isNpc
or
negate(cmdchks.isNpc)

which would be implemented as:
Code:

1.
2. function negate(fun)
3. return function(x)
4. return not fun(x)
5. end
6. end
7.

Of course, for common things it's a lot simpler to just provide the straight-up function…


That makes a bit more sense, the function references I mean. It actually looks a lot like the InputFilter interface I've put on my handle model, though definitely not quite the same. The InputFilter essentially takes place before the Handler looks through commands. It's intended use is to, for instance, filter commands that the player shouldn't be in a state to type at the moment - or potentially allow access to contextual commands that are only available for a limited time and not from the main pool. So like the IronRealms muds Tutorials, where your every action is guided, you could use an inputfilter to respond False if it doesn't match whatever conditions are set. Another potential use, like I said, is if you have a combo-combat system where a kick makes it so you can punch, and you don't want to deal with a 'canPunch' state, you put up the filter to catch Punch if it's done in the next 5 seconds (or whatever)

Not exactly the same, but the same basic approach. Filters are collected in one place and cycled, if any return false input does not continue to the main command pool.

Quote
If you want to have your own "skin" of a long sword, but keep all stats intact, that should be its own mechanism; you shouldn't have to recreate the entire object. But I digress…

I agree that this approach is better; the only catch is, as you say, that you need the staff to support it.


That's pretty much what it comes down to. Say that 99% of the time you don't need to do allot more than specify the timer, fatigue cost, name, weight, and damage type of a weapon - when you hit that 1% chance and want something else, it can be chafing. That's why Python is coming into the picture this time, though, so that those things can still be extensible in a completely optional way through various triggers such as verbs (action words tagged onto commands that get checked after regular commands) or combat events like OnHit, OnMiss, etc.


Quote
Couldn't you in principle use an editor-buffer approach like what most OLCs currently do? It's not nearly as nice, but it works…


One problem with this is in the 'sanity checking' I do for my input, which is to trim non-display ASCII characters and leading\trailing spaces. This would completely murder Python's indentation formatting which means I'd have to do something like introduce a beginning of line token to convert to a Tab like:
def function(a, b):
^ta + b = 1


Which is ugly to write (for scripters), or I need to be more lax on my initial input. I can't really make an exception on the primary input, as that's built at a much lower layer than the Handler has access to. It isn't aware that the Handle exists (which is kind of the point).

This is why I talked about ZMP before, though, Elanthis added an input subnegotiation so that you could deal with it at a separate logic layer of the MUD, that is more game-aware. Most MUD protocols define server-to-client commands, but very little (if any) define any client-to-server commands, which are just as important in many ways - or maybe it just seems that way because of how i've structured my architecture.

Edit: I posted a kindergarten diagram here, if you're curious: D&W Diagram
08 Oct, 2008, David Haley wrote in the 10th comment:
Votes: 0
About to go to bed so will be brief…

- I like the input filter idea you described – that does seem like a great way to allow contextual commands very easily, without having to add all kinds of logic to the command interpreter itself. Just throw on a filter, and the interpreter remains exactly the same. Nice…

- I also like the use of filters to enable time-dependent commands without having to put the state into the player object (at least as far as the command interpreter is concerned).

- Whitespace: the fact that Python actually cares about such things as whitespace is one of my major pet peeves with the language. I understand the value of enforcing good style, but the interpreter itself really shouldn't care about text coming in all nicely formatted or text coming in stripped of as much whitespace as possible…

- Nick Gammon has also been working with Lasher (I think) from Aardwolf (I think) on a subnegotiation protocol for various things, mainly related to the mini-windows I talked about before. It lets the client and server communicate "invisibly" as far as the player is concerned, which has all the benefits that you've been referring to.

- I like your idea of a "reporter" layer. I'll have to think about that a bit.

Incidentally I fixed a typo in my earlier post: I had negate(isNpc), which is not what I meant at all :wink:

And on a totally random tangent, out of curiosity why do you use backward slashes? You're the only person I've ever seen do that when indicating a split between e.g. terms/concepts. I can imagine that using backslashes would drive some Linux-ish environments nuts :wink:
08 Oct, 2008, Vassi wrote in the 11th comment:
Votes: 0
DavidHaley said:
About to go to bed so will be brief…

- I like the input filter idea you described – that does seem like a great way to allow contextual commands very easily, without having to add all kinds of logic to the command interpreter itself. Just throw on a filter, and the interpreter remains exactly the same. Nice…

- I also like the use of filters to enable time-dependent commands without having to put the state into the player object (at least as far as the command interpreter is concerned).


It certainly seems so, I have to admit it's new in this iteration of the engine, I'm curious to get to using it. It just seems easier to put a Sleep filter in the list that rejects any command besides wake (for instance). I would still track the sleep state on the player, but I don't have to go and edit other commands to check for it.

Quote
- Whitespace: the fact that Python actually cares about such things as whitespace is one of my major pet peeves with the language. I understand the value of enforcing good style, but the interpreter itself really shouldn't care about text coming in all nicely formatted or text coming in stripped of as much whitespace as possible…


Agreed. It's a little jarring. I mean, it drives me nuts when C#\PHP isn't indented or bracketed properly but at least I know I can always do goofy stuff like write my entire program on one line if I had to or wanted to.

Quote
- Nick Gammon has also been working with Lasher (I think) from Aardwolf (I think) on a subnegotiation protocol for various things, mainly related to the mini-windows I talked about before. It lets the client and server communicate "invisibly" as far as the player is concerned, which has all the benefits that you've been referring to.


Do you have any forum threads or reference for this? I might be interested in getting in on that action, or champion an alternative ;)

Quote
- I like your idea of a "reporter" layer. I'll have to think about that a bit.


I'm a big stickler for formatting output. (For the record, I hate most MUDs because they're very Wall of Text-y) So I've always had output functions for everything, like SendSay(string message, Avatar speaker), SendTell(string message, Avatar speaker) DisplayRoom(Room room) etc.

Abstracting this made sense after deciding to support Telnet, because if I wanted to do plain\no-color i'd have to do a bunch of ifs or something to figure out if my Say\Send should be parsed for color. Or MXP, etc. I can have an MXP Reporter, an ANSI Reporter, a ZMP reporter (For my own client) etc. I'm trying to work on a global way to declare styles, too, kind of like MXP but server side so that <blue>text</blue> (or whatever tags I end up choosing) can mean one thing in the ANSI reporter and another in the MXP reporter and be stripped out in the Normal reporter etc.

The reporter and filter layers also came out in large part because of a single feature I hit the wall trying to implement a year or two back: Shapeshifting. If you look at the above model I linked what I'm about to say will make more sense, Player\Avatar object is married to the Handler - because when the handler sends the args to a command it also has to send the player so the game can do stuff to it - but the connection object (from the hub) used to be married to the Avatar object.

This time around I've decoupled that a bit, the Avatar objects are still married to the handler but the connection is no longer married to the Player object but it is referenced to the Reporter object. Anyway, the way I'm going to try for a 'clean' shapeshift system is to implement an Avatar stack in the handler. When the handle passes the Avatar into the command it will pass the top-most avatar on the stack, which could be the player (and his\her skills) or a shapeshifted form, which could enhance the player's skills, have new ones, or replace them with something else - depending on the inheritance choices.

Take it a step further and you can implement a possession mechanic, where you push one player's avatar into another's stack, then you filter the possessed player's input so they can maybe do tells but not much else, and you hook the possessor into the possessed player's reporter and you've essentially switched control without ever moving the connection object. That's probably alittle confusing without a diagram though =x

Quote
And on a totally random tangent, out of curiosity why do you use backward slashes? You're the only person I've ever seen do that when indicating a split between e.g. terms/concepts. I can imagine that using backslashes would drive some Linux-ish environments nuts :wink:


I honestly never noticed that, but now that I think about it it's easier for me to press the \ key than the / key, because of the way I type.
08 Oct, 2008, David Haley wrote in the 12th comment:
Votes: 0
Vassi said:
Agreed. It's a little jarring. I mean, it drives me nuts when C#\PHP isn't indented or bracketed properly but at least I know I can always do goofy stuff like write my entire program on one line if I had to or wanted to.

Right – and although I don't write code that's not properly indented myself, situations like your editor buffer crop up. I just don't see why the language has to be whitespace sensitive. Lua's syntax doesn't have semi-colons etc. and yet isn't whitespace sensitive (except in one rather obscure situation).

Vassi said:
Quote
- Nick Gammon has also been working with Lasher (I think) from Aardwolf (I think) on a subnegotiation protocol for various things, mainly related to the mini-windows I talked about before. It lets the client and server communicate "invisibly" as far as the player is concerned, which has all the benefits that you've been referring to.


Do you have any forum threads or reference for this? I might be interested in getting in on that action, or champion an alternative ;)

Sure… here is the section on miniwindows. Here is a plugin for parsing the subnegotiation te... (note that most data is sent normally, but the subnegotiation is used to trigger/control it). And here, linked from that last URL, is the introduction to the protocol itself. There's a link from there to Aardwolf's blog giving more detail.

Vassi said:
I'm a big stickler for formatting output. (For the record, I hate most MUDs because they're very Wall of Text-y) So I've always had output functions for everything, like SendSay(string message, Avatar speaker), SendTell(string message, Avatar speaker) DisplayRoom(Room room) etc.

I like the idea of separating the semantics of what is being sent from the actual text of what is being sent. Ideally – as you have done, it seems – the rendering to text or pictures or whatever would happen at the very last moment.

Vassi said:
I'm trying to work on a global way to declare styles, too, kind of like MXP but server side so that <blue>text</blue> (or whatever tags I end up choosing) can mean one thing in the ANSI reporter and another in the MXP reporter and be stripped out in the Normal reporter etc.

Seems reasonable enough, and not too hard. Well, I guess it depends on what range of styles you're talking about…

Vassi said:
[I'm snipping a bit here] Player\Avatar object is married to the Handler - (…) but the connection object (from the hub) used to be married to the Avatar object. (…) This time around I've decoupled that a bit, the Avatar objects are still married to the handler but the connection is no longer married to the Player object but it is referenced to the Reporter object.

I like this approach, not that I'm biased, of course, because it's the approach I'm going for as well. :wink: But seriously, it never did make much sense for me to have the connection be so utterly connected to the character.

In my ideal world, players and mobs are perfectly identical except that players get commands over a socket and mobs get commands from an AI engine. Output to mobs gets sent to the AI engine, and output to players gets sent over the socket. In other words, conceptually at least, they are controlled in exactly the same way, the only difference being the source of actions.

Of course, this idealized conception doesn't really make sense in terms of implementation but I think it captures pretty well the intention. It does sort of fit into what you're describing, in that the AI reporter could be some kind of decision algorithm, whereas the player reporter would render it to text (or whatever) and send it over the wire.


Vassi said:
Quote
And on a totally random tangent, out of curiosity why do you use backward slashes? You're the only person I've ever seen do that when indicating a split between e.g. terms/concepts. I can imagine that using backslashes would drive some Linux-ish environments nuts :wink:


I honestly never noticed that, but now that I think about it it's easier for me to press the \ key than the / key, because of the way I type.

Oh, ok :smile: Was just curious…
08 Oct, 2008, Vassi wrote in the 13th comment:
Votes: 0
Quote
In my ideal world, players and mobs are perfectly identical except that players get commands over a socket and mobs get commands from an AI engine. Output to mobs gets sent to the AI engine, and output to players gets sent over the socket. In other words, conceptually at least, they are controlled in exactly the same way, the only difference being the source of actions.

Of course, this idealized conception doesn't really make sense in terms of implementation but I think it captures pretty well the intention. It does sort of fit into what you're describing, in that the AI reporter could be some kind of decision algorithm, whereas the player reporter would render it to text (or whatever) and send it over the wire.


That doesn't sound that idealized at all. In fact it's kind of scary because that is also one of my main goals and thats exactly the niche reporters will fill for NPCs. What I'm attempting to do is have Avatars be an interface so that commands treat everything that implements it the same. Hence, if Mobs implement a reporter then someone says something they'll be treated to the mob.SendSay() treatment as well, which lets you trigger quests\AI whatever you want.

Likewise, you can use the same command logic for Mobs and Players so that your only worry is scripting the meaningful logic of when to do what, rather then when to do what AND how to do it.

A well de-coupled system lets you do all of these things and more like if you have a familiar or pet that acts on its own and then you want to 'phase' into it so you can control its actions (again, the stacking of avatars). I really can't wait until I'm done with all this groundwork so I can start experimenting. Unfortunately, nothing good has ever come of a hurried foundation.
08 Oct, 2008, David Haley wrote in the 14th comment:
Votes: 0
What I'm concerned about is that it will be overkill and become quite expensive in terms of implementation. I'm not sure if mob behavior should be controlled to such a fine-grained individual level. For example, you don't always need your mobs' AI to be active unless the player is somewhere nearby. Oblivion has an AI distance setting that I believe makes the AI agents basically go to sleep if they are beyond the radius – that lets you save CPU cycles on slower machines. Something like that for MUDs might make sense as well, at least for most mobs. (For some mobs, you would actually want them to be doing their thing all the time.)
08 Oct, 2008, Vassi wrote in the 15th comment:
Votes: 0
DavidHaley said:
What I'm concerned about is that it will be overkill and become quite expensive in terms of implementation. I'm not sure if mob behavior should be controlled to such a fine-grained individual level. For example, you don't always need your mobs' AI to be active unless the player is somewhere nearby. Oblivion has an AI distance setting that I believe makes the AI agents basically go to sleep if they are beyond the radius – that lets you save CPU cycles on slower machines. Something like that for MUDs might make sense as well, at least for most mobs. (For some mobs, you would actually want them to be doing their thing all the time.)


I think that's an issue better solved by other bits of your architecture though, depending on how you cycle through your mobs (which I haven't quite decided myself, either) for instance in my case I'll either cycle through blocks(lands, whatever), and if they have players in them, cycle through the mob list for that land and do the AI thing. Or I'll cycle through a master list of mobs and check to see if the block they're in has PC activity, or if they have priority (like you said about exceptions, for instance if it's a scripted mob supposed to be 'patrolling' from one end to the other)

There are plenty of alternatives here, obviously. I like the land-based checking because you can save a lot of checks on lands that don't have mobs. I like the second approach because you can have exceptions. Another exception is to do land-based and if I need some kind of 'special' mob I'll handle it special by kicking off an event sequence that is then handled by the event-timer firing specific scripts (or the same script with changing variables)

Edit: One advantage I have, that I don't know if Lua supports, is that the IronPython implementation does allow for 'compiling' python scripts. So what I do is check the file to see if it's been edited since I last ran it, and if not, I pull out a pre-compiled version of the script. If it's been changed - or I don't have a pre-compiled version - I precompile it and hold onto a reference. This increased my performance by a factor of 9-10 in basic counting\looping tests.
08 Oct, 2008, David Haley wrote in the 16th comment:
Votes: 0
It sounds like your approach of using "blocks" is basically another way of looking at the AI-distance I was talking about. It sounds good to me. Keeping a global list of exceptions seems like a reasonable way to shortcut the block handling.

In Lua, you can precompile the Lua text into Lua bytecode. There's no optimization, so the only savings are when you load the script. What kind of benchmarks were you using when you got a 9-10 factor increase? Incidentally, there is a LuaJIT for x86 architectures that gets you massive performance increases because it compiles the Lua bytecode into assembly.
08 Oct, 2008, Vassi wrote in the 17th comment:
Votes: 0
DavidHaley said:
It sounds like your approach of using "blocks" is basically another way of looking at the AI-distance I was talking about. It sounds good to me. Keeping a global list of exceptions seems like a reasonable way to shortcut the block handling.


I assumed that most muds had the concept of blocks in the implementation of areas, area files, etc. I keep three sets of references (whether that's bad practice or not, I don't know, but it's might convenient) I keep a master list of everything, the block keeps a list of each item, player, or mob inside of it, and so does the room. So each room hands off the reference to the next, when moving around, and if the new room is in a different block the block will hand off to the other (all of these hand-offs also having event\scripting hooks ;))

It makes more sense to query the lands to see if they're unfolded and active before doing anything with the stuff inside.

Quote
In Lua, you can precompile the Lua text into Lua bytecode. There's no optimization, so the only savings are when you load the script. What kind of benchmarks were you using when you got a 9-10 factor increase? Incidentally, there is a LuaJIT for x86 architectures that gets you massive performance increases because it compiles the Lua bytecode into assembly.


I guess it depends what you mean by loading, and if it's one time. The way the IPY interpreter works you can either interpret the file every time, or compile it and run the compiled module. Loading time for the whole system is attrocious on a first run (thankfully, first-run literally means only the very first script you interpret) but the compiling is very helpful. The test is nothing special, only a simple script that adds a couple of things together and prints a message. This test is wrapped inside of a for loop to simulate calling it various number of times.

Honestly, even interpreted, I don't think performance would be that big of an issue at < 100 or so players, but precompiling was easy to do so it seemed like a no-brainer. Most scripts do not change on a regular basis once they've been tested and debugged.
08 Oct, 2008, David Haley wrote in the 18th comment:
Votes: 0
I don't think that SMAUG has a list of players per area; it does have a count, and a list of players per room, but data doesn't get aggregated upwards in the hierarchical division.

Vassi said:
The way the IPY interpreter works you can either interpret the file every time, or compile it and run the compiled module.

By compiling, do you mean compile the text to bytecode, or compile to assembly language like what a JIT would do? If you mean the former, Lua does that by default and you only read the actual strings once (upon load). If you mean the latter, you need LuaJIT to get to the machine code level.
08 Oct, 2008, Vassi wrote in the 19th comment:
Votes: 0
DavidHaley said:
By compiling, do you mean compile the text to bytecode, or compile to assembly language like what a JIT would do? If you mean the former, Lua does that by default and you only read the actual strings once (upon load). If you mean the latter, you need LuaJIT to get to the machine code level.


From what I understand, IPY compiling is equivalent to LuaJIT. It doesn't hold on to any byte-code it generates for interpreted scripts unless you load a script into the runtime as an include, which does not help you for scripts you need to run more than once. In those cases, if you're not compiling, the file is read - turned into byte-code - then JITed by the VM every time you run the script, which is pretty standard fare(? I think cPython does 'optimize' by keeping the byte-code as pyc files? But it still has to JIT them)

Hence the large performance improvement. Still, IPy runs, on average, as fast or slightly faster than cPython in most scenarious except for heavy loop-based ones where things get instantiated a lot. Then you start to see some degradation, which is slightly more noteable in Mono.
10 Oct, 2008, Vassi wrote in the 20th comment:
Votes: 0
DavidHaley said:
Couldn't you in principle use an editor-buffer approach like what most OLCs currently do? It's not nearly as nice, but it works..


After thinking about this I can really only think of four ways to do it, and I'm not sure which one I prefer. In some ways I like 2 the best, because of how simple it would be to setup in my own situation and the fact that it's codebase dependent, rather than 4 - which is client dependent.

1) A simple web-script(PHP, Python, Whatever) to handle user uploads to whatever directory you want. You'd have to log-in users based on your account\character files (easy enough, if you use a database for those bits, but not much harder if you use flatfile). This fails if your MUD and webhost are not on the same server.

2) Again a web-script, but this time have it communicate directly with the server via a 'service socket'. This lets you do the script processing from inside the MUD server. The easiest way to authenticate this is to make sure the connection is from the local loopback or some pre-authorized IP. This would work even if your webhost is not on the same server - but relies on you being able to easily check incoming connections and treat them differently. The command would essentially be a byte-blast of the contents of the file and the username who is requesting the file be saved, this one allows you to provide more intelligent feedback like "Authorization Failed" or "File Already Exists" or even the chance to detect Syntax errors.

3) A line-buffer editor, as we discussed, but IMO this is a very awkward way to write a script, and copying and pasting seems error-prone. Getting a more robust buffer mode is client dependent for reasons bemoaned by everyone who wants a better OLC.

4) A client-specific way of sending data in such a manner that it is not 'cleaned up' and can be treated in a special manner. This would allow something like an in-client editor that can then send the data through.
0.0/28