first-pass: actor descriptions in Lua

This commit is contained in:
Glenn Maynard
2006-10-09 05:51:12 +00:00
parent d0ab27b056
commit 7d795e5703
4 changed files with 161 additions and 1 deletions
+52
View File
@@ -314,6 +314,33 @@ static void MergeActorXML( XNode *pChild, const XNode *pParent )
}
}
namespace
{
XNode *LoadXNodeFromLuaShowErrors( const RString &sFile )
{
RString sScript;
if( !GetFileContents(sFile, sScript) )
return NULL;
Lua *L = LUA->Get();
RString sError;
if( !LuaHelpers::RunScript(L, sScript, sFile, sError, 1) )
{
lua_pop( L, 1 );
LUA->Release( L );
sError = ssprintf( "Lua runtime error: %s", sError.c_str() );
Dialog::OK( sError, "LUA_ERROR" );
return NULL;
}
XNode *pRet = XmlFileUtil::XNodeFromTable( L );
LUA->Release( L );
return pRet;
}
}
/*
* If pParent is non-NULL, it's the parent node when nesting XML, which is
* used only by ActorUtil::LoadFromNode.
@@ -344,6 +371,16 @@ Actor* ActorUtil::MakeActor( const RString &sPath_, const XNode *pParent, Actor
}
}
if( ft == FT_Directory )
{
RString sLuaPath = sPath + "default.lua";
if( DoesFileExist(sLuaPath) )
{
sPath = sLuaPath;
ft = FT_Lua;
}
}
RString sDir = Dirname( sPath );
switch( ft )
{
@@ -367,6 +404,19 @@ Actor* ActorUtil::MakeActor( const RString &sPath_, const XNode *pParent, Actor
MergeActorXML( &xml, pParent );
return ActorUtil::LoadFromNode( sDir, &xml );
}
case FT_Lua:
{
auto_ptr<XNode> pNode( LoadXNodeFromLuaShowErrors(sPath) );
if( pNode.get() == NULL )
{
// XNode will warn about the error
return new Actor;
}
MergeActorXML( pNode.get(), pParent );
Actor *pRet = ActorUtil::LoadFromNode( sDir, pNode.get() );
return pRet;
}
case FT_Bitmap:
case FT_Movie:
{
@@ -503,6 +553,7 @@ static const char *FileTypeNames[] = {
"Movie",
"Directory",
"Xml",
"Lua",
"Model",
};
XToString( FileType, NUM_FileType );
@@ -513,6 +564,7 @@ FileType ActorUtil::GetFileType( const RString &sPath )
sExt.MakeLower();
if( sExt=="xml" ) return FT_Xml;
else if( sExt=="lua" ) return FT_Lua;
else if(
sExt=="png" ||
sExt=="jpg" ||
+1
View File
@@ -33,6 +33,7 @@ enum FileType
FT_Movie,
FT_Directory,
FT_Xml,
FT_Lua,
FT_Model,
NUM_FileType,
FT_Invalid
+106 -1
View File
@@ -640,8 +640,113 @@ void XmlFileUtil::CompileXNodeTree( XNode *pNode, const RString &sFile )
LUA->Release( L );
}
namespace
{
XNode *XNodeFromTableRecursive( lua_State *L, const RString &sName, LuaReference &ProcessedTables )
{
XNode *pNode = new XNode( sName );
/* Set the value of the node to the table. */
{
XNodeLuaValue *pValue = new XNodeLuaValue;
lua_pushvalue( L, -1 );
pValue->SetValueFromStack( L );
pNode->SetValueFrom( pValue );
}
/* Iterate over the table, pulling out attributes and tables to process. */
map<RString, LuaReference> NodesToAdd;
lua_pushnil( L );
while( lua_next(L, -2) )
{
lua_pushvalue( L, -2 );
RString sName;
LuaHelpers::Pop( L, sName );
/* If this entry is a table, add it recursively. */
if( lua_istable(L, -1) )
{
NodesToAdd[sName].SetFromStack( L );
continue;
}
if( lua_isstring(L, -1) && EndsWith(sName, "Command") )
{
RString sExpression;
LuaHelpers::Pop( L, sExpression );
LuaHelpers::ParseCommandList( L, sExpression, "" /* XXX */ );
}
/* Otherwise, add an attribute. */
XNodeLuaValue *pValue = new XNodeLuaValue;
pValue->SetValueFromStack( L );
pNode->AppendAttrFrom( sName, pValue );
}
lua_pop( L, 1 ); // pop nil
/* Recursively process tables. */
FOREACHM( RString, LuaReference, NodesToAdd, t )
{
const RString &sNodeName = t->first;
LuaReference &NodeToAdd = t->second;
/* Check if the table is on the stack. */
ProcessedTables.PushSelf( L );
NodeToAdd.PushSelf( L ); // push table
lua_gettable( L, -2 );
bool bSawThisTableAlready = !lua_isnil(L, -1);
lua_pop( L, 2 ); // pop lua_gettable result, ProcessedTables
if( bSawThisTableAlready )
continue;
/* Add the table to the stack. */
ProcessedTables.PushSelf( L );
NodeToAdd.PushSelf( L );
lua_pushboolean( L, true );
lua_settable( L, -3 );
lua_pop( L, 1 ); // pop ProcessedTables
NodeToAdd.PushSelf( L );
XNode *pNewNode = XNodeFromTableRecursive( L, sNodeName, ProcessedTables );
if( pNewNode )
pNode->AppendChild( pNewNode );
/* Remove the table from the stack. */
ProcessedTables.PushSelf( L );
NodeToAdd.PushSelf( L );
lua_pushnil( L );
lua_settable( L, -3 );
lua_pop( L, 1 ); // pop ProcessedTables
}
return pNode;
}
}
/*
* (c) 2001-2004 Chris Danford
* Pop a table off of the stack, and return an XNode tree referring recursively
* to entries in the table.
*
* The table may not contain table cycles; if a cycle is detected, only the first
* table seen will have a corresponding XNode.
*
* Users of the resulting XNode may access the original table via PushValue.
*/
XNode *XmlFileUtil::XNodeFromTable( lua_State *L )
{
/* Maintain a set of references that we've created. Tables may loop; XNode trees may
* not. If we encounter a cycle, skip creating an XNode for that node. */
LuaReference ProcessedTables;
lua_newtable( L );
ProcessedTables.SetFromStack( L );
return XNodeFromTableRecursive( L, "Layer", ProcessedTables );
}
/*
* (c) 2001-2006 Chris Danford, Glenn Maynard
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
+2
View File
@@ -5,6 +5,7 @@
class RageFileBasic;
class XNode;
struct lua_State;
namespace XmlFileUtil
{
@@ -19,6 +20,7 @@ namespace XmlFileUtil
bool SaveToFile( const XNode *pNode, RageFileBasic &f, const RString &sStylesheet = "", bool bWriteTabs = true );
void CompileXNodeTree( XNode *pNode, const RString &sFile );
XNode *XNodeFromTable( lua_State *L );
}
#endif