/×
關于文件版本塊的結(jié)構(gòu)定義方法。
×/
struct chunk{
JDWORD type;
JDWORD version;
JDWORD size;
}
通過 type 來識別這個 chunk 的類型,如果是已知的類型就按照其對應的版本號 Version 來讀取數(shù)據(jù)
如果不是則跳過該 chunk 并給出一定的警告信息。
size 保存了這個 chunk 的實際長度,通常情況下不包含自己的長度。
可以通過和實際加載的數(shù)據(jù)長度進行對比,如果兩個值不行等,就說明其版本或者數(shù)據(jù)存在錯誤~無法繼續(xù)加載。
舉個例子。
我們有一個結(jié)構(gòu)體。
struct MapInfo{
int width;
int height;
int mapdata[100];
// 下面兩個變量是在 2.0 版本之后才會出現(xiàn)的。
int posX;
int posY;
};
現(xiàn)在要把這個結(jié)構(gòu)體按照我們的保存結(jié)構(gòu)進行保存。
首先給這個結(jié)構(gòu)定義一種chunk類型,以確保他在程序中是唯一的標志。
例如。 我們定義
#define MAP_INFO_CHUNK_TYPE 0x1000
#define MAP_INFO_CHUNK_VERSION 0x0010 //表示 1.0
保存函數(shù):
JResult saveMapInfo( JIStream* pStream , const MapInfo* mi ){
chunk c;
c.type = MAP_INFO_CHUNK_TYPE;
c.version = MAP_INFO_CHUNK_VERSION; //根據(jù)不同的版本。進行寫入。
c.size = 0;
JDWORD cur_pos = pStream->getPos();
pStream->write( c ); //先把數(shù)據(jù)寫入文件緩沖。(占位置)
if( c.version >= 0x0010 ){
c.size += pStream->write( mi->width );
c.size += pStream->write( mi->height );
c.size += pStream->write( mi->mapdata );
}
if( c.version >= 0x0020 ){ //
c.size += pStream->write( mi->posX );
c.size += pStream->write( mi->posY );
}
pStream->setPos( TPOS_SET , cur_pos );
pStream->write( c ); //回寫chunk數(shù)據(jù)。
return JROK;
}
讀取函數(shù):
JDWORD loadMapInfo( JIStream* pStream , const MapInfo* mi ){
chunk c;
JDWORD size = 0;
size += pStream->read( &c );
if( c.type != MAP_INFO_CHUNK_TYPE ){
JSetLastErrorEx( "error chunk type!\n" );
return size;
}
if( c.version >= 0x0010 ){
size += pStream->read( mi->width );
size += pStream->read( mi->height );
size += pStream->read( mi->mapdata );
}
if( c.version >= 0x0020 ){ //未來各個版本之間的控制。 向下兼容。
size += pStream->read( mi->posX );
size += pStream->read( mi->posY );
}
//檢查數(shù)據(jù)讀取長度是否和chunk中記錄的相同!
if( size != c.size ){
JSetLastErrorEx( "data chunk have a error existed!\n" );
return size;
}
return size; //這里應該返回該函數(shù)總共在這個過程中讀取的字節(jié)長度。
//以便以后在多層次的嵌套或者遞歸式可以很方便的求出下一個chunk的位置。
}
大概就是如此。
另外很多情況下一個chunk中可以包含很多子chunk以實現(xiàn)嵌套
#define SCENE_VERSION_V1 100
#define SCENE_VERSION_V2 200
#define SCENE_VERSION_V3 300
#define SCENE_CURRENT_VERSION SCENE_VERSION_V3
#define HEADER_VERSION_V1 100
#define HEADER_VERSION_V2 200
#define HEADER_VERSION_V3 300 
#define HEADER_CURRENT_VERSION HEADER_VERSION_V3
#define GRID_VERSION_V1 100
#define GRID_VERSION_V2 200
#define GRID_VERSION_V3 300
#define GRID_CURRENT_VERSION GRID_VERSION_V3
JResult GridDisplacement::saveMap( JIStream* pStream )2


{ 3
#define SAVECHUNK( func ) { \4
chunk_t chunk; \5
JIStream::tPos cpos = write_chunk( pStream , chunk ); \6
chunk.size =(JDWORD)(func); \7
JIStream::tPos tcurrent = pStream->getPos(); \8
write_chunk( pStream , chunk , cpos ); \9
pStream->setPos( tcurrent , JIStream::TPOS_SET ); }10

