Source SDK Base 2013 Gameinfo.txt... WTF?!

Grab your favourite IDE and tinker with the innards of game engines

Source SDK Base 2013 Gameinfo.txt... WTF?!

Postby SM Sith Lord on Sun Dec 01, 2013 2:10 pm

The new Gameinfo.txt is 100% confusing my arse. Can somebody who is enlightened write a lengthy post explaining what the hell is going on in it?

I understood the old one fine, it was super simple. To have a game that required nothing other than the SDK, it would just look like this:
Code: Select all
"GameInfo"
{
   FileSystem
   {
      SteamAppId            218
      ToolsAppId            211

      SearchPaths
      {
         Game            |gameinfo_path|.
         Game            |all_source_engine_paths|hl2
      }
   }
}


The |all_source_engine_paths|hl2 would mount the required Source engine assets, but the user did not have to own HL2 at all. So it was super simple: search the mod's path, and also search Source engine's path (always). Mounting additional games was as easy to adding in another search path and a matching AdditionalContentID line to go along with it.

Now, using the 2013 version, it seems like a basic Source mod is searching 20 different locations. So I have 2 main questions:

1. What does the most basic Gameinfo.txt look like in 2013? One that does not mount any content other than the SDK and the mod.

2. What does a basic Gameinfo.txt that mounts TF2 resources as well look like in 2013?

I'd really appreciate some help here. Everything has gone smoothly with porting my mod over to 2013, except I can't figure out how to properly modify the Gameinfo.txt.

Reference: https://github.com/ValveSoftware/source ... meinfo.txt
SM Sith Lord
Been Here A While
Been Here A While
 
Joined: Sat Nov 25, 2006 4:25 pm
Location: Los Angles, CA

Re: Source SDK Base 2013 Gameinfo.txt... WTF?!

Postby Dr. Delta on Sun Dec 01, 2013 5:21 pm

This is what I'm using:

