09 Jan, 2013, Runter wrote in the 21st comment:
Votes: 0
I agree that it's not a bad idea to edit json directly, but I think if someone is proposing a superset of json and editing that directly, then it should be clear that it's an interface that looks like json, but is actually something else. Like YAML. And if it compiles from that interface directly into json, that should also be clearly understood that the interface is YAML (or whatever the superset is) but it's exported to JSON when you save it.
09 Jan, 2013, quixadhal wrote in the 22nd comment:
Votes: 0
Easy for humans to read, perhaps… but one typo and your file is corrupt, hence you should NOT be writing JSON directly, no matter what the propoganda page says. :)

If you want people to edit the files directly, then you want a format designed to be more flexible, and you have to pay the price of having a much more involved parser to munge it into data objects. That's what the old DikuMUD format was.

Trying to do both is, IMHO, pointless. I would let the MUD read and write JSON directly and make simple templates for your favorite editor to let you edit the data "by hand". Editing the files should be strictly a last resort for debugging, or because you haven't yet made an editor/template system.
09 Jan, 2013, Runter wrote in the 23rd comment:
Votes: 0
quixadhal said:
Easy for humans to read, perhaps… but one typo and your file is corrupt, hence you should NOT be writing JSON directly, no matter what the propoganda page says. :)

If you want people to edit the files directly, then you want a format designed to be more flexible, and you have to pay the price of having a much more involved parser to munge it into data objects. That's what the old DikuMUD format was.

Trying to do both is, IMHO, pointless. I would let the MUD read and write JSON directly and make simple templates for your favorite editor to let you edit the data "by hand". Editing the files should be strictly a last resort for debugging, or because you haven't yet made an editor/template system.



Actually, json is very similar to other structured, human readable formats. It's perfectly fine to edit it directly. It's a compromise between easy to parse, easy to read/write, and easy to transmit. It's a rope bridge for a lot of developers to just let people edit it directly, and there's not any really doom day scenario for "corrupting" the file. You give them an error message and they try again. Keep in mind, there's tons of XML editors out that that let you visually edit it, and that's fine, but there's also nothing wrong with editing XML/HTML/json/etc (and possibly corrupting it!) by hand. There's no reason to be purist on this matter.
09 Jan, 2013, Telgar wrote in the 24th comment:
Votes: 0
quixadhal said:
First of all, JSON isn't meant to be a human data protocol, it's mean to serialize and deserialize data in a clean and efficient way. :)

Nobody in their right mind would be editing JSON data directly. If you have the object in code, you edit the object and re-serialize it. If you have the object on disk, you use an editor which reads in JSON and provides you with the object data to edit, then re-serializes it as it saves it back out. The end user should never, under any circumstances, be touching the JSON data directly.

That's the point.

Using industry standards means you can use anybody's JSON-compliant editor to work with the data and *NOT* have to worry about getting the format wrong when saving it. It also means anybody can easily build a "world editor" that reads in your JSON data files with about 3 lines of code. Those are good things.


Yes, yes, and yes.

The only use case here is importing zones from other muds, which is a manual process involving some scripted conversion and an intermediate fixup step where some human intervention may be required. In that case, it is useful for the intermediate representation to be human readable before being imported. Once imported, everything remains true to the JSON spec.

Also, I fixed that one-character-off typo problem by adding context specific errors and even reporting the error on which the line occurs. This was actually the primary motivation for changing the JSON parser at all. Debugging the import script when you are dealing with perfectly machine formatted JSON all squeezed on one line is simply impossible for something as large as an entire zone in one file.

Like I says, if the folks at Mozilla saw what I did they would probably draw and quarter me… please don't beat them to it.

</sidebar>

Let's get back to talking about arendir's cool mud framework!
12 Jan, 2013, quixadhal wrote in the 25th comment:
Votes: 0
Ah, but see… maybe someone who runs your codebase doesn't want it to be a one-time-only step, but instead wants to have the world dynamically generated by some automated engine outside the game (a terrain generator, perhaps)… in which case, said terrain software might well export plain JSON output. Making a custom JSON-like thing means now you also need to write glue software, probably in perl, and hope and pray that part doesn't have to be updated when EITHER side gets updated.

Quote
Let's get back to talking about arendir's cool mud framework!


Ok! :)

Out of curiosity, arendir, did you consider writing your codebase in java instead of C++? It just occured to me that since it uses a javascript engine to handle in-game objects/events, having the base code be java would make modifying the things in the server seem very familiar. Added bonus of being cross-platform. Of course, it won't be as efficient as C++, but…

