[openjk] 33/130: Replace reading wrappers

Simon McVittie smcv at debian.org
Fri Oct 28 11:09:14 UTC 2016


This is an automated email from the git hooks/post-receive script.

smcv pushed a commit to branch debian/master
in repository openjk.

commit cb022b2780e470a3240b87bb5e5a3e772b730320
Author: bibendovsky <bibendovsky at hotmail.com>
Date:   Mon Jul 11 19:46:52 2016 +0300

    Replace reading wrappers
---
 code/cgame/FxScheduler.cpp           |  13 ++-
 code/cgame/cg_main.cpp               |  12 ++-
 code/game/G_Timer.cpp                |  21 +++-
 code/game/Q3_Interface.cpp           |  52 ++++++++--
 code/game/Q3_Interface.h             |   2 +
 code/game/g_main.cpp                 |  11 ++-
 code/game/g_objectives.cpp           |   6 +-
 code/game/g_public.h                 |   3 +-
 code/game/g_roff.cpp                 |  17 +++-
 code/game/g_savegame.cpp             |  43 ++++++---
 code/icarus/IcarusImplementation.cpp |  29 +++++-
 code/icarus/IcarusInterface.h        |   1 +
 code/qcommon/cm_load.cpp             |  12 ++-
 code/qcommon/q_shared.h              |   2 +-
 code/rd-vanilla/G2_misc.cpp          |   2 +-
 code/server/sv_game.cpp              |   3 +
 code/server/sv_savegame.cpp          | 179 ++++++++++++++++++++++++++---------
 codeJK2/cgame/cg_main.cpp            |  12 ++-
 codeJK2/game/G_Timer.cpp             |  20 +++-
 codeJK2/game/Q3_Interface.cpp        |   2 +
 codeJK2/game/Q3_Registers.cpp        |  47 +++++++--
 codeJK2/game/g_main.cpp              |  11 ++-
 codeJK2/game/g_objectives.cpp        |   6 +-
 codeJK2/game/g_public.h              |   2 +
 codeJK2/game/g_roff.cpp              |  17 +++-
 codeJK2/game/g_savegame.cpp          |  42 +++++---
 codeJK2/icarus/Instance.cpp          |  37 ++++++--
 codeJK2/icarus/Sequence.cpp          |  61 +++++++++---
 codeJK2/icarus/Sequencer.cpp         |  38 ++++++--
 codeJK2/icarus/TaskManager.cpp       |  95 ++++++++++++++-----
 codeJK2/icarus/interface.h           |   1 +
 shared/qcommon/ojk_saved_game.cpp    |  23 +++--
 32 files changed, 629 insertions(+), 193 deletions(-)

diff --git a/code/cgame/FxScheduler.cpp b/code/cgame/FxScheduler.cpp
index cf50709..34379ef 100644
--- a/code/cgame/FxScheduler.cpp
+++ b/code/cgame/FxScheduler.cpp
@@ -42,6 +42,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include "qcommon/safe/string.h"
 #include <cmath>
 #include "qcommon/ojk_sg_wrappers.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 CFxScheduler	theFxScheduler;
 
@@ -109,14 +110,22 @@ void CFxScheduler::LoadSave_Read()
 {
 	Clean();	// need to get rid of old pre-cache handles, or it thinks it has some older effects when it doesn't
 	g_vstrEffectsNeededPerSlot.clear();	// jic
-	::sg_read_no_cast(::gi, INT_ID('F','X','L','E'), ::gLoopedEffectArray);
+
+    ::gi.saved_game->read_chunk(
+        INT_ID('F','X','L','E'),
+        ::gLoopedEffectArray);
+
 	//
 	// now read in and re-register the effects we need for those structs...
 	//
 	for (int iFX = 0; iFX < MAX_LOOPED_FX; iFX++)
 	{
 		char sFX_Filename[MAX_QPATH];
-		::sg_read_no_cast(::gi, INT_ID('F','X','F','N'), sFX_Filename);
+
+        ::gi.saved_game->read_chunk(
+            INT_ID('F','X','F','N'),
+            sFX_Filename);
+
 		g_vstrEffectsNeededPerSlot.push_back( sFX_Filename );
 	}
 }
diff --git a/code/cgame/cg_main.cpp b/code/cgame/cg_main.cpp
index 2ffa679..96fa0f0 100644
--- a/code/cgame/cg_main.cpp
+++ b/code/cgame/cg_main.cpp
@@ -29,7 +29,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include "../qcommon/sstring.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 //NOTENOTE: Be sure to change the mirrored code in g_shared.h
 typedef	std::map< sstring_t, unsigned char  >	namePrecache_m;
@@ -1914,8 +1914,14 @@ void CG_WriteTheEvilCGHackStuff(void)
 }
 void CG_ReadTheEvilCGHackStuff(void)
 {
-	::sg_read<int32_t>(::gi, INT_ID('F','P','S','L'), ::gi_cg_forcepowerSelect);
-	::sg_read<int32_t>(::gi, INT_ID('I','V','S','L'), ::gi_cg_inventorySelect);
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('F','P','S','L'),
+        ::gi_cg_forcepowerSelect);
+
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('I','V','S','L'),
+        ::gi_cg_inventorySelect);
+
 	gbUseTheseValuesFromLoadSave = qtrue;
 }
 
diff --git a/code/game/G_Timer.cpp b/code/game/G_Timer.cpp
index eb8cf38..19d53b9 100644
--- a/code/game/G_Timer.cpp
+++ b/code/game/G_Timer.cpp
@@ -23,7 +23,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include "g_local.h"
 #include "../Rufl/hstring.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 #define MAX_GTIMERS	16384
 
@@ -211,7 +211,9 @@ void TIMER_Load( void )
 	{
 		unsigned char numTimers;
 
-		::sg_read<uint8_t>(::gi, INT_ID('T','I','M','E'), numTimers);
+        ::gi.saved_game->read_chunk<uint8_t>(
+            INT_ID('T','I','M','E'),
+            numTimers);
 
 		//Read back all entries
 		for ( int i = 0; i < numTimers; i++ )
@@ -222,8 +224,19 @@ void TIMER_Load( void )
 			assert (sizeof(g_timers[0]->time) == sizeof(time) );//make sure we're reading the same size as we wrote
 
 			//Read the id string and time
-			::sg_read_no_cast(::gi, INT_ID('T','M','I','D'), tempBuffer, 0);
-			::sg_read<int32_t>(::gi, INT_ID('T','D','T','A'), time);
+            ::gi.saved_game->read_chunk(
+                INT_ID('T','M','I','D'));
+
+            auto& sg_buffer = ::gi.saved_game->get_buffer();
+
+            std::uninitialized_copy(
+                sg_buffer.cbegin(),
+                sg_buffer.cend(),
+                tempBuffer);
+
+            ::gi.saved_game->read_chunk<int32_t>(
+                INT_ID('T','D','T','A'),
+                time);
 
 			//this is odd, we saved all the timers in the autosave, but not all the ents are spawned yet from an auto load, so skip it
 			if (ent->inuse)
diff --git a/code/game/Q3_Interface.cpp b/code/game/Q3_Interface.cpp
index 13e9c5d..a013736 100644
--- a/code/game/Q3_Interface.cpp
+++ b/code/game/Q3_Interface.cpp
@@ -41,7 +41,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include "g_vehicles.h"
 #include "g_navigator.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 extern	cvar_t	*com_buildScript;
 
@@ -7280,19 +7280,30 @@ void CQuake3GameInterface::VariableLoadFloats( varFloat_m &fmap )
 	int		numFloats;
 	char	tempBuffer[1024];
 
-	::sg_read<int32_t>(::gi, INT_ID('F','V','A','R'), numFloats);
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('F','V','A','R'),
+        numFloats);
 
 	for ( int i = 0; i < numFloats; i++ )
 	{
 		int idSize;
 
-		::sg_read<int32_t>(::gi, INT_ID('F','I','D','L'), idSize);
-		::sg_read_no_cast(::gi, INT_ID('F','I','D','S'), tempBuffer, idSize);
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('F','I','D','L'),
+            idSize);
+
+        ::gi.saved_game->read_chunk(
+            INT_ID('F','I','D','S'),
+            tempBuffer,
+            idSize);
+
 		tempBuffer[ idSize ] = 0;
 
 		float	val;
 
-		::sg_read<float>(::gi, INT_ID('F','V','A','L'), val);
+        ::gi.saved_game->read_chunk<float>(
+            INT_ID('F','V','A','L'),
+            val);
 
 		DeclareVariable( TK_FLOAT, (const char *) &tempBuffer );
 		SetFloatVariable( (const char *) &tempBuffer, val );
@@ -7311,18 +7322,34 @@ void CQuake3GameInterface::VariableLoadStrings( int type, varString_m &fmap )
 	char	tempBuffer[1024];
 	char	tempBuffer2[1024];
 
-	::sg_read<int32_t>(::gi, INT_ID('S','V','A','R'), numFloats);
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('S','V','A','R'),
+        numFloats);
 
 	for ( int i = 0; i < numFloats; i++ )
 	{
 		int idSize;
 
-		::sg_read<int32_t>(::gi, INT_ID('S','I','D','L'), idSize);
-		::sg_read_no_cast(::gi, INT_ID('S','I','D','S'), tempBuffer, idSize);
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('S','I','D','L'),
+            idSize);
+
+        ::gi.saved_game->read_chunk(
+            INT_ID('S','I','D','S'),
+            tempBuffer,
+            idSize);
+
 		tempBuffer[ idSize ] = 0;
 
