diff --git a/stepmania/src/Actor.cpp b/stepmania/src/Actor.cpp index a61b5c0746..d958dc49e6 100644 --- a/stepmania/src/Actor.cpp +++ b/stepmania/src/Actor.cpp @@ -258,6 +258,7 @@ void Actor::LoadFromNode( const RString& sDir, const XNode* pNode ) } } + Lua *L = LUA->Get(); FOREACH_CONST_Attr( pNode, pAttr ) { // Load Name, if any. @@ -272,10 +273,11 @@ void Actor::LoadFromNode( const RString& sDir, const XNode* pNode ) else if( sKeyName == "BaseZoomZ" ) SetBaseZoomZ( pValue->GetValue() ); else if( EndsWith(sKeyName,"Command") ) { - apActorCommands apac = ActorUtil::ParseActorCommands( pValue->GetValue(), ssprintf("%s: %s", sDir.c_str(), sKeyName.c_str()) ); - + LuaReference *pRef = new LuaReference; + pValue->PushValue( L ); + pRef->SetFromStack( L ); RString sCmdName = sKeyName.Left( sKeyName.size()-7 ); - AddCommand( sCmdName, apac ); + AddCommand( sCmdName, apActorCommands( pRef ) ); } } @@ -291,14 +293,13 @@ void Actor::LoadFromNode( const RString& sDir, const XNode* pNode ) RString sName; c->GetAttrValue( "Name", sName ); - RString sValue; - c->GetAttrValue( "Value", sValue ); + c->PushAttrValue( L, "Value" ); - LuaHelpers::RunAtExpressionS( sName ); - apActorCommands apac = ActorUtil::ParseActorCommands( sValue, ssprintf("%s: %s", sDir.c_str(), sKeyName.c_str()) ); - - AddCommand( sName, apac ); + LuaReference *pRef = new LuaReference; + pRef->SetFromStack( L ); + AddCommand( sName, apActorCommands( pRef ) ); } + LUA->Release( L ); /* There's an InitCommand. Run it now. This can be used to eg. change Z to * modify draw order between BGAs in a Foreground. */ diff --git a/stepmania/src/ActorUtil.cpp b/stepmania/src/ActorUtil.cpp index 75fe0a56e1..28ec9b24ff 100644 --- a/stepmania/src/ActorUtil.cpp +++ b/stepmania/src/ActorUtil.cpp @@ -200,14 +200,10 @@ Actor* ActorUtil::LoadFromNode( const RString& sDir, const XNode* pNode, Actor * if( !pChild->GetAttrValue( "Name", sName ) ) Dialog::OK( ssprintf("Param node in '%s' is missing the attribute \"Name\"", sDir.c_str()), "MISSING_ATTRIBUTE" ); - LuaHelpers::RunAtExpressionS( sName ); - - RString s; - if( !pChild->GetAttrValue( "Value", s ) ) + Lua *L = LUA->Get(); + if( !pChild->PushAttrValue( L, "Value" ) ) Dialog::OK( ssprintf("Param node in '%s' is missing the attribute \"Value\"", sDir.c_str()), "MISSING_ATTRIBUTE" ); - Lua *L = LUA->Get(); - LuaHelpers::RunExpression( L, s, sDir ); SetParamFromStack( L, sName, &setOldParams[sName] ); LUA->Release(L); } @@ -368,6 +364,7 @@ Actor* ActorUtil::MakeActor( const RString &sPath_, const XNode *pParent, Actor return new Actor; } + XmlFileUtil::CompileXNodeTree( &xml, sPath ); MergeActorXML( &xml, pParent ); return ActorUtil::LoadFromNode( sDir, &xml ); } diff --git a/stepmania/src/XmlFile.cpp b/stepmania/src/XmlFile.cpp index 483b773262..1b4c41e603 100644 --- a/stepmania/src/XmlFile.cpp +++ b/stepmania/src/XmlFile.cpp @@ -12,6 +12,7 @@ #include "RageUtil.h" #include "DateTime.h" #include "Foreach.h" +#include "LuaManager.h" XNode::XNode() { @@ -62,11 +63,19 @@ void XNodeStringValue::GetValue( int &out ) const { out = atoi(m_sValue); } void XNodeStringValue::GetValue( float &out ) const { out = StringToFloat(m_sValue); } void XNodeStringValue::GetValue( bool &out ) const { out = atoi(m_sValue) != 0; } void XNodeStringValue::GetValue( unsigned &out ) const { out = strtoul(m_sValue,NULL,0); } +void XNodeStringValue::PushValue( lua_State *L ) const +{ + LuaHelpers::Push( L, m_sValue ); +} void XNodeStringValue::SetValue( const RString &v ) { m_sValue = v; } void XNodeStringValue::SetValue( int v ) { m_sValue = ssprintf("%d",v); } void XNodeStringValue::SetValue( float v ) { m_sValue = ssprintf("%f",v); } void XNodeStringValue::SetValue( unsigned v ) { m_sValue = ssprintf("%u",v); } +void XNodeStringValue::SetValueFromStack( lua_State *L ) +{ + LuaHelpers::Pop( L, m_sValue ); +} const XNodeValue *XNode::GetAttr( const RString &attrname ) const { @@ -76,6 +85,18 @@ const XNodeValue *XNode::GetAttr( const RString &attrname ) const return NULL; } +bool XNode::PushAttrValue( lua_State *L, const RString &sName ) const +{ + const XNodeValue *pAttr = GetAttr(sName); + if( pAttr == NULL ) + { + lua_pushnil( L ); + return false; + } + pAttr->PushValue( L ); + return true; +} + XNodeValue *XNode::GetAttr( const RString &attrname ) { XAttrs::iterator it = m_attrs.find( attrname ); @@ -95,6 +116,18 @@ XNode *XNode::GetChild( const RString &sName ) return NULL; } +bool XNode::PushChildValue( lua_State *L, const RString &sName ) const +{ + const XNode *pChild = GetChild(sName); + if( pChild == NULL ) + { + lua_pushnil( L ); + return false; + } + pChild->m_pValue->PushValue( L ); + return true; +} + const XNode *XNode::GetChild( const RString &sName ) const { multimap::const_iterator it = m_childs.find( sName ); diff --git a/stepmania/src/XmlFile.h b/stepmania/src/XmlFile.h index 8bf04fe225..c982b13fe6 100644 --- a/stepmania/src/XmlFile.h +++ b/stepmania/src/XmlFile.h @@ -6,6 +6,7 @@ #include struct DateTime; class RageFileBasic; +struct lua_State; class XNodeValue { @@ -18,6 +19,7 @@ public: virtual void GetValue( float &out ) const = 0; virtual void GetValue( bool &out ) const = 0; virtual void GetValue( unsigned &out ) const = 0; + virtual void PushValue( lua_State *L ) const = 0; template T GetValue() const { T val; GetValue(val); return val; } @@ -26,6 +28,7 @@ public: virtual void SetValue( int v ) = 0; virtual void SetValue( float v ) = 0; virtual void SetValue( unsigned v ) = 0; + virtual void SetValueFromStack( lua_State *L ) = 0; }; class XNodeStringValue: public XNodeValue @@ -40,11 +43,13 @@ public: void GetValue( float &out ) const; void GetValue( bool &out ) const; void GetValue( unsigned &out ) const; + void PushValue( lua_State *L ) const; void SetValue( const RString &v ); void SetValue( int v ); void SetValue( float v ); void SetValue( unsigned v ); + void SetValueFromStack( lua_State *L ); }; typedef map XAttrs; @@ -98,12 +103,14 @@ public: XNodeValue *GetAttr( const RString &sAttrName ); template bool GetAttrValue( const RString &sName, T &out ) const { const XNodeValue *pAttr=GetAttr(sName); if(pAttr==NULL) return false; pAttr->GetValue(out); return true; } + bool PushAttrValue( lua_State *L, const RString &sName ) const; // in one level child nodes const XNode *GetChild( const RString &sName ) const; XNode *GetChild( const RString &sName ); template bool GetChildValue( const RString &sName, T &out ) const { const XNode *pChild=GetChild(sName); if(pChild==NULL) return false; pChild->GetValue(out); return true; } + bool PushChildValue( lua_State *L, const RString &sName ) const; // modify DOM template diff --git a/stepmania/src/XmlFileUtil.cpp b/stepmania/src/XmlFileUtil.cpp index e0e1a7c90a..199471bb1b 100644 --- a/stepmania/src/XmlFileUtil.cpp +++ b/stepmania/src/XmlFileUtil.cpp @@ -529,6 +529,117 @@ bool XmlFileUtil::SaveToFile( const XNode *pNode, const RString &sFile, const RS return SaveToFile( pNode, f, sStylesheet, bWriteTabs ); } +#include "LuaManager.h" +#include "LuaReference.h" +class XNodeLuaValue: public XNodeValue +{ +public: + LuaReference m_Value; + XNodeValue *Copy() const { return new XNodeLuaValue( *this ); } + + template + T GetValue() const { T val; GetValue(val); return val; } + + void GetValue( RString &out ) const; + void GetValue( int &out ) const; + void GetValue( float &out ) const; + void GetValue( bool &out ) const; + void GetValue( unsigned &out ) const; + void PushValue( lua_State *L ) const; + + void SetValue( const RString &v ); + void SetValue( int v ); + void SetValue( float v ); + void SetValue( unsigned v ); + void SetValueFromStack( lua_State *L ); +}; + +void XNodeLuaValue::PushValue( lua_State *L ) const +{ + m_Value.PushSelf( L ); +} + +void XNodeLuaValue::GetValue( RString &out ) const { Lua *L = LUA->Get(); PushValue( L ); LuaHelpers::Pop( L, out ); LUA->Release( L ); } +void XNodeLuaValue::GetValue( int &out ) const { Lua *L = LUA->Get(); PushValue( L ); LuaHelpers::Pop( L, out ); LUA->Release( L ); } +void XNodeLuaValue::GetValue( float &out ) const { Lua *L = LUA->Get(); PushValue( L ); LuaHelpers::Pop( L, out ); LUA->Release( L ); } +void XNodeLuaValue::GetValue( bool &out ) const { Lua *L = LUA->Get(); PushValue( L ); LuaHelpers::Pop( L, out ); LUA->Release( L ); } +void XNodeLuaValue::GetValue( unsigned &out ) const { Lua *L = LUA->Get(); PushValue( L ); float fVal; LuaHelpers::Pop( L, fVal ); out = fVal; LUA->Release( L ); } + +void XNodeLuaValue::SetValueFromStack( lua_State *L ) +{ + m_Value.SetFromStack( L ); +} + +void XNodeLuaValue::SetValue( const RString &v ) { Lua *L = LUA->Get(); LuaHelpers::Push( L, v ); SetValueFromStack( L ); LUA->Release( L ); } +void XNodeLuaValue::SetValue( int v ) { Lua *L = LUA->Get(); LuaHelpers::Push( L, v ); SetValueFromStack( L ); LUA->Release( L ); } +void XNodeLuaValue::SetValue( float v ) { Lua *L = LUA->Get(); LuaHelpers::Push( L, v ); SetValueFromStack( L ); LUA->Release( L ); } +void XNodeLuaValue::SetValue( unsigned v ) { Lua *L = LUA->Get(); LuaHelpers::Push( L, (float) v ); SetValueFromStack( L ); LUA->Release( L ); } + +namespace +{ + void CompileXMLNodeValue( Lua *L, const RString &sName, XNodeValue *&pValue, const RString &sFile ) + { + RString sExpression; + pValue->GetValue( sExpression ); + + if( EndsWith(sName, "Command") && sExpression.size() > 0 && sExpression[0] == '%' ) + { + sExpression.erase( 0, 1 ); + if( !LuaHelpers::RunExpression(L, sExpression, sFile) ) + { + /* Compiling or running failed. An error was already logged; just push a dummy + * return value. */ + lua_pushnil( L ); + } + } + else if( EndsWith(sName, "Command") && (sExpression.size() == 0 || sExpression[0] != '%') ) + { + LuaHelpers::ParseCommandList( L, sExpression, sFile ); + } + else if( sExpression.size() > 0 && sExpression[0] == '@' ) + { + /* This is a raw string. */ + sExpression.erase( 0, 1 ); + LuaHelpers::Push( L, sExpression ); + } + else + { + if( !LuaHelpers::RunExpression(L, sExpression, sFile) ) + { + /* Compiling or running failed. An error was already logged; just push a dummy + * return value. */ + lua_pushnil( L ); + } + } + + delete pValue; + pValue = new XNodeLuaValue; + pValue->SetValueFromStack( L ); + } +} + +void XmlFileUtil::CompileXNodeTree( XNode *pNode, const RString &sFile ) +{ + vector aToCompile; + aToCompile.push_back( pNode ); + + Lua *L = LUA->Get(); + while( aToCompile.size() ) + { + pNode = aToCompile.back(); + aToCompile.pop_back(); + FOREACH_Child( pNode, pChild ) + aToCompile.push_back( pChild ); + + CompileXMLNodeValue( L, pNode->GetName(), pNode->m_pValue, sFile ); + + FOREACH_Attr( pNode, pAttr ) + CompileXMLNodeValue( L, pAttr->first, pAttr->second, sFile ); + } + + LUA->Release( L ); +} + /* * (c) 2001-2004 Chris Danford * All rights reserved. diff --git a/stepmania/src/XmlFileUtil.h b/stepmania/src/XmlFileUtil.h index 3e0d28276a..72f2e7e3b2 100644 --- a/stepmania/src/XmlFileUtil.h +++ b/stepmania/src/XmlFileUtil.h @@ -17,6 +17,8 @@ namespace XmlFileUtil RString GetXML( const XNode *pNode ); bool SaveToFile( const XNode *pNode, const RString &sFile, const RString &sStylesheet = "", bool bWriteTabs = true ); bool SaveToFile( const XNode *pNode, RageFileBasic &f, const RString &sStylesheet = "", bool bWriteTabs = true ); + + void CompileXNodeTree( XNode *pNode, const RString &sFile ); } #endif