I'm in the position of trying to mess with java a bit myself (got a new android device for christmas!), and I really don't want to deal with CoffeeMUD as a learning experience. :)
12 Jan, 2013, arendjr wrote in the 26th comment:
Votes: 0
Quote
Out of curiosity, arendir, did you consider writing your codebase in java instead of C++? It just occured to me that since it uses a javascript engine to handle in-game objects/events, having the base code be java would make modifying the things in the server seem very familiar. Added bonus of being cross-platform. Of course, it won't be as efficient as C++, but…


Indeed I put a bit of thought into my choice of technology. I realized early on that I would need scripting support for game objects, as recompiling your code base for every behavorial change to AI for example simply wouldn't cut it. But I also didn't want something that was entirely written in a scripted language, for lack of sandboxing and performance. For the scripted part JavaScript was a natural choice for me as I'm already very familiar with the language, it's one of the most performant scripted languages out there (maybe only beaten by the JIT version for LUA), and it's immensely popular so its use might attract other programmers.

For the native part I believe there really is no other decent choice other than C++ if you want to embed a JavaScript engine, and communicate well between native code and JavaScript. To my knowledge there are only two really good APIs out there that provide bindings between native code and JavaScript. They are the V8 API and QtScript, and both are C++ APIs*. V8 would be the fastest of the two, but QtScript is the easiest to integrate, and I already had experience with Qt, so I chose the latter. Also the use of Qt is providing me with a host of other benefits, including portability.

Btw, to make the experience between script code and native code more familiar, I actually went the other way around: I mirrored a bunch of utility function from the Qt API to JavaScript (by default the utility methods for String and Array and such in JavaScript are rather limited). Classes implemented in C++, but relevant to script code, are exposed using the C++ <-> JavaScript bridge that QtScript provides, making the experiences really similar. I'll give an example, first the C++ version of a command, then the JavaScript one (no, I don't keep two versions of the same command in my code base, the C++ version has been reconstructed here to show what it would look like):

C++:
void DrinkCommand::execute(Character *player, const QString &command) {

super::prepareExecute(player, command);

GameObjectPtrList pool = player->inventory() + currentRoom()->items();
GameObjectPtr item = takeObject(pool);
if (!requireSome(item, "Drink what?")) {
return;
}

if (!item->hasTrigger("ondrink")) {
send("You cannot drink that.");
return;
}

if (!item->invokeTrigger("ondrink", player)) {
return;
}

item->setDeleted();
}


JavaScript:
DrinkCommand.prototype.execute = function(player, command) {

this.prepareExecute(player, command);

var pool = player.inventory.concat(player.currentRoom.items);
var item = this.takeObject(pool);
if (!this.requireSome(item, "Drink what?")) {
return;
}

if (!item.hasTrigger("ondrink")) {
this.send("You cannot drink that.");
return;
}

if (!item.invokeTrigger("ondrink", player)) {
return;
}

item.setDeleted();
};


Finally, I like to say my code is just as portable and cross-platform as it would've been had I used Java. I just don't have Windows at home, so I've never even tried to build the code on it, hence why I don't support it. In theory it should work, maybe with some tweaking of the build settings.

Hope that's a thorough explanation :)

*) Of course there are other choices as well, but they tend to be severly limited one way or another:
- Rhino is the only viable option for Java as far as I know. Unfortunately it's slow and it's Java <-> JavaScript bridge is rather clumsy as I detailed earlier in this thread.
- Android is of course also Java-based and it contains a JavaScript engine as part of its WebKit integration. Unfortunately you cannot invoke the JavaScript engine standalone, plus it's not even possible to call JavaScript code from Java and return the result of your statement back to the Java side. Also calling Java code from JavaScript is not thread-safe, leading to more headaches.
- OS X has a decent bridge between WebKit and Objective C, but it's limited to OS X only (even the iOS version is not as capable as it does not allow exposing Objective C objects to JavaScript), and it's also not a standalone JavaScript engine.
- There's a stream of JavaScript engines coming from Mozilla, but they're also not very suitable for stand-alone use as far as I know. Their XPCOM mechanism for bridging native code and JavaScript is also very archaic.
13 Jan, 2013, quixadhal wrote in the 27th comment:
Votes: 0
But, I can't run your mud server on my blue ray player! *grin*

That makes very good sense, and it looks like you've done a nice job making script and "hard" code very similar. I'm somewhat surprised and saddened that there isn't a good Java to Javascript bridge, as that seems like it would make perfect sense and be something both sides would actually work towards.

