Riffs by Raph: How Virtual Worlds Work Part 4

Making objects in a virtual world actually do something is way harder than just drawing them – and as we have seen, drawing them is already fraught with challenges.

Items as pure data

Once upon a time, in the old days of DikuMUDs, every object in the game was of a type – ITEM_WEAPON, ITEM_CONTAINER and so on. These were akin to what I referred to as templates in the last article. But they were hard-coded into the game server.

If you added new content to the game, you were limited by the data fields that were provided. You couldn’t add new behaviors to a vanilla DikuMUD at all. That item type defined everything the item could do, and a worldbuilder couldn't change the code to add new item types.

To extend the behaviors a little bit, there was a small set of “special procedures” also hardcoded into the game – things like “magic_missile” or “energy_drain.” The slang term for these was “procs,” and to this day players speak of weapons that “proc” monsters. You could basically fill in a field on a weapon and specify that it had a “spec proc,” choosing from that limited menu.

If we look back at the previous article, and think about what this means for portability of object ownership, one fact jumps out at us: the functionality of a given object in a DikuMUD is inextricably bound up with the context in which it lives: the DikuMUD game server. There wasn’t any code attached to the item that could come with it as it moved between worlds. Instead, it really was just a database entry. The meaning of the fields was entirely dependent on the game server.

Attaching behaviors

Modern worlds are more flexible, thank goodness. The concept of attaching a block of script code to the individual item opened up the ability for an item and its intended behavior to both be “data” in the database. This  allowed people who were not the operators of the world to add functionality.

Each object in the database maintained a list of the scripts attached to it. When this tech first came along, the scripts were literally placed directly in fields on the object itself.

Later on, they became their own data type, and they were instead linked to the object template and the object instance. This allowed scripts to be attached and detached from objects on the fly.

This was an architectural revolution: suddenly a behavior might get attached to anything. You could share behaviors across objects. You could mix and match behaviors from different sources and use them as building blocks to create more sophisticated gameplay.

There are still limitations. A behavior doesn’t carry a whole game system with it. Each script still has dependencies on other scripts. For example, let’s say you have an apple. You want it to be food, so you might attach this behavior to it:

When this object is eaten

{

Figure out how much food value the object has

Increment my stomach’s fullness by that much

Make sure I don’t go over the max stomach fullness!

Delete the eaten object

}

That seems simple… but it has assumptions:

  • Where does “eaten” come from? That implies a whole UI, the concept of food in the first place, etc.
  • If the object has a food value, but it wasn’t food until this behavior was attached, then where is the food value stored? Are there generic empty fields on the object (“since the food script is attached, check storage box #1?” How do you pre-populate it? Do scripts need to be able to add fields on the fly?
  • Wait, the player has a stomach? Is that defined in the player template? If I am adding “food” as a concept via script, then probably not. That means I need to add “food eater” as a script to the player, and have that script add the necessary fields.
  • The stomach has a max? Where is that defined?

Worse… what if you want to add poison to a food? (The answer, by the way, is overloading the event handler for the “eaten” message, which then means you need to be able to define script precedence…)

Even worse… what if the world you are importing this into is an RTS, where there isn’t an avatar in the first place?

If you tried to carry just the food script from one world to another, it would utterly fail to work, because all those assumptions are dependencies.

Object portability isn’t entirely hopeless

People often think  you could just set up mappings between the values of fields in one game and the fields in another game. And indeed, we have had things like “compatible player files” since early home computer RPGs in the late 1970s and early 1980’s. But we should not underestimate the magnitude of the task of figuring out what value a cooked pie from Breath of the Wild has in Halo -- or mapping every game to every other game.

There are no standards right now for “what things can do” in a virtual world, and we shouldn't want them. The act of setting the standard is also setting the limit, which would curb creativity enormously. There’s far too much possibility to be explored still.

That said, since scripts are just data – just text! -- you could load them from a remote site. If there’s a popular set of scripts that lots of people load from a common location on the web, then standards could start to emerge based on actual usage. As long as scripts could actually add data fields on the fly, as long as scripts could come packaged with all dependencies internal, and as long as things like “eaten” could be just messages to the object – you could indeed share behaviors across worlds.

We know this works, because we’ve built it before, including at my previous startup Metaplace.

Ironically for fans of decentralization, though, the literal decentralizing of the script locations results instead in centralizing the point of failure. If that script has a bug, everyone’s eating stops working. So instead, you need to make copies… maintain version history… worry about forks… build consensus on how to extend or change the behavior…

We are back to “tech is for people”

What used to be a technical problem then becomes a people problem. It becomes the political challenge of managing open source software projects. With the extra complication that a poisoned apple isn’t like application software. There is no right answer for how it should work!

  • A sci fi game may want to use this very differently from a fantasy game where witches can enchant apples.
  • The scale for “stomach fullness” may need to be wildly different for a game where you can play anything from an insect to a mammoth.
  • A survival game might want actual nutritional values rather than a single “food” value.
  • A casual title’s gameplay experience may be badly damaged by that degree of complexity.
  • If you can carry food to a new world and eating restores health, that might really unbalance a game where you aren’t supposed to be able to heal at all.

This is why carrying object functionality around between worlds is above all a thorny social problem, and item portability in the way that most people dream of it is far more likely to be limited to appearances for a long while. The exception would be cases where there is central control over, or at least strong agreement on, the game design across multiple worlds.

Which leaves us with the largest social problem of them all, one I touched on lightly a couple of articles ago: ownership.


How Virtual Worlds Work - Part 1
How Virtual Worlds Work - Part 2
How Virtual Worlds Work - Part 3
How Virtual Worlds Work - Part 4