Precaching (def files)

From The DarkMod Wiki
Jump to: navigation, search

Originally written by Ishtvan on http://forums.thedarkmod.com/topic/3798

Some people probably knew about this already (at least Gildoran seems to have), but I didn't know about it and other FM authors might end up making their own def files, so I think we should document it:

What does pre-caching actually do?

It loads the data to be cached, at loading time of the map. Thus it prevents excessive disk hits at playtime, which can cause sutterting in the map while playing.

In order to precache things in your def file, you must use specific prefixes. For example, if your def file contains another entity to spawn, use "def_<description of entity>" for the key name, and that other entity will also be precached. Models must have "model_<description>", sounds must have "snd_<description>", guis must have "gui_*" materials "mtr_*", etc.

I copied the code that precaches things so you can see all the prefixes. Every time you see MatchPrefix( "<something>" ), it means the key for tha thing must begin with <something> in order for it to cache.

The Code

/*
=================== 
idGameLocal::CacheDictionaryMedia

This is called after parsing an EntityDef and for each entity spawnArgs before
merging the entitydef.  It could be done post-merge, but that would
avoid the fast pre-cache check associated with each entityDef
===================
*/
void idGameLocal::CacheDictionaryMedia( const idDict *dict ) {
   const idKeyValue *kv;

   if ( dict == NULL ) {
       if ( cvarSystem->GetCVarBool( "com_makingBuild") ) {
           DumpOggSounds();
       }
       return;
   }

   if ( cvarSystem->GetCVarBool( "com_makingBuild" ) ) {
       GetShakeSounds( dict );
   }

   kv = dict->MatchPrefix( "model" );
   while( kv ) {
       if ( kv->GetValue().Length() ) {
           declManager->MediaPrint( "Precaching model %s\n", kv->GetValue().c_str() );
           // precache model/animations
           if ( declManager->FindType( DECL_MODELDEF, kv->GetValue(), false ) == NULL ) {
               // precache the render model
               renderModelManager->FindModel( kv->GetValue() );
               // precache .cm files only
               collisionModelManager->LoadModel( kv->GetValue(), true );
           }
       }
       kv = dict->MatchPrefix( "model", kv );
   }

   kv = dict->FindKey( "s_shader" );
   if ( kv && kv->GetValue().Length() ) {
       declManager->FindType( DECL_SOUND, kv->GetValue() );
   }

   kv = dict->MatchPrefix( "snd", NULL );
   while( kv ) {
       if ( kv->GetValue().Length() ) {
           declManager->FindType( DECL_SOUND, kv->GetValue() );
       }
       kv = dict->MatchPrefix( "snd", kv );
   }


   kv = dict->MatchPrefix( "gui", NULL );
   while( kv ) {
       if ( kv->GetValue().Length() ) {
           if ( !idStr::Icmp( kv->GetKey(), "gui_noninteractive" )
               || !idStr::Icmpn( kv->GetKey(), "gui_parm", 8 )    
               || !idStr::Icmp( kv->GetKey(), "gui_inventory" ) ) {
               // unfortunate flag names, they aren't actually a gui
           } else {
               declManager->MediaPrint( "Precaching gui %s\n", kv->GetValue().c_str() );
               idUserInterface *gui = uiManager->Alloc();
               if ( gui ) {
                   gui->InitFromFile( kv->GetValue() );
                   uiManager->DeAlloc( gui );
               }
           }
       }
       kv = dict->MatchPrefix( "gui", kv );
   }

   kv = dict->FindKey( "texture" );
   if ( kv && kv->GetValue().Length() ) {
       declManager->FindType( DECL_MATERIAL, kv->GetValue() );
   }

   kv = dict->MatchPrefix( "mtr", NULL );
   while( kv ) {
       if ( kv->GetValue().Length() ) {
           declManager->FindType( DECL_MATERIAL, kv->GetValue() );
       }
       kv = dict->MatchPrefix( "mtr", kv );
   }

   // handles hud icons
   kv = dict->MatchPrefix( "inv_icon", NULL );
   while ( kv ) {
       if ( kv->GetValue().Length() ) {
           declManager->FindType( DECL_MATERIAL, kv->GetValue() );
       }
       kv = dict->MatchPrefix( "inv_icon", kv );
   }

   // handles teleport fx.. this is not ideal but the actual decision on which fx to use
   // is handled by script code based on the teleport number
   kv = dict->MatchPrefix( "teleport", NULL );
   if ( kv && kv->GetValue().Length() ) {
       int teleportType = atoi( kv->GetValue() );
       const char *p = ( teleportType ) ? va( "fx/teleporter%i.fx", teleportType ) : "fx/teleporter.fx";
       declManager->FindType( DECL_FX, p );
   }

   kv = dict->MatchPrefix( "fx", NULL );
   while( kv ) {
       if ( kv->GetValue().Length() ) {
           declManager->MediaPrint( "Precaching fx %s\n", kv->GetValue().c_str() );
           declManager->FindType( DECL_FX, kv->GetValue() );
       }
       kv = dict->MatchPrefix( "fx", kv );
   }

   kv = dict->MatchPrefix( "smoke", NULL );
   while( kv ) {
       if ( kv->GetValue().Length() ) {
           idStr prtName = kv->GetValue();
           int dash = prtName.Find('-');
           if ( dash > 0 ) {
               prtName = prtName.Left( dash );
           }
           declManager->FindType( DECL_PARTICLE, prtName );
       }
       kv = dict->MatchPrefix( "smoke", kv );
   }

   kv = dict->MatchPrefix( "skin", NULL );
   while( kv ) {
       if ( kv->GetValue().Length() ) {
           declManager->MediaPrint( "Precaching skin %s\n", kv->GetValue().c_str() );
           declManager->FindType( DECL_SKIN, kv->GetValue() );
       }
       kv = dict->MatchPrefix( "skin", kv );
   }

   kv = dict->MatchPrefix( "def", NULL );
   while( kv ) {
       if ( kv->GetValue().Length() ) {
           FindEntityDef( kv->GetValue().c_str(), false );
       }
       kv = dict->MatchPrefix( "def", kv );
   }

   kv = dict->MatchPrefix( "pda_name", NULL );
   while( kv ) {
       if ( kv->GetValue().Length() ) {
           declManager->FindType( DECL_PDA, kv->GetValue().c_str(), false );
       }
       kv = dict->MatchPrefix( "pda_name", kv );
   }

   kv = dict->MatchPrefix( "video", NULL );
   while( kv ) {
       if ( kv->GetValue().Length() ) {
           declManager->FindType( DECL_VIDEO, kv->GetValue().c_str(), false );
       }
       kv = dict->MatchPrefix( "video", kv );
   }

   kv = dict->MatchPrefix( "audio", NULL );
   while( kv ) {
       if ( kv->GetValue().Length() ) {
           declManager->FindType( DECL_AUDIO, kv->GetValue().c_str(), false );
       }
       kv = dict->MatchPrefix( "audio", kv );
   }

   kv = dict->MatchPrefix( "xdata", NULL );
   while( kv ) {
       if ( kv->GetValue().Length() ) {
           declManager->FindType( DECL_XDATA, kv->GetValue().c_str(), false );
       }
       kv = dict->MatchPrefix( "xdata", kv );
   }
}