first-pass: actor descriptions in Lua
This commit is contained in:
@@ -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" ||
|
||||
|
||||
@@ -33,6 +33,7 @@ enum FileType
|
||||
FT_Movie,
|
||||
FT_Directory,
|
||||
FT_Xml,
|
||||
FT_Lua,
|
||||
FT_Model,
|
||||
NUM_FileType,
|
||||
FT_Invalid
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user