Discusses how communication between the server and client works.
The Circumreality server application communicates with the client software
(on the player's computer) over the internet. All communications
are done using a MML string (basically XML).
The Basic IF library supplies several functions useful for
sending messages over the Internet to the client.
Most of the functions have two flavors, one that sends the
message immediately, although it will be queued up on the
client. The other returns a MML string; several of these
strings can be appended and then sent all at once to the
client. Functions that return the MML string are generally
prepended with "MML", such as MMLAudioPlay(), which returns
a MML string, while MMLAudioPlay() sends the string immediately.
The most commonly used communication functions are:
-
ActorLanguageSet() - Calling this function
sets the current language (through LanguageSet()), to whatever
language the actor has chosen as their preferred language.
Before sending any message to an actor, you should call
ActorLanguageSet() to ensure they will receive the message
in the proper language.
-
AudioPlay() - Plays a wave or MIDI (music) file
on the user's computer.
-
AutoCommand() - Has the user's computer send
a command back to the server, such as "go north". At first
glance this function may seem pointless, but it is useful
since the message will be sent only when the
client's playback queue gets to this point.
AutoCommand() is particularly useful for story segments
since a small portion of audio and animation can be queued
up on the user's system. When all that is played, the
AutoCommand() will cause a message to be send back to the
server, which in turn sends a bit more of the story.
-
ObjectDisplayUpdate() - Whenever an object
is changed (such as turned on or opened) its visuals may
change. Calling ObjectDisplayUpdate() will update the
object's visuals to one of the players.
-
ObjectDisplayUpdateAll() - This is just
like ObjectDisplayUpdate() except that all of the players
in the room will get the visual update.
-
RoomDisplayUpdate() - When the contents of
a room has changed, calling this will update the visuals
(room display, contents, inventory) for one of the
players.
-
RoomDisplayUpdateAll() - Just like
RoomDisplayUpdate() except all players in the room are
notified.
-
Silence() - Calling this will add silence to
the queue, creating a pause between actions.
-
SpeakNarrator() - Causes the text-to-speech
to be played on the player's computer. The voice used
will be the narrator's.
-
SpeakObject() - Causes the text-to-speech
to be played on the player's computer. The voice used
will be the object's.
-
StringCleanup() - This utility function
removes potentially unsafe characters from names (or other strings)
that come from from the user's command.
Some less commonly used functions are:
-
AmbientLoopVar() - Some ambient sounds that
include loops have the ability to loop in different ways
depending upon the value of "ambient loop variables". This
function lets the server set the value of the variable.
-
AmbientUpdate() - This updates the ambient
sounds played on a player's computer. The ambient sounds
are a set of sounds based on the player's room, and sometimes
even items carried by the player.
-
ChatDisplayUpdate() - Update's the actor's
chat window.
-
ChatVerbUpdate() - Update's the actor's
chat window.
-
CommandLineShow() - Shows or hides the command
line. If the command line is hidden the player must click
on hotspots or menus, and cannot type in commands directly.
-
Position360() - Changes the player's facing
for the 360 degree images.
-
VerbWindowShow() - Shows or hides the player's
verb window.
The MML string functions don't actually send a message to
the player's computer. Instead, they return a string with the
message. The message can then be sent at a later date, combined
with other messages, or passed into other MMLxxx() functions.
-
MMLAmbientLoopVar() - Like AmbientLoopVar()
except it returns the string.
-
MMLAmbientSounds() - This function combines
several "<Ambient>" resources into a single "<AmbientSounds>..</AmbientSounds>"
message that can be sent to the client.
-
MMLAudioPlay() - Like AudioPlay() except
it returns the string.
-
MMLAutoCommand() - Like AutoCommand() except
it returns the string.
-
MMLCommandLineShow() - Like CommandLineShow() except
it returns the string.
-
MMLDelay() - See the "Queues and delays" section
for a complete description.
-
MMLDisplayWindow() - Calling this will create
a new window on the client's computer and display the provided
object within the window. If the window already exists then
it will be updated.
-
MMLDisplayWindowMain() - This function combined
MMLObjectDisplay() with MMLDislpayWindowMain() to make
it very easy to update the image shown in the main window.
-
MMLGroup() - MMLGroup() is used to wrap up groups
of related object images (See MMLObjectDisplay() or the
method VisualAndMenuGet()). The groups of images are then combined
using MMLIconWindow().
-
MMLIconWindow() - Creates a new window on the
player's computer that displays a series of objects. If the
icon window already exists then it will be updated with
the new information. The objects
are arranged into groups. For example: The inventory window
has a group of items immediately held by the player character,
followed by groups for items contained within other items.
-
MMLObjectDisplay() - The MMLObjectDisplay()
function creates an "<ObjectDisplay>" MML command, which
is used to name an object, provide a visual for it, and
perhaps a menu. You may also wish to look at the
VisualAndMenuGet() method documentation.
The <ObjectDisplay> MML
command can be used in a few different ways: The MML
string can be passed to MMLGroup() or MMLDisplayWindow() to
specify what objects are displayed in an icon or display window.
Alternatively, the <ObjectDisplay> MML can be sent directly
to the client using ConnectionSend(); doing this will cause
any visuals for the object to be updated to whatever is
in the new MML.
-
MMLObjectDisplayGroup() - This function
is used to get the <ObjectDisplay> MML for the contents
of an object.
-
MMLPosition360() - Like Position360() except
this returns the MML.
-
MMLQueue() - See "Queues and delays" for more
information.
-
MMLQueueSimultaneous() - See "Queues and delays"
for more information.
-
MMLSilence() - Like Silence() except this returns
the MML.
-
MMLSpeakNarrator() - Like SpeakNarrator() except
this returns the MML string.
-
MMLSpeakObject() - Like SpeakObject() except
this returns the MML string.
Whenever a message is sent to the client (using ConnectionSend()),
there is an option for placing the message in the main queue
or acting on it right away. If the message is placed in the main
queue it will ignored until that point of the queue is reached.
The queue allows you to have the client play a sound (waiting
until the sound is finished), speak (waiting until the speech
is finished), display an image, speak again (waiting until
the speech is finished), etc.
If the message are marked for immediate use, then all of the
events will happen at the sime time... except the
speech. The text-to-speech system can only generate one voice
at a time, so even if you tell it to speak several sentences
at once, it will end up speaking them one at a time.
All of this can easily be done using ConnectionSend() and the
MMLxxx() functions above.
However, what if you want a sound to play concurrently with
the second audio (both being played after the image is
displayed)? Or what if you wanted the sound to play half
way through the speech?
To do this you would use MMLDelay().
The <Delay> MML command causes another queue to be created
which runs at the same time as the original one. Therefore,
if you call add MMLDelay (0, rWaveToPlay) into the queue then
at the point in the queue where the message is processed, it
will create a new queue that playes "rWaveToPlay". When
rWaveToPlay is finished playing the second queue will
automatically shut down.
If you pass a time into delay, such as MMLDelay (5, rWaveToPlay)
then the wave won't play until 5 seconds of the next sound (or
speech) has been played. (For example: MMLDelay(5,rWaveToPlay) +
MMLNarratorSpeak(...) will play the sound 5 seconds after the
narrator begins to speak.)
Since the amount of time to speak will vary depending upon the
user's speed settings (or language selected), you can have the
delayed wave play a percentage of the way through the next
sound (or speech). Just use a negative number to indicate
the percentage. (For example: MMLDelay(-50,rWAveToPlay) +
MMLNarratorSpeak(...) will start the wave playing half way
through.)
But what if you want your secondary queue to play more than
one wave, or perform some other action?
That's where MMLQueue() comes in. It combines
a series of MML actions into a queue MML. This queue can then
be passed into MMLDelay(). After the delay occurs, the queue
will be processed one at a time.
(For example: MMLDelay(-50, MMLQueue(rWaveToPlay, rWaveOther)) +
MMLNarratorSpeak(...) will play rWavePlay half way through the
speech. When rWavePlay is finished, rWaveOther will be played,
sequentially after rWavePlay, but concurrently with MMLNarratorSpeak()).
You can also use MMLQueue() when calling ConnectionSend().
If you have the message queued up in the main queue then nothing
unusual happens. However, if ConnectionSend() is set to immediate
playback, then the queued events (in MMLQueue()) will start playing
in their own queue, but sequentially.
The Basic IF Library also includes a
function, MMLQueueSimultaneous that combines
MMLDelay(0, xxx) with MMLQueue(). It just makes programming
a bit easier.
Using the MMLQueue() and MMLDelay() functions you can create
complex timings on the user's computer. These are particularly
useful for the story segments, which often rely on simple
animations.
Share with your friends: |