11
SAVECHUNK( save_header( &chunk , pStream ) );12
SAVECHUNK( save_grid( &chunk , pStream ) );13
SAVECHUNK( save_sector( &chunk , pStream ) );14

15
#undef SAVECHUNCK16
return JR_OK;17
}分成三個部分保存,header, grid ,sector,每個都有自己的版本控制,
size_t GridDisplacement::load_header( chunk_t* pc , JIStream* pStream )2


{3
size_t size = 0;4

if( pc->version >= HEADER_VERSION_V1 )
{5
size = pStream->read( name , sizeof( name ) );6
}7
8

if( pc->version >= HEADER_VERSION_V1+1 )
{9
size += pStream->read( &player_info.start_point , sizeof( vec3 ) );10
}11
12
//if( pc->version >= HEADER_VERSION_V4 ){13
// size += pStream->read( width );14
// size += pStream->read( height );15
//}16

17
return size;18
}19

20
size_t GridDisplacement::save_header( chunk_t* pc , JIStream* pStream )21


{22
pc->version = HEADER_CURRENT_VERSION;23
pc->name = MF_HEADER;24

25
size_t size = 0;26
size += pStream->write( name , sizeof(name) );27
size += pStream->write( &player_info.start_point , sizeof( vec3 ) );28
29
//if( HEADER_CURRENT_VERSION >= HEADER_VERSION_V3 ){30
// size += pStream->write( width ); //HEADER_VERSION_V4 added31
// size += pStream->write( height );32
//}33

34
//size += pStream->write( pitch );35
return size;36
}37

38
size_t GridDisplacement::load_grid( chunk_t* pc , JIStream* pStream )39


{40
size_t size = 0;41

42
size += pStream->read( width );43
size += pStream->read( height );44
size += pStream->read( pitch );45

46

if( JROK( generate_maze( width , height ) ) )
{47
r_setLastErrorMsg( "load_grid error ! generate_maze" ) ;48
return 0;49
}50

51
// size += pStream->read( grids , pitch * height );52

53
return size;54
}55

56
size_t GridDisplacement::save_grid( chunk_t* pc , JIStream* pStream )57


{58
pc->version = GRID_CURRENT_VERSION;59
pc->name = MF_GRIDS;60

61
size_t size = 0;62
size += pStream->write( width );63
size += pStream->write( height );64
size += pStream->write( pitch );65

66
// size += pStream->write( grids , pitch * height );67

68
return size;69
}
LoadMap分別加載
JResult GridDisplacement::loadMap( JIStream* pStream )

{
chunk_t chunk;
//JResult result = JR_OK;
const char* lpszErrorPos = NULL;
// while( !pStream->eof() )
{
#define LOADCHUNK( func ) if( chunk.size != (func) ){ lpszErrorPos=#func; goto _END; }
// switch( chunk.name )
// {
// case MF_HEADER:
pStream->read( &chunk , sizeof( chunk_t ) );
LOADCHUNK( load_header( &chunk , pStream ) );
// break;
// case MF_GRIDS:
pStream->read( &chunk , sizeof( chunk_t ) );
LOADCHUNK( load_grid( &chunk , pStream ) );
// break;
// case MF_SECTOR:
pStream->read( &chunk , sizeof( chunk_t ) );
LOADCHUNK( load_sector( &chunk , pStream ) );
// break;
// default:
// JNOTE( "GD_load_map_warning! unknow chunk%x\n" , chunk.name );
// pStream->setPos( chunk.size , JIStream::TPOS_CUR );
// break;
// }
#undef LOADCHUNK
}
_END:
if( lpszErrorPos )
{
//JNOTE( "GD_load_map_error! pos:%s <%s>\n" , lpszErrorPos , r_getLastErrorMsg() );
return JR_FAILED;
}

for( int i=0;i<sector_count;i++ )
{
Sector* ps = §ors[ i ];
for( int j=0;j<ps->obj_list.count();j++ )
{
IObject* pi = ps->obj_list[ j ];
if( pi && pi->getType() == IObject::LIGHT )
{
GLight* light = (GLight*)pi;
if( light->light_ptr )
{
light->light_ptr->need_update_static_UT = JTRUE;
light->light_ptr->need_update = JTRUE;
}
}
}
}
return JR_OK;
}

