Create actors with ActorUtil::Create in ActorUtil::MakeActor. This means

ActorUtil::LoadFromNode always uses ActorUtil::Create.  Previously, sprites
and models loaded without an explicit Class= were loaded directly.

Nested XML is merged explicitly.  Before, we loaded the final actor, and then
called Actor::LoadFromNode to pull in attributes from each nested XML node
as ActorUtil::LoadFromNode recursed back out, which was a bit confusing.  It
also caused weirdness with InitCommand: each time called it again, possibly
with a different InitCommand.  We need to only call it once, after all nodes
are loaded.

(MergeActorXML is a little annoying, but it does make it more clear what's
really happening.)
This commit is contained in:
Glenn Maynard
2005-10-11 21:59:48 +00:00
parent 1733cc128c
commit fbe094d34c
2 changed files with 65 additions and 25 deletions
+64 -24
View File
@@ -194,23 +194,9 @@ Actor* ActorUtil::LoadFromNode( const CString& sDir, const XNode* pNode )
ActorUtil::ResolvePath( sNewPath, sDir ); ActorUtil::ResolvePath( sNewPath, sDir );
pReturn = ActorUtil::MakeActor( sNewPath ); pReturn = ActorUtil::MakeActor( sNewPath, pNode );
if( pReturn == NULL ) if( pReturn == NULL )
goto all_done; goto all_done;
/*
* Hack: take attributes from the file loading the new actor,
* and load them on top of the new file. This way, you can do
* eg:
*
* file1.xml: <Layer File="file2" OnCommand="x,10" />
* file2.xml: <Layer File="image" OffCommand="y,10" />
*
* Be sure to only run the low-level load, to pull in commands;
* don't reload the high-level actor, and don't rerun Init (which
* has already been run).
*/
pReturn->Actor::LoadFromNode( sDir, pNode );
} }
all_done: all_done:
@@ -235,20 +221,69 @@ all_done:
return pReturn; return pReturn;
} }
Actor* ActorUtil::MakeActor( const CString &sPath_ ) /*
* Merge a parent and child XML. For example,
*
* parent.xml: <Layer File="child" OnCommand="x,10" />
* child.xml: <Layer1 File="image" OffCommand="y,10" />
*
* results in:
*
* <Layer1 File="image" OnCommand="x,10" OffCommand="y,10" />
*
* The result is a copy of the child, with attributes and children
* from the parent merged, excluding the attribute "File". Warn
* about duplicate attributes.
*/
static void MergeActorXML( XNode *pChild, const XNode *pParent )
{ {
FOREACH_CONST_Child( pParent, p )
pChild->AppendChild( new XNode(*p) );
FOREACH_CONST_Attr( pParent, p )
{
if( p->first == "File" )
continue;
CString sOld;
if( pChild->GetChildValue(p->first, sOld) )
{
CString sWarning =
ssprintf( "Overriding \"%s\" (\"%s\") in XML node \"%s\" with \"%s\" in XML node \"%s\"",
p->first.c_str(),
p->second.c_str(),
pChild->m_sName.c_str(),
sOld.c_str(),
pParent->m_sName.c_str() );
Dialog::OK( sWarning, "XML_ATTRIB_OVERRIDE" );
}
pChild->AppendAttr( p->first, p->second );
}
}
/*
* If pParent is non-NULL, it's the parent node when nesting XML, which is
* used only by ActorUtil::LoadFromNode.
*/
Actor* ActorUtil::MakeActor( const CString &sPath_, const XNode *pParent )
{
static const XNode dummy;
if( pParent == NULL )
pParent = &dummy;
CString sPath( sPath_ ); CString sPath( sPath_ );
/* If @ expressions are allowed through this path, we've already /* If @ expressions are allowed through this path, we've already
* evaluated them. Make sure we don't allow double-evaluation. */ * evaluated them. Make sure we don't allow double-evaluation. */
ASSERT_M( sPath.empty() || sPath[0] != '@', sPath ); ASSERT_M( sPath.empty() || sPath[0] != '@', sPath );
CString sDir = Dirname( sPath );
FileType ft = GetFileType( sPath ); FileType ft = GetFileType( sPath );
switch( ft ) switch( ft )
{ {
case FT_Directory: case FT_Directory:
{ {
CString sDir = sPath; sDir = sPath;
if( sDir.Right(1) != "/" ) if( sDir.Right(1) != "/" )
sDir += '/'; sDir += '/';
@@ -270,21 +305,26 @@ Actor* ActorUtil::MakeActor( const CString &sPath_ )
// XNode will warn about the error // XNode will warn about the error
return new Actor; return new Actor;
} }
CString sDir = Dirname( sPath );
MergeActorXML( &xml, pParent );
return ActorUtil::LoadFromNode( sDir, &xml ); return ActorUtil::LoadFromNode( sDir, &xml );
} }
case FT_Bitmap: case FT_Bitmap:
case FT_Movie: case FT_Movie:
{ {
Sprite* pSprite = new Sprite; XNode xml( *pParent );
pSprite->Load( sPath ); xml.AppendAttr( "Texture", sPath );
return pSprite;
return ActorUtil::Create( "Sprite", sDir, &xml );
} }
case FT_Model: case FT_Model:
{ {
Model* pModel = new Model; XNode xml( *pParent );
pModel->Load( sPath ); xml.AppendAttr( "Meshes", sPath );
return pModel; xml.AppendAttr( "Materials", sPath );
xml.AppendAttr( "Bones", sPath );
return ActorUtil::Create( "Model", sDir, &xml );
} }
default: default:
RageException::Throw("File \"%s\" has unknown type, \"%s\"", RageException::Throw("File \"%s\" has unknown type, \"%s\"",
+1 -1
View File
@@ -67,7 +67,7 @@ namespace ActorUtil
// Return a Sprite, BitmapText, or Model depending on the file type // Return a Sprite, BitmapText, or Model depending on the file type
Actor* LoadFromNode( const CString& sAniDir, const XNode* pNode ); Actor* LoadFromNode( const CString& sAniDir, const XNode* pNode );
Actor* MakeActor( const CString &sPath ); Actor* MakeActor( const CString &sPath, const XNode *pParent = NULL );
void ResolvePath( CString &sPath, const CString &sName ); void ResolvePath( CString &sPath, const CString &sName );