Bundles! Have component bundles largely working. Wrote test code and ANT

tasks and XML parsing rule sets all the good stuff. Rewired up all the
cast code to be amenable to bundling and did some other revamping.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@640 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2001-11-27 08:09:35 +00:00
parent be313f8922
commit c25741d8e6
27 changed files with 1554 additions and 918 deletions
@@ -0,0 +1,85 @@
//
// $Id: ActionRuleSet.java,v 1.1 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.tools.xml;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSetBase;
import com.samskivert.util.StringUtil;
import com.samskivert.xml.CallMethodSpecialRule;
import com.samskivert.xml.SetFieldRule;
import com.samskivert.xml.SetPropertyFieldsRule;
import com.threerings.cast.ActionSequence;
/**
* The action rule set is used to parse the attributes of an action
* sequence instance.
*/
public class ActionRuleSet extends RuleSetBase
{
/** The component of the digester path that is appended by the action
* rule set to match a action. This is appended to whatever prefix is
* provided to the action rule set to obtain the complete XML path to
* a matched action. */
public static final String ACTION_PATH = "/action";
/**
* Instructs the action rule set to match actions with the supplied
* prefix. For example, passing a prefix of <code>actions</code> will
* match actions in the following XML file:
*
* <pre>
* &lt;actions&gt;
* &lt;action&gt;
* // ...
* &lt;/action&gt;
* &lt;/actions&gt;
* </pre>
*
* This must be called before adding the ruleset to a digester.
*/
public void setPrefix (String prefix)
{
_prefix = prefix;
}
/**
* Adds the necessary rules to the digester to parse our actions.
*/
public void addRuleInstances (Digester digester)
{
// this creates the appropriate instance when we encounter a
// <action> tag
digester.addObjectCreate(_prefix + ACTION_PATH,
ActionSequence.class.getName());
// grab the name attribute from the <action> tag
digester.addRule(_prefix + ACTION_PATH,
new SetPropertyFieldsRule(digester));
// grab the other attributes from their respective tags
digester.addRule(_prefix + ACTION_PATH + "/framesPerSecond",
new SetFieldRule(digester, "framesPerSecond"));
CallMethodSpecialRule origin = new CallMethodSpecialRule(digester) {
public void parseAndSet (String bodyText, Object target)
throws Exception {
int[] coords = StringUtil.parseIntArray(bodyText);
if (coords.length != 2) {
String errmsg = "Invalid <origin> specification '" +
bodyText + "'.";
throw new Exception(errmsg);
}
((ActionSequence)target).origin.setLocation(
coords[0], coords[1]);
}
};
digester.addRule(_prefix + ACTION_PATH + "/origin", origin);
}
/** The prefix at which me match our actions. */
protected String _prefix;
}
@@ -0,0 +1,60 @@
//
// $Id: ClassRuleSet.java,v 1.1 2001/11/27 08:09:35 mdb Exp $
package com.threerings.cast.tools.xml;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSetBase;
import com.samskivert.xml.SetPropertyFieldsRule;
import com.threerings.cast.ComponentClass;
/**
* The class rule set is used to parse the attributes of a component class
* instance.
*/
public class ClassRuleSet extends RuleSetBase
{
/** The component of the digester path that is appended by the class
* rule set to match a component class. This is appended to whatever
* prefix is provided to the class rule set to obtain the complete XML
* path to a matched class. */
public static final String CLASS_PATH = "/class";
/**
* Instructs the class rule set to match component classes with the
* supplied prefix. For example, passing a prefix of
* <code>classes</code> will match classes in the following XML file:
*
* <pre>
* &lt;classes&gt;
* &lt;class .../&gt;
* &lt;/classes&gt;
* </pre>
*
* This must be called before adding the ruleset to a digester.
*/
public void setPrefix (String prefix)
{
_prefix = prefix;
}
/**
* Adds the necessary rules to the digester to parse our classes.
*/
public void addRuleInstances (Digester digester)
{
// this creates the appropriate instance when we encounter a
// <class> tag
digester.addObjectCreate(_prefix + CLASS_PATH,
ComponentClass.class.getName());
// grab the attributes from the <class> tag
digester.addRule(_prefix + CLASS_PATH,
new SetPropertyFieldsRule(digester));
}
/** The prefix at which me match our component classes. */
protected String _prefix;
}
@@ -1,249 +0,0 @@
//
// $Id: XMLComponentParser.java,v 1.5 2001/11/20 04:15:43 mdb Exp $
package com.threerings.cast.tools.xml;
import java.awt.Point;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import org.xml.sax.*;
import com.samskivert.util.*;
import com.samskivert.xml.SimpleParser;
import com.threerings.media.tile.TileSet;
import com.threerings.media.tools.tile.xml.XMLTileSetParser;
import com.threerings.cast.Log;
import com.threerings.cast.ActionSequence;
import com.threerings.cast.ComponentClass;
import com.threerings.cast.CharacterComponent;
/**
* Parses an XML character component description file and populates
* hashtables with {@link ActionSequence}, {@link ComponentClass}, and the
* information necessary to construct {@link CharacterComponent} objects.
*
* <p> Does not currently perform validation on the input XML stream,
* though the parsing code assumes the XML document is well-formed.
*/
public class XMLComponentParser extends SimpleParser
{
// documentation inherited
public void startElement (
String uri, String localName, String qName, Attributes attributes)
{
if (qName.equals("charactercomponents")) {
// save off the image directory
_imagedir = attributes.getValue("imagedir");
// load the tile sets
loadTileSets(attributes.getValue("tilesets"));
} else if (qName.equals("action")) {
// construct and save off the action sequence object
ActionSequence as = getActionSequence(attributes);
_actions.put(as.asid, as);
} else if (qName.equals("class")) {
// construct and save off the component class object
ComponentClass cclass = getComponentClass(attributes);
_classes.put(cclass.clid, cclass);
} else if (qName.equals("component")) {
// construct and save off the character component
CharacterComponent component = getComponent(attributes);
_components.put(component.getId(), component);
}
}
/**
* Loads the component descriptions in the given file into the
* given component data hashtables.
*/
public void loadComponents (String file, HashIntMap actions,
HashIntMap classes, HashIntMap components)
throws IOException
{
// save off hashtables for reference while parsing
_actions = actions;
_classes = classes;
_components = components;
// clear out remnants of any previous parsing antics
_imagedir = null;
_tilesets.clear();
// parse the file
parseFile(file);
}
/**
* Returns the image directory the component tile images reside
* within.
*/
public String getImageDir ()
{
return _imagedir;
}
/**
* Loads the tile sets in the XML file at the given path into the
* tile sets available for reference by the action sequences.
*/
protected void loadTileSets (String path)
{
// make sure we have a reasonable path
if (path == null) {
Log.warning("Null component tile set description file path.");
return;
}
// parse the tile set description file
XMLTileSetParser p = new XMLTileSetParser();
try {
p.loadTileSets(path, _tilesets);
} catch (IOException e) {
Log.warning("Exception loading component tile set descriptions " +
"[path=" + path + "].");
}
}
/**
* Returns a new action sequence object as described by the given
* attributes.
*/
protected ActionSequence getActionSequence (Attributes attrs)
{
ActionSequence as = new ActionSequence();
as.asid = parseInt(attrs.getValue("asid"));
as.name = attrs.getValue("name");
as.fileid = attrs.getValue("fileid");
String tileset = attrs.getValue("tileset");
as.tileset = (TileSet)_tilesets.get(tileset);
if (as.tileset == null) {
Log.warning("Action sequence references non-existent " +
"tile set [asid=" + as.asid +
", tileset=" + tileset + "].");
}
as.fps = parseInt(attrs.getValue("fps"));
parsePoint(attrs.getValue("origin"), as.origin);
return as;
}
/**
* Returns a new component class object as described by the given
* attributes.
*/
protected ComponentClass getComponentClass (Attributes attrs)
{
ComponentClass cclass = new ComponentClass();
cclass.clid = parseInt(attrs.getValue("clid"));
cclass.name = attrs.getValue("name");
cclass.render = parseInt(attrs.getValue("render"));
return cclass;
}
/**
* Returns a new character component object as described by the
* given attributes.
*/
protected CharacterComponent getComponent (Attributes attrs)
{
// retrieve the component attributes
int cid = parseInt(attrs.getValue("cid"));
String fileid = attrs.getValue("fileid");
String val = attrs.getValue("asids");
int asids[] = StringUtil.parseIntArray(val);
int clid = parseInt(attrs.getValue("clid"));
ComponentClass cclass = (ComponentClass)_classes.get(clid);
// gather the array of relevant action sequences
ActionSequence seqs[] = getActionSequences(asids);
// construct the component sans frames for now
CharacterComponent component =
new CharacterComponent(cid, fileid, seqs, cclass);
// warn if the component has notably invalid attributes
validateComponent(cid, asids, clid);
return component;
}
/**
* Outputs a warning regarding the given component id if the given
* action sequence ids and component class id for that component
* don't exist.
*/
protected void validateComponent (int cid, int asids[], int clid)
{
// check the action sequence ids
for (int ii = 0; ii < asids.length; ii++) {
int asid = asids[ii];
if (_actions.get(asid) == null) {
Log.warning(
"Component references non-existent action sequence " +
"[cid=" + cid + ", asid=" + asid + "].");
}
}
// check the class id
if (_classes.get(clid) == null) {
Log.warning("Component references non-existent class " +
"[cid=" + cid + ", clid=" + clid + "].");
}
}
/**
* Returns an array of action sequence objects corresponding to
* the action sequence ids in the given array.
*/
protected ActionSequence[] getActionSequences (int asids[])
{
// sort the action sequence ids for better regularity
Arrays.sort(asids);
// create and populate the array
ActionSequence[] seqs = new ActionSequence[asids.length];
for (int ii = 0; ii < asids.length; ii++) {
seqs[ii] = (ActionSequence)_actions.get(asids[ii]);
}
return seqs;
}
/**
* Converts a string containing values as (x, y) into the
* corresponding integer values and populates the given point
* object.
*
* @param str the point values in string format.
* @param point the point object to populate.
*/
protected void parsePoint (String str, Point point)
{
int vals[] = StringUtil.parseIntArray(str);
point.setLocation(vals[0], vals[1]);
}
/** The image directory containing the component image files. */
protected String _imagedir;
/** The hashtable of component tile sets. */
protected HashMap _tilesets = new HashMap();
/** The hashtable of action sequences gathered while parsing. */
protected HashIntMap _actions;
/** The hashtable of component classes gathered while parsing. */
protected HashIntMap _classes;
/** The hashtable of character components gathered while parsing. */
protected HashIntMap _components;
}
@@ -1,155 +0,0 @@
//
// $Id: XMLComponentRepository.java,v 1.7 2001/11/18 04:09:21 mdb Exp $
package com.threerings.cast.tools.xml;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import com.samskivert.util.Config;
import com.samskivert.util.HashIntMap;
import com.threerings.cast.*;
import com.threerings.cast.util.TileUtil;
import com.threerings.media.ImageManager;
import com.threerings.media.tile.TileManager;
import com.threerings.miso.Log;
import com.threerings.miso.util.MisoUtil;
/**
* The xml component repository provides access to character
* components obtained from component descriptions stored in an XML
* file.
*/
public class XMLComponentRepository implements ComponentRepository
{
/**
* Constructs an xml component repository.
*/
public XMLComponentRepository (Config config)
{
// load component types and components
String file = config.getValue(COMPONENTS_KEY, DEFAULT_COMPONENTS);
try {
XMLComponentParser p = new XMLComponentParser();
p.loadComponents(file, _actions, _classes, _components);
_imagedir = p.getImageDir();
} catch (IOException ioe) {
Log.warning("Exception loading component descriptions " +
"[ioe=" + ioe + "].");
}
}
// documentation inherited
public CharacterComponent getComponent (int cid)
throws NoSuchComponentException
{
// get the component information
CharacterComponent c = (CharacterComponent)_components.get(cid);
if (c == null) {
throw new NoSuchComponentException(cid);
}
// get the character animation frames
c.setFrames(TileUtil.getComponentFrames(_imagedir, c));
return c;
}
// documentation inherited
public Iterator enumerateComponentClasses ()
{
return Collections.unmodifiableMap(_classes).values().iterator();
}
// documentation inherited
public Iterator enumerateComponentsByClass (int clid)
{
return new ComponentIterator(clid);
}
/**
* Iterates over all components of a specified component type, and
* optionally a specified component class, in the component
* hashtable.
*/
protected class ComponentIterator implements Iterator
{
/**
* Constructs an iterator that iterates over all components of
* the specified component class.
*/
public ComponentIterator (int clid)
{
_clid = clid;
_iter = _components.keys();
advance();
}
public boolean hasNext ()
{
return (_next != null);
}
public Object next ()
{
Object next = _next;
advance();
return next;
}
public void remove ()
{
throw new UnsupportedOperationException();
}
protected void advance ()
{
while (_iter.hasNext()) {
Integer cid = (Integer)_iter.next();
CharacterComponent c =
(CharacterComponent)_components.get(cid);
if (c.getComponentClass().clid == _clid) {
_next = cid;
return;
}
}
_next = null;
}
/** The component class id for inclusion in the iterator. */
protected int _clid;
/** The next character component associated with this
* iterator, or null if no more exist. */
protected Object _next;
/** The iterator over all components in the repository. */
protected Iterator _iter;
}
/** The config key for the character description file. */
protected static final String COMPONENTS_KEY =
MisoUtil.CONFIG_KEY + ".components";
/** The default character description file. */
protected static final String DEFAULT_COMPONENTS =
"rsrc/config/miso/components.xml";
/** The image directory containing the component image files. */
protected String _imagedir;
/** The hashtable of component types. */
protected HashIntMap _actions = new HashIntMap();
/** The hashtable of component classes. */
protected HashIntMap _classes = new HashIntMap();
/** The hashtable of character components. */
protected HashIntMap _components = new HashIntMap();
}