PHAT-CLIENT TUTORIAL
The following explores the common interfaces between the MOO and MAM (Multi-Agent Management) system. PLEASE REALIZE that it is intended primarily for programmers who want to have an understanding of how to make a MOO environment interface to the agent framework. Hopefully you have already taken a moment to look at the packages and agent types to get an overall sense of the project architecture, as well as the messaging and agent layers, which demonstrates how to create your own customized messages and agent types.
PROXY is a project that ties together the MOO and MAM system quite closely. In theory the MOO and MAM could be separated entirely. The MAM is a purely peer-to-peer system that requires no central server to run. It collapses client/server hierarchies by having everyone using the system run as both, and uses unique discovery methods to put agents in contact with each other. However, the MOO is a centralized server environment running on a single machine (by default 'http://proxy.arts.uci.edu:7000/62' via httpd and 'telnet://proxy.arts.uci.ed:7777' via telnet) that the MAM points to on startup.
Why did we mix a decentralized peer-to-peer agent framework with a centralized MOO system? Good question. The answer is primarily to provide a sense of context for agent interactions (human to human, human to software, and software to software). Lots of good work has gone on over the years to make MOO servers that facilitate robust and extensible online community and communication. We wanted to not only take advantage of that work, but take it to the next level as well, by interfacing it to our agent system. We also wanted to make it flexible enough that others could make our system work with their own MOO server if they so desired.
NOTE: To interface to a different MOO (as stated in the FAQ) you simply need to modify the 'phat-prefs.xml' file (inside the 'cfg/' directory) and make it point to whatever moo location ('moo-hostname') and port number ('port') you want. In order for login and authentication to happen properly on startup, you also need to choose two keywords or keyphrases to send to the agent system ('connect-key-text'). The first of these is a word or phrase that appears during an initial connect (usually something like 'Connected'). The second should be a word or phrase that appears when a connection is redirected (usually something like 'Redirecting'). Once done, then you need to start defining your custom MOO-based XML messages for passing back out to MAM.
Be aware that certain MAM functionality will be lost when you connect to a different MOO, since the new MOO will not yet have the necessary MAM messages for execution. For example, you will be unable to: do real-time translation of chat-based communication and Web pages; export your agent's data cache as text-only ('Display: ASCII Mode') for navigation via MOO; auto-generate VRML representations of the agent's exported data cache; or Auto Map the agent's in-MOO movement via HTML or VRML.
QUICK LINKS: MUE/MOO and MAM interfaces
- MOO > MAM
- MAM > MOO
- MAM Message
- Phat-Client Tutorial: Menuing and Functionality
- Phat-Client Tutorial: Agent Attributes
- Phat-Client Tutorial: Custom Look & Feel
- Phat-Client Tutorial: [for programmers] Packages and Agent Types
- Phat-Client Tutorial: [for programmers] Messaging and Agent Layers
- Phat-Client Tutorial: [for programmers] MUE/MOO and MAM interfaces
- Phat-Client Tutorial: [for programmers] MUE/MOO Game and Utility Code
- Phat-Client Tutorial: [for programmers] Server-Side Scripts
- Phat-Client Tutorial: [for programmers] MAM UML Documentation
- Phat-Client Tutorial: [for programmers] MAM Javadocs
- PROXY portal
- MAM > MOO
MOO > MAM
All the messages that get passed out from MOO and received by MAM are written in XML. Here's an example of an XML message ('DoMooCombatDeathMessage') that is sent to MAM from MOO when an agent dies during in-MOO combat:
<mam-message type="mam.messaging.DoMooCombatDeathMessage"> <Source pref="true" type="mam.internetworking.RoutingTag" value="**myClient**" /> <Destination pref="true" type="mam.internetworking.RoutingTag" value="local.mamCommunicator" /> </mam-message>
The structure of the XML message breaks down as follows: mam-message type which calls the appropriate MAM message; Source pref, type, value; and Destination pref, type, value. It is possible to pass arbitrary values as part of the message parameters, either as additional tags or as attributes.
For both Source and Destination the pref is a persistence preference, indicating whether the message gets marshaled automatically or not. We do a mapping between XML elements and Java objects. The pref generally gets set to true. The type refers to the java class you are restoring to or from. The value is simply the value of the named element.
An XML MOO message can be attached to any object or action in the MOO environment. In the case of the 'DoMooCombatDeathMessage' we attached it to a verb that gets called when a user's hit points reach zero during combat. The verb has a portion that does a check on a 'dobj.phat_client' property to see how the user is currently connected, as well as a 'dobj.death_message' property to see if there is an XML message like the above to pass back to MAM. Here's the relevant verb portion:
if ( dobj.phat_client != 0 && ( dobj.death_message != "" ) ) for line in ( dobj.death_message ) dobj:tell( line ); endfor endif
MAM > MOO
Here's the MAM code that does something with that message once it's received. In this case the code is received and handled by both the MamCommunicator.java (part of the 'applications.proxy.main' package):
public void handleDoMooCombatDeathMessage( AgentMessage m ) { m.setDestination( getIpAgentRoutingTag() ); getFacility().sendAgentMessage( m ); }
as well as the InformationPersonaeAgent.java (part of the 'mam.agent' package):
public void handleDoMooCombatDeathMessage( AgentMessage m ) { Iterator itrKnowledgeAgents = m_knowledgeAgents.iterator(); while( itrKnowledgeAgents.hasNext() ) { MamId deadAgentId = ( MamId ) itrKnowledgeAgents.next(); EventDeclareKnowledgeAgentRemovedMessage eventDeclareKnowledgeAgentRemovedMessage = new EventDeclareKnowledgeAgentRemovedMessage( getRoutingTagToSelf(), IP_AGENT_KNOWLEDGE_ACTIVITY_LISTENER_TAG, deadAgentId ); eventDeclareKnowledgeAgentRemovedMessage.setLocal(); getFacility().sendAgentMessage( eventDeclareKnowledgeAgentRemovedMessage ); } m_knowledgeAgents.clear(); }
What happens in the above examples is: 1) 'MamCommunicator' handles the 'DoMooCombatDeathMessage' and sends it along to the 'InformationPersonaeAgent'; and 2) the 'InformationPersonaeAgent' handles the message and then iterates through all the currently ingested 'KnowledgeAgents' and removes them, causing the user to have to start rebuilding the agent's knowledge base from scratch.
MAM MESSAGE
Here's the acutal message (from the 'mam.messaging' package):
package mam.messaging; import java.io.*; import java.util.*; import mam.id.*; import mam.internetworking.*; import mam.xml.*; public class DoMooCombatDeathMessage extends AgentMessage { public DoMooCombatDeathMessage() { super(); } public DoMooCombatDeathMessage( RoutingTag source, RoutingTag destination ) { this( source, destination, null ); } public DoMooCombatDeathMessage( RoutingTag source, RoutingTag destination, MamId responseTo ) { super( source, destination, responseTo ); } }
The message composition is consistent with the discussion in the messaging and agent layers section of the tutorial. Of primary concern here is the routing source, the routing destination, and whether a response is intended.
Please send comments to nideffer@uci.edu.