Code: Select all
"GameInfo"
{
   game       "WCS-DEV"
   title       "Worst Case Scenario"
   title2      ""

   type      singleplayer_only

   developer    "Dr. Delta"
   developer_url    "http://url.com"
   manual      "http://url.com/manual.pdf"

   FileSystem
   {
      SteamAppId            243730      // This sets the app ID in Steam
      
      //
      // The code that loads this file automatically does a few things here:
      //
      // 1. For each "Game" search path, it adds a "GameBin" path, in <dir>\bin
      // 2. For each "Game" search path, it adds another "Game" path in front of it with _<langage> at the end.
      //    For example: c:\hl2\cstrike on a french machine would get a c:\hl2\cstrike_french path added to it.
      // 3. For the first "Game" search path, it adds a search path called "MOD".
      // 4. For the first "Game" search path, it adds a search path called "DEFAULT_WRITE_PATH".
      //

      //
      // Search paths are relative to the base directory, which is where hl2.exe is found.
      //
      // |gameinfo_path| points at the directory where gameinfo.txt is.
      // We always want to mount that directory relative to gameinfo.txt, so
      // people can mount stuff in c:\mymod, and the main game resources are in
      // someplace like c:\program files\valve\steam\steamapps\half-life 2.
      //
      SearchPaths
      {
         // First, mount all user customizations.  This will search for VPKs and subfolders
         // and mount them in alphabetical order.  The easiest way to distribute a mod is to
         // pack up the custom content into a VPK.  To "install" a mod, just drop it in this
         // folder.
         //
         // Note that this folder is scanned only when the game is booted.
         game+mod         ep2/custom/*
         game+mod         episodic/custom/*
         game+mod         hl2/custom/*

         // Now search loose files.  We'll set the directory containing the gameinfo.txt file
         // as the first "mod" search path (after any user customizations).  This is also the one
         // that's used when writing to the "mod" path.
         game+mod+mod_write+default_write_path      |gameinfo_path|.
         gamebin            |gameinfo_path|bin

         // We search VPK files before ordinary folders, because most files will be found in
         // VPK and we can avoid making thousands of file system calls to attempt to open files
         // in folders where they don't exist.  (Searching a VPK is much faster than making an operating
         // system call.)
         game_lv            hl2/hl2_lv.vpk
         game+mod         ep2/ep2_english.vpk
         game+mod         ep2/ep2_pak.vpk
         game            |all_source_engine_paths|episodic/ep1_english.vpk
         game            |all_source_engine_paths|episodic/ep1_pak.vpk
         game            |all_source_engine_paths|hl2/hl2_english.vpk
         game            |all_source_engine_paths|hl2/hl2_pak.vpk
         game            |all_source_engine_paths|hl2/hl2_textures.vpk
         game            |all_source_engine_paths|hl2/hl2_sound_vo_english.vpk
         game            |all_source_engine_paths|hl2/hl2_sound_misc.vpk
         game            |all_source_engine_paths|hl2/hl2_misc.vpk
         platform         |all_source_engine_paths|platform/platform_misc.vpk

         // Add the HL2 directory as a game search path.  This is also where where writes
         // to the "game" path go.
         game+game_write      ep2

         // Where the game's binaries are
         gamebin            episodic/bin

         // Last, mount in shared HL2 loose files
         game            |all_source_engine_paths|episodic
         game            |all_source_engine_paths|hl2
         platform         |all_source_engine_paths|platform
      }
   }
}


I believe this only mounts HL2/HL2-EP1/HL2-EP2 content. I wouldn't know about TF2, sorry.
Last edited by Dr. Delta on Sat Oct 31, 2020 3:53 pm, edited 2 times in total.
User avatar
Dr. Delta
Veteran
Veteran
 
Joined: Thu Dec 27, 2007 1:18 pm
Location: People's Republic of Porygon

Re: Source SDK Base 2013 Gameinfo.txt... WTF?!

Postby SM Sith Lord on Sun Dec 01, 2013 5:29 pm

Thank you for posting that Dr. Delta, good to see one that is confirmed to be working.

I've gotten my MP based mod to mount Counter-Strike: Source content using the following Gameinfo.txt, but as you'll see I could only accomplish this using hard-coded folder paths so far. I'll keep tweaking it and see if I can get them mounted the proper way.

Code: Select all
   FileSystem
   {
      SteamAppId            243750
      
      SearchPaths
      {
         game+mod         hl2mp/custom/*
         game+mod         hl2/custom/*

         game+mod+mod_write+default_write_path      |gameinfo_path|.
         gamebin            |gameinfo_path|bin

         game_lv            hl2/hl2_lv.vpk
         game+mod         hl2mp/hl2mp_english.vpk
         game+mod         hl2mp/hl2mp_pak.vpk
         game            "C:\Program Files (x86)\Steam\SteamApps\common\Counter-Strike Source\cstrike\cstrike_pak_dir.vpk"
         game            |all_source_engine_paths|hl2/hl2_english.vpk
         game            |all_source_engine_paths|hl2/hl2_pak.vpk
         game            |all_source_engine_paths|hl2/hl2_textures.vpk
         game            |all_source_engine_paths|hl2/hl2_sound_vo_english.vpk
         game            |all_source_engine_paths|hl2/hl2_sound_misc.vpk
         game            |all_source_engine_paths|hl2/hl2_misc.vpk
         platform         |all_source_engine_paths|platform/platform_misc.vpk

         game+game_write      hl2mp

         gamebin            hl2mp/bin

         game            "C:\Program Files (x86)\Steam\SteamApps\common\Counter-Strike Source\cstrike"
         game            |all_source_engine_paths|hl2mp
         game            |all_source_engine_paths|hl2
         platform         |all_source_engine_paths|platform
      }
   }
SM Sith Lord
Been Here A While
Been Here A While
 
Joined: Sat Nov 25, 2006 4:25 pm
Location: Los Angles, CA

Re: Source SDK Base 2013 Gameinfo.txt... WTF?!

Postby SM Sith Lord on Mon Dec 02, 2013 5:38 pm

As per the VDC, here is the same Gameinfo.txt but with relative paths instead of the hard-coded ones, but there's still a problem.

Code: Select all
   FileSystem
   {
      SteamAppId            243750
      
      SearchPaths
      {
         game+mod         hl2mp/custom/*
         game+mod         hl2/custom/*
         game+mod         "|all_source_engine_paths|../Counter-Strike Source/cstrike/custom/*"

         game+mod+mod_write+default_write_path      |gameinfo_path|.
         gamebin            |gameinfo_path|bin

         game_lv            hl2/hl2_lv.vpk
         game+mod         hl2mp/hl2mp_english.vpk
         game+mod         hl2mp/hl2mp_pak.vpk
         game            "|all_source_engine_paths|../Counter-Strike Source/cstrike/cstrike_pak_dir.vpk"
         game            |all_source_engine_paths|hl2/hl2_english.vpk
         game            |all_source_engine_paths|hl2/hl2_pak.vpk
         game            |all_source_engine_paths|hl2/hl2_textures.vpk
         game            |all_source_engine_paths|hl2/hl2_sound_vo_english.vpk
         game            |all_source_engine_paths|hl2/hl2_sound_misc.vpk
         game            |all_source_engine_paths|hl2/hl2_misc.vpk
         platform         |all_source_engine_paths|platform/platform_misc.vpk

         game+game_write      hl2mp

         gamebin            hl2mp/bin

         game            "|all_source_engine_paths|../Counter-Strike Source/cstrike"
         game            |all_source_engine_paths|hl2mp
         game            |all_source_engine_paths|hl2
         platform         |all_source_engine_paths|platform
      }
   }


The problem is that it is literally moving up 1 folder level from the Source SDK 2013 folder, looking for a folder called "Counter-Strike Source" and going from there. But what if the player uses a game cache on an alternate hard drive? Would that mean that the folder would not be 1 level up from the SDK 2013 folder? It'd be on an entirely different drive letter! I assume this would be a problem.

Perhaps there are other keywords besides |all_source_engine_paths| that would solve this issue?
SM Sith Lord
Been Here A While
Been Here A While
 
Joined: Sat Nov 25, 2006 4:25 pm
Location: Los Angles, CA

Re: Source SDK Base 2013 Gameinfo.txt... WTF?!

Postby Dr. Delta on Wed Dec 04, 2013 12:11 am

SM Sith Lord wrote:But what if the player uses a game cache on an alternate hard drive? Would that mean that the folder would not be 1 level up from the SDK 2013 folder? It'd be on an entirely different drive letter! I assume this would be a problem.

Perhaps there are other keywords besides |all_source_engine_paths| that would solve this issue?


No idea, but I can't get sourcemods to work with alternative steam locations anyways. So, I think this is something we'll need to live with I think. Interesting someone else also ran into this, I decided that it's probably a Source/Steam/Valve issue we'll be unable to fix; so I decided to not waste my time on it.
User avatar
Dr. Delta
Veteran
Veteran
 
Joined: Thu Dec 27, 2007 1:18 pm
Location: People's Republic of Porygon

Re: Source SDK Base 2013 Gameinfo.txt... WTF?!

Postby SM Sith Lord on Thu Dec 05, 2013 11:09 am

I meant that even if the mod was in the normal directory, but Counter-Strike Source was in an alternate directory, simply going up 1 level from the mod and looking for a folder called Counter-Strike Source would be fail.

You can use full folder paths to point to any folder you need, but that is not very useful if you don't already know the full folder path to your Counter-Strike Source resources.
SM Sith Lord
Been Here A While
Been Here A While
 
Joined: Sat Nov 25, 2006 4:25 pm
Location: Los Angles, CA

Re: Source SDK Base 2013 Gameinfo.txt... WTF?!

Postby SM Sith Lord on Fri Dec 06, 2013 4:35 pm

NOTE: This is a post I put on the Steam forums about this same topic, but with some new information, so I'm posting it here too.

I am now writing the code that allows players to mount content for their other Source engine games and I need to figure out the proper way to do this in 2013.

So far I have been able to mount CS:S content by using this in my gameinfo.txt:
Code: Select all
       FileSystem
       {
          SteamAppId            243750
         
          SearchPaths
          {
             game+mod         hl2mp/custom/*
             game+mod         hl2/custom/*
             game+mod         "|all_source_engine_paths|../Counter-Strike Source/cstrike/custom/*"

             game+mod+mod_write+default_write_path      |gameinfo_path|.
             gamebin            |gameinfo_path|bin

             game_lv            hl2/hl2_lv.vpk
             game+mod         hl2mp/hl2mp_english.vpk
             game+mod         hl2mp/hl2mp_pak.vpk
             game            "|all_source_engine_paths|../Counter-Strike Source/cstrike/cstrike_pak_dir.vpk"
             game            |all_source_engine_paths|hl2/hl2_english.vpk
             game            |all_source_engine_paths|hl2/hl2_pak.vpk
             game            |all_source_engine_paths|hl2/hl2_textures.vpk
             game            |all_source_engine_paths|hl2/hl2_sound_vo_english.vpk
             game            |all_source_engine_paths|hl2/hl2_sound_misc.vpk
             game            |all_source_engine_paths|hl2/hl2_misc.vpk
             platform         |all_source_engine_paths|platform/platform_misc.vpk

             game+game_write      hl2mp

             gamebin            hl2mp/bin

             game            "|all_source_engine_paths|../Counter-Strike Source/cstrike"
             game            |all_source_engine_paths|hl2mp
             game            |all_source_engine_paths|hl2
             platform         |all_source_engine_paths|platform
          }
       }


First I'll describe what I did and why, and then at the end I'll explain why I think this method is not the proper way to do it.

Code: Select all
game+mod         "|all_source_engine_paths|../Counter-Strike Source/cstrike/custom/*"

This line is so the player's CS:S addons (the content in their CS:S custom folder) can also be used in my game.

Code: Select all
game            "|all_source_engine_paths|../Counter-Strike Source/cstrike/cstrike_pak_dir.vpk"

This line mount the majority of CS:S content. For other games like TF2, you will have to include MANY different VPK's from their folder. It gets messy, but works just the same. Note that maps and some other content are NOT in these VPKs!

Code: Select all
game            "|all_source_engine_paths|../Counter-Strike Source/cstrike"

This will mount the remaining files such as maps and any other loose files that the player has sitting in their CS:S folder.

THE PROBLEM
The problem comes in the way that the CS:S folder itself is located. As far as I can tell, it works like this:
  • Start in C:\Program Files (x86)\Steam\SteamApps\common\Source SDK Base 2013 Multiplayer
  • Move up 1 folder level to C:\Program Files (x86)\Steam\SteamApps\common
  • Look for a folder named Counter-Strike Source in this location

But what if the player has their CS:S installed onto a different hard drive? Their Counter-Strike Source folder wouldn't even be on the same drive letter, and certainly not in C:\Program Files (x86)\Steam\SteamApps\common.

What exactly does "|all_source_engine_paths|" mean? And are there any other variables that can be used here?

NOTE
Mounting content from HL2 and HL2: MP is very different than mounting content from other games because the HL2 and HL2: MP content is included within the Source SDK Base 2013 Multiplayer folder itself. Trying to mount TF2 or CS:S content the same way that HL2 and HL2: MP content is mounted does not work.

On a side note, I am also still trying to figure out what order things should be mounted in to insure that my game's files takes priority over the ones mounted from TF2 or CS:S.
SM Sith Lord
Been Here A While
Been Here A While
 
Joined: Sat Nov 25, 2006 4:25 pm
Location: Los Angles, CA

Re: Source SDK Base 2013 Gameinfo.txt... WTF?!

Postby SM Sith Lord on Sun Dec 08, 2013 2:21 am

Using the best information I could find, here is my solution to mounting content via modifying the gameinfo.txt.

First of all, this is the gameinfo.txt that I am starting with. It is for 2013 MP and does not mount any additional content as-is. All of the lines that would mount content are commented out. The other additional keys are markers required for my code to work later on:
Code: Select all
"GameInfo"
{
   game   "SMARCADE: Anarchy Edition"

   nodifficulty 1
   hasportals 0
   nomodels 1
   nohimodel 1
   nocrosshair 1

   hidden_maps
   {
      "test_speakers"      1
      "test_hardware"      1
   }

   developer   "Elijah Newman-Gomez"
   developer_url   "http://www.smsithlord.com/"
   manual      "http://www.smarcade.net/"
   icon   "smarcade"

   FileSystem
   {
      SteamAppId            243750
      
      SearchPaths
      {
         // SMARCADE's resources first (allowing custom content)
         category                  smarcade
         game+mod                  |gameinfo_path|custom/*
         game+mod+mod_write+default_write_path   |gameinfo_path|.
         gamebin                  |gameinfo_path|bin
         endcategory                  smarcade

         // Next use SDKBASE resources
         category                  sdkbase
         platform                  |all_source_engine_paths|platform
         platform                  |all_source_engine_paths|platform/platform_misc.vpk
         game+game_write               hl2mp
         gamebin                  hl2mp/bin
         endcategory                  sdkbase

         // SDKCONTENT resources
         category                  sdkcontent
         game_lv                  hl2/hl2_lv.vpk
         game+mod                  hl2mp/hl2mp_english.vpk
         game+mod                  hl2mp/hl2mp_pak.vpk
         game                     |all_source_engine_paths|hl2/hl2_english.vpk
         game                     |all_source_engine_paths|hl2/hl2_pak.vpk
         game                     |all_source_engine_paths|hl2/hl2_textures.vpk
         game                     |all_source_engine_paths|hl2/hl2_sound_vo_english.vpk
         game                     |all_source_engine_paths|hl2/hl2_sound_misc.vpk
         game                     |all_source_engine_paths|hl2/hl2_misc.vpk
         game                     |all_source_engine_paths|hl2mp
         game                     |all_source_engine_paths|hl2
         endcategory                  sdkcontent

         category                  smarcade_download
         game+download               |gameinfo_path|download
         endcategory                  smarcade_download

         // CUSTOM content from other mounted games
         category                  custom
//         game                      "|all_source_engine_paths|../Counter-Strike Source/cstrike/custom/*"
//         game                      "|all_source_engine_paths|../Half-Life 2 Deathmatch/hl2mp/custom/*"
         endcategory                  custom

         // ADDITIONALVPK resources
         category                  additionalvpk
//         game                     "|all_source_engine_paths|../Counter-Strike Source/cstrike/cstrike_pak_dir.vpk"
//         game                     "|all_source_engine_paths|../Half-Life 2 Deathmatch/hl2mp/hl2mp_pak_dir.vpk"
         endcategory                  additionalvpk

         // ADDITIONALLOOSE resources
         category                  additionalloose
//         game                     "|all_source_engine_paths|../Counter-Strike Source/cstrike"
//         game                     "|all_source_engine_paths|../Half-Life 2 Deathmatch/hl2mp"
         endcategory                  additionalloose

         // Lastly, check for downloaded content
         category                  download
//         game                     "|all_source_engine_paths|../Counter-Strike Source/cstrike/download"
//         game                     "|all_source_engine_paths|../Half-Life 2 Deathmatch/hl2mp/download"
         endcategory                  download
      }
   }
}


Now here is the code I wrote to modify the gameinfo.txt. It uses the STL for strings, so you'll want to clean it up before you do a release build:
Code: Select all
bool ModifyGameInfo(KeyValues* gameinfoKV, const char* appID, const char* path, bool remove)
{
   KeyValues* pOldSearchPathsKV = filesystemKV->FindKey("FileSystem/SearchPaths");

   // Each appID requires a very specific set of VPKs to mount.  This KeyValues will keep track of these.
   KeyValues* vpk_files = new KeyValues("vpk_files");

   // CS:S 240
   vpk_files->SetString("240/cstrike_pak_dir", "cstrike_pak_dir");

   // TF2 440
   vpk_files->SetString("440/tf2_misc_dir", "tf2_misc_dir");
   vpk_files->SetString("440/tf2_sound_misc_dir", "tf2_sound_misc_dir");
   vpk_files->SetString("440/tf2_sound_vo_english_dir", "tf2_sound_vo_english_dir");
   vpk_files->SetString("440/tf2_textures_dir", "tf2_textures_dir");

   // Portal 400
   vpk_files->SetString("400/portal_pak_dir", "portal_pak_dir");

   // HL2: DM 320
   vpk_files->SetString("320/hl2mp_pak_dir", "hl2mp_pak_dir");

   // HL2: Episode 2 420
   vpk_files->SetString("420/ep2_pak_dir", "ep2_pak_dir");

   // HL2: Episode 1 380
   vpk_files->SetString("380/ep1_pak_dir", "ep1_pak_dir");

   // Half-Life 2 220
   vpk_files->SetString("220/hl2_misc_dir", "hl2_misc_dir");
   vpk_files->SetString("220/hl2_pak_dir", "hl2_pak_dir");
   vpk_files->SetString("220/hl2_sound_misc_dir", "hl2_sound_misc_dir");
   vpk_files->SetString("220/hl2_voice_vo_english_dir", "hl2_voice_vo_english_dir");
   vpk_files->SetString("220/hl2_textures_dir", "hl2_textures_dir");

   // Half-Life 2: Lost Coast 340
   vpk_files->SetString("340/lostcoast_pak_dir", "lostcoast_pak_dir");

   // end of vpk_files keyvalues

   // We are going to create a new SearchPaths key, then replace the existing one with the new one.
   KeyValues* pSearchPathsKV = new KeyValues("SearchPaths");

   int state = 0;
   for( KeyValues *sub = pOldSearchPathsKV->GetFirstValue(); sub; sub = sub->GetNextValue() )
   {
      if( state == 0 )
      {
         // 0 = looking for "endcategory" "custom"
         std::string targetPath = path;
         targetPath += "/custom/*";

         if( !Q_strcmp(sub->GetName(), "game") && !Q_strcmp(sub->GetString(), targetPath.c_str()) )
         {
            // this is the the target path

            if( !remove )
            {
               // add this entry
               KeyValues* kv = pSearchPathsKV->CreateNewKey();
               kv->SetName(sub->GetName());
               kv->SetString("", sub->GetString());
            }

            // advance the state
            state++;
         }
         else if( !Q_strcmp(sub->GetName(), "endcategory") && !Q_strcmp(sub->GetString(), "custom") )
         {
            // we have reached the end of the category

            if( !remove )
            {
               // add the new entry
               KeyValues* kv = pSearchPathsKV->CreateNewKey();
               kv->SetName("game");
               kv->SetString("", targetPath.c_str());
            }

            // add this entry
            KeyValues* kv = pSearchPathsKV->CreateNewKey();
            kv->SetName(sub->GetName());
            kv->SetString("", sub->GetString());

            // advance the state
            state++;
         }
         else
         {
            // default

            // add this entry
            KeyValues* kv = pSearchPathsKV->CreateNewKey();
            kv->SetName(sub->GetName());
            kv->SetString("", sub->GetString());

            // do NOT advance the state
         }
      }
      else if( state == 1 )
      {
         // 1 = looking for "endcategory" "additionalvpk"

         // Need to locate every VPK that this AppID requires
         KeyValues* app_vpk_files = vpk_files->FindKey(appID);

         if( app_vpk_files )
         {
            bool bSkip = false;
            for( KeyValues *vpk = app_vpk_files->GetFirstValue(); vpk; vpk = vpk->GetNextValue() )
            {
               std::string targetPath = path;
               targetPath += "/";
               targetPath += vpk->GetString();
               targetPath += ".vpk";

               if( !Q_strcmp(sub->GetName(), "game") && !Q_strcmp(sub->GetString(), targetPath.c_str()) )
               {
                  // this is the the target path
                  if( !remove )
                  {
                     // add this entry
                     KeyValues* kv = pSearchPathsKV->CreateNewKey();
                     kv->SetName(sub->GetName());
                     kv->SetString("", sub->GetString());
                  }

                  // remove this from the list of needed VPKs
                  vpk->SetName("");
                  vpk->SetString("", "");

                  bSkip = true;
                  break;
               }
            }

            if( !Q_strcmp(sub->GetName(), "endcategory") && !Q_strcmp(sub->GetString(), "additionalvpk") )
            {
               // we have reached the end of the category

               if( !remove )
               {
                  // add the new entries
                  for( KeyValues *vpk = app_vpk_files->GetFirstValue(); vpk; vpk = vpk->GetNextValue() )
                  {
                     if( !Q_strcmp(vpk->GetName(), "") )
                        continue;

                     std::string targetPath = path;
                     targetPath += "/";
                     targetPath += vpk->GetString();
                     targetPath += ".vpk";

                     KeyValues* kv = pSearchPathsKV->CreateNewKey();
                     kv->SetName("game");
                     kv->SetString("", targetPath.c_str());

                     // remove this from the list of needed VPKs as well, for consistency's sake
                     vpk->SetName("");
                     vpk->SetString("", "");
                  }
               }

               // add this entry
               KeyValues* kv = pSearchPathsKV->CreateNewKey();
               kv->SetName(sub->GetName());
               kv->SetString("", sub->GetString());

               // advance the state
               state++;
            }
            else if( !bSkip )
            {
               // default

               // add this entry
               KeyValues* kv = pSearchPathsKV->CreateNewKey();
               kv->SetName(sub->GetName());
               kv->SetString("", sub->GetString());

               // do NOT advance the state
            }
         }
      }
      else if( state == 2 )
      {
         // 2 = looking for "endcategory" "additionalloose"

         if( !Q_strcmp(sub->GetName(), "game") && !Q_strcmp(sub->GetString(), path) )
         {
            // this is the the target path

            if( !remove )
            {
               // add this entry
               KeyValues* kv = pSearchPathsKV->CreateNewKey();
               kv->SetName(sub->GetName());
               kv->SetString("", sub->GetString());
            }

            // advance the state
            state++;
         }
         else if( !Q_strcmp(sub->GetName(), "endcategory") && !Q_strcmp(sub->GetString(), "additionalloose") )
         {
            // we have reached the end of the category

            if( !remove )
            {
               // add the new entry
               KeyValues* kv = pSearchPathsKV->CreateNewKey();
               kv->SetName("game");
               kv->SetString("", path);
            }

            // add this entry
            KeyValues* kv = pSearchPathsKV->CreateNewKey();
            kv->SetName(sub->GetName());
            kv->SetString("", sub->GetString());

            // advance the state
            state++;
         }
         else
         {
            // default

            // add this entry
            KeyValues* kv = pSearchPathsKV->CreateNewKey();
            kv->SetName(sub->GetName());
            kv->SetString("", sub->GetString());

            // do NOT advance the state
         }
      }
      else if( state == 3 )
      {
         // 3 = looking for "endcategory" "download"

         std::string targetPath = path;
         targetPath += "/download";

         if( !Q_strcmp(sub->GetName(), "game") && !Q_strcmp(sub->GetString(), targetPath.c_str()) )
         {
            // this is the the target path

            if( !remove )
            {
               // add this entry
               KeyValues* kv = pSearchPathsKV->CreateNewKey();
               kv->SetName(sub->GetName());
               kv->SetString("", sub->GetString());
            }

            // advance the state
            state++;
         }
         else if( !Q_strcmp(sub->GetName(), "endcategory") && !Q_strcmp(sub->GetString(), "download") )
         {
            // we have reached the end of the category

            if( !remove )
            {
               // add the new entry
               KeyValues* kv = pSearchPathsKV->CreateNewKey();
               kv->SetName("game");
               kv->SetString("", targetPath.c_str());
            }

            // add this entry
            KeyValues* kv = pSearchPathsKV->CreateNewKey();
            kv->SetName(sub->GetName());
            kv->SetString("", sub->GetString());

            // advance the state
            state++;
         }
         else
         {
            // default

            // add this entry
            KeyValues* kv = pSearchPathsKV->CreateNewKey();
            kv->SetName(sub->GetName());
            kv->SetString("", sub->GetString());

            // do NOT advance the state
         }
      }
      else if( state == 4 )
      {
         // 4 = trailing entry, just copy it in

         // add this entry
         KeyValues* kv = pSearchPathsKV->CreateNewKey();
         kv->SetName(sub->GetName());
         kv->SetString("", sub->GetString());

         // do NOT advance the state
      }
   }

   // Now determine if it all succeeded (thus far)
   if( state < 3 )
   {
      Msg("GAMEINFO_ERROR: Failed one or more operations when modifying SearchPaths.\n");

      vpk_files->deleteThis();
      return false;
   }

   // Now replace the old SearchPaths with the new one
   pOldSearchPathsKV->Clear();
   pOldSearchPathsKV->SetName("");

   filesystemKV->AddSubKey(pSearchPathsKV);

   vpk_files->deleteThis();
   return true;
}


And here is an example of code that calls it:
Code: Select all
int main()
{
   // Load the gameinfo.txt
   KeyValues* gameinfoKV = new KeyValues("GameInfo");
   gameinfoKV->LoadFromFile(g_pFullFileSystem, "gameinfo.txt", "MOD");


   // Let's mount Counter-Strike: Source
   ModifyGameInfo(gameinfoKV, 240, "|all_source_engine_paths|../Counter-Strike Source/cstrike", false);

   // And also Half-Life 2: Deathmatch
   ModifyGameInfo(gameinfoKV, 320, "|all_source_engine_paths|../Half-Life 2 Deathmatch/hl2mp", false);

   // Let's UN-mount Team Fortress 2
   ModifyGameInfo(gameinfoKV, 440, "|all_source_engine_paths|../Team Fortress 2/tf", true);

   // Now let's save the gameinfo.txt back out
   gameinfo->SaveToFile(g_pFullFileSystem, "gameinfo.txt", "MOD");

   // And close the game (it needs to be restarted)
   engine->ClientCmd("exit\n");
}


It's not optimized by any means, but it is working well enough so far.
SM Sith Lord
Been Here A While
Been Here A While
 
Joined: Sat Nov 25, 2006 4:25 pm
Location: Los Angles, CA

Re: Source SDK Base 2013 Gameinfo.txt... WTF?!

Postby dark0r on Sun Dec 08, 2013 9:46 pm

There is a Steam API to get the absolute path of where an app/game is installed:
https://github.com/SteamRE/open-steamwo ... s005.h#L74
Use ISteamApps005::GetAppInstallDir instead of relative paths to pass the correct path to IFileSystem::AddSearchPath on mod startup.
dark0r
Been Here A While
Been Here A While
 
Joined: Sat Mar 25, 2006 10:16 am
Location: de_hell

Return to Programming

Who is online

Users browsing this forum: No registered users

cron