Files
narya/src/java/com/threerings/cast/bundle/BundledComponentRepository.java
T
Michael Bayne a52d62d532 Modified ActionFrames because having it implement MultiFrameImage and just
"remember" which orientation it should be doing was not working out
because multiple sprites can share the same action frames and they would
step on one anothers' toes.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1360 542714f4-19e9-0310-aa3c-eee0fc999fb1
2002-05-15 23:54:05 +00:00

394 lines
13 KiB
Java

//
// $Id: BundledComponentRepository.java,v 1.12 2002/05/15 23:54:05 mdb Exp $
package com.threerings.cast.bundle;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import com.samskivert.io.NestableIOException;
import com.samskivert.util.HashIntMap;
import com.samskivert.util.Tuple;
import org.apache.commons.collections.FilterIterator;
import org.apache.commons.collections.Predicate;
import com.threerings.resource.ResourceBundle;
import com.threerings.resource.ResourceManager;
import com.threerings.media.ImageManager;
import com.threerings.media.util.Colorization;
import com.threerings.media.util.ImageUtil;
import com.threerings.media.sprite.MultiFrameImage;
import com.threerings.media.tile.ImageProvider;
import com.threerings.media.tile.NoSuchTileException;
import com.threerings.media.tile.Tile;
import com.threerings.media.tile.TileSet;
import com.threerings.util.DirectionCodes;
import com.threerings.cast.ActionFrames;
import com.threerings.cast.CharacterComponent;
import com.threerings.cast.ComponentClass;
import com.threerings.cast.ComponentRepository;
import com.threerings.cast.FrameProvider;
import com.threerings.cast.Log;
import com.threerings.cast.NoSuchComponentException;
/**
* A component repository implementation that obtains information from
* resource bundles.
*
* @see ResourceManager
*/
public class BundledComponentRepository
implements DirectionCodes, ComponentRepository
{
/**
* Constructs a repository which will obtain its resource set from the
* supplied resource manager.
*
* @param rmgr the resource manager from which to obtain our resource
* set.
* @param imgr the image manager that we'll use to decode and cache
* images.
* @param name the name of the resource set from which we will be
* loading our component data.
*
* @exception IOException thrown if an I/O error occurs while reading
* our metadata from the resource bundles.
*/
public BundledComponentRepository (
ResourceManager rmgr, ImageManager imgr, String name)
throws IOException
{
// keep this guy around
_imgr = imgr;
// first we obtain the resource set from whence will come our
// bundles
ResourceBundle[] rbundles = rmgr.getResourceSet(name);
// look for our metadata info in each of the bundles
try {
for (int i = 0; i < rbundles.length; i++) {
if (_actions == null) {
_actions = (HashMap)BundleUtil.loadObject(
rbundles[i], BundleUtil.ACTIONS_PATH);
}
if (_actionSets == null) {
_actionSets = (HashMap)BundleUtil.loadObject(
rbundles[i], BundleUtil.ACTION_SETS_PATH);
}
if (_classes == null) {
_classes = (HashMap)BundleUtil.loadObject(
rbundles[i], BundleUtil.CLASSES_PATH);
}
}
// now go back and load up all of the component information
for (int i = 0; i < rbundles.length; i++) {
HashIntMap comps = (HashIntMap)BundleUtil.loadObject(
rbundles[i], BundleUtil.COMPONENTS_PATH);
if (comps == null) {
continue;
}
// create a frame provider for this bundle
FrameProvider fprov = new ResourceBundleProvider(rbundles[i]);
// now create character component instances for each component
// in the serialized table
Iterator iter = comps.keySet().iterator();
while (iter.hasNext()) {
int componentId = ((Integer)iter.next()).intValue();
Tuple info = (Tuple)comps.get(componentId);
createComponent(componentId, (String)info.left,
(String)info.right, fprov);
}
}
} catch (ClassNotFoundException cnfe) {
throw new NestableIOException(
"Internal error unserializing metadata", cnfe);
}
}
// documentation inherited
public CharacterComponent getComponent (int componentId)
throws NoSuchComponentException
{
CharacterComponent component = (CharacterComponent)
_components.get(componentId);
if (component == null) {
throw new NoSuchComponentException(componentId);
}
return component;
}
// documentation inherited
public CharacterComponent getComponent (String className, String compName)
throws NoSuchComponentException
{
// look up the list for that class
ArrayList comps = (ArrayList)_classComps.get(className);
if (comps != null) {
// scan the list for the named component
int ccount = comps.size();
for (int i = 0; i < ccount; i++) {
CharacterComponent comp = (CharacterComponent)comps.get(i);
if (comp.name.equals(compName)) {
return comp;
}
}
}
throw new NoSuchComponentException(className, compName);
}
// documentation inherited
public ComponentClass getComponentClass (String className)
{
return (ComponentClass)_classes.get(className);
}
// documentation inherited
public Iterator enumerateComponentClasses ()
{
return _classes.values().iterator();
}
// documentation inherited
public Iterator enumerateActionSequences ()
{
return _actions.values().iterator();
}
// documentation inherited
public Iterator enumerateComponentIds (final ComponentClass compClass)
{
Predicate classP = new Predicate() {
public boolean evaluate (Object input) {
CharacterComponent comp = (CharacterComponent)
_components.get(input);
return comp.componentClass.equals(compClass);
}
};
return new FilterIterator(_components.keySet().iterator(), classP);
}
/**
* Creates a component and inserts it into the component table.
*/
protected void createComponent (
int componentId, String cclass, String cname, FrameProvider fprov)
{
// look up the component class information
ComponentClass clazz = (ComponentClass)_classes.get(cclass);
if (clazz == null) {
Log.warning("Non-existent component class " +
"[class=" + cclass + ", name=" + cname +
", id=" + componentId + "].");
return;
}
// create the component
CharacterComponent component = new CharacterComponent(
componentId, cname, clazz, fprov);
// stick it into the appropriate tables
_components.put(componentId, component);
// we have a hash of lists for mapping components by class/name
ArrayList comps = (ArrayList)_classComps.get(cclass);
if (comps == null) {
comps = new ArrayList();
_classComps.put(cclass, comps);
}
if (!comps.contains(component)) {
comps.add(component);
} else {
Log.info("Requested to register the same component twice? " +
"[component=" + component + "].");
}
}
/**
* Instances of these provide images to our component action tilesets
* and frames to our components.
*/
protected class ResourceBundleProvider
implements ImageProvider, FrameProvider
{
/**
* Constructs an instance that will obtain image data from the
* specified resource bundle.
*/
public ResourceBundleProvider (ResourceBundle bundle)
{
_bundle = bundle;
}
// documentation inherited
public Image loadImage (String path)
throws IOException
{
// obtain the image data from our resource bundle
InputStream imgin = _bundle.getResource(path);
if (imgin == null) {
String errmsg = "No such image in resource bundle " +
"[bundle=" + _bundle + ", path=" + path + "].";
throw new FileNotFoundException(errmsg);
}
return _imgr.loadImage(imgin);
}
// documentation inherited
public ActionFrames getFrames (
CharacterComponent component, String action)
{
// get the tileset for this action
TileSet aset = (TileSet)_actionSets.get(action);
if (aset == null) {
Log.warning("Can't provide animation frames for undefined " +
"action [action=" + action +
", component=" + component + "].");
return null;
}
// construct the appropriate image path for the component
String path = component.componentClass.name + "/" +
component.name + "/" + action +
BundleUtil.IMAGE_EXTENSION;
// clone the tileset with this new image path
try {
TileSet fset = aset.clone(path);
fset.setImageProvider(this);
return new TileSetFrameImage(fset);
} catch (CloneNotSupportedException cnse) {
Log.warning("Unable to clone tileset [action=" + action +
", component=" + component +
", set=" + aset + "].");
return null;
}
}
/** The resource bundle from which we obtain image data. */
protected ResourceBundle _bundle;
}
/**
* Used to provide multiframe images using data obtained from a
* tileset.
*/
protected static class TileSetFrameImage implements ActionFrames
{
/**
* Constructs a tileset frame image with the specified tileset and
* for the specified orientation.
*/
public TileSetFrameImage (TileSet set)
{
_set = set;
}
// documentation inherited from interface
public MultiFrameImage getFrames (final int orient)
{
return new MultiFrameImage() {
// documentation inherited
public int getFrameCount ()
{
return _set.getTileCount() / DIRECTION_COUNT;
}
// documentation inherited from interface
public int getWidth (int index)
{
Tile tile = getTile(orient, index);
return (tile == null) ? 0 : tile.getWidth();
}
// documentation inherited from interface
public int getHeight (int index)
{
Tile tile = getTile(orient, index);
return (tile == null) ? 0 : tile.getHeight();
}
// documentation inherited from interface
public void paintFrame (Graphics g, int index, int x, int y)
{
Tile tile = getTile(orient, index);
if (tile != null) {
tile.paint(g, x, y);
}
}
// documentation inherited from interface
public boolean hitTest (int index, int x, int y)
{
Tile tile = getTile(orient, index);
return (tile != null) ? tile.hitTest(x, y) : false;
}
};
}
// documentation inherited from interface
public ActionFrames cloneColorized (Colorization[] zations)
{
return new TileSetFrameImage(_set.cloneColorized(zations));
}
/**
* Fetches the requested tile.
*/
protected Tile getTile (int orient, int index)
{
int fcount = _set.getTileCount() / DIRECTION_COUNT;
int tileIndex = orient * fcount + index;
try {
return _set.getTile(tileIndex);
} catch (NoSuchTileException nste) {
Log.warning("Can't extract action frame [set=" + _set +
", orient=" + orient + ", index=" + index + "].");
return null;
}
}
/** The tileset from which we obtain our frame images. */
protected TileSet _set;
}
/** We use the image manager to decode and cache images. */
protected ImageManager _imgr;
/** A table of action sequences. */
protected HashMap _actions;
/** A table of action sequence tilesets. */
protected HashMap _actionSets;
/** A table of component classes. */
protected HashMap _classes;
/** A table of component lists indexed on classname. */
protected HashMap _classComps = new HashMap();
/** The component table. */
protected HashIntMap _components = new HashIntMap();
}