-		::sg_read<int32_t>(::gi, INT_ID('S','V','S','Z'), idSize);
-		::sg_read_no_cast(::gi, INT_ID('S','V','A','L'), tempBuffer2, idSize);
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('S','V','S','Z'),
+            idSize);
+
+        ::gi.saved_game->read_chunk(
+            INT_ID('S','V','A','L'),
+            tempBuffer2,
+            idSize);
+
 		tempBuffer2[ idSize ] = 0;
 
 		switch ( type )
@@ -11112,6 +11139,11 @@ int		CQuake3GameInterface::ReadSaveData( unsigned int chid, void *address, int l
 	return gi.ReadFromSaveGame( chid, address, length, addressptr );
 }
 
+ojk::ISavedGame* CQuake3GameInterface::get_saved_game()
+{
+    return ::gi.saved_game;
+}
+
 int		CQuake3GameInterface::LinkGame( int entID, int icarusID )
 {
 	gentity_t	*pEntity = &g_entities[entID];
diff --git a/code/game/Q3_Interface.h b/code/game/Q3_Interface.h
index 56bcb05..3bc97b1 100644
--- a/code/game/Q3_Interface.h
+++ b/code/game/Q3_Interface.h
@@ -701,6 +701,8 @@ public:
 	int		ReadSaveData( unsigned int chid, void *address, int length, void **addressptr = NULL );
 	int		LinkGame( int entID, int icarusID );
 
+    ojk::ISavedGame* get_saved_game() override;
+
 	// Access functions
 	int		CreateIcarus( int entID);
 			//Polls the engine for the sequencer of the entity matching the name passed
diff --git a/code/game/g_main.cpp b/code/game/g_main.cpp
index 302d856..288be0c 100644
--- a/code/game/g_main.cpp
+++ b/code/game/g_main.cpp
@@ -37,7 +37,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 //rww - RAGDOLL_END
 
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 extern void WP_SaberLoadParms( void );
 extern qboolean G_PlayerSpawned( void );
@@ -113,7 +113,10 @@ void WriteInUseBits(void)
 
 void ReadInUseBits(void)
 {
-	::sg_read<uint32_t>(::gi, INT_ID('I','N','U','S'), ::g_entityInUseBits);
+    ::gi.saved_game->read_chunk<uint32_t>(
+        INT_ID('I','N','U','S'),
+        ::g_entityInUseBits);
+
 	// This is only temporary. Once I have converted all the ent->inuse refs,
 	// it won;t be needed -MW.
 	for(int i=0;i<MAX_GENTITIES;i++)
@@ -2118,7 +2121,9 @@ void G_LoadSave_WriteMiscData(void)
 
 void G_LoadSave_ReadMiscData(void)
 {
-	::sg_read<int32_t>(::gi, INT_ID('L','C','K','D'), player_locked);
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('L','C','K','D'),
+        ::player_locked);
 }
 
 
diff --git a/code/game/g_objectives.cpp b/code/game/g_objectives.cpp
index e7a87d7..92afb43 100644
--- a/code/game/g_objectives.cpp
+++ b/code/game/g_objectives.cpp
@@ -30,7 +30,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include "objectives.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 qboolean	missionInfo_Updated;
 
@@ -86,7 +86,9 @@ OBJ_LoadMissionObjectives
 */
 void OBJ_LoadMissionObjectives( gclient_t *client )
 {
-	::sg_read_no_cast(::gi, INT_ID('O','B','J','T'), client->sess.mission_objectives);
+    ::gi.saved_game->read_chunk(
+        INT_ID('O','B','J','T'),
+        client->sess.mission_objectives);
 }
 
 
diff --git a/code/game/g_public.h b/code/game/g_public.h
index 8c178f0..599c615 100644
--- a/code/game/g_public.h
+++ b/code/game/g_public.h
@@ -27,6 +27,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 
 #include "qcommon/ojk_sg_wrappers_fwd.h"
+#include "qcommon/ojk_i_saved_game_fwd.h"
 
 
 #define	GAME_API_VERSION	8
@@ -190,7 +191,7 @@ typedef struct {
 	int			(*ReadFromSaveGame)(unsigned int chid, void *pvAddress, int iLength, void **ppvAddressPtr );
 	int			(*ReadFromSaveGameOptional)(unsigned int chid, void *pvAddress, int iLength, void **ppvAddressPtr );
 
-    ojk::SavedGame* saved_game;
+    ojk::ISavedGame* saved_game;
 
 	// add commands to the console as if they were typed in
 	// for map changing, etc
diff --git a/code/game/g_roff.cpp b/code/game/g_roff.cpp
index 8fdecd1..5f3176e 100644
--- a/code/game/g_roff.cpp
+++ b/code/game/g_roff.cpp
@@ -26,7 +26,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include "../cgame/cg_local.h"
 #include "g_functions.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 // The list of precached ROFFs
 roff_list_t	roffs[MAX_ROFFS];
@@ -678,13 +678,22 @@ void G_LoadCachedRoffs()
 	char	buffer[MAX_QPATH];
 
 	// Get the count of goodies we need to revive
-	::sg_read<int32_t>(::gi, INT_ID('R','O','F','F'), count);
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('R','O','F','F'),
+        count);
 
 	// Now bring 'em back to life
 	for ( i = 0; i < count; i++ )
 	{
-		::sg_read<int32_t>(::gi, INT_ID('S','L','E','N'), len);
-		::sg_read_no_cast(::gi, INT_ID('R','S','T','R'), buffer, len);
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('S','L','E','N'),
+            len);
+
+        ::gi.saved_game->read_chunk(
+            INT_ID('R','S','T','R'),
+            buffer,
+            len);
+
 		G_LoadRoff( buffer );
 	}
 }
diff --git a/code/game/g_savegame.cpp b/code/game/g_savegame.cpp
index dcc46aa..54e2d02 100644
--- a/code/game/g_savegame.cpp
+++ b/code/game/g_savegame.cpp
@@ -31,7 +31,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include "../cgame/cg_camera.h"
 #include "../qcommon/sstring.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 extern void OBJ_LoadTacticalInfo(void);
 
@@ -189,7 +189,10 @@ static char *GetStringPtr(int iStrlen, char *psOriginal/*may be NULL*/)
 
 		assert(iStrlen+1<=(int)sizeof(sString));
 
-		::sg_read_no_cast(::gi, INT_ID('S','T','R','G'), sString, iStrlen);
+        ::gi.saved_game->read_chunk(
+            INT_ID('S','T','R','G'),
+            sString,
+            iStrlen);
 
 		// TAG_G_ALLOC is always blown away, we can never recycle
 		if (psOriginal && gi.bIsFromZone(psOriginal, TAG_G_ALLOC)) {
@@ -927,13 +930,18 @@ static void ReadGEntities(qboolean qbAutosave)
 	int		iCount;
 	int		i;
 
-	::sg_read<int32_t>(::gi, INT_ID('N','M','E','D'), iCount);
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('N','M','E','D'),
+        iCount);
 
 	int iPreviousEntRead = -1;
 	for (i=0; i<iCount; i++)
 	{
 		int iEntIndex;
-		::sg_read<int32_t>(::gi, INT_ID('E','D','N','M'), iEntIndex);
+
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('E','D','N','M'),
+            iEntIndex);
 
 		if (iEntIndex >= globals.num_entities)
 		{
@@ -1046,7 +1054,9 @@ static void ReadGEntities(qboolean qbAutosave)
 		{
 			parms_t tempParms;
 
-			::sg_read_no_cast(::gi, INT_ID('P','A','R','M'), tempParms);
+            ::gi.saved_game->read_chunk(
+                INT_ID('P','A','R','M'),
+                tempParms);
 
 			// so can we pinch the original's one or do we have to alloc a new one?...
 			//
@@ -1097,10 +1107,13 @@ static void ReadGEntities(qboolean qbAutosave)
 		// the scary ghoul2 stuff...  (fingers crossed)
 		//
 		{
-			char *pGhoul2Data = NULL;
-			::sg_read_allocate(::gi, INT_ID('G','H','L','2'), pGhoul2Data);
+            ::gi.saved_game->read_chunk(
+                INT_ID('G','H','L','2'));
+
+            auto buffer = ::gi.saved_game->get_buffer();
+            auto pGhoul2Data = reinterpret_cast<char*>(buffer.data());
+
 			gi.G2API_LoadGhoul2Models(pEnt->ghoul2, pGhoul2Data);	// if it's going to crash anywhere...   <g>
-			gi.Free(pGhoul2Data);
 		}
 
 //		gi.unlinkentity (pEntOriginal);
@@ -1163,7 +1176,10 @@ static void ReadGEntities(qboolean qbAutosave)
 		// check that Icarus has loaded everything it saved out by having a marker chunk after it...
 		//
 		static int iBlah = 1234;
-		::sg_read<int32_t>(::gi, INT_ID('I','C','O','K'), iBlah);
+
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('I','C','O','K'),
+            iBlah);
 	}
 	if (!qbAutosave)
 	{
@@ -1231,8 +1247,8 @@ void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition)
 		ReadLevelLocals();	// level_locals_t level
 
 		//Read & throw away objective info