It might be worth peeking at the source to DGD, as I know Dworkin has made his driver windows compatible, and so you could probably see how different the socket and startup code is from that example (DGD is GPL'd now). I don't advocate running a MUD on windows, but for people who insist… it's better to make it run native in visual studio, than try to mess around with cygwhine or similar. Also, running a service makes it easier to manage when your machine reboots and so forth.
14 Jan, 2013, Telgar wrote in the 28th comment:
Votes: 0
SpiderMonkey (the Mozilla Javascript engine) has excellent bindings for C and C++ embedding, has a JIT compiler and is competitively fast compared with V8. I chose it because the API was easy to work with and the codebase was easy to customize, but most importantly, it satisfied my design goals.

My #1 design requirement was the ability to stop infinite loops without changing the server threading model. It isn't clear that V8 can support this. SpiderMonkey does. If you think carefully about the JIT, there are actually deep requirements to make that possible. You basically need a way to escape a

while (true) {
}


block. To do that from JITed code, you have to have an "escape hatch" which gets checked at the end of every basic block. I don't know much about the internals of V8, maybe that is possible now, but I don't believe it was at the time I started my project. It's possible they chose not to add such a check to every basic block for performance reasons. There is a way to halt execution of a script in V8, but this requires another thread, and there is no way I want threads infecting the C code base I am working with (it already has "threading support" which consists of being able to offload tasks like zone reset and freeing discarded objects to the worker thread… which has no locking whatsoever).
14 Jan, 2013, Telgar wrote in the 29th comment:
Votes: 0
quixadhal said:
Ah, but see… maybe someone who runs your codebase doesn't want it to be a one-time-only step, but instead wants to have the world dynamically generated by some automated engine outside the game (a terrain generator, perhaps)… in which case, said terrain software might well export plain JSON output. Making a custom JSON-like thing means now you also need to write glue software, probably in perl, and hope and pray that part doesn't have to be updated when EITHER side gets updated.


You misunderstand - I don't accept some different data format that isn't compatible with JSON. I accept a very slight superset of JSON. So legal, properly formatted JSON generated by some automated process is always perfectly accepted, and you don't need to write any glue software. Otherwise, I would be shooting myself a giant hole in the foot!!
14 Jan, 2013, Telgar wrote in the 30th comment:
Votes: 0
quixadhal said:
But, I can't run your mud server on my blue ray player! *grin*

That makes very good sense, and it looks like you've done a nice job making script and "hard" code very similar. I'm somewhat surprised and saddened that there isn't a good Java to Javascript bridge, as that seems like it would make perfect sense and be something both sides would actually work towards.


Getting competitive performance from a Javascript interpreter nowadays requires JIT code. This turns out not to be easy to do when you are running in a managed code base. Raw assembly emission is a little less than typesafe!!! So you are never going to be 100% native Java code, which means you need bindings back and forth between C / C++ and assembly. This is already becoming a mess - now you are juggling 4 languages. Also, it seems like GC management would be crazy, unless you find a way to re-use the native GC system for managing Javascript objects as well. That sounds a little hard considering how mismatched the languages are in terms of type safety and strictness.
14 Jan, 2013, Runter wrote in the 31st comment:
Votes: 0
Nowadays Java and Javascript are pretty far removed. (They kinda always were, but I think there was some influence in the motivations, at least.) So it makes a little less sense with that in mind, other than historical.

http://en.wikipedia.org/wiki/JavaScript#...
14 Jan, 2013, arendjr wrote in the 32nd comment:
Votes: 0
Quote
SpiderMonkey (the Mozilla Javascript engine) has excellent bindings for C and C++ embedding, has a JIT compiler and is competitively fast compared with V8. I chose it because the API was easy to work with and the codebase was easy to customize, but most importantly, it satisfied my design goals.

Ah, I just found the JSAPI they provide. That's indeed a lot better than using XPCOM. But to call it excellent is really stretching it from my perspective. Taking a look at the code examples, it seems like a huge chore to create the bindings between native code and script: https://developer.mozilla.org/en-US/docs...

Compare that to QtScript which does most of the hard work for you: http://doc.qt.digia.com/qt/scripting.htm...

Quote
My #1 design requirement was the ability to stop infinite loops without changing the server threading model.

All JavaScript engines support stopping infinite loops. V8 and QtScript both require you to interrupt the running script from another thread, that's true, but it's not only the more performant option, it's also the more reliable one. It seems backwards to me to make a requirement out of something that really isn't that desirable in the first place.

EDIT: I glimpsed over the "without changing the server threading model" part, so I updated the above reply.


Quote
Getting competitive performance from a Javascript interpreter nowadays requires JIT code. This turns out not to be easy to do when you are running in a managed code base. Raw assembly emission is a little less than typesafe!!! So you are never going to be 100% native Java code, which means you need bindings back and forth between C / C++ and assembly. This is already becoming a mess - now you are juggling 4 languages. Also, it seems like GC management would be crazy, unless you find a way to re-use the native GC system for managing Javascript objects as well. That sounds a little hard considering how mismatched the languages are in terms of type safety and strictness.

Exactly this. As Runter also mentioned, Java and JavaScript are pretty far removed. Getting Java to play nice from its VM with JavaScript in its JIT interpreter would almost be an inhuman task :)
19 Jan, 2013, Telgar wrote in the 33rd comment:
Votes: 0
@arendjr, in your Javascript code above, why are you using prototypal inheritance for your command objects? What is the actual state encapsulated in (this) ?
19 Jan, 2013, arendjr wrote in the 34th comment:
Votes: 0
Telgar said:
@arendjr, in your Javascript code above, why are you using prototypal inheritance for your command objects? What is the actual state encapsulated in (this) ?

