Enough AS cast implementation to render a basic character sprite from component bundles.

git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@970 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
Mike Thomas
2010-08-10 20:28:25 +00:00
parent 4b09709590
commit 57f020afb8
17 changed files with 1829 additions and 6 deletions
@@ -0,0 +1,309 @@
//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/nenya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.cast {
import flash.events.Event;
import com.threerings.cast.ComponentDataPack;
import com.threerings.media.tile.TileDataPack;
import com.threerings.util.ArrayUtil;
import com.threerings.util.DataPack;
import com.threerings.util.Log;
import com.threerings.util.Map;
import com.threerings.util.Maps;
import com.threerings.util.StringUtil;
public class DataPackComponentRepository
implements ComponentRepository
{
private static var log :Log = Log.getLog(DataPackComponentRepository);
public function DataPackComponentRepository (compUrl :String)
{
_rootUrl = compUrl;
loadComponentMeta(compUrl + "metadata.jar");
}
protected function loadComponentMeta (compMetaUrl :String) :void
{
_metaPack = new TileDataPack(compMetaUrl, metaLoadingComplete);
}
/**
* Handle the successful completion of datapack loading.
*
* @private
*/
protected function metaLoadingComplete (event :Event) :void
{
var actionXml :XML = _metaPack.getFileAsXML("actions.xml");
var classesXml :XML = _metaPack.getFileAsXML("classes.xml");
for each (var aXml :XML in actionXml.action) {
var action :ActionSequence = ActionSequence.fromXml(aXml);
_actions.put(action.name, action);
}
for each (var cXml :XML in classesXml.elements("class")) {
var compClass :ComponentClass = ComponentClass.fromXml(cXml);
_classes.put(compClass.name, compClass);
}
parseComponentMap(_metaPack.getFileAsString("compmap.txt"));
// Notify them all and clear our list.
for each (var func :Function in _notifyOnLoad) {
func();
}
_notifyOnLoad = [];
}
protected function parseComponentMap (map :String) :void
{
var lines :Array = map.split("\n");
var tileCount :int = int(lines[0]);
for (var ii :int = 1; ii < lines.length; ii++) {
var line :String = lines[ii];
var toks :Array = line.split(" := ");
if (toks.length >= 3) {
var id :int = int(toks[2]);
var cclass :String = String(toks[0]);
var cname :String = String(toks[1]);
createComponent(id, cclass, cname);
}
}
}
/**
* Creates a component and inserts it into the component table.
*/
protected function createComponent (componentId :int, cclass :String, cname :String) :void
{
// look up the component class information
var clazz :ComponentClass = _classes.get(cclass);
if (clazz == null) {
log.warning("Non-existent component class",
"class", cclass, "name", cname, "id", componentId);
return;
}
// create the component - we'll set the frame provider as soon as we can.
var component :CharacterComponent = new CharacterComponent(componentId, cname, clazz, null);
// stick it into the appropriate tables
_components.put(componentId, component);
// we have a hash of lists for mapping components by class/name
var comps :Array = _classComps.get(cclass);
if (comps == null) {
comps = [];
_classComps.put(cclass, comps);
}
if (!ArrayUtil.contains(comps, component)) {
comps.push(component);
} else {
log.info("Requested to register the same component twice?", "comp", component);
}
}
public function notifyOnLoad (func :Function) :void
{
_notifyOnLoad.push(func);
}
/**
* Returns the {@link CharacterComponent} object for the given component identifier.
*/
public function getComponent (componentId :int) :CharacterComponent
{
var component :CharacterComponent = _components.get(componentId);
if (component == null) {
throw new NoSuchComponentError(componentId);
}
return component;
}
/**
* Returns the {@link CharacterComponent} object with the given component class and name.
*/
public function getComponentByName (className :String, compName :String) :CharacterComponent
{
// look up the list for that class
var comps :Array = _classComps.get(className);
if (comps != null) {
for each (var comp :CharacterComponent in comps) {
if (comp.name == compName) {
return comp;
}
}
}
throw new NoSuchComponentError(className + "/" + compName);
}
public function load (compIds :Array, notify :Function) :void
{
var complete :Boolean = true;
var toLoad :Array = [];
for each (var cid :int in compIds) {
var comp :CharacterComponent = getComponent(cid);
if (!comp.isLoaded()) {
toLoad.push(comp);
}
}
var waiting :int = toLoad.length;
if (waiting == 0) {
notify();
} else {
for each (var load :CharacterComponent in toLoad) {
load.notifyOnLoad(function() :void {
waiting--;
if (waiting == 0) {
notify();
}
});
loadComponent(load);
}
}
}
protected function loadComponent (comp :CharacterComponent) :void
{
var packName :String = comp.componentClass.name + "/" + comp.name;
var pack :ComponentDataPack = _packs.get(packName);
if (pack == null || !pack.isComplete()) {
loadPack(packName, comp);
} else {
comp.setFrameProvider(pack);
}
}
protected function loadPack (packName :String, comp :CharacterComponent) :void
{
var pack :ComponentDataPack = _packs.get(packName);
if (pack != null && pack.isComplete()) {
// Already loaded
return;
}
var completeListener :Function = function () :void {
comp.setFrameProvider(_packs.get(packName));
}
var listeners :Array = _packListeners.get(packName);
if (listeners == null) {
listeners = [];
_packListeners.put(packName, listeners);
var packCompleteListener :Function = function () :void {
for each (var listener :Function in listeners) {
listener();
}
_packListeners.remove(packName);
}
pack = new ComponentDataPack(getPackUrl(packName), _actions, packCompleteListener);
_packs.put(packName, pack);
}
listeners.push(completeListener);
}
protected function getPackUrl (packName :String) :String
{
return _rootUrl + packName + "/components.jar";
}
/**
* Returns the {@link ComponentClass} with the specified name or null if none exists with that
* name.
*/
public function getComponentClass (className :String) :ComponentClass
{
return _classes.get(className);
}
/**
* Iterates over the {@link ComponentClass} instances representing all available character
* component classes.
*/
public function getComponentClasses () :Array
{
return _classes.values();
}
/**
* Iterates over the {@link ActionSequence} instances representing every available action
* sequence.
*/
public function getActionSequences () :Array
{
return _actions.values();
}
/**
* Iterates over the component ids of all components in the specified class.
*/
public function getComponentIds (compClass :ComponentClass) :Array
{
var result :Array = [];
_classes.forEach(function (key :int, value :CharacterComponent) :Boolean {
if (value.componentClass.equals(compClass)) {
result.push(key);
}
return false;
});
return result;
}
/** Everyone who cares when we're loaded. */
protected var _notifyOnLoad :Array = [];
/** Contains the component meta-data for all components. */
protected var _metaPack : DataPack;
/** The URL for our components. */
protected var _rootUrl :String;
/** Map of pack name to listeners waiting for that pack to resolve. */
protected var _packListeners :Map = Maps.newMapOf(String);
/** The map of packs we've already loaded up and resolved. */
protected var _packs :Map = Maps.newMapOf(String);
/** All our component classes by name. */
protected var _classes :Map = Maps.newMapOf(String);
/** All our action sequences by name. */
protected var _actions :Map = Maps.newMapOf(String);
/** The map of componentId to CharacterComponent */
protected var _components :Map = Maps.newMapOf(int);
/** A table of component lists indexed on classname. */
protected var _classComps :Map = Maps.newMapOf(String);
}
}