-		objectives_t	junkObj[MAX_MISSION_OBJ];
-		::sg_read_no_cast(::gi, INT_ID('O','B','J','T'), junkObj);
+        ::gi.saved_game->read_chunk(
+            INT_ID('O','B','J','T'));
 	}
 	else
 	{
@@ -1265,7 +1281,10 @@ void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition)
 	// check that the whole file content was loaded by specifically requesting an end-marker...
 	//
 	static int iDONE = 1234;
-	::sg_read<int32_t>(::gi, INT_ID('D','O','N','E'), iDONE);
+
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('D','O','N','E'),
+        iDONE);
 }
 
 extern int killPlayerTimer;
diff --git a/code/icarus/IcarusImplementation.cpp b/code/icarus/IcarusImplementation.cpp
index bc2ecff..6b0385b 100644
--- a/code/icarus/IcarusImplementation.cpp
+++ b/code/icarus/IcarusImplementation.cpp
@@ -34,7 +34,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include "../qcommon/q_shared.h"
 #include "../qcommon/qcommon.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 #define STL_ITERATE( a, b )		for ( a = b.begin(); a != b.end(); ++a )
 #define STL_INSERT( a, b )		a.insert( a.end(), b );
@@ -679,13 +679,17 @@ int CIcarus::Load()
 	CreateBuffer();
 
 	IGameInterface* game = IGameInterface::GetGame(m_flavor);
+    auto saved_game = game->get_saved_game();
 
 	//Clear out any old information
 	Free();
 
 	//Check to make sure we're at the ICARUS save block
 	double	version;
-	::sg_read<double>(game, INT_ID('I','C','A','R'), version);
+
+    saved_game->read_chunk<double>(
+        INT_ID('I','C','A','R'),
+        version);
 
 	//Versions must match!
 	if ( version != ICARUS_VERSION )
@@ -696,7 +700,15 @@ int CIcarus::Load()
 	}
 
 	// Read into the buffer all our data.
-	/*m_ulBytesAvailable = */::sg_read_no_cast(game, INT_ID('I','S','E','Q'), m_byBuffer, 0 );	//fixme, use real buff size
+	saved_game->read_chunk(
+        INT_ID('I','S','E','Q'));
+
+    auto& sg_buffer = saved_game->get_buffer();
+
+    std::uninitialized_copy(
+        sg_buffer.cbegin(),
+        sg_buffer.cend(),
+        m_byBuffer);
 
 	//Load all signals
 	if ( LoadSignals() == false )
@@ -806,7 +818,16 @@ void CIcarus::BufferRead( void *pDstBuff, unsigned long ulNumBytesToRead )
 	{// We've tried to read past the buffer...
 		IGameInterface::GetGame()->DebugPrint( IGameInterface::WL_ERROR, "BufferRead: Buffer underflow, Looking for new block." );
 		// Read in the next block.
-		/*m_ulBytesAvailable = */::sg_read_no_cast(IGameInterface::GetGame(), INT_ID('I','S','E','Q'), m_byBuffer, 0 );	//FIXME, to actually check underflows, use real buff size
+        IGameInterface::GetGame()->get_saved_game()->read_chunk(
+            INT_ID('I','S','E','Q'));
+
+        auto& sg_buffer = IGameInterface::GetGame()->get_saved_game()->get_buffer();
+
+        std::uninitialized_copy(
+            sg_buffer.cbegin(),
+            sg_buffer.cend(),
+            m_byBuffer);
+
 		m_ulBytesRead = 0;	//reset buffer
 	}
 
diff --git a/code/icarus/IcarusInterface.h b/code/icarus/IcarusInterface.h
index 9ba27ec..71acf2b 100644
--- a/code/icarus/IcarusInterface.h
+++ b/code/icarus/IcarusInterface.h
@@ -147,6 +147,7 @@ public:
 	virtual int		WriteSaveData( unsigned int chid, const void *data, int length ) = 0;
 	virtual int		ReadSaveData( unsigned int chid, void *address, int length, void **addressptr = NULL )  = 0;
 	virtual int		LinkGame( int gameID, int icarusID ) = 0;
+    virtual ojk::ISavedGame* get_saved_game() = 0;
 
 	// Access functions
 