The state is rather trivial really. The this.prepareExecute() call you see at the top is implemented in the base class (Command) and will set some player-related properties and parse the command into words. This way this.send() will know who to send the message too, this.takeObject() will interpret the words from the command and check if there's a matching object in the given pool, etc.. It's just for convenience of writing the commands.
19 Jan, 2013, Telgar wrote in the 35th comment:
Votes: 0
Seems a bit heavy handed, don't you think? It looks like you are using the Command pattern, but I don't really see a use for encapsulating the parse state inside an instance of the command object itself. Evidence of awkwardness includes using this.send when you have the player passed in the function, and use of a prototype when it isn't really needed. In general, inheritance is not a good thing in Javascript, and you should only use it when you are getting a large benefit from doing so. Why not:

DrinkCommand.execute = function(player, command) {
state = Parser.prepareExecute(player, command);
var pool = player.inventory.concat(player.currentRoom.items);
var item = state.takeObject(pool);
if (!state.requireSome(item, "Drink what?")) {
return;
}
if (!item.hasTrigger("ondrink")) {
player.send("You cannot drink that.");
return;
}
if (!item.invokeTrigger("ondrink", player)) {
return;
}
item.setDeleted();
};


Or, even better, get rid of the boilerplate prepareExecute and make it the responsibility of the caller:

Parser.registerCommand("drink", {
synonyms: ["chug", "sip", "slurp" ],
execute : function(player, state) {
var pool = player.inventory.concat(player.currentRoom.items);
var item = state.takeObject(pool);
if (!state.requireSome(item, "Drink what?")) {
return;
}
if (!item.hasTrigger("ondrink")) {
player.send("You cannot drink that.");
return;
}
if (!item.invokeTrigger("ondrink", player)) {
return;
}
item.setDeleted();
},
help_description: "Use DRINK to drink liquids out of any fountains, containers or bodies of water you may find."
});


Now you can be free of that "new" thing that Crockford is so not fond of.
19 Jan, 2013, arendjr wrote in the 36th comment:
Votes: 0
These are good suggestions, thanks. I like the idea of moving the Parser out of the command. Making it the responsibility of the caller would not always work though, a few commands actually have some custom behavior.

Getting rid of the inheritence would not be a goal of itself to me, though. I made the JavaScript and C++ versions as similar as possible on purpose :)
20 Jan, 2013, Telgar wrote in the 37th comment:
Votes: 0
This is the fun of Javascript, there is only like 8 billion ways to do things… :grinning:
29 Jan, 2013, Ludwig wrote in the 38th comment:
Votes: 0
I tried the demo. The 'distant events' feature is neat. Spammy too.

I noticed that I can hear sounds "behind" me. I'm guessing my character is facing a particular direction. Is there a way to face a different direction without moving?
29 Jan, 2013, arendjr wrote in the 39th comment:
Votes: 0
Thanks!

Yes, you're character automatically faces with his back the exit he came from. By doing "look <exit>" you will face that particular direction. I've also thought about an explicit "turn" command for turning left/right/around, but haven't gotten around to implementing yet.

I agree it can be spammy, though I'm reasonably satisfied with the amount here, especially given that this feature was implemented after the little demo world was created, so the world isn't even really designed for it. Currently however I'm implementing dynamic descriptions and will integrate that into the demo world. Then I'll also update it so the distant events become more sensible. Expect an update on the demo server in a week or so :)
30 Jan, 2013, DemiGod wrote in the 40th comment:
Votes: 0
If anyone is working on a project within PlainText, I would like to hear about it.

I appreciate the simple elegance of this engine and would like to work with a coder within it. You can reference my talents here:

http://www.mudbytes.net/topic-4153-64899...
20.0/44