implement course radar value caching

This commit is contained in:
Glenn Maynard
2005-03-07 22:30:39 +00:00
parent 021e36535c
commit 776060e913
7 changed files with 187 additions and 18 deletions
+114 -11
View File
@@ -10,6 +10,7 @@
#include "MsdFile.h"
#include "PlayerOptions.h"
#include "SongOptions.h"
#include "SongCacheIndex.h"
#include "RageUtil.h"
#include "TitleSubstitution.h"
#include "Steps.h"
@@ -47,12 +48,33 @@ PlayMode Course::GetPlayMode() const
void Course::LoadFromCRSFile( CString sPath )
{
LOG->Trace( "Course::LoadFromCRSFile( '%s' )", sPath.c_str() );
Init();
m_sPath = sPath; // save path
bool bUseCache = true;
{
/* First look in the cache for this course. Don't bother
* honoring FastLoad for checking the course hash, since
* courses are normally grouped into a few directories, not
* one directory per course. XXX: if !FastLoad, regen
* cache if the used songs have changed */
unsigned uHash = SONGINDEX->GetCacheHash( m_sPath );
if( !DoesFileExist(GetCacheFilePath()) )
bUseCache = false;
if( !PREFSMAN->m_bFastLoad && GetHashForDirectory(m_sPath) != uHash )
bUseCache = false; // this cache is out of date
}
if( bUseCache )
{
CString sCacheFile = GetCacheFilePath();
LOG->Trace( "Course::LoadFromCRSFile(\"%s\") (\"%s\")", sPath.c_str(), sCacheFile.c_str() );
sPath = sCacheFile.c_str();
}
else
LOG->Trace( "Course::LoadFromCRSFile(\"%s\")", sPath.c_str() );
MsdFile msd;
if( !msd.ReadFile(sPath) )
RageException::Throw( "Error opening CRS file '%s'.", sPath.c_str() );
@@ -243,7 +265,15 @@ void Course::LoadFromCRSFile( CString sPath )
m_entries.push_back( new_entry );
}
else if( bUseCache && !stricmp(sValueName, "RADAR") )
{
StepsType st = (StepsType) atoi(sParams[1]);
CourseDifficulty cd = (CourseDifficulty) atoi(sParams[2]);
RadarValues rv;
rv.FromString( sParams[3] );
m_RadarCache[CacheEntry(st, cd)] = rv;
}
else
LOG->Trace( "Unexpected value named '%s'", sValueName.c_str() );
}
@@ -260,6 +290,33 @@ void Course::LoadFromCRSFile( CString sPath )
* song was found in the course. */
if( m_sBannerPath != "" && !m_entries.empty() )
BANNERCACHE->CacheBanner( m_sBannerPath );
/* Cache each trail RadarValues that's slow to load, so we
* don't have to do it at runtime. */
if( !bUseCache )
{
FOREACH_StepsType( st )
{
FOREACH_CourseDifficulty( cd )
{
Trail *pTrail = GetTrail( st, cd );
if( pTrail == NULL || !pTrail->SlowGetRadarValues() )
continue;
RadarValues rv = pTrail->GetRadarValues();
m_RadarCache[CacheEntry(st, cd)] = rv;
}
}
/* If we have any cache data, write the cache file. */
if( m_RadarCache.size() )
{
CString sCachePath = GetCacheFilePath();
Save( sCachePath, true );
SONGINDEX->AddCacheIndex( m_sPath, GetHashForFile(m_sPath) );
}
}
}
void Course::RevertFromDisk()
@@ -270,6 +327,11 @@ void Course::RevertFromDisk()
LoadFromCRSFile( m_sPath );
}
CString Course::GetCacheFilePath() const
{
return SongCacheIndex::GetCacheFilePath( "Courses", m_sPath );
}
void Course::Init()
{
m_bIsAutogen = false;
@@ -291,14 +353,18 @@ void Course::Init()
m_iTrailCacheSeed = 0;
}
void Course::Save()
void Course::Save( CString sPath, bool bSavingCache )
{
ASSERT( !m_bIsAutogen );
/* By default, save to the file we loaded from. */
if( sPath == "" )
sPath = m_sPath;
RageFile f;
if( !f.Open( m_sPath, RageFile::WRITE ) )
if( !f.Open( sPath, RageFile::WRITE ) )
{
LOG->Warn( "Could not write course file '%s': %s", m_sPath.c_str(), f.GetError().c_str() );
LOG->Warn( "Could not write course file '%s': %s", sPath.c_str(), f.GetError().c_str() );
return;
}
@@ -316,6 +382,29 @@ void Course::Save()
f.PutLine( ssprintf("#METER:%s:%i;", CourseDifficultyToString(cd).c_str(), m_iCustomMeter[cd]) );
}
if( bSavingCache )
{
f.PutLine( "// cache tags:" );
RadarCache_t::const_iterator it;
for( it = m_RadarCache.begin(); it != m_RadarCache.end(); ++it )
{
// #RADAR:type:difficulty:value,value,value...;
const CacheEntry &entry = it->first;
StepsType st = entry.first;
CourseDifficulty cd = entry.second;
CStringArray asRadarValues;
const RadarValues &rv = it->second;
for( int r=0; r < NUM_RADAR_CATEGORIES; r++ )
asRadarValues.push_back( ssprintf("%.3f", rv[r]) );
CString sLine = ssprintf( "#RADAR:%i:%i:", st, cd );
sLine += join( ",", asRadarValues ) + ";";
f.PutLine( sLine );
}
f.PutLine( "// end cache tags" );
}
for( unsigned i=0; i<m_entries.size(); i++ )
{
const CourseEntry& entry = m_entries[i];
@@ -608,13 +697,15 @@ Trail* Course::GetTrail( StepsType st, CourseDifficulty cd ) const
//
// Look in the Trail cache
//
TrailCache_t::iterator it = m_TrailCache.find( CacheEntry(st, cd) );
if( it != m_TrailCache.end() )
{
CacheData &cache = it->second;
if( cache.null )
return NULL;
return &cache.trail;
TrailCache_t::iterator it = m_TrailCache.find( CacheEntry(st, cd) );
if( it != m_TrailCache.end() )
{
CacheData &cache = it->second;
if( cache.null )
return NULL;
return &cache.trail;
}
}
//
@@ -630,6 +721,18 @@ Trail* Course::GetTrail( StepsType st, CourseDifficulty cd ) const
return NULL;
}
//
// If we have cached RadarValues for this trail, insert them.
//
{
RadarCache_t::const_iterator it = m_RadarCache.find( CacheEntry( st, cd ) );
if( it != m_RadarCache.end() )
{
const RadarValues &rv = it->second;
trail.SetRadarValues(rv);
}
}
cache.null = false;
return &cache.trail;
}
+5 -1
View File
@@ -132,7 +132,7 @@ public:
void LoadFromCRSFile( CString sPath );
void RevertFromDisk();
void Init();
void Save();
void Save( CString sPath = "", bool bSavingCache=false ); /* default is source file */
void AutogenEndlessFromGroup( CString sGroupName, Difficulty dc );
void AutogenNonstopFromGroup( CString sGroupName, Difficulty dc );
void AutogenOniFromArtist( CString sArtistName, CString sArtistNameTranslit, vector<Song*> aSongs, Difficulty dc );
@@ -151,6 +151,7 @@ public:
void Invalidate( Song *pStaleSong );
void GetAllCachedTrails( vector<Trail *> &out );
CString GetCacheFilePath() const;
const CourseEntry *FindFixedSong( const Song *pSong ) const;
@@ -170,6 +171,9 @@ private:
typedef map<CacheEntry, CacheData> TrailCache_t;
mutable TrailCache_t m_TrailCache;
mutable int m_iTrailCacheSeed;
typedef map<CacheEntry, RadarValues> RadarCache_t;
RadarCache_t m_RadarCache;
};
#endif
+31
View File
@@ -58,6 +58,37 @@ void RadarValues::LoadFromNode( const XNode* pNode )
pNode->GetChildValue( RadarCategoryToString(rc), m_fValues[rc] );
}
/* iMaxValues is only used for writing compatibility fields in non-cache
* SM files; they're never actually read. */
CString RadarValues::ToString( int iMaxValues ) const
{
if( iMaxValues == -1 )
iMaxValues = NUM_RADAR_CATEGORIES;
iMaxValues = min( iMaxValues, (int)NUM_RADAR_CATEGORIES );
CStringArray asRadarValues;
for( int r=0; r < iMaxValues; r++ )
asRadarValues.push_back( ssprintf("%.3f", m_fValues[r]) );
return join( ",",asRadarValues );
}
void RadarValues::FromString( CString sRadarValues )
{
CStringArray saValues;
split( sRadarValues, ",", saValues, true );
if( saValues.size() != NUM_RADAR_CATEGORIES )
{
MakeUnknown();
return;
}
FOREACH_RadarCategory(rc)
m_fValues[rc] = strtof( saValues[rc], NULL );
}
/*
* (c) 2001-2004 Chris Danford
* All rights reserved.
+3
View File
@@ -43,6 +43,9 @@ struct RadarValues
XNode* CreateNode() const;
void LoadFromNode( const XNode* pNode );
CString ToString( int iMaxValues = -1 ) const; // default = all
void FromString( CString sValues );
};
+1
View File
@@ -65,6 +65,7 @@ void SongCacheIndex::ReadCacheIndex()
EmptyDir( CACHE_DIR );
EmptyDir( CACHE_DIR "Banners/" );
EmptyDir( CACHE_DIR "Songs/" );
EmptyDir( CACHE_DIR "Courses/" );
CacheIndex.Clear();
}
+31 -6
View File
@@ -40,6 +40,26 @@ bool TrailEntry::ContainsTransformOrTurn() const
return false;
}
/* Return true if GetRadarValues may be very slow (reads, decodes and
* transforms the Steps), in which case it's worth caching it in Course. */
bool Trail::SlowGetRadarValues() const
{
FOREACH_CONST( TrailEntry, m_vEntries, e )
{
const Steps *pSteps = e->pSteps;
if( !pSteps->IsAutogen() && e->ContainsTransformOrTurn() )
return true;
}
return false;
}
void Trail::SetRadarValues( const RadarValues &rv )
{
m_CachedRadarValues = rv;
m_bRadarValuesCached = true;
}
RadarValues Trail::GetRadarValues() const
{
if( IsMystery() )
@@ -55,8 +75,8 @@ RadarValues Trail::GetRadarValues() const
}
else
{
m_bRadarValuesCached = true;
m_CachedRadarValues.Zero();
RadarValues rv;
rv.Zero();
FOREACH_CONST( TrailEntry, m_vEntries, e )
{
@@ -75,16 +95,21 @@ RadarValues Trail::GetRadarValues() const
if( po.ContainsTransformOrTurn() )
NoteDataUtil::TransformNoteData( nd, po, pSteps->m_StepsType );
NoteDataUtil::TransformNoteData( nd, e->Attacks, pSteps->m_StepsType, e->pSong );
RadarValues rv;
NoteDataUtil::GetRadarValues( nd, e->pSong->m_fMusicLengthSeconds, rv );
m_CachedRadarValues += rv;
RadarValues transformed_rv;
NoteDataUtil::GetRadarValues( nd, e->pSong->m_fMusicLengthSeconds, transformed_rv );
rv += transformed_rv;
}
else
{
m_CachedRadarValues += pSteps->GetRadarValues();
rv += pSteps->GetRadarValues();
}
}
/* Hack: SetRadarValues is non-const (a const setter doesn't
* make sense), but it only modifies a mutable value. Just
* cast away const. */
const_cast<Trail*>(this)->SetRadarValues( rv );
return m_CachedRadarValues;
}
}
+2
View File
@@ -62,7 +62,9 @@ public:
m_bRadarValuesCached = false;
}
bool SlowGetRadarValues() const;
RadarValues GetRadarValues() const;
void SetRadarValues( const RadarValues &rv ); // for pre-populating cache
int GetMeter() const;
int GetTotalMeter() const;
float GetLengthSeconds() const;