diff --git a/code/qcommon/cm_load.cpp b/code/qcommon/cm_load.cpp
index d809a7e..a7250ca 100644
--- a/code/qcommon/cm_load.cpp
+++ b/code/qcommon/cm_load.cpp
@@ -25,7 +25,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include "cm_local.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_saved_game.h"
 
 #ifdef BSPC
 void SetPlaneSignbits (cplane_t *out) {
@@ -1230,7 +1230,15 @@ and recalculates the area connections
 */
 void	CM_ReadPortalState ()
 {
-	::sg_read<int32_t>(::SG_Read, INT_ID('P','R','T','S'), ::cmg.areaPortals, ::cmg.numAreas * ::cmg.numAreas);
+    //auto saved_game = static_cast<ojk::ISavedGame*>(
+    //    &ojk::SavedGame::get_instance());
+    auto saved_game = &ojk::SavedGame::get_instance();
+
+    saved_game->read_chunk<int32_t>(
+        INT_ID('P','R','T','S'),
+        ::cmg.areaPortals,
+        ::cmg.numAreas * ::cmg.numAreas);
+
 	CM_FloodAreaConnections (cmg);
 }
 
diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h
index 4f0cd70..b0be5d8 100644
--- a/code/qcommon/q_shared.h
+++ b/code/qcommon/q_shared.h
@@ -161,7 +161,7 @@ float FloatSwap( const float *f );
 
 #include "qcommon/q_platform.h"
 #include "qcommon/ojk_sg_wrappers_fwd.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game_fwd.h"
 
 
 // ================================================================
diff --git a/code/rd-vanilla/G2_misc.cpp b/code/rd-vanilla/G2_misc.cpp
index 5b51819..4ad50ac 100644
--- a/code/rd-vanilla/G2_misc.cpp
+++ b/code/rd-vanilla/G2_misc.cpp
@@ -51,7 +51,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #ifdef _G2_GORE
 #include "../ghoul2/ghoul2_gore.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game_fwd.h"
 
 #define GORE_TAG_UPPER (256)
 #define GORE_TAG_MASK (~255)
diff --git a/code/server/sv_game.cpp b/code/server/sv_game.cpp
index 0d5d9aa..ec5296d 100644
--- a/code/server/sv_game.cpp
+++ b/code/server/sv_game.cpp
@@ -30,6 +30,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include "server.h"
 #include "../client/vmachine.h"
 #include "../client/client.h"
+#include "qcommon/ojk_saved_game.h"
 /*#include "..\renderer\tr_local.h"
 #include "..\renderer\tr_WorldEffects.h"*/
 /*
@@ -933,6 +934,8 @@ void SV_InitGameProgs (void) {
 	import.ReadFromSaveGame	= SG_Read;
 	import.ReadFromSaveGameOptional = SG_ReadOptional;
 
+    import.saved_game = &ojk::SavedGame::get_instance();
+
 	import.AdjustAreaPortalState = SV_AdjustAreaPortalState;
 	import.AreasConnected = CM_AreasConnected;
 
diff --git a/code/server/sv_savegame.cpp b/code/server/sv_savegame.cpp
index 03e6256..bc8d173 100644
--- a/code/server/sv_savegame.cpp
+++ b/code/server/sv_savegame.cpp
@@ -38,7 +38,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include <map>
 
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_saved_game.h"
 
 static char	saveGameComment[iSG_COMMENT_SIZE];
 
@@ -260,7 +260,13 @@ qboolean SG_Open( const char *psPathlessBaseName )
 		return qfalse;
 	}
 	giSaveGameVersion=-1;//jic
-	::sg_read<int32_t>(::SG_Read, INT_ID('_','V','E','R'), ::giSaveGameVersion);
+
+    auto saved_game = &ojk::SavedGame::get_instance();
+
+    saved_game->read_chunk<int32_t>(
+        INT_ID('_','V','E','R'),
+        ::giSaveGameVersion);
+
 	if (giSaveGameVersion != iSAVEGAME_VERSION)
 	{
 		SG_Close();
@@ -582,7 +588,12 @@ static void WriteGame(qboolean autosave)
 static qboolean ReadGame (void)
 {
 	qboolean qbAutoSave;
-	::sg_read<int32_t>(::SG_Read, INT_ID('G','A','M','E'), qbAutoSave);
+
+    auto saved_game = &ojk::SavedGame::get_instance();
+
+    saved_game->read_chunk<int32_t>(
+        INT_ID('G','A','M','E'),
+        qbAutoSave);
 
 	if (qbAutoSave)
 	{
@@ -591,25 +602,41 @@ static qboolean ReadGame (void)
 		// read health/armour etc...
 		//
 		memset(s,0,sizeof(s));
-		::sg_read_no_cast(::SG_Read, INT_ID('C','V','S','V'), s);
+
+        saved_game->read_chunk(
+            INT_ID('C','V','S','V'),
+            s);
+
 		Cvar_Set( sCVARNAME_PLAYERSAVE, s );
 
 		// read ammo...
 		//
 		memset(s,0,sizeof(s));
-		::sg_read_no_cast(::SG_Read, INT_ID('A','M','M','O'), s);
+
+        saved_game->read_chunk(
+            INT_ID('A','M','M','O'),
+            s);
+
 		Cvar_Set( "playerammo", s);
 
 		// read inventory...
 		//
 		memset(s,0,sizeof(s));
-		::sg_read_no_cast(::SG_Read, INT_ID('I','V','T','Y'), s);
+
+        saved_game->read_chunk(
+            INT_ID('I','V','T','Y'),
+            s);
+
 		Cvar_Set( "playerinv", s);
 
 		// read force powers...
 		//
 		memset(s,0,sizeof(s));
-		::sg_read_no_cast(::SG_Read, INT_ID('F','P','L','V'), s);
+
+        saved_game->read_chunk(
+            INT_ID('F','P','L','V'),
+            s);
+
 		Cvar_Set( "playerfplvl", s );
 	}
 
@@ -667,22 +694,34 @@ void SG_WriteCvars(void)
 
 void SG_ReadCvars(void)
 {
-	int		iCount;
-	char	*psName;
-	char	*psValue;
+    int iCount;
+    const char* psName;
+    const char* psValue;
 
-	::sg_read<int32_t>(::SG_Read, INT_ID('C','V','C','N'), iCount);
+    auto saved_game = &ojk::SavedGame::get_instance();
 
-	for (int i = 0; i < iCount; i++)
-	{
-		::sg_read_allocate(::SG_Read, INT_ID('C','V','A','R'), psName);
-		::sg_read_allocate(::SG_Read, INT_ID('V','A','L','U'), psValue);
+    saved_game->read_chunk<int32_t>(
+        INT_ID('C','V','C','N'),
+        iCount);
 
-		Cvar_Set (psName, psValue);
+    for (int i = 0; i < iCount; ++i)
+    {
+        saved_game->read_chunk(
+            INT_ID('C','V','A','R'));
 
-		Z_Free( psName );
-		Z_Free( psValue );
-	}
+        auto name_buffer = saved_game->get_buffer();
+        psName = reinterpret_cast<const char*>(name_buffer.data());
+
+
+        saved_game->read_chunk(
+            INT_ID('V','A','L','U'));
+
+        auto value_buffer = saved_game->get_buffer();
+        psValue = reinterpret_cast<const char*>(value_buffer.data());
+
+
+        ::Cvar_Set(psName, psValue);
+    }
 }
 
 void SG_WriteServerConfigStrings( void )
@@ -740,23 +779,33 @@ void SG_ReadServerConfigStrings( void )
 	//
 	int iCount;
 
-	::sg_read<int32_t>(::SG_Read, INT_ID('C','S','C','N'), iCount);
+    auto saved_game = &ojk::SavedGame::get_instance();
+
+    saved_game->read_chunk<int32_t>(
+        INT_ID('C','S','C','N'),
+        iCount);
 
 	Com_DPrintf( "Reading %d configstrings...\n",iCount);
 
 	for (int i = 0; i<iCount; i++)
 	{
 		int iIndex;
-		char *psName;
+		const char *psName;
 
-		::sg_read<int32_t>(::SG_Read, INT_ID('C','S','I','N'), iIndex);
-		::sg_read_allocate(::SG_Read, INT_ID('C','S','D','A'), psName);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('C','S','I','N'),
+            iIndex);
+
+        saved_game->read_chunk(
+            INT_ID('C','S','D','A'));
+
+        auto& sg_buffer = saved_game->get_buffer();
+        psName = reinterpret_cast<const char*>(sg_buffer.data());
 
 		Com_DPrintf( "Cfg str %d = %s\n",iIndex, psName);
 
 		//sv.configstrings[iIndex] = psName;
 		SV_SetConfigstring(iIndex, psName);
-		Z_Free(psName);
 	}
 }
 
@@ -805,25 +854,39 @@ int SG_GetSaveGameComment(const char *psPathlessBaseName, char *sComment, char *
 
 	qbSGReadIsTestOnly = qtrue;	// do NOT leave this in this state
 
-	if ( !SG_Open( psPathlessBaseName ))
+    auto saved_game = &ojk::SavedGame::get_instance();
+
+	if (!saved_game->open(
+        psPathlessBaseName))
 	{
 		qbSGReadIsTestOnly = qfalse;
 		return 0;
 	}
 
-	if (::sg_read_no_cast(::SG_Read, INT_ID('C','O','M','M'), sComment, iSG_COMMENT_SIZE ))
+    if (saved_game->read_chunk(
+        INT_ID('C','O','M','M'),
+        sComment,
+        iSG_COMMENT_SIZE))
 	{
 		unsigned int fileTime = 0;
-		if (::sg_read<uint32_t>(::SG_Read, INT_ID('C','M','T','M'), fileTime))	//read
+
+		if (saved_game->read_chunk<uint32_t>(
+            INT_ID('C','M','T','M'),
+            fileTime))
 		{
 			tFileTime = SG_GetTime (fileTime);
 #ifdef JK2_MODE
-			if (::sg_read<uint32_t>(::SG_Read, INT_ID('S','H','L','N'), iScreenShotLength))
+			if (saved_game->read_chunk<uint32_t>(
+                INT_ID('S','H','L','N'),
+                iScreenShotLength))
 			{
-				if (::sg_read_skip(::SG_Read, INT_ID('S','H','O','T'), iScreenShotLength))
+                if (saved_game->read_chunk(INT_ID('S','H','O','T')))
 				{
 #endif
-			if (::sg_read_no_cast(::SG_Read, INT_ID('M','P','C','M'), sMapName, iSG_MAPCMD_SIZE))	// read
+            if (saved_game->read_chunk(
+                INT_ID('M','P','C','M'),
+                sMapName,
+                iSG_MAPCMD_SIZE))
 			{
 				ret = tFileTime;
 			}
@@ -835,10 +898,8 @@ int SG_GetSaveGameComment(const char *psPathlessBaseName, char *sComment, char *
 	}
 	qbSGReadIsTestOnly = qfalse;
 
-	if (!SG_Close())
-	{
-		return 0;
-	}
+    saved_game->close();
+
 	return ret;
 }
 
@@ -867,11 +928,16 @@ static qboolean SG_ReadScreenshot(qboolean qbSetAsLoadingScreen, void *pvDest =
 static qboolean SG_ReadScreenshot(qboolean qbSetAsLoadingScreen, void *pvDest)
 {
 	qboolean bReturn = qfalse;
+    auto saved_game = &ojk::SavedGame::get_instance();
 
 	// get JPG screenshot data length...
 	//
 	size_t iScreenShotLength = 0;
-	::sg_read<uint32_t>(::SG_Read, INT_ID('S','H','L','N'), iScreenShotLength);
+
+    saved_game->read_chunk<uint32_t>(
+        INT_ID('S','H','L','N'),
+        iScreenShotLength);
+
 	//
 	// alloc enough space plus extra 4K for sloppy JPG-decode reader to not do memory access violation...
 	//
@@ -879,7 +945,11 @@ static qboolean SG_ReadScreenshot(qboolean qbSetAsLoadingScreen, void *pvDest)
 	//
 	// now read the JPG data...
 	//
-	::sg_read_no_cast(::SG_Read, INT_ID('S','H','O','T'), pJPGData, iScreenShotLength);
+    saved_game->read_chunk(
+        INT_ID('S','H','O','T'),
+        pJPGData,
+        iScreenShotLength);
+
 	//
 	// decompress JPG data...
 	//
@@ -923,8 +993,13 @@ qboolean SG_GetSaveImage( const char *psPathlessBaseName, void *pvAddress )
 		return qfalse;
 	}
 
-	::sg_read_skip(::SG_Read, INT_ID('C','O','M','M'), 0);	// skip
-	::sg_read_skip<uint32_t>(::SG_Read, INT_ID('C','M','T','M'));
+    auto saved_game = &ojk::SavedGame::get_instance();
+
+    saved_game->read_chunk(
+        INT_ID('C','O','M','M'));
+
+    saved_game->read_chunk(
+        INT_ID('C','M','T','M'));
 
 	qboolean bGotSaveImage = SG_ReadScreenshot(qfalse, pvAddress);
 
@@ -1119,14 +1194,24 @@ qboolean SG_ReadSavegame(const char *psPathlessBaseName)
 
 	// Read in all the server data...
 	//
-	::sg_read_no_cast(::SG_Read, INT_ID('C','O','M','M'), sComment);
+    auto saved_game = &ojk::SavedGame::get_instance();
+
+    saved_game->read_chunk(
+        INT_ID('C','O','M','M'),
+        sComment);
+
 	Com_DPrintf("Reading: %s\n", sComment);
-	::sg_read_skip<uint32_t>(::SG_Read, INT_ID('C','M','T','M'));
+
+    saved_game->read_chunk(
+        INT_ID('C','M','T','M'));
 
 #ifdef JK2_MODE
 	SG_ReadScreenshot(qtrue);	// qboolean qbSetAsLoadingScreen
 #endif
-	::sg_read_no_cast(::SG_Read, INT_ID('M','P','C','M'), sMapCmd);
+    saved_game->read_chunk(
+        INT_ID('M','P','C','M'),
+        sMapCmd);
+
 	SG_ReadCvars();
 
 	// read game state
@@ -1139,8 +1224,16 @@ qboolean SG_ReadSavegame(const char *psPathlessBaseName)
 	//
 	if (!qbAutosave)
 	{
-		::sg_read<int32_t>(::SG_Read, INT_ID('T','I','M','E'), ::sv.time);
-		::sg_read<int32_t>(::SG_Read, INT_ID('T','I','M','R'), ::sv.timeResidual);
+        auto saved_game = &ojk::SavedGame::get_instance();
+
+        saved_game->read_chunk<int32_t>(
+            INT_ID('T','I','M','E'),
+            ::sv.time);
+
+        saved_game->read_chunk<int32_t>(
+            INT_ID('T','I','M','R'),
+            ::sv.timeResidual);
+
 		CM_ReadPortalState();
 		SG_ReadServerConfigStrings();
 	}
diff --git a/codeJK2/cgame/cg_main.cpp b/codeJK2/cgame/cg_main.cpp
index c4c84fc..1f2b761 100644
--- a/codeJK2/cgame/cg_main.cpp
+++ b/codeJK2/cgame/cg_main.cpp
@@ -29,7 +29,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include "../../code/qcommon/sstring.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 //NOTENOTE: Be sure to change the mirrored code in g_shared.h
 typedef std::map< sstring_t, unsigned char, std::less<sstring_t>, std::allocator< unsigned char >  >	namePrecache_m;
@@ -1647,8 +1647,14 @@ void CG_WriteTheEvilCGHackStuff(void)
 }
 void CG_ReadTheEvilCGHackStuff(void)
 {
-	::sg_read<int32_t>(::gi, INT_ID('F','P','S','L'), gi_cg_forcepowerSelect);
-	::sg_read<int32_t>(::gi, INT_ID('I','V','S','L'), gi_cg_inventorySelect);
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('F','P','S','L'),
+        ::gi_cg_forcepowerSelect);
+
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('I','V','S','L'),
+        ::gi_cg_inventorySelect);
+
 	gbUseTheseValuesFromLoadSave = qtrue;
 }
 
diff --git a/codeJK2/game/G_Timer.cpp b/codeJK2/game/G_Timer.cpp
index 80fb4be..b767a6d 100644
--- a/codeJK2/game/G_Timer.cpp
+++ b/codeJK2/game/G_Timer.cpp
@@ -24,7 +24,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include "g_local.h"
 #include "../../code/Rufl/hstring.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 #define MAX_GTIMERS	16384
 
@@ -218,7 +218,9 @@ void TIMER_Load( void )
 	{
 		int numTimers;
 
-		::sg_read<int32_t>(::gi, INT_ID('T','I','M','E'), numTimers);
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('T','I','M','E'),
+            numTimers);
 
 		//Make sure there's something to read
 		if ( numTimers == 0 )
@@ -232,7 +234,9 @@ void TIMER_Load( void )
 
 			assert (sizeof(g_timers[0]->time) == sizeof(time) );//make sure we're reading the same size as we wrote
 
-			::sg_read<int32_t>(::gi, INT_ID('T','S','L','N'), length);
+            ::gi.saved_game->read_chunk<int32_t>(
+                INT_ID('T','S','L','N'),
+                length);
 			
 			if ( length >= 1024 ) {
 				assert( 0 );
@@ -240,8 +244,14 @@ void TIMER_Load( void )
 			}
 
 			//Read the id and time
-			::sg_read_no_cast(::gi, INT_ID('T','S','N','M'), tempBuffer, length);
-			::sg_read<int32_t>(::gi, INT_ID('T','D','T','A'), time);
+            ::gi.saved_game->read_chunk(
+                INT_ID('T','S','N','M'),
+                tempBuffer,
+                length);
+
+            ::gi.saved_game->read_chunk<int32_t>(
+                INT_ID('T','D','T','A'),
+                time);
 
 			//this is odd, we saved all the timers in the autosave, but not all the ents are spawned yet from an auto load, so skip it
 			if (ent->inuse)
diff --git a/codeJK2/game/Q3_Interface.cpp b/codeJK2/game/Q3_Interface.cpp
index bd34699..7d2c82c 100644
--- a/codeJK2/game/Q3_Interface.cpp
+++ b/codeJK2/game/Q3_Interface.cpp
@@ -9266,6 +9266,8 @@ void Interface_Init( interface_export_t *pe )
 	pe->I_ReadSaveData			=	gi.ReadFromSaveGame;
 	pe->I_LinkEntity			=	ICARUS_LinkEntity;
 
+    pe->saved_game = gi.saved_game;
+
 	gclient_t	*client;
 	client = &level.clients[0];
 	memset(&client->sess,0,sizeof(client->sess));
diff --git a/codeJK2/game/Q3_Registers.cpp b/codeJK2/game/Q3_Registers.cpp
index 269e4f6..debb294 100644
--- a/codeJK2/game/Q3_Registers.cpp
+++ b/codeJK2/game/Q3_Registers.cpp
@@ -25,7 +25,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include "g_local.h"
 #include "Q3_Registers.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 extern	void	Q3_DebugPrint( int level, const char *format, ... );
 
@@ -362,19 +362,30 @@ void Q3_VariableLoadFloats( varFloat_m &fmap )
 	int		numFloats;
 	char	tempBuffer[1024];
 
-	::sg_read<int32_t>(::gi, INT_ID('F','V','A','R'), numFloats);
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('F','V','A','R'),
+        numFloats);
 
 	for ( int i = 0; i < numFloats; i++ )
 	{
 		int idSize;
 		
-		::sg_read<int32_t>(::gi, INT_ID('F','I','D','L'), idSize);
-		::sg_read_no_cast(::gi, INT_ID('F','I','D','S'), tempBuffer, idSize);
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('F','I','D','L'),
+            idSize);
+
+        ::gi.saved_game->read_chunk(
+            INT_ID('F','I','D','S'),
+            tempBuffer,
+            idSize);
+
 		tempBuffer[ idSize ] = 0;
 
 		float	val;
 
-		::sg_read_no_cast(::gi, INT_ID('F','V','A','L'), val);
+        ::gi.saved_game->read_chunk<float>(
+            INT_ID('F','V','A','L'),
+            val);
 
 		Q3_DeclareVariable( TK_FLOAT, (const char *) &tempBuffer );
 		Q3_SetFloatVariable( (const char *) &tempBuffer, val );
@@ -393,18 +404,34 @@ void Q3_VariableLoadStrings( int type, varString_m &fmap )
 	char	tempBuffer[1024];
 	char	tempBuffer2[1024];
 
-	::sg_read<int32_t>(::gi, INT_ID('S','V','A','R'), numFloats);
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('S','V','A','R'),
+        numFloats);
 
 	for ( int i = 0; i < numFloats; i++ )
 	{
 		int idSize;
 		
-		::sg_read<int32_t>(::gi, INT_ID('S','I','D','L'), idSize);
-		::sg_read_no_cast(::gi, INT_ID('S','I','D','S'), tempBuffer, idSize);
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('S','I','D','L'),
+            idSize);
+
+        ::gi.saved_game->read_chunk(
+            INT_ID('S','I','D','S'),
+            tempBuffer,
+            idSize);
+
 		tempBuffer[ idSize ] = 0;
 
-		::sg_read<int32_t>(::gi, INT_ID('S','V','S','Z'), idSize);
-		::sg_read_no_cast(::gi, INT_ID('S','V','A','L'), tempBuffer2, idSize);
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('S','V','S','Z'),
+            idSize);
+
+        ::gi.saved_game->read_chunk(
+            INT_ID('S','V','A','L'),
+            tempBuffer2,
+            idSize);
+
 		tempBuffer2[ idSize ] = 0;
 
 		switch ( type )
diff --git a/codeJK2/game/g_main.cpp b/codeJK2/game/g_main.cpp
index bc09a5d..dd435f6 100644
--- a/codeJK2/game/g_main.cpp
+++ b/codeJK2/game/g_main.cpp
@@ -36,7 +36,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include "../cgame/cg_local.h"	// yeah I know this is naughty, but we're shipping soon...
 #include "time.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 extern CNavigator		navigator;
 
@@ -96,7 +96,10 @@ void WriteInUseBits(void)
 
 void ReadInUseBits(void)
 {
-	::sg_read<uint32_t>(::gi, INT_ID('I','N','U','S'), ::g_entityInUseBits);
+    ::gi.saved_game->read_chunk<uint32_t>(
+        INT_ID('I','N','U','S'),
+        ::g_entityInUseBits);
+
 	// This is only temporary. Once I have converted all the ent->inuse refs,
 	// it won;t be needed -MW.
 	for(int i=0;i<MAX_GENTITIES;i++)
@@ -1486,7 +1489,9 @@ void G_LoadSave_WriteMiscData(void)
 
 void G_LoadSave_ReadMiscData(void)
 {
-	::sg_read<int32_t>(::gi, INT_ID('L','C','K','D'), player_locked);
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('L','C','K','D'),
+        ::player_locked);
 }
 
 
diff --git a/codeJK2/game/g_objectives.cpp b/codeJK2/game/g_objectives.cpp
index 8420d2a..3f35a57 100644
--- a/codeJK2/game/g_objectives.cpp
+++ b/codeJK2/game/g_objectives.cpp
@@ -32,7 +32,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include "objectives.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 qboolean	missionInfo_Updated;
 
@@ -88,7 +88,9 @@ OBJ_LoadMissionObjectives
 */
 void OBJ_LoadMissionObjectives( gclient_t *client )
 {
-    ::sg_read_no_cast(::gi, INT_ID('O','B','J','T'), client->sess.mission_objectives);
+    ::gi.saved_game->read_chunk(
+        INT_ID('O','B','J','T'),
+        client->sess.mission_objectives);
 }
 
 
diff --git a/codeJK2/game/g_public.h b/codeJK2/game/g_public.h
index a428f7e..f09e3e0 100644
--- a/codeJK2/game/g_public.h
+++ b/codeJK2/game/g_public.h
@@ -179,6 +179,8 @@ typedef struct {
 	int			(*ReadFromSaveGame)(unsigned int chid, void *pvAddress, int iLength, void **ppvAddressPtr );
 	int			(*ReadFromSaveGameOptional)(unsigned int chid, void *pvAddress, int iLength, void **ppvAddressPtr );
 
+    ojk::ISavedGame* saved_game;
+
 	// add commands to the console as if they were typed in
 	// for map changing, etc
 	void	(*SendConsoleCommand)( const char *text );
diff --git a/codeJK2/game/g_roff.cpp b/codeJK2/game/g_roff.cpp
index abdda30..97d8e65 100644
--- a/codeJK2/game/g_roff.cpp
+++ b/codeJK2/game/g_roff.cpp
@@ -26,7 +26,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include "g_roff.h"
 #include "g_icarus.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 // The list of precached ROFFs
 roff_list_t	roffs[MAX_ROFFS];
@@ -653,13 +653,22 @@ void G_LoadCachedRoffs()
 	char	buffer[MAX_QPATH];
 
 	// Get the count of goodies we need to revive
-	::sg_read<int32_t>(::gi, INT_ID('R','O','F','F'), count);
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('R','O','F','F'),
+        count);
 
 	// Now bring 'em back to life
 	for ( i = 0; i < count; i++ )
 	{
-		::sg_read<int32_t>(::gi, INT_ID('S','L','E','N'), len);
-		::sg_read_no_cast(::gi, INT_ID('R','S','T','R'), buffer, len);
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('S','L','E','N'),
+            len);
+
+        ::gi.saved_game->read_chunk(
+            INT_ID('R','S','T','R'),
+            buffer,
+            len);
+
 		G_LoadRoff( buffer );
 	}
 }
