void rewind_recording( void) { if(replay.game_is_being_recorded) { /* This is unnecessary, because it is called from reset_player_queues, */ /* which is always called from revert_game */ /* FilmFile.SetLength(sizeof(recording_header)); FilmFile.SetPosition(sizeof(recording_header)); */ // Alternative that does not use "SetLength", but instead creates and re-creates the file. FilmFile.SetPosition(0); byte Header[SIZEOF_recording_header]; FilmFile.Read(SIZEOF_recording_header,Header); FilmFile.Close(); FilmFileSpec.Delete(); FilmFileSpec.Create(_typecode_film); FilmFileSpec.Open(FilmFile,true); FilmFile.Write(SIZEOF_recording_header,Header); // Use the packed length here!!! replay.header.length= SIZEOF_recording_header; } }
void stop_recording( void) { if (replay.game_is_being_recorded) { replay.game_is_being_recorded = false; short player_index; int32 total_length; assert(replay.valid); for (player_index= 0; player_index<dynamic_world->player_count; player_index++) { save_recording_queue_chunk(player_index); } /* Rewrite the header, since it has the new length */ FilmFile.SetPosition(0); byte Header[SIZEOF_recording_header]; pack_recording_header(Header,&replay.header,1); // ZZZ: removing code that does stuff from assert() argument. BUT... // should we really be asserting on this anyway? I mean, the write could fail // in 'normal operation' too, not just when we screwed something up in writing the program? bool successfulWrite = FilmFile.Write(SIZEOF_recording_header,Header); assert(successfulWrite); FilmFile.GetLength(total_length); assert(total_length==replay.header.length); FilmFile.Close(); } replay.valid= false; }
/* Note that we _must_ set the header information before we start recording!! */ void start_recording( void) { assert(!replay.valid); replay.valid= true; if(get_recording_filedesc(FilmFileSpec)) FilmFileSpec.Delete(); if (FilmFileSpec.Create(_typecode_film)) { /* I debate the validity of fsCurPerm here, but Alain had it, and it has been working */ if (FilmFileSpec.Open(FilmFile,true)) { replay.game_is_being_recorded= true; // save a header containing information about the game. byte Header[SIZEOF_recording_header]; pack_recording_header(Header,&replay.header,1); FilmFile.Write(SIZEOF_recording_header,Header); } } }
/********************************************************************************************* * * Function: save_recording_queue_chunk * Purpose: saves one chunk of the queue to the recording file, using run-length encoding. * *********************************************************************************************/ void save_recording_queue_chunk( short player_index) { uint8 *location; uint32 last_flag, count, flag = 0; int16 i, run_count, num_flags_saved, max_flags; static uint8 *buffer= NULL; ActionQueue *queue; // The data format is (run length (int16)) + (action flag (uint32)) int DataSize = sizeof(int16) + sizeof(uint32); if (buffer == NULL) buffer = new byte[RECORD_CHUNK_SIZE * DataSize]; location= buffer; count= 0; // keeps track of how many bytes we'll save. last_flag= (uint32)NONE; queue= get_player_recording_queue(player_index); // don't want to save too much stuff max_flags= MIN(RECORD_CHUNK_SIZE, get_recording_queue_size(player_index)); // save what's in the queue run_count= num_flags_saved= 0; for (i = 0; i<max_flags; i++) { flag = queue->buffer[queue->read_index]; INCREMENT_QUEUE_COUNTER(queue->read_index); if (i && flag != last_flag) { ValueToStream(location,run_count); ValueToStream(location,last_flag); count += DataSize; num_flags_saved += run_count; run_count = 1; } else { run_count++; } last_flag = flag; } // now save the final run ValueToStream(location,run_count); ValueToStream(location,last_flag); count += DataSize; num_flags_saved += run_count; if (max_flags<RECORD_CHUNK_SIZE) { short end_indicator = END_OF_RECORDING_INDICATOR; ValueToStream(location,end_indicator); int32 end_flag = 0; ValueToStream(location,end_flag); count += DataSize; num_flags_saved += RECORD_CHUNK_SIZE-max_flags; } FilmFile.Write(count,buffer); replay.header.length+= count; vwarn(num_flags_saved == RECORD_CHUNK_SIZE, csprintf(temporary, "bad recording: %d flags, max=%d, count = %u;dm #%p #%u", num_flags_saved, max_flags, count, buffer, count)); }