//----------------------------------------------------------------------------- void ReplayPlay::load() { m_ghost_karts.clearAndDeleteAll(); char s[1024]; FILE *fd = openReplayFile(/*writeable*/false, m_custom_replay_file); if(!fd) { Log::error("Replay", "Can't read '%s', ghost replay disabled.", getReplayFilename().c_str()); destroy(); return; } Log::info("Replay", "Reading replay file '%s'.", getReplayFilename().c_str()); const unsigned int line_skipped = getNumGhostKart() + 7; for (unsigned int i = 0; i < line_skipped; i++) fgets(s, 1023, fd); // eof actually doesn't trigger here, since it requires first to try // reading behind eof, but still it's clearer this way. while(!feof(fd)) { if(fgets(s, 1023, fd)==NULL) // eof reached break; readKartData(fd, s); } fprintf(fd, "Replay file end.\n"); fclose(fd); } // load
/** Saves the replay data stored in the internal data structures. */ void ReplayRecorder::Save() { #ifdef DEBUG printf("%d frames, %d removed because of frequency compression\n", m_count, m_count_skipped_time); #endif FILE *fd = openReplayFile(/*writeable*/true); if(!fd) { Log::error("ReplayRecorder", "Can't open '%s' for writing - can't save replay data.", getReplayFilename().c_str()); return; } Log::info("ReplayRecorder", "Replay saved in '%s'.\n", getReplayFilename().c_str()); World *world = World::getWorld(); unsigned int num_karts = world->getNumKarts(); fprintf(fd, "Version: %d\n", getReplayVersion()); fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty()); fprintf(fd, "track: %s\n", world->getTrack()->getIdent().c_str()); fprintf(fd, "Laps: %d\n", race_manager->getNumLaps()); unsigned int max_frames = (unsigned int)( stk_config->m_replay_max_time / stk_config->m_replay_dt ); for(unsigned int k=0; k<num_karts; k++) { fprintf(fd, "model: %s\n", world->getKart(k)->getIdent().c_str()); fprintf(fd, "size: %d\n", m_count_transforms[k]); unsigned int num_transforms = std::min(max_frames, m_count_transforms[k]); for(unsigned int i=0; i<num_transforms; i++) { const TransformEvent *p=&(m_transform_events[k][i]); fprintf(fd, "%f %f %f %f %f %f %f %f\n", p->m_time, p->m_transform.getOrigin().getX(), p->m_transform.getOrigin().getY(), p->m_transform.getOrigin().getZ(), p->m_transform.getRotation().getX(), p->m_transform.getRotation().getY(), p->m_transform.getRotation().getZ(), p->m_transform.getRotation().getW() ); } // for i fprintf(fd, "events: %d\n", (int)m_kart_replay_event[k].size()); for(unsigned int i=0; i<m_kart_replay_event[k].size(); i++) { const KartReplayEvent *p=&(m_kart_replay_event[k][i]); fprintf(fd, "%f %d\n", p->m_time, p->m_type); } } fclose(fd); } // Save
/** Opens a replay file which is determined by sub classes. * \param writeable True if the file should be opened for writing. * \param full_path True if the file is full path. * \return A FILE *, or NULL if the file could not be opened. */ FILE* ReplayBase::openReplayFile(bool writeable, bool full_path) { FILE *fd = fopen(full_path ? getReplayFilename().c_str() : (file_manager->getReplayDir() + getReplayFilename()).c_str(), writeable ? "w" : "r"); if (!fd) { return NULL; } return fd; } // openReplayFile
/** Saves the replay data stored in the internal data structures. */ void ReplayRecorder::save() { if (m_incorrect_replay || !m_complete_replay) { MessageQueue::add(MessageQueue::MT_ERROR, _("Incomplete replay file will not be saved.")); return; } #ifdef DEBUG Log::debug("ReplayRecorder", "%d frames, %d removed because of" "frequency compression", m_count, m_count_skipped_time); #endif const World *world = World::getWorld(); const unsigned int num_karts = world->getNumKarts(); float min_time = 99999.99f; for (unsigned int k = 0; k < num_karts; k++) { if (world->getKart(k)->isGhostKart()) continue; float cur_time = world->getKart(k)->getFinishTime(); if (cur_time < min_time) min_time = cur_time; } int day, month, year; StkTime::getDate(&day, &month, &year); std::string time = StringUtils::toString(min_time); std::replace(time.begin(), time.end(), '.', '_'); std::ostringstream oss; oss << Track::getCurrentTrack()->getIdent() << "_" << year << month << day << "_" << num_karts << "_" << time << ".replay"; m_filename = oss.str(); FILE *fd = openReplayFile(/*writeable*/true); if (!fd) { Log::error("ReplayRecorder", "Can't open '%s' for writing - " "can't save replay data.", getReplayFilename().c_str()); return; } core::stringw msg = _("Replay saved in \"%s\".", (file_manager->getReplayDir() + getReplayFilename()).c_str()); MessageQueue::add(MessageQueue::MT_GENERIC, msg); fprintf(fd, "version: %d\n", getReplayVersion()); for (unsigned int real_karts = 0; real_karts < num_karts; real_karts++) { const AbstractKart *kart = world->getKart(real_karts); if (kart->isGhostKart()) continue; // XML encode the username to handle Unicode fprintf(fd, "kart: %s %s\n", kart->getIdent().c_str(), StringUtils::xmlEncode(kart->getController()->getName()).c_str()); } fprintf(fd, "kart_list_end\n"); fprintf(fd, "reverse: %d\n", (int)race_manager->getReverseTrack()); fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty()); fprintf(fd, "track: %s\n", Track::getCurrentTrack()->getIdent().c_str()); fprintf(fd, "laps: %d\n", race_manager->getNumLaps()); fprintf(fd, "min_time: %f\n", min_time); unsigned int max_frames = (unsigned int)( stk_config->m_replay_max_time / stk_config->m_replay_dt ); for (unsigned int k = 0; k < num_karts; k++) { if (world->getKart(k)->isGhostKart()) continue; fprintf(fd, "size: %d\n", m_count_transforms[k]); unsigned int num_transforms = std::min(max_frames, m_count_transforms[k]); for (unsigned int i = 0; i < num_transforms; i++) { const TransformEvent *p = &(m_transform_events[k][i]); const PhysicInfo *q = &(m_physic_info[k][i]); const KartReplayEvent *r = &(m_kart_replay_event[k][i]); fprintf(fd, "%f %f %f %f %f %f %f %f %f %f %f %f %f %f %d %d %d %d %d\n", p->m_time, p->m_transform.getOrigin().getX(), p->m_transform.getOrigin().getY(), p->m_transform.getOrigin().getZ(), p->m_transform.getRotation().getX(), p->m_transform.getRotation().getY(), p->m_transform.getRotation().getZ(), p->m_transform.getRotation().getW(), q->m_speed, q->m_steer, q->m_suspension_length[0], q->m_suspension_length[1], q->m_suspension_length[2], q->m_suspension_length[3], r->m_nitro_usage, (int)r->m_zipper_usage, r->m_skidding_state, (int)r->m_red_skidding, (int)r->m_jumping ); } // for i } fclose(fd); } // save