diff --git a/codeJK2/game/g_savegame.cpp b/codeJK2/game/g_savegame.cpp
index e0e4333..2d4f6e4 100644
--- a/codeJK2/game/g_savegame.cpp
+++ b/codeJK2/game/g_savegame.cpp
@@ -34,7 +34,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 #include "g_icarus.h"
 #include "../../code/qcommon/sstring.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 extern void OBJ_LoadTacticalInfo(void);
 
@@ -185,7 +185,10 @@ char *GetStringPtr(int iStrlen, char *psOriginal/*may be NULL*/)
 
 		assert(iStrlen+1<=(int)sizeof(sString));
 
-		::sg_read_no_cast(::gi, INT_ID('S','T','R','G'), sString, iStrlen);
+        ::gi.saved_game->read_chunk(
+            INT_ID('S','T','R','G'),
+            sString,
+            iStrlen);
 
 		// we can't do string recycling with the new g_alloc pool dumping, so just always alloc here...
 		//
@@ -758,13 +761,17 @@ static void ReadGEntities(qboolean qbAutosave)
 	int		iCount;
 	int		i;
 
-	::sg_read<int32_t>(::gi, INT_ID('N','M','E','D'), iCount);
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('N','M','E','D'),
+        iCount);
 
 	int iPreviousEntRead = -1;
 	for (i=0; i<iCount; i++)
 	{
 		int iEntIndex;
-		::sg_read<int32_t>(::gi, INT_ID('E','D','N','M'), iEntIndex);
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('E','D','N','M'),
+            iEntIndex);
 
 		if (iEntIndex >= globals.num_entities)
 		{
@@ -864,7 +871,9 @@ static void ReadGEntities(qboolean qbAutosave)
 		{
 			parms_t tempParms;
 
-			::sg_read_no_cast(::gi, INT_ID('P','A','R','M'), tempParms);
+            ::gi.saved_game->read_chunk(
+                INT_ID('P','A','R','M'),
+                tempParms);
 
 			// so can we pinch the original's one or do we have to alloc a new one?...
 			//
@@ -890,9 +899,14 @@ static void ReadGEntities(qboolean qbAutosave)
 		//
 		{
 			char *pGhoul2Data = NULL;
-			::sg_read_allocate(::gi, INT_ID('G','H','L','2'), pGhoul2Data);
+
+            ::gi.saved_game->read_chunk(
+                INT_ID('G','H','L','2'));
+
+            auto buffer = ::gi.saved_game->get_buffer();
+            pGhoul2Data = reinterpret_cast<char*>(buffer.data());
+
 			gi.G2API_LoadGhoul2Models(pEnt->ghoul2, pGhoul2Data);	// if it's going to crash anywhere...   <g>
-			gi.Free(pGhoul2Data);
 		}
 
 //		gi.unlinkentity (pEntOriginal);
@@ -951,7 +965,10 @@ static void ReadGEntities(qboolean qbAutosave)
 		// check that Icarus has loaded everything it saved out by having a marker chunk after it...
 		//
 		static int iBlah = 1234;
-		::sg_read<int32_t>(::gi, INT_ID('I','C','O','K'), iBlah);
+
+        ::gi.saved_game->read_chunk<int32_t>(
+            INT_ID('I','C','O','K'),
+            iBlah);
 	}
 	if (!qbAutosave)
 	{
@@ -1010,8 +1027,8 @@ void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition)
 		EvaluateFields(savefields_gClient, &junkClient, &level.clients[0], INT_ID('G','C','L','I'), sizeof(*level.clients), qfalse);
 
 		//Read & throw away objective info
-		objectives_t	junkObj[MAX_MISSION_OBJ];
-		::sg_read_no_cast(::gi, INT_ID('O','B','J','T'), junkObj);
+        ::gi.saved_game->read_chunk(
+            INT_ID('O','B','J','T'));
 
 		ReadLevelLocals();	// level_locals_t level
 	}
