Save Game Files

From Valve Developer Community

Jump to: navigation, search
Abstract Coding series

Levels & XPOptimizationProcedural TexturesSights & SniperriflesSpecial effectsVehiclesThreadsSave Game FilesNight VisionNon-offensive WeaponsDynamic Weapon SpawnsDynamic Weapon Spawns (Advanced)

If you just want to save your entity's state, see Data Descriptions.

Source stores game state in .sav files and other data in other various files (.hl1, .hl2, .hl3, etc.) in the /SAVE/ directory of a source mod/game. Source uses a series of Block Handlers to save and load (restore) information from save games.

Block Handlers

Save game contains a series of data blocks used by various block handlers. The purpose of the data blocks are defined by the block handlers. Each block has a header and a body saved in the save game files. In a default OB Ep2-based mod, the following block handlers are defined.

Server
g_EntitySaveRestoreBlockHandler (Server Entity Data)
g_PhysSaveRestoreBlockHandler (CServer Physics Data)
g_AI_SaveRestoreBlockHandler (AI Data)
g_Template_SaveRestoreBlockHandler (Unknown)
g_DefaultResponseSystemSaveRestoreBlockHandler (Response System Data)
g_Commentary_SaveRestoreBlockHandler (Commentary System Data)
g_EventQueue_SaveRestoreBlockHandler (Event Queue Data)
g_AchievementSaveRestoreBlockHandler (Achievement Data)
Client
g_EntitySaveRestoreBlockHandler (Client Entity Data)
g_PhysSaveRestoreBlockHandler (Client Physics Data)
g_ViewEffectsSaveRestoreBlockHandler (Client View Effects)

On each save, all block handlers are called and they can write data to the save game file. On load, the block handlers parse the data they previously saved and restores the scene. Block Handlers are registered with g_pGameSaveRestoreBlockSet->AddBlockHandler() and removed using g_pGameSaveRestoreBlockSet->RemoveBlockHandler() on game shutdown. Each block handler is a subclass of CDefSaveRestoreBlockHandler.

Example

In this example, we add a new block handler in Server.dll that saves a string to save games and outputs it to the console upon load of a saved game.

In gameinterface.cpp in CServerGameDLL::DLLInit() add:

g_pGameSaveRestoreBlockSet->AddBlockHandler( GetMyBlockHandlerSaveRestoreBlockHandler() );


In gameinterface.cpp in CServerGameDLL::DLLShutdown() add:

g_pGameSaveRestoreBlockSet->RemoveBlockHandler( GetMyBlockHandlerSaveRestoreBlockHandler() );

In a new MyBlockHandler.cpp file add

#include "cbase.h"
#include "gameinterface.h"
#include "MyBlockHandler.h"
 
static short MYBLOCKHANDLER_SAVE_RESTORE_VERSION = 1;
 
class CMyBlockHandlerSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler
{
public:
	const char *GetBlockName()
	{
		return "MyBlockHandler";
	}
 
	//---------------------------------
 
	void Save( ISave *pSave )
	{
		pSave->StartBlock( "MyBlockHandler" );
 
		char*	Data		=	"\n == OMG OH MY GOD, I JUST GOT SAVED TO A SAVE FILE! ==\n\n";
		size_t	DataLength	=	strlen(Data)+1;
 
		pSave->WriteData( (const char*)&DataLength, sizeof(DataLength) );
		pSave->WriteData( (const char*)Data, (int)DataLength );
 
		pSave->EndBlock();
	}
 
	//---------------------------------
 
	void WriteSaveHeaders( ISave *pSave )
	{
		pSave->WriteShort( &MYBLOCKHANDLER_SAVE_RESTORE_VERSION );
	}
 
	//---------------------------------
 
	void ReadRestoreHeaders( IRestore *pRestore )
	{
		// No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so.
		short version;
		pRestore->ReadShort( &version );
		// only load if version matches and if we are loading a game, not a transition
		m_fDoLoad = ( ( version == MYBLOCKHANDLER_SAVE_RESTORE_VERSION ) && 
			( ( MapLoad_LoadGame == gpGlobals->eLoadType ) || ( MapLoad_NewGame == gpGlobals->eLoadType )  ) 
		);
	}
 
	//---------------------------------
 
	void Restore( IRestore *pRestore, bool createPlayers )
	{
		if ( m_fDoLoad )
		{
			pRestore->StartBlock();
 
			size_t	DataLength;
 
			pRestore->ReadData((char*)&DataLength,sizeof(size_t),0);
 
			char*	Data	=	new char[DataLength];
 
			pRestore->ReadData((char*)Data,(int)DataLength,DataLength);
 
			Color ConsoleColor(100,255,100,255);
			ConColorMsg(ConsoleColor,Data);
 
			delete[] Data;
 
			pRestore->EndBlock();
		}
	}
 
private:
	bool m_fDoLoad;
};
 
//-----------------------------------------------------------------------------
 
CMyBlockHandlerSaveRestoreBlockHandler g_MyBlockHandlerSaveRestoreBlockHandler;
 
//-------------------------------------
 
ISaveRestoreBlockHandler *GetMyBlockHandlerSaveRestoreBlockHandler()
{
	return &g_MyBlockHandlerSaveRestoreBlockHandler;
}

In a new MyBlockHandler.h add

#ifndef MyBlockHandler_H
#define MyBlockHandler_H
 
#include "saverestore.h"
 
ISaveRestoreBlockHandler *GetMyBlockHandlerSaveRestoreBlockHandler();
 
#endif

Remember to include MyBlockHandler.h in gameinterface.h.

Uses

This technology allows developers to save specific and long amounts of data without using network tables. It's easy to implement and highly flexible. It is used by Maxsi Distribution to save achievement information.

Personal tools
Namespaces
Variants
Actions