(I suggest you open this diagram in a seperate
window while reading...)
This diagram illustrates the 3 different types of relations - normal, inheritance
(extends), and container relations. Extends means just normal
Java class inheritance and Implements means implementing a Java
Interface. Container relations represent branches in the container
tree (or container hierarchy). The container tree is a bunch of connected
nodes where each node has zero or one parent and any number of children
(see the example). Each node
(ie Physical) has semaphores that show which events they are interested
in. When an event occurs, it will propagate to all objects are supposed
to notice it, using the container tree as it's infrastructure.
Most relations are container relations, since this provides a nice consistent
object structure. In fact, the red container relations show
how objects relate to each other while the black extends
relations show how classes relate to each other.
And what about the lonely blue arrow saying that "World has 0-n accounts"?
That means that the world doesn't directly contain these accounts
directly - it only keeps references to them. Why? Because the
Account is actually kept as a child of the body which it controls (study
the diagram...). And an Account cannot have two parents, so I couldn't
make it a child of the World as well. In fact, if an Account is a
child of the world it will really be a Soul controlling the world...
kinda funky, eh?
Likewise, the blue arrow connecting Activity and Physical indicate that
they are not connected via the container hierarchy (this would be impossible
since Activity is not a subclass of Physical and can therefore not be in
the container hierarchy at all).
Item is simply the top of the hierarchy, for items that have a name,
an icon, and other such basic things. Any classes representing objects
that are not in the container hierarchy (for whatever reason) will
extend Item instead of Physical.
Another important aspect of Item is that it has an abstract set
of "properties" and can provide a "property viewer" that displays the values
of these properties. Each subclass of Item can add it's own set of properties
and expand the property viewer to display these as well. So, to summarize,
all subclasses of Item:
Can be displayed in the client with an icon and a name
Can fire events and be notified of events fired by other Items
Have a set of properties and can provide a graphical viewer for these properties
Physical is the very heart of White Orb. Almost everything
in the game is a subclass of Physical. A better name might be "Node",
since it really only represents a node in the container tree. Not necessarily
a "physical item" that can be seen and felt. All event handling and
container tree code is here.
The most important thing about Physical is the fact that it has
a parent (or a location) and a set of children.
The only object that can have a null location is the World (the
top of the container hierarchy). Which means if you take any Physical
and recursively check it's parents, you'll always end up in the world.
Physical also takes care of the event propagation so that events can
travel up and down the container hiearchy, so if someone standing a few
squares away makes a sound the event propagation mechanism will make sure
the sound event reaches those that should hear it. But the details of that
will be described in the event propagation
Some Physicals have Senses. That means they can hear and see
things. Senses is a subclass of EventFilter which is just
what it sounds like - an object who's sole purpose is to filter the events
it receives. Joe's Senses filter away all events that reach Joe but
shouldn't be detected by him.
If someone has cast a curse on a Physical it may very well also
contain an Effect. For all practical purposes it acst like
a normal item (can be moved around and all that), but works like a parasite
and is often invisible. If someone has cast a curse on Joe that turns
him into a werewolf every evening, Joe (being a Physical) will contain
a WerewolfEffect. The effect will keep track of the time and when
evening comes along it will turn Joe into a werewolf. See the document
on magic and effects for more details.
A Physical may be involved in an Activity. Furthermore
an Activity can have more than one participant (but a Physical cannot be
involved in more than one Activity at a time - get the distinction?).
That is the reason why Activity is outside the container hierarchy (it
is a subclass of Item, not Physical). There is no natural place in
the container hierarchy for it to reside, since it involves more than one
Physical. See the Activity document for more
Each Physical may also have a Soul (or several - but that's
rare). The Soul is the one actually controlling the actions of the
Physical, the Physical is also known as the soul's body. To
know what actions to execute, however, the Soul must receive events so
it knows what's occuring near the Physical. This is where the Senses
Let's say Joe is controlled by a player client. The player client
is actually an Account, or a special type of Soul that is
controlled by an external player client (ie a real person!). In order
to receive events that reach Joe, the Account needs to become a child of
Joe. However this is not enough - let's say Joe has terrible hearing!
Many of the sounds that reach Joe will not really be heard
by Joe. The solution is that the Account becomes a child
of Joe's Senses, instead of Joe himself. Because the Senses
will filter out all events that Joe wouldn't be able to hear.
In some cases, however, souls will want to "cheat". Imagine a
player possessing a sword, so that you can control it. Even though
the sword has no eyes and ears (ie no Senses), the player will want
to know what the sword "sees" and "hears". In that case, the Soul
will make itself a child of the sword directly. It may then
"make up" a Senses object that it maintains internally and filters all
events through, just to simulate a certain eyesight or hearing range (so
that it isn't overwhelmed with events). But now I'm gonna lay off
An NPCSoul is a Soul that is run by the server, using AI algorithms,
behavioural rules, and hip stuff like that. From the body's point
of view (the Physical that the soul is controlling) there's no difference
between an NPCSoul and an Account - they are both simply
Souls. See the document on Souls and AI
As you can see, Soul, Effect, and Activity all have
one thing in common - they implement the Active interface.
Active objects provide an interface for receiving info about the
result of an action (ie if the action succeeded or failed). Soul,
Effect, and Activity can all produce actions so they will want to know
if their actions succeeded. See the document
on Actions for more details.
ItemHolder is a general representation of a collection of Physicals
- a simple container class for nodes that can contain an arbitrary number
of anonymous children. The main difference from Physical is that
ItemHolders can contain any type of children (as long as they are Physicals).
Most other subclasses of Physical are made to contain only specific types
of children, in specific numbers (for example Physical itself is made to
contain 0-n Souls, 0-n Effects, and 0-1 Senses - nothing else). The
property viewer provided by ItemHolder displays the actual contents (as
opposed to the properties of the ItemHolder itself, since it hardly has
ItemHolder has two subclasses: Place and PCStorage. Place
represents a single square in the world, and includes terrain functionality.
So there will be subclasses to Place such as Forest, Desert, Water, etc.
Place implements physical constraints such as checking if an item can fit,
or imposing restrictions for certain items - for example damaging items
of a certain type that enter.
PCStorage is where your character goes when you are not logged on.
The deal here is that no events will go in or out of the PCStorage and
that players within cannot mess around with each other - and stuff like
that. For now there is one global PCStorage, a direct child of the
World. But later on Hotels and things like that will be maintaining
their own PCStorages.
There is only one World and it is the top of the container hierarchy,
the root node. It is the only Physical that can survive having
a location of null! It keeps track of the top-level Areas
(as children) and contains a PCStorage for characters that are not
logged on. It also keeps an index of all Accounts, regardless
of their locations. Important distinction here - the Accounts are
not children of the World - they are children of the bodies they
control. The World needs an index of them, however, for client bootstrapping
An Area is a matrix (or two-dimensional array) of Places.
It is a unit of geography. Note that an Area has a location as well,
so it may very well be inside a Place which in turn is inside another Area!
Nested Areas are thus possible. Areas that are not inside another
area must be direct children of the World, as mentioned above.
Areas are special in the sense that their children (the Places)
are spacially related to each other. Therefore an Area has the important
duty of figuring out how far to propagate an event - it might determine
that only a certain subset of the matrix should receive an event because
the others are too far away. This is how the propagation of events
Finally a Creature is, well, a creature. Creatures are alive,
and can be killed. They can also hold things - this is represented
by the two children that all Creatures have: "worn" and "held". These
are instances of ItemHolder which in turn, of course, can contain other
objects. See the container hierarchy
example - it should clearly illustrate this. The worn/held structure
is a good start, but it can be greatly advanced later to include things
like where on the body something is worn, how it is held, and stuff like
Thing is the superclass of all the "normal" items you would encounter
in a tile-based game - things like trees, bags, swords, potatoes, doors,
bushes, pools, arrows, cups, stones, walls, books, etc, etc, etc.
I haven't defined this hierarchy yet (only made a small simple one so far
for testing purposes), but it will be very large and I will write a seperate
document describing it later on.