refactor NoteSkins

This commit is contained in:
Glenn Maynard
2007-02-06 08:03:34 +00:00
parent ff42847669
commit a76708dd9f
7 changed files with 197 additions and 77 deletions
+10 -10
View File
@@ -260,14 +260,19 @@ namespace
return NULL;
}
XNode *pRet = ActorUtil::LoadXNodeFromStackShowErrors( L );
XNode *pRet = NULL;
if( ActorUtil::LoadTableFromStackShowErrors(L) )
pRet = XmlFileUtil::XNodeFromTable( L );
LUA->Release( L );
return pRet;
}
}
XNode *ActorUtil::LoadXNodeFromStackShowErrors( Lua *L )
/* Run the function at the top of the stack, which returns an actor description
* table. If the table was returned, return true and leave it on the stack.
* If not, display an error, return false, and leave nothing on the stack. */
bool ActorUtil::LoadTableFromStackShowErrors( Lua *L )
{
LuaReference func;
lua_pushvalue( L, -1 );
@@ -277,10 +282,9 @@ XNode *ActorUtil::LoadXNodeFromStackShowErrors( Lua *L )
if( !LuaHelpers::RunScriptOnStack(L, sError, 0, 1) )
{
lua_pop( L, 1 );
LUA->Release( L );
sError = ssprintf( "Lua runtime error: %s", sError.c_str() );
Dialog::OK( sError, "LUA_ERROR" );
return NULL;
return false;
}
if( lua_type(L, -1) != LUA_TTABLE )
@@ -292,15 +296,11 @@ XNode *ActorUtil::LoadXNodeFromStackShowErrors( Lua *L )
lua_getinfo( L, ">nS", &debug );
sError = ssprintf( "%s: must return a table", debug.short_src );
LUA->Release( L );
Dialog::OK( sError, "LUA_ERROR" );
return NULL;
return false;
}
XNode *pRet = XmlFileUtil::XNodeFromTable( L );
return pRet;
return true;
}
/*
+1 -1
View File
@@ -71,7 +71,7 @@ namespace ActorUtil
RString GetSourcePath( const XNode *pNode );
RString GetWhere( const XNode *pNode );
bool GetAttrPath( const XNode *pNode, const RString &sName, RString &sOut );
XNode *LoadXNodeFromStackShowErrors( Lua *L );
bool LoadTableFromStackShowErrors( Lua *L );
bool ResolvePath( RString &sPath, const RString &sName );
+1 -1
View File
@@ -30,7 +30,7 @@ void GhostArrowRow::Load( const PlayerState* pPlayerState, float fYReverseOffset
m_bHoldIsActive.push_back( false );
m_bHoldWasActive.push_back( false );
m_Ghost.push_back( ActorUtil::MakeActor( NOTESKIN->GetPath(sButton, "tap explosion"), this ) );
m_Ghost.push_back( NOTESKIN->LoadActor(sButton, "Explosion", this) );
m_Ghost[c]->SetName( "GhostArrow" );
}
}
+15 -23
View File
@@ -135,25 +135,17 @@ static map<NoteSkinAndPath, NoteResource *> g_NoteResource;
static NoteResource *MakeNoteResource( const RString &sButton, const RString &sElement, bool bSpriteOnly )
{
RString sElementAndType = sElement;
NoteSkinAndPath nsap( NOTESKIN->GetCurrentNoteSkin(), NOTESKIN->GetPath(sButton, sElementAndType) );
RString sElementAndType = ssprintf( "%s, %s", sButton.c_str(), sElement.c_str() );
NoteSkinAndPath nsap( NOTESKIN->GetCurrentNoteSkin(), sElementAndType );
map<NoteSkinAndPath, NoteResource *>::iterator it = g_NoteResource.find( nsap );
if( it == g_NoteResource.end() )
{
NoteResource *pRes = new NoteResource( nsap );
pRes->m_pActor = ActorUtil::MakeActor( nsap.sPath );
pRes->m_pActor = NOTESKIN->LoadActor( sButton, sElement, NULL, bSpriteOnly );
ASSERT( pRes->m_pActor );
/* Make sure pActor is a Sprite (or something derived from Sprite). */
if( bSpriteOnly )
{
Sprite *pSprite = dynamic_cast<Sprite *>( pRes->m_pActor );
if( pSprite == NULL )
RageException::Throw( "%s: must be a Sprite", nsap.sPath.c_str() );
}
g_NoteResource[nsap] = pRes;
it = g_NoteResource.find( nsap );
}
@@ -220,14 +212,14 @@ Sprite *NoteColorSprite::Get()
}
static const char *HoldTypeNames[] = {
"hold",
"roll",
"Hold",
"Roll",
};
XToString( HoldType );
static const char *ActiveTypeNames[] = {
"active",
"inactive",
"Active",
"Inactive",
};
XToString( ActiveType );
@@ -252,19 +244,19 @@ void NoteDisplay::Load( int iColNum, const PlayerState* pPlayerState, float fYRe
cache->Load( sButton );
m_TapNote.Load( sButton, "tap note" );
m_TapMine.Load( sButton, "tap mine" );
m_TapLift.Load( sButton, "tap lift" );
m_TapNote.Load( sButton, "Tap Note" );
m_TapMine.Load( sButton, "Tap Mine" );
m_TapLift.Load( sButton, "Tap Lift" );
FOREACH_HoldType( ht )
{
FOREACH_ActiveType( at )
{
m_HoldHead[ht][at].Load( sButton, HoldTypeToString(ht)+" head "+ActiveTypeToString(at) );
m_HoldTopCap[ht][at].Load( sButton, HoldTypeToString(ht)+" topcap "+ActiveTypeToString(at) );
m_HoldBody[ht][at].Load( sButton, HoldTypeToString(ht)+" body "+ActiveTypeToString(at) );
m_HoldBottomCap[ht][at].Load( sButton, HoldTypeToString(ht)+" bottomcap "+ActiveTypeToString(at) );
m_HoldTail[ht][at].Load( sButton, HoldTypeToString(ht)+" tail "+ActiveTypeToString(at) );
m_HoldHead[ht][at].Load( sButton, HoldTypeToString(ht)+" Head "+ActiveTypeToString(at) );
m_HoldTopCap[ht][at].Load( sButton, HoldTypeToString(ht)+" Topcap "+ActiveTypeToString(at) );
m_HoldBody[ht][at].Load( sButton, HoldTypeToString(ht)+" Body "+ActiveTypeToString(at) );
m_HoldBottomCap[ht][at].Load( sButton, HoldTypeToString(ht)+" Bottomcap "+ActiveTypeToString(at) );
m_HoldTail[ht][at].Load( sButton, HoldTypeToString(ht)+" Tail "+ActiveTypeToString(at) );
}
}
}
+167 -40
View File
@@ -11,6 +11,8 @@
#include "PrefsManager.h"
#include "Foreach.h"
#include "ActorUtil.h"
#include "XmlFileUtil.h"
#include "Sprite.h"
#include <map>
@@ -18,8 +20,9 @@ NoteSkinManager* NOTESKIN = NULL; // global object accessable from anywhere in t
const RString NOTESKINS_DIR = "NoteSkins/";
const RString GLOBAL_BASE_NOTESKIN_DIR = NOTESKINS_DIR + "common/default/";
const RString GAME_COMMON_NOTESKIN_NAME = "common";
const RString GAME_BASE_NOTESKIN_NAME = "default";
const RString GLOBAL_BASE_DIR = NOTESKINS_DIR + GAME_COMMON_NOTESKIN_NAME + "/";
static map<RString,RString> g_PathCache;
struct NoteSkinData
@@ -29,6 +32,8 @@ struct NoteSkinData
// When looking for an element, search these dirs from head to tail.
vector<RString> vsDirSearchOrder;
LuaReference m_Loader;
};
namespace
@@ -88,38 +93,91 @@ void NoteSkinManager::LoadNoteSkinData( const RString &sNoteSkinName, NoteSkinDa
data_out.metrics.Clear();
data_out.vsDirSearchOrder.clear();
/* Load global NoteSkin defaults */
data_out.metrics.ReadFile( GLOBAL_BASE_NOTESKIN_DIR+"metrics.ini" );
data_out.vsDirSearchOrder.insert( data_out.vsDirSearchOrder.begin(), GLOBAL_BASE_NOTESKIN_DIR );
/* Load game NoteSkin defaults */
data_out.metrics.ReadFile( GetNoteSkinDir(GAME_BASE_NOTESKIN_NAME)+"metrics.ini" );
data_out.vsDirSearchOrder.insert( data_out.vsDirSearchOrder.begin(), GetNoteSkinDir(GAME_BASE_NOTESKIN_NAME) );
/* Read the current NoteSkin and all of its fallbacks */
LoadNoteSkinDataRecursive( sNoteSkinName, data_out );
}
void NoteSkinManager::LoadNoteSkinDataRecursive( const RString &sNoteSkinName, NoteSkinData& data_out )
void NoteSkinManager::LoadNoteSkinDataRecursive( const RString &sNoteSkinName_, NoteSkinData& data_out )
{
static int depth = 0;
depth++;
ASSERT_M( depth < 20, "Circular NoteSkin fallback references detected." );
RString sNoteSkinName(sNoteSkinName_);
RString sDir = GetNoteSkinDir(sNoteSkinName);
int iDepth = 0;
bool bLoadedCommon = false;
bool bLoadedBase = false;
while(1)
{
++iDepth;
ASSERT_M( iDepth < 20, "Circular NoteSkin fallback references detected." );
// read global fallback the current NoteSkin (if any)
RString sFallback;
IniFile ini;
ini.ReadFile( sDir+"metrics.ini" );
RString sDir = NOTESKINS_DIR + m_pCurGame->m_szName + "/" + sNoteSkinName + "/";
if( !FILEMAN->IsADirectory(sDir) )
{
sDir = GLOBAL_BASE_DIR + sNoteSkinName + "/";
if( !FILEMAN->IsADirectory(sDir) )
{
LOG->Trace( "NoteSkin \"%s\" references skin \"%s\" that is not present",
data_out.sName.c_str(), sNoteSkinName.c_str() );
return;
}
}
if( ini.GetValue("Global","FallbackNoteSkin",sFallback) )
LoadNoteSkinDataRecursive( sFallback, data_out );
LOG->Trace( "LoadNoteSkinDataRecursive: %s (%s)", sNoteSkinName.c_str(), sDir.c_str() );
data_out.metrics.ReadFile( sDir+"metrics.ini" );
data_out.vsDirSearchOrder.insert( data_out.vsDirSearchOrder.begin(), sDir );
// read global fallback the current NoteSkin (if any)
IniFile ini;
ini.ReadFile( sDir+"metrics.ini" );
depth--;
if( !sNoteSkinName.CompareNoCase(GAME_BASE_NOTESKIN_NAME) )
bLoadedBase = true;
if( !sNoteSkinName.CompareNoCase(GAME_COMMON_NOTESKIN_NAME) )
bLoadedCommon = true;
RString sFallback;
if( !ini.GetValue("Global","FallbackNoteSkin", sFallback) )
{
if( !bLoadedBase )
sFallback = GAME_BASE_NOTESKIN_NAME;
else if( !bLoadedCommon )
sFallback = GAME_COMMON_NOTESKIN_NAME;
}
XmlFileUtil::MergeIniUnder( &ini, &data_out.metrics );
data_out.vsDirSearchOrder.insert( data_out.vsDirSearchOrder.end(), sDir );
if( sFallback.empty() )
break;
sNoteSkinName = sFallback;
}
LuaReference refScript;
for( vector<RString>::reverse_iterator dir = data_out.vsDirSearchOrder.rbegin(); dir != data_out.vsDirSearchOrder.rend(); ++dir )
{
RString sFile = *dir + "NoteSkin.lua";
RString sScript;
if( !FILEMAN->IsAFile(sFile) )
continue;
if( !GetFileContents(sFile, sScript) )
continue;
LOG->Trace( "Load script \"%s\"", sFile.c_str() );
Lua *L = LUA->Get();
RString sError;
refScript.PushSelf( L );
if( !LuaHelpers::RunScript(L, sScript, "@" + sFile, sError, 1, 1) )
{
LOG->Trace( "Error running %s: %s", sFile.c_str(), sError.c_str() );
lua_pop( L, 1 );
}
else
{
refScript.SetFromStack( L );
}
LUA->Release( L );
}
data_out.m_Loader = refScript;
}
@@ -160,13 +218,6 @@ bool NoteSkinManager::DoNoteSkinsExistForGame( const Game *pGame )
return !asSkinNames.empty();
}
RString NoteSkinManager::GetNoteSkinDir( const RString &sSkinName )
{
RString sGame = m_pCurGame->m_szName;
return NOTESKINS_DIR + sGame + "/" + sSkinName + "/";
}
void NoteSkinManager::GetAllNoteSkinNamesForGame( const Game *pGame, vector<RString> &AddTo )
{
if( pGame == m_pCurGame )
@@ -241,8 +292,6 @@ try_again:
{
if( sButtonName.empty() )
sPath = GetPathFromDirAndFile( *iter, sElement );
else if( *iter == GLOBAL_BASE_NOTESKIN_DIR )
sPath = GetPathFromDirAndFile( *iter, "Fallback "+sElement );
else
sPath = GetPathFromDirAndFile( *iter, sButtonName+" "+sElement );
if( !sPath.empty() )
@@ -251,17 +300,35 @@ try_again:
if( sPath.empty() )
{
FOREACH_CONST( RString, data.vsDirSearchOrder, iter )
{
if( !sButtonName.empty() )
sPath = GetPathFromDirAndFile( *iter, "Fallback "+sElement );
if( !sPath.empty() )
break; // done searching
}
}
if( sPath.empty() )
{
RString sPaths;
FOREACH_CONST( RString, data.vsDirSearchOrder, dir )
{
if( !sPaths.empty() )
sPaths += ", ";
sPaths += *dir;
}
RString message = ssprintf(
"The NoteSkin element \"%s %s\" could not be found in \"%s\", \"%s\", or \"%s\".",
"The NoteSkin element \"%s %s\" could not be found in any of the following directories:\n%s",
sButtonName.c_str(), sElement.c_str(),
GetNoteSkinDir(m_sCurrentNoteSkin).c_str(),
GetNoteSkinDir(GAME_BASE_NOTESKIN_NAME).c_str(),
GLOBAL_BASE_NOTESKIN_DIR.c_str() );
sPaths.c_str() );
if( Dialog::AbortRetryIgnore(message) == Dialog::retry )
{
FILEMAN->FlushDirCache( GetNoteSkinDir(m_sCurrentNoteSkin) );
FILEMAN->FlushDirCache( GAME_BASE_NOTESKIN_NAME );
FOREACH_CONST( RString, data.vsDirSearchOrder, dir )
FILEMAN->FlushDirCache( *dir );
g_PathCache.clear();
goto try_again;
}
@@ -295,8 +362,8 @@ try_again:
if( Dialog::AbortRetryIgnore(message) == Dialog::retry )
{
FILEMAN->FlushDirCache( GetNoteSkinDir(m_sCurrentNoteSkin) );
FILEMAN->FlushDirCache( GAME_BASE_NOTESKIN_NAME );
FOREACH_CONST( RString, data.vsDirSearchOrder, dir )
FILEMAN->FlushDirCache( *dir );
g_PathCache.clear();
goto try_again;
}
@@ -311,6 +378,56 @@ try_again:
return sPath;
}
bool NoteSkinManager::PushActorTemplate( Lua *L, const RString &sButton, const RString &sElement, bool bSpriteOnly )
{
map<RString,NoteSkinData>::const_iterator iter = g_mapNameToData.find( m_sCurrentNoteSkin );
ASSERT( iter != g_mapNameToData.end() );
const NoteSkinData &data = iter->second;
LuaThreadVariable varButton( "Button", sButton );
LuaThreadVariable varElement( "Element", sElement );
LuaThreadVariable varSpriteOnly( "SpriteOnly", LuaReference::Create(bSpriteOnly) );
ASSERT( !data.m_Loader.IsNil() );
data.m_Loader.PushSelf( L );
lua_remove( L, -2 );
lua_getfield( L, -1, "Load" );
return ActorUtil::LoadTableFromStackShowErrors(L);
}
Actor *NoteSkinManager::LoadActor( const RString &sButton, const RString &sElement, Actor *pParent, bool bSpriteOnly )
{
Lua *L = LUA->Get();
if( !PushActorTemplate(L, sButton, sElement, bSpriteOnly) )
{
// ActorUtil will warn about the error
return new Actor;
}
auto_ptr<XNode> pNode( XmlFileUtil::XNodeFromTable(L) );
if( pNode.get() == NULL )
{
// XNode will warn about the error
return new Actor;
}
LUA->Release( L );
Actor *pRet = ActorUtil::LoadFromNode( pNode.get(), pParent );
if( bSpriteOnly )
{
/* Make sure pActor is a Sprite (or something derived from Sprite). */
Sprite *pSprite = dynamic_cast<Sprite *>( pRet );
if( pSprite == NULL )
LOG->Warn( "%s: %s %s must be a Sprite", m_sCurrentNoteSkin.c_str(), sButton.c_str(), sElement.c_str() );
}
return pRet;
}
RString NoteSkinManager::GetPathFromDirAndFile( const RString &sDir, const RString &sFileName )
{
vector<RString> matches; // fill this with the possible files
@@ -337,11 +454,21 @@ class LunaNoteSkinManager: public Luna<NoteSkinManager>
public:
static int GetPath( T* p, lua_State *L ) { lua_pushstring(L, p->GetPath(SArg(1),SArg(2)) ); return 1; }
static int GetMetricA( T* p, lua_State *L ) { p->GetMetricA(SArg(1),SArg(2))->PushSelf(L); return 1; }
static int LoadActor( T* p, lua_State *L )
{
RString sButton = SArg(1);
RString sElement = SArg(2);
if( !p->PushActorTemplate(L, sButton, sElement, false) )
lua_pushnil( L );
return 1;
}
LunaNoteSkinManager()
{
ADD_METHOD( GetPath );
ADD_METHOD( GetMetricA );
ADD_METHOD( LoadActor );
}
};
+2 -1
View File
@@ -27,6 +27,8 @@ public:
const RString &GetCurrentNoteSkin() { return m_sCurrentNoteSkin; }
RString GetPath( const RString &sButtonName, const RString &sElement );
bool PushActorTemplate( Lua *L, const RString &sButton, const RString &sElement, bool bSpriteOnly );
Actor *LoadActor( const RString &sButton, const RString &sElement, Actor *pParent = NULL, bool bSpriteOnly = false );
RString GetMetric( const RString &sButtonName, const RString &sValue );
int GetMetricI( const RString &sButtonName, const RString &sValueName );
@@ -38,7 +40,6 @@ public:
void PushSelf( lua_State *L );
protected:
RString GetNoteSkinDir( const RString &sSkinName );
RString GetPathFromDirAndFile( const RString &sDir, const RString &sFileName );
void GetAllNoteSkinNamesForGame( const Game *pGame, vector<RString> &AddTo );
+1 -1
View File
@@ -20,7 +20,7 @@ void ReceptorArrow::Load( const PlayerState* pPlayerState, int iColNo )
m_iColNo = iColNo;
RString sButton = GAMESTATE->GetCurrentStyle()->ColToButtonName( iColNo );
m_pReceptor.Load( NOTESKIN->GetPath(sButton,"receptor") );
m_pReceptor.Load( NOTESKIN->LoadActor(sButton, "Receptor") );
this->AddChild( m_pReceptor );
bool bReverse = m_pPlayerState->m_PlayerOptions.GetCurrent().GetReversePercentForColumn(m_iColNo) > 0.5f;