@@ -1044,7 +1061,10 @@ void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition)
 	// check that the whole file content was loaded by specifically requesting an end-marker...
 	//
 	static int iDONE = 1234;
-	::sg_read<int32_t>(::gi, INT_ID('D','O','N','E'), iDONE);
+
+    ::gi.saved_game->read_chunk<int32_t>(
+        INT_ID('D','O','N','E'),
+        iDONE);
 }
 
 extern int killPlayerTimer;
diff --git a/codeJK2/icarus/Instance.cpp b/codeJK2/icarus/Instance.cpp
index 0d9693b..3e31873 100644
--- a/codeJK2/icarus/Instance.cpp
+++ b/codeJK2/icarus/Instance.cpp
@@ -30,7 +30,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include <assert.h>
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 // Instance
 
@@ -443,7 +443,9 @@ int ICARUS_Instance::LoadSignals( void )
 {
 	int numSignals;
 
-	::sg_read<int32_t>(m_interface, INT_ID('I','S','I','G'), numSignals);
+    m_interface->saved_game->read_chunk<int32_t>(
+        INT_ID('I','S','I','G'),
+        numSignals);
 
 	for ( int i = 0; i < numSignals; i++ )
 	{
@@ -451,12 +453,17 @@ int ICARUS_Instance::LoadSignals( void )
 		int		length;
 
 		//Get the size of the string
-		::sg_read<int32_t>(m_interface, INT_ID('S','I','G','#'), length);
+        m_interface->saved_game->read_chunk<int32_t>(
+            INT_ID('S','I','G','#'),
+            length);
 
 		assert( length < (int)sizeof( buffer ) );
 
 		//Get the string
-		::sg_read_no_cast(m_interface, INT_ID('S','I','G','N'), buffer, length);
+        m_interface->saved_game->read_chunk(
+            INT_ID('S','I','G','N'),
+            buffer,
+            length);
 
 		//Turn it on and add it to the system
 		Signal( (const char *) &buffer );
@@ -497,7 +504,9 @@ int ICARUS_Instance::LoadSequences( void )
 	int			numSequences;
 
 	//Get the number of sequences to read in
-	::sg_read<int32_t>(m_interface, INT_ID('#','S','E','Q'), numSequences);
+    m_interface->saved_game->read_chunk<int32_t>(
+        INT_ID('#','S','E','Q'),
+        numSequences);
 
 	int	*idTable = new int[ numSequences ];
 
@@ -505,7 +514,10 @@ int ICARUS_Instance::LoadSequences( void )
 		return false;
 
 	//Load the sequencer ID table
-	::sg_read<int32_t>(m_interface, INT_ID('S','Q','T','B'), idTable, numSequences);
+    m_interface->saved_game->read_chunk<int32_t>(
+        INT_ID('S','Q','T','B'),
+        idTable,
+        numSequences);
 
 	//First pass, allocate all container sequences and give them their proper IDs
 	if ( AllocateSequences( numSequences, idTable ) == false )
@@ -541,7 +553,9 @@ int ICARUS_Instance::LoadSequencers( void )
 	int			numSequencers;
 
 	//Get the number of sequencers to load
-	::sg_read<int32_t>(m_interface, INT_ID('#','S','Q','R'), numSequencers);
+    m_interface->saved_game->read_chunk<int32_t>(
+        INT_ID('#','S','Q','R'),
+        numSequencers);
 	
 	//Load all sequencers
 	for ( int i = 0; i < numSequencers; i++ )
@@ -570,7 +584,10 @@ int ICARUS_Instance::Load( void )
 
 	//Check to make sure we're at the ICARUS save block
 	double	version;
-	::sg_read<double>(m_interface, INT_ID('I','C','A','R'), version);
+
+    m_interface->saved_game->read_chunk<double>(
+        INT_ID('I','C','A','R'),
+        version);
 
 	//Versions must match!
 	if ( version != ICARUS_VERSION )
@@ -600,7 +617,9 @@ int ICARUS_Instance::Load( void )
 		return false;
 	}
 
-	::sg_read<double>(m_interface, INT_ID('I','E','N','D'), version);
+    m_interface->saved_game->read_chunk<double>(
+        INT_ID('I','E','N','D'),
+        version);
 
 	return true;
 }
