Files
itgmania212121/stepmania/src/NoteSkinManager.cpp
T

365 lines
11 KiB
C++
Raw Normal View History

2003-02-16 04:01:45 +00:00
#include "global.h"
#include "NoteSkinManager.h"
#include "RageFileManager.h"
#include "RageLog.h"
#include "RageException.h"
#include "GameState.h"
2004-07-25 17:07:32 +00:00
#include "Game.h"
2004-06-28 07:26:00 +00:00
#include "Style.h"
#include "RageUtil.h"
2003-09-03 04:30:29 +00:00
#include "RageDisplay.h"
2004-06-10 22:47:51 +00:00
#include "arch/Dialog/Dialog.h"
2004-03-01 02:45:29 +00:00
#include "PrefsManager.h"
2004-07-30 06:32:24 +00:00
#include "Foreach.h"
2006-09-21 02:48:15 +00:00
#include "ActorUtil.h"
NoteSkinManager* NOTESKIN = NULL; // global object accessable from anywhere in the program
2006-01-22 01:00:06 +00:00
const RString NOTESKINS_DIR = "NoteSkins/";
const RString GLOBAL_BASE_NOTESKIN_DIR = NOTESKINS_DIR + "common/default/";
static map<RString,RString> g_PathCache;
NoteSkinManager::NoteSkinManager()
{
GAME_BASE_NOTESKIN_NAME.Load( "NoteSkinManager", "GameBaseNoteSkin" );
m_pCurGame = NULL;
}
NoteSkinManager::~NoteSkinManager()
{
}
void NoteSkinManager::RefreshNoteSkinData( const Game* pGame )
{
if( m_pCurGame == pGame )
return;
m_pCurGame = pGame;
2004-02-17 22:16:22 +00:00
// clear path cache
g_PathCache.clear();
2006-01-22 01:00:06 +00:00
RString sBaseSkinFolder = NOTESKINS_DIR + pGame->m_szName + "/";
vector<RString> asNoteSkinNames;
2003-04-22 04:54:04 +00:00
GetDirListing( sBaseSkinFolder + "*", asNoteSkinNames, true );
2005-06-23 08:05:09 +00:00
StripCvs( asNoteSkinNames );
2003-04-22 04:54:04 +00:00
m_mapNameToData.clear();
2003-04-23 02:45:51 +00:00
for( unsigned j=0; j<asNoteSkinNames.size(); j++ )
{
2006-01-22 01:00:06 +00:00
RString sName = asNoteSkinNames[j];
2003-04-22 04:54:04 +00:00
sName.MakeLower();
m_mapNameToData[sName] = NoteSkinData();
LoadNoteSkinData( sName, m_mapNameToData[sName] );
}
2003-04-22 04:54:04 +00:00
}
2006-01-22 01:00:06 +00:00
void NoteSkinManager::LoadNoteSkinData( const RString &sNoteSkinName, NoteSkinData& data_out )
2003-04-22 04:54:04 +00:00
{
data_out.sName = sNoteSkinName;
2005-01-07 14:28:00 +00:00
data_out.metrics.Clear();
2004-07-30 06:32:24 +00:00
data_out.vsDirSearchOrder.clear();
/* Load global NoteSkin defaults */
2004-05-23 02:27:51 +00:00
data_out.metrics.ReadFile( GLOBAL_BASE_NOTESKIN_DIR+"metrics.ini" );
2004-07-30 06:32:24 +00:00
data_out.vsDirSearchOrder.push_front( GLOBAL_BASE_NOTESKIN_DIR );
/* Load game NoteSkin defaults */
2004-05-23 02:27:51 +00:00
data_out.metrics.ReadFile( GetNoteSkinDir(GAME_BASE_NOTESKIN_NAME)+"metrics.ini" );
2004-07-30 06:32:24 +00:00
data_out.vsDirSearchOrder.push_front( GetNoteSkinDir(GAME_BASE_NOTESKIN_NAME) );
2004-07-30 06:32:24 +00:00
/* Read the current NoteSkin and all of its fallbacks */
LoadNoteSkinDataRecursive( sNoteSkinName, data_out );
}
2006-01-22 01:00:06 +00:00
void NoteSkinManager::LoadNoteSkinDataRecursive( const RString &sNoteSkinName, NoteSkinData& data_out )
2004-07-30 06:32:24 +00:00
{
static int depth = 0;
depth++;
ASSERT_M( depth < 20, "Circular NoteSkin fallback references detected." );
2006-01-22 01:00:06 +00:00
RString sDir = GetNoteSkinDir(sNoteSkinName);
2004-07-30 06:32:24 +00:00
// read global fallback the current NoteSkin (if any)
2006-01-22 01:00:06 +00:00
RString sFallback;
2004-07-30 06:32:24 +00:00
IniFile ini;
ini.ReadFile( sDir+"metrics.ini" );
if( ini.GetValue("Global","FallbackNoteSkin",sFallback) )
LoadNoteSkinDataRecursive( sFallback, data_out );
data_out.metrics.ReadFile( sDir+"metrics.ini" );
data_out.vsDirSearchOrder.push_front( sDir );
depth--;
2003-04-22 04:54:04 +00:00
}
2006-01-22 01:00:06 +00:00
void NoteSkinManager::GetNoteSkinNames( vector<RString> &AddTo )
2003-04-22 04:54:04 +00:00
{
GetNoteSkinNames( GAMESTATE->m_pCurGame, AddTo );
}
2006-01-22 01:00:06 +00:00
void NoteSkinManager::GetNoteSkinNames( const Game* pGame, vector<RString> &AddTo, bool bFilterDefault )
{
GetAllNoteSkinNamesForGame( pGame, AddTo );
2004-02-17 22:23:07 +00:00
/* Move "default" to the front if it exists. */
vector<RString>::iterator iter = find( AddTo.begin(), AddTo.end(), GAME_BASE_NOTESKIN_NAME.GetValue() );
if( iter != AddTo.end() )
{
AddTo.erase( iter );
if( !bFilterDefault || !PREFSMAN->m_bHideDefaultNoteSkin )
AddTo.insert( AddTo.begin(), GAME_BASE_NOTESKIN_NAME );
}
2003-04-22 04:54:04 +00:00
}
2006-01-22 01:00:06 +00:00
bool NoteSkinManager::DoesNoteSkinExist( const RString &sSkinName )
2003-04-22 04:54:04 +00:00
{
2006-01-22 01:00:06 +00:00
vector<RString> asSkinNames;
GetAllNoteSkinNamesForGame( GAMESTATE->m_pCurGame, asSkinNames );
2003-04-22 04:54:04 +00:00
for( unsigned i=0; i<asSkinNames.size(); i++ )
if( 0==stricmp(sSkinName, asSkinNames[i]) )
return true;
return false;
}
bool NoteSkinManager::DoNoteSkinsExistForGame( const Game *pGame )
{
vector<RString> asSkinNames;
GetAllNoteSkinNamesForGame( pGame, asSkinNames );
return !asSkinNames.empty();
}
2006-01-22 01:00:06 +00:00
RString NoteSkinManager::GetNoteSkinDir( const RString &sSkinName )
{
2006-01-22 01:00:06 +00:00
RString sGame = m_pCurGame->m_szName;
2003-12-10 09:44:16 +00:00
return NOTESKINS_DIR + sGame + "/" + sSkinName + "/";
}
void NoteSkinManager::GetAllNoteSkinNamesForGame( const Game *pGame, vector<RString> &AddTo )
{
if( pGame == m_pCurGame )
{
/* Faster: */
for( map<RString,NoteSkinData>::const_iterator iter = m_mapNameToData.begin();
iter != m_mapNameToData.end(); ++iter )
{
AddTo.push_back( iter->second.sName );
}
}
else
{
RString sBaseSkinFolder = NOTESKINS_DIR + pGame->m_szName + "/";
GetDirListing( sBaseSkinFolder + "*", AddTo, true );
StripCvs( AddTo );
}
}
2006-01-22 01:00:06 +00:00
RString NoteSkinManager::GetMetric( const RString &sButtonName, const RString &sValue )
{
ASSERT( !m_sCurrentNoteSkin.empty() );
2006-01-22 01:00:06 +00:00
RString sNoteSkinName = m_sCurrentNoteSkin;
2003-09-12 04:44:53 +00:00
sNoteSkinName.MakeLower();
2006-01-22 01:00:06 +00:00
map<RString,NoteSkinData>::const_iterator it = m_mapNameToData.find(sNoteSkinName);
2004-05-23 22:17:26 +00:00
ASSERT_M( it != m_mapNameToData.end(), sNoteSkinName ); // this NoteSkin doesn't exist!
const NoteSkinData& data = it->second;
2006-01-22 01:00:06 +00:00
RString sReturn;
2003-04-22 04:54:04 +00:00
if( data.metrics.GetValue( sButtonName, sValue, sReturn ) )
return sReturn;
2003-04-22 04:54:04 +00:00
if( !data.metrics.GetValue( "NoteDisplay", sValue, sReturn ) )
RageException::Throw( "Could not read metric \"%s::%s\" or \"NoteDisplay::%s\" in \"%s\".",
sButtonName.c_str(), sValue.c_str(), sValue.c_str(), sNoteSkinName.c_str() );
return sReturn;
}
2006-01-22 01:00:06 +00:00
int NoteSkinManager::GetMetricI( const RString &sButtonName, const RString &sValueName )
{
return atoi( GetMetric(sButtonName,sValueName) );
}
2006-01-22 01:00:06 +00:00
float NoteSkinManager::GetMetricF( const RString &sButtonName, const RString &sValueName )
{
2006-06-12 06:42:25 +00:00
return StringToFloat( GetMetric(sButtonName,sValueName) );
}
2006-01-22 01:00:06 +00:00
bool NoteSkinManager::GetMetricB( const RString &sButtonName, const RString &sValueName )
{
return atoi( GetMetric(sButtonName,sValueName) ) != 0;
}
2006-01-22 01:00:06 +00:00
apActorCommands NoteSkinManager::GetMetricA( const RString &sButtonName, const RString &sValueName )
{
return ActorUtil::ParseActorCommands( GetMetric(sButtonName,sValueName) );
}
2006-01-22 01:00:06 +00:00
RString NoteSkinManager::GetPath( const RString &sButtonName, const RString &sElement )
{
2004-07-30 06:32:24 +00:00
try_again:
2006-01-22 01:00:06 +00:00
const RString CacheString = m_sCurrentNoteSkin + "/" + sButtonName + "/" + sElement;
map<RString,RString>::iterator it = g_PathCache.find( CacheString );
2004-02-17 22:16:22 +00:00
if( it != g_PathCache.end() )
return it->second;
2006-01-22 01:00:06 +00:00
map<RString,NoteSkinData>::const_iterator iter = m_mapNameToData.find( m_sCurrentNoteSkin );
ASSERT( iter != m_mapNameToData.end() );
const NoteSkinData &data = iter->second;
2004-07-30 06:32:24 +00:00
2006-01-22 01:00:06 +00:00
RString sPath; // fill this in below
FOREACHD_CONST( RString, data.vsDirSearchOrder, iter )
2004-07-30 06:32:24 +00:00
{
if( sButtonName.empty() )
sPath = GetPathFromDirAndFile( *iter, sElement );
else if( *iter == GLOBAL_BASE_NOTESKIN_DIR )
2005-10-05 05:49:50 +00:00
sPath = GetPathFromDirAndFile( *iter, "Fallback "+sElement );
else
sPath = GetPathFromDirAndFile( *iter, sButtonName+" "+sElement );
if( !sPath.empty() )
break; // done searching
2004-07-30 06:32:24 +00:00
}
2004-02-17 22:23:07 +00:00
2004-07-30 06:32:24 +00:00
if( sPath.empty() )
{
2006-01-22 01:00:06 +00:00
RString message = ssprintf(
"The NoteSkin element \"%s %s\" could not be found in \"%s\", \"%s\", or \"%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() );
2004-07-30 06:32:24 +00:00
if( Dialog::AbortRetryIgnore(message) == Dialog::retry )
{
FILEMAN->FlushDirCache( GetNoteSkinDir(m_sCurrentNoteSkin) );
FILEMAN->FlushDirCache( GAME_BASE_NOTESKIN_NAME );
2004-07-30 06:32:24 +00:00
g_PathCache.clear();
goto try_again;
}
RageException::Throw( "%s", message.c_str() );
}
2005-12-08 08:24:30 +00:00
int iLevel = 0;
while( GetExtension(sPath) == "redir" )
{
2005-12-08 08:24:30 +00:00
iLevel++;
ASSERT_M( iLevel < 100, ssprintf("Infinite recursion while looking up %s - %s", sButtonName.c_str(), sElement.c_str()) );
2006-01-22 01:00:06 +00:00
RString sNewFileName;
GetFileContents( sPath, sNewFileName, true );
2006-01-22 01:00:06 +00:00
RString sRealPath;
2004-07-30 06:32:24 +00:00
2006-01-22 01:00:06 +00:00
FOREACHD_CONST( RString, data.vsDirSearchOrder, iter )
2004-07-30 06:32:24 +00:00
{
sRealPath = GetPathFromDirAndFile( *iter, sNewFileName );
2004-07-30 06:32:24 +00:00
if( !sRealPath.empty() )
break; // done searching
}
if( sRealPath == "" )
{
2006-01-22 01:00:06 +00:00
RString message = ssprintf(
"NoteSkinManager: The redirect \"%s\" points to the file \"%s\", which does not exist. "
"Verify that this redirect is correct.",
sPath.c_str(), sNewFileName.c_str());
2004-06-10 22:47:51 +00:00
if( Dialog::AbortRetryIgnore(message) == Dialog::retry )
{
FILEMAN->FlushDirCache( GetNoteSkinDir(m_sCurrentNoteSkin) );
FILEMAN->FlushDirCache( GAME_BASE_NOTESKIN_NAME );
2004-02-17 22:16:22 +00:00
g_PathCache.clear();
2004-07-30 06:32:24 +00:00
goto try_again;
}
RageException::Throw( "%s", message.c_str() );
}
sPath = sRealPath;
}
2004-02-17 22:16:22 +00:00
g_PathCache[CacheString] = sPath;
return sPath;
}
2004-02-17 08:25:32 +00:00
2006-01-22 01:00:06 +00:00
RString NoteSkinManager::GetPathFromDirAndFile( const RString &sDir, const RString &sFileName )
{
2006-01-22 01:00:06 +00:00
vector<RString> matches; // fill this with the possible files
GetDirListing( sDir+sFileName+"*", matches, false, true );
2003-09-03 04:30:29 +00:00
if( matches.empty() )
2006-01-22 01:00:06 +00:00
return RString();
2003-09-03 04:30:29 +00:00
if( matches.size() > 1 )
{
2006-01-22 01:00:06 +00:00
RString sError = "Multiple files match '"+sDir+sFileName+"'. Please remove all but one of these files.";
2004-06-10 22:47:51 +00:00
Dialog::OK( sError );
2003-09-03 04:30:29 +00:00
}
return matches[0];
}
2004-06-08 01:24:17 +00:00
// lua start
#include "LuaBinding.h"
2005-06-20 05:02:03 +00:00
class LunaNoteSkinManager: public Luna<NoteSkinManager>
{
public:
LunaNoteSkinManager() { LUA->Register( Register ); }
static int GetPath( T* p, lua_State *L ) { lua_pushstring(L, p->GetPath(SArg(1),SArg(2)) ); return 1; }
2005-10-05 07:37:26 +00:00
static int GetMetricA( T* p, lua_State *L ) { p->GetMetricA(SArg(1),SArg(2))->PushSelf(L); return 1; }
DEFINE_METHOD( GetGameBaseNoteSkinName, GAME_BASE_NOTESKIN_NAME.GetValue() )
static void Register(lua_State *L)
{
ADD_METHOD( GetPath );
2005-10-05 07:37:26 +00:00
ADD_METHOD( GetMetricA );
ADD_METHOD( GetGameBaseNoteSkinName );
Luna<T>::Register( L );
// Add global singleton if constructed already. If it's not constructed yet,
// then we'll register it later when we reinit Lua just before
// initializing the display.
if( NOTESKIN )
{
lua_pushstring(L, "NOTESKIN");
2005-06-15 02:27:16 +00:00
NOTESKIN->PushSelf( L );
lua_settable(L, LUA_GLOBALSINDEX);
}
}
};
LUA_REGISTER_CLASS( NoteSkinManager )
// lua end
2004-06-08 01:24:17 +00:00
/*
* (c) 2003-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/