diff --git a/src/Aircraft/continuous.cxx b/src/Aircraft/continuous.cxx index 632d73a96..30512adbc 100644 --- a/src/Aircraft/continuous.cxx +++ b/src/Aircraft/continuous.cxx @@ -187,7 +187,37 @@ static bool ReadFGReplayData2( return true; } -std::unique_ptr ReadFGReplayData( +/* Removes items more than away from . can be -ve. */ +template +static void remove_far_away(Container& container, Iterator it, int n) +{ + SG_LOG(SG_GENERAL, SG_DEBUG, "container.size()=" << container.size()); + if (n > 0) + { + for (int i=0; isecond->load_signals) + || (load_multiplayer && !it->second->load_multiplayer) + || (load_extra_properties && !it->second->load_extra_properties) + ) + { + /* This frame is in the continuous.m_in_pos_to_frame cache, but + doesn't contain all of the required items, so we need to reload. */ + continuous.m_in_pos_to_frame.erase(it); + it = continuous.m_in_pos_to_frame.end(); + } } - bool ok; - if (in_compression) + if (it == continuous.m_in_pos_to_frame.end()) { - uint8_t flags; - uint32_t compressed_size; - in.read((char*) &flags, sizeof(flags)); - in.read((char*) &compressed_size, sizeof(compressed_size)); - simgear::ZlibDecompressorIStream in_decompress(in, SGPath(), simgear::ZLibCompressionFormat::ZLIB_RAW); - ok = ReadFGReplayData2(in_decompress, config, load_signals, load_multiplayer, load_extra_properties, ret.get()); + /* Load FGReplayData at offset . + + We need to clear any eof bit, otherwise seekg() will not work (which is + pretty unhelpful). E.g. see: + https://stackoverflow.com/questions/16364301/whats-wrong-with-the-ifstream-seekg + */ + SG_LOG(SG_SYSTEMS, SG_BULK, "reading frame. pos=" << pos); + in.clear(); + in.seekg(pos); + + ret.reset(new FGReplayData); + + readRaw(in, ret->sim_time); + if (!in) + { + SG_LOG(SG_SYSTEMS, SG_DEBUG, "Failed to read fgtape frame at offset " << pos); + return nullptr; + } + bool ok; + if (in_compression) + { + uint8_t flags; + uint32_t compressed_size; + in.read((char*) &flags, sizeof(flags)); + in.read((char*) &compressed_size, sizeof(compressed_size)); + simgear::ZlibDecompressorIStream in_decompress(in, SGPath(), simgear::ZLibCompressionFormat::ZLIB_RAW); + ok = ReadFGReplayData2(in_decompress, config, load_signals, load_multiplayer, load_extra_properties, ret.get()); + } + else + { + ok = ReadFGReplayData2(in, config, load_signals, load_multiplayer, load_extra_properties, ret.get()); + } + if (!ok) + { + SG_LOG(SG_SYSTEMS, SG_DEBUG, "Failed to read fgtape frame at offset " << pos); + return nullptr; + } + it = continuous.m_in_pos_to_frame.lower_bound(pos); + it = continuous.m_in_pos_to_frame.insert(it, std::make_pair(pos, ret)); + + /* Delete faraway items. */ + size_t size_old = continuous.m_in_pos_to_frame.size(); + int n = 2; + size_t size_max = 2*n - 1; + remove_far_away(continuous.m_in_pos_to_frame, it, n); + remove_far_away(continuous.m_in_pos_to_frame, it, -n); + size_t size_new = continuous.m_in_pos_to_frame.size(); + SG_LOG(SG_GENERAL, SG_DEBUG, "" + << " n=" << size_old + << " size_max=" << size_max + << " size_old=" << size_old + << " size_new=" << size_new + ); + assert(size_new <= size_max); } else { - ok = ReadFGReplayData2(in, config, load_signals, load_multiplayer, load_extra_properties, ret.get()); - } - if (!ok) - { - SG_LOG(SG_SYSTEMS, SG_DEBUG, "Failed to read fgtape frame at offset " << pos); - return nullptr; + ret = it->second; } return ret; } @@ -514,7 +587,17 @@ SGPropertyNode_ptr continuousWriteHeader( return config; } -bool replayContinuousInternal( +/* Replays one frame from Continuous recording. and are +offsets in file of frames that are >= and <