diff --git a/codeJK2/icarus/Sequence.cpp b/codeJK2/icarus/Sequence.cpp
index 5add77e..721c145 100644
--- a/codeJK2/icarus/Sequence.cpp
+++ b/codeJK2/icarus/Sequence.cpp
@@ -29,7 +29,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include <assert.h>
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 CSequence::CSequence( void )
 {
@@ -440,22 +440,34 @@ int CSequence::Load( void )
 	int				bID, bSize;
 	void			*bData;
 
+    auto saved_game = m_owner->GetInterface()->saved_game;
+
 	//Get the parent sequence
-	::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('S','P','I','D'), id);
+    saved_game->read_chunk<int32_t>(
+        INT_ID('S','P','I','D'),
+        id);
+
 	m_parent = ( id != -1 ) ? m_owner->GetSequence( id ) : NULL;
 	
 	//Get the return sequence
-	::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('S','R','I','D'), id);
+    saved_game->read_chunk<int32_t>(
+        INT_ID('S','R','I','D'),
+        id);
+
 	m_return = ( id != -1 ) ? m_owner->GetSequence( id ) : NULL;
 
 	//Get the number of children
-	::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('S','N','C','H'), m_numChildren);
+    saved_game->read_chunk<int32_t>(
+        INT_ID('S','N','C','H'),
+        m_numChildren);
 
 	//Reload all children
 	for ( i = 0; i < m_numChildren; i++ )
 	{
 		//Get the child sequence ID
-		::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('S','C','H','D'), id);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('S','C','H','D'),
+            id);
 
 		//Get the desired sequence
 		if ( ( sequence = m_owner->GetSequence( id ) ) == NULL )
@@ -470,46 +482,67 @@ int CSequence::Load( void )
 
 	
 	//Get the sequence flags
-	::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('S','F','L','G'), m_flags);
+    saved_game->read_chunk<int32_t>(
+        INT_ID('S','F','L','G'),
+        m_flags);
 
 	//Get the number of iterations
-	::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('S','I','T','R'), m_iterations);
+    saved_game->read_chunk<int32_t>(
+        INT_ID('S','I','T','R'),
+        m_iterations);
 
 	int	numCommands;
 
 	//Get the number of commands
-	::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('S','N','M','C'), numCommands);
+    saved_game->read_chunk<int32_t>(
+        INT_ID('S','N','M','C'),
+        numCommands);
 
 	//Get all the commands
 	for ( i = 0; i < numCommands; i++ )
 	{
 		//Get the block ID and create a new container
-		::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('B','L','I','D'), id);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('B','L','I','D'),
+            id);
+
 		block = new CBlock;
 		
 		block->Create( id );
 		
 		//Read the block's flags
-		::sg_read<uint8_t>(m_owner->GetInterface(), INT_ID('B','F','L','G'), flags);
+        saved_game->read_chunk<uint8_t>(
+            INT_ID('B','F','L','G'),
+            flags);
+
 		block->SetFlags( flags );
 
 		//Get the number of block members
-		::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('B','N','U','M'), numMembers);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('B','N','U','M'),
+            numMembers);
 		
 		for ( int j = 0; j < numMembers; j++ )
 		{
 			//Get the member ID
-			::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('B','M','I','D'), bID);
+            saved_game->read_chunk<int32_t>(
+                INT_ID('B','M','I','D'),
+                bID);
 			
 			//Get the member size
-			::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('B','S','I','Z'), bSize);
+            saved_game->read_chunk<int32_t>(
+                INT_ID('B','S','I','Z'),
+                bSize);
 
 			//Get the member's data
 			if ( ( bData = ICARUS_Malloc( bSize ) ) == NULL )
 				return false;
 
 			//Get the actual raw data
-			::sg_read_no_cast(m_owner->GetInterface(), INT_ID('B','M','E','M'), bData, bSize);
+            saved_game->read_chunk(
+                INT_ID('B','M','E','M'),
+                static_cast<uint8_t*>(bData),
+                bSize);
 
 			//Write out the correct type
 			switch ( bID )
diff --git a/codeJK2/icarus/Sequencer.cpp b/codeJK2/icarus/Sequencer.cpp
index bbf7184..457a12d 100644
--- a/codeJK2/icarus/Sequencer.cpp
+++ b/codeJK2/icarus/Sequencer.cpp
@@ -31,7 +31,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include "assert.h"
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 // Sequencer 
 
@@ -2387,7 +2387,9 @@ int	CSequencer::Load( void )
 	int i;
 
 	//Get the owner of this sequencer
-	::sg_read<int32_t>(m_ie, INT_ID('S','Q','R','E'), m_ownerID);
+    m_ie->saved_game->read_chunk<int32_t>(
+        INT_ID('S','Q','R','E'),
+        m_ownerID);
 
 	//Link the entity back to the sequencer
 	m_ie->I_LinkEntity( m_ownerID, this, m_taskManager );
@@ -2397,12 +2399,16 @@ int	CSequencer::Load( void )
 	int			numSequences, seqID, taskID, numTasks;
 
 	//Get the number of sequences to read
-	::sg_read<int32_t>(m_ie, INT_ID('S','Q','R','#'), numSequences);
+    m_ie->saved_game->read_chunk<int32_t>(
+        INT_ID('S','Q','R','#'),
+        numSequences);
 
 	//Read in all the sequences
 	for ( i = 0; i < numSequences; i++ )
 	{
-		::sg_read<int32_t>(m_ie, INT_ID('S','Q','R','I'), seqID);
+        m_ie->saved_game->read_chunk<int32_t>(
+            INT_ID('S','Q','R','I'),
+            seqID);
 
 		seq = m_owner->GetSequence( seqID );
 
@@ -2419,16 +2425,22 @@ int	CSequencer::Load( void )
 	m_taskManager->Load();
 
 	//Get the number of tasks in the map
-	::sg_read<int32_t>(m_ie, INT_ID('S','Q','T','#'), numTasks);
+    m_ie->saved_game->read_chunk<int32_t>(
+        INT_ID('S','Q','T','#'),
+        numTasks);
 
 	//Read in, and reassociate the tasks to the sequences
 	for ( i = 0; i < numTasks; i++ )
 	{
 		//Read in the task's ID
-		::sg_read<int32_t>(m_ie, INT_ID('S','T','I','D'), taskID);
+        m_ie->saved_game->read_chunk<int32_t>(
+            INT_ID('S','T','I','D'),
+            taskID);
 		
 		//Read in the sequence's ID
-		::sg_read<int32_t>(m_ie, INT_ID('S','S','I','D'), seqID);
+        m_ie->saved_game->read_chunk<int32_t>(
+            INT_ID('S','S','I','D'),
+            seqID);
 
 		taskGroup = m_taskManager->GetTaskGroup( taskID );
 
@@ -2445,15 +2457,21 @@ int	CSequencer::Load( void )
 	int	curGroupID;
 
 	//Get the current task group
-	::sg_read<int32_t>(m_ie, INT_ID('S','Q','C','T'), curGroupID);
+    m_ie->saved_game->read_chunk<int32_t>(
+        INT_ID('S','Q','C','T'),
+        curGroupID);
 
 	m_curGroup = ( curGroupID == -1 ) ? NULL : m_taskManager->GetTaskGroup( curGroupID );
 
 	//Get the number of commands
-	::sg_read<int32_t>(m_ie, INT_ID('S','Q','#','C'), m_numCommands);
+    m_ie->saved_game->read_chunk<int32_t>(
+        INT_ID('S','Q','#','C'),
+        m_numCommands);
 
 	//Get the current sequence
-	::sg_read<int32_t>(m_ie, INT_ID('S','Q','C','S'), seqID);
+    m_ie->saved_game->read_chunk<int32_t>(
+        INT_ID('S','Q','C','S'),
+        seqID);
 
 	m_curSequence = ( seqID != -1 ) ? m_owner->GetSequence( seqID ) : NULL;
 
diff --git a/codeJK2/icarus/TaskManager.cpp b/codeJK2/icarus/TaskManager.cpp
index f17bad7..bd386f6 100644
--- a/codeJK2/icarus/TaskManager.cpp
+++ b/codeJK2/icarus/TaskManager.cpp
@@ -32,7 +32,7 @@ along with this program; if not, see <http://www.gnu.org/licenses/>.
 
 #include <assert.h>
 #include "qcommon/ojk_sg_wrappers.h"
-#include "qcommon/ojk_saved_game_fwd.h"
+#include "qcommon/ojk_i_saved_game.h"
 
 #define ICARUS_VALIDATE(a) if ( a == false ) return TASK_FAILED;
 
@@ -1816,11 +1816,17 @@ void CTaskManager::Load( void )
 	int				bID, bSize;
 	int				i;
 
+    auto saved_game = m_owner->GetInterface()->saved_game;
+
 	//Get the GUID
-	::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('T','M','I','D'), m_GUID);
+    saved_game->read_chunk<int32_t>(
+        INT_ID('T','M','I','D'),
+        m_GUID);
 
 	//Get the number of tasks to follow
-	::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('T','S','K','#'), numTasks);
+    saved_game->read_chunk<int32_t>(
+        INT_ID('T','S','K','#'),
+        numTasks);
 	
 	//Reload all the tasks
 	for ( i = 0; i < numTasks; i++ )
@@ -1830,11 +1836,17 @@ void CTaskManager::Load( void )
 		assert( task );
 
 		//Get the GUID
-		::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('T','K','I','D'), id);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('T','K','I','D'),
+            id);
+
 		task->SetGUID( id );
 
 		//Get the time stamp
-		::sg_read<uint32_t>(m_owner->GetInterface(), INT_ID('T','K','T','S'), timeStamp);
+        saved_game->read_chunk<uint32_t>(
+            INT_ID('T','K','T','S'),
+            timeStamp);
+
 		task->SetTimeStamp( timeStamp );
 
 		//
@@ -1842,25 +1854,37 @@ void CTaskManager::Load( void )
 		//
 
 		//Get the block ID and create a new container
-		::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('B','L','I','D'), id);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('B','L','I','D'),
+            id);
+
 		block = new CBlock;
 		
 		block->Create( id );
 		
 		//Read the block's flags
-		::sg_read<uint8_t>(m_owner->GetInterface(), INT_ID('B','F','L','G'), flags);
+        saved_game->read_chunk<uint8_t>(
+            INT_ID('B','F','L','G'),
+            flags);
+
 		block->SetFlags( flags );
 
 		//Get the number of block members
-		::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('B','N','U','M'), numMembers);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('B','N','U','M'),
+            numMembers);
 		
 		for ( int j = 0; j < numMembers; j++ )
 		{
 			//Get the member ID
-			::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('B','M','I','D'), bID);
+            saved_game->read_chunk<int32_t>(
+                INT_ID('B','M','I','D'),
+                bID);
 			
 			//Get the member size
-			::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('B','S','I','Z'), bSize);
+            saved_game->read_chunk<int32_t>(
+                INT_ID('B','S','I','Z'),
+                bSize);
 
 			//Get the member's data
 			if ( ( bData = ICARUS_Malloc( bSize ) ) == NULL )
@@ -1870,7 +1894,10 @@ void CTaskManager::Load( void )
 			}
 
 			//Get the actual raw data
-			::sg_read_no_cast(m_owner->GetInterface(), INT_ID('B','M','E','M'), bData, bSize);
+            saved_game->read_chunk(
+                INT_ID('B','M','E','M'),
+                static_cast<uint8_t*>(bData),
+                bSize);
 
 			//Write out the correct type
 			switch ( bID )
@@ -1921,7 +1948,9 @@ void CTaskManager::Load( void )
 	//Load the task groups
 	int numTaskGroups;
 	
-	::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('T','G','#','G'), numTaskGroups);
+    saved_game->read_chunk<int32_t>(
+        INT_ID('T','G','#','G'),
+        numTaskGroups);
 
 	if ( numTaskGroups == 0 )
 		return;
@@ -1936,7 +1965,10 @@ void CTaskManager::Load( void )
 		assert( taskGroup );
 
 		//Get this task group's ID
-		::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('T','K','G','#'), taskIDs[i]);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('T','K','G','#'),
+            taskIDs[i]);
+
 		taskGroup->m_GUID = taskIDs[i];
 		
 		m_taskGroupIDMap[ taskIDs[i] ] = taskGroup;
@@ -1951,35 +1983,47 @@ void CTaskManager::Load( void )
 		assert( taskGroup );
 
 		//Load the parent ID
-		::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('T','K','G','P'), id);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('T','K','G','P'),
+            id);
 		
 		if ( id != -1 )
 			taskGroup->m_parent = ( GetTaskGroup( id ) != NULL ) ? GetTaskGroup( id ) : NULL;
 
 		//Get the number of commands in this group
-		::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('T','G','N','C'), numMembers);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('T','G','N','C'),
+            numMembers);
 
 		//Get each command and its completion state
 		for ( int j = 0; j < numMembers; j++ )
 		{
 			//Get the ID
-			::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('G','M','I','D'), id);
+            saved_game->read_chunk<int32_t>(
+                INT_ID('G','M','I','D'),
+                id);
 
 			//Write out the state of completion
-			::sg_read<uint8_t>(m_owner->GetInterface(), INT_ID('G','M','D','N'), completed);
+            saved_game->read_chunk<uint8_t>(
+                INT_ID('G','M','D','N'),
+                completed);
 
 			//Save it out
 			taskGroup->m_completedTasks[ id ] = completed;
 		}
 
 		//Get the number of completed tasks
-		::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('T','G','D','N'), taskGroup->m_numCompleted);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('T','G','D','N'),
+            taskGroup->m_numCompleted);
 	}
 
 	//Reload the currently active group
 	int curGroupID;
 
-	::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('T','G','C','G'), curGroupID);
+    saved_game->read_chunk<int32_t>(
+        INT_ID('T','G','C','G'),
+        curGroupID);
 
 	//Reload the map entries
 	for ( i = 0; i < numTaskGroups; i++ )
@@ -1988,13 +2032,20 @@ void CTaskManager::Load( void )
 		int		length;
 		
 		//Get the size of the string
-		::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('T','G','N','L'), length);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('T','G','N','L'),
+            length);
 
 		//Get the string
-		::sg_read_no_cast(m_owner->GetInterface(), INT_ID('T','G','N','S'), name, length);
+        saved_game->read_chunk(
+            INT_ID('T','G','N','S'),
+            name,
+            length);
 
 		//Get the id
-		::sg_read<int32_t>(m_owner->GetInterface(), INT_ID('T','G','N','I'), id);
+        saved_game->read_chunk<int32_t>(
+            INT_ID('T','G','N','I'),
+            id);
 
 		taskGroup = GetTaskGroup( id );
 		assert( taskGroup );
diff --git a/codeJK2/icarus/interface.h b/codeJK2/icarus/interface.h
index 051c8c9..39cc915 100644
--- a/codeJK2/icarus/interface.h
+++ b/codeJK2/icarus/interface.h
@@ -85,6 +85,7 @@ typedef struct interface_export_s
 	int				(*I_ReadSaveData)( unsigned int chid, void *address, int length, void **addressptr/* = NULL */);
 	int				(*I_LinkEntity)( int entID, CSequencer *sequencer, CTaskManager *taskManager );
 
+    ojk::ISavedGame* saved_game;
 } interface_export_t;
 
 #endif	//__INTERFACE__
diff --git a/shared/qcommon/ojk_saved_game.cpp b/shared/qcommon/ojk_saved_game.cpp
index fa254a2..5ff9c8b 100644
--- a/shared/qcommon/ojk_saved_game.cpp
+++ b/shared/qcommon/ojk_saved_game.cpp
@@ -54,11 +54,14 @@ bool SavedGame::open(
         }
     }
 
+    if (is_succeed) {
+        is_readable_ = true;
+    }
 
     int sg_version = -1;
 
     if (is_succeed) {
-        static_cast<void>(ISavedGame::read_chunk<int32_t>(
+        static_cast<void>(read_chunk<int32_t>(
             INT_ID('_', 'V', 'E', 'R'),
             sg_version));
 
@@ -73,9 +76,7 @@ bool SavedGame::open(
         }
     }
 
-    if (is_succeed) {
-        is_readable_ = true;
-    } else {
+    if (!is_succeed) {
         close();
     }
 
@@ -109,14 +110,15 @@ bool SavedGame::create(
         return false;
     }
 
+
+    is_writable_ = false;
+
     int sg_version = iSAVEGAME_VERSION;
 
-    static_cast<void>(ISavedGame::write_chunk<int32_t>(
+    static_cast<void>(write_chunk<int32_t>(
         INT_ID('_', 'V', 'E', 'R'),
         sg_version));
 
-    is_writable_ = false;
-
     return true;
 }
 
@@ -149,6 +151,8 @@ bool SavedGame::is_writable() const
 bool SavedGame::read_chunk(
     const SavedGame::ChunkId chunk_id)
 {
+    io_buffer_offset_ = 0;
+
     auto chunk_id_string = get_chunk_id_string(
         chunk_id);
 
@@ -198,7 +202,7 @@ bool SavedGame::read_chunk(
     if (bBlockIsCompressed) {
         uiLoaded += ::FS_Read(
             &uiCompressedLength,
-            static_cast<int>(uiCompressedLength),
+            static_cast<int>(sizeof(uiCompressedLength)),
             file_handle_);
 
         rle_buffer_.resize(
@@ -209,6 +213,9 @@ bool SavedGame::read_chunk(
             uiCompressedLength,
             file_handle_);
 
+        io_buffer_.resize(
+            uiLoadedLength);
+
         decompress(
             rle_buffer_,
             io_buffer_);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/openjk.git



More information about the Pkg-games-commits mailing list