void HISTORY::save(EMUFILE *os, bool really_save) { if (really_save) { int real_pos, last_tick = 0; // write "HISTORY" string os->fwrite(historySaveID, HISTORY_ID_LEN); // write vars write32le(historyCursorPos, os); write32le(historyTotalItems, os); // write items starting from history_start_pos for (int i = 0; i < historyTotalItems; ++i) { real_pos = (historyStartPos + i) % historySize; snapshots[real_pos].save(os); bookmarkBackups[real_pos].save(os); os->fwrite(¤tBranchNumberBackups[real_pos], 1); if (i / SAVING_HISTORY_PROGRESSBAR_UPDATE_RATE > last_tick) { playback.setProgressbar(i, historyTotalItems); last_tick = i / PROGRESSBAR_UPDATE_RATE; } } } else { // write "HISTORX" string os->fwrite(historySkipSaveID, HISTORY_ID_LEN); } }
// returns true if couldn't load bool GREENZONE::load(EMUFILE *is, unsigned int offset) { free(); if (offset) { if (is->fseek(offset, SEEK_SET)) goto error; } else { reset(); playback.restartPlaybackFromZeroGround(); // reset Playback cursor to frame 0 return false; } int frame = 0, prev_frame = -1, size = 0; int last_tick = 0; // read "GREENZONE" string char save_id[GREENZONE_ID_LEN]; if ((int)is->fread(save_id, GREENZONE_ID_LEN) < GREENZONE_ID_LEN) goto error; if (!strcmp(greenzone_skipsave_id, save_id)) { // string says to skip loading Greenzone // read LagLog lagLog.load(is); // read Playback cursor position if (read32le(&frame, is)) { currFrameCounter = frame; greenzoneSize = currFrameCounter + 1; savestates.resize(greenzoneSize); if (currFrameCounter) { // there must be one savestate in the file if (read32le(&size, is) && size >= 0) { savestates[frame].resize(size); if (is->fread(&savestates[frame][0], size) == size) { if (loadSavestateOfFrame(currFrameCounter)) { FCEU_printf("No Greenzone in the file\n"); return false; } } } } else { // literally no Greenzone in the file, but this is still not a error reset(); playback.restartPlaybackFromZeroGround(); // reset Playback cursor to frame 0 FCEU_printf("No Greenzone in the file, Playback at frame 0\n"); return false; } } goto error; } if (strcmp(greenzone_save_id, save_id)) goto error; // string is not valid // read LagLog lagLog.load(is); // read size if (read32le(&size, is) && size >= 0 && size <= currMovieData.getNumRecords()) { greenzoneSize = size; savestates.resize(greenzoneSize); // read Playback cursor position if (read32le(&frame, is)) { currFrameCounter = frame; int greenzone_tail_frame = currFrameCounter - taseditorConfig.greenzoneCapacity; int greenzone_tail_frame2 = greenzone_tail_frame - 2 * taseditorConfig.greenzoneCapacity; int greenzone_tail_frame4 = greenzone_tail_frame - 4 * taseditorConfig.greenzoneCapacity; int greenzone_tail_frame8 = greenzone_tail_frame - 8 * taseditorConfig.greenzoneCapacity; int greenzone_tail_frame16 = greenzone_tail_frame - 16 * taseditorConfig.greenzoneCapacity; // read savestates while(1) { if (!read32le(&frame, is)) break; if (frame < 0) break; // -1 = eof // update TASEditor progressbar from time to time if (frame / PROGRESSBAR_UPDATE_RATE > last_tick) { playback.setProgressbar(frame, greenzoneSize); last_tick = frame / PROGRESSBAR_UPDATE_RATE; } // read savestate if (!read32le(&size, is)) break; if (size < 0) break; if (frame <= greenzone_tail_frame16 || (frame <= greenzone_tail_frame8 && (frame & 0xF)) || (frame <= greenzone_tail_frame4 && (frame & 0x7)) || (frame <= greenzone_tail_frame2 && (frame & 0x3)) || (frame <= greenzone_tail_frame && (frame & 0x1))) { // skip loading this savestate if (is->fseek(size, SEEK_CUR) != 0) break; } else { // load this savestate if ((int)savestates.size() <= frame) savestates.resize(frame + 1); savestates[frame].resize(size); if ((int)is->fread(&savestates[frame][0], size) < size) break; prev_frame = frame; // successfully read one Greenzone frame info } } if (prev_frame+1 == greenzoneSize) { // everything went fine - load savestate at cursor position if (loadSavestateOfFrame(currFrameCounter)) return false; } // uh, okay, but maybe we managed to read at least something useful from the file // first see if original position of currFrameCounter was read successfully if (loadSavestateOfFrame(currFrameCounter)) { greenzoneSize = prev_frame+1; // cut greenZoneCount to last good frame FCEU_printf("Greenzone loaded partially\n"); return false; } // then at least jump to some frame that was read successfully for (; prev_frame >= 0; prev_frame--) { if (loadSavestateOfFrame(prev_frame)) { currFrameCounter = prev_frame; greenzoneSize = prev_frame+1; // cut greenZoneCount to this good frame FCEU_printf("Greenzone loaded partially, Playback moved to the end of greenzone\n"); return false; } } } } error: FCEU_printf("Error loading Greenzone\n"); reset(); playback.restartPlaybackFromZeroGround(); // reset Playback cursor to frame 0 return true; }
// returns true if couldn't load bool HISTORY::load(EMUFILE *is, unsigned int offset) { int i = -1; SNAPSHOT snap; BOOKMARK bookm; if (offset) { if (is->fseek(offset, SEEK_SET)) goto error; } else { reset(); return false; } // read "HISTORY" string char save_id[HISTORY_ID_LEN]; if ((int)is->fread(save_id, HISTORY_ID_LEN) < HISTORY_ID_LEN) goto error; if (!strcmp(historySkipSaveID, save_id)) { // string says to skip loading History FCEU_printf("No History in the file\n"); reset(); return false; } if (strcmp(historySaveID, save_id)) goto error; // string is not valid // delete old items snapshots.resize(historySize); bookmarkBackups.resize(historySize); currentBranchNumberBackups.resize(historySize); // read vars if (!read32le(&historyCursorPos, is)) goto error; if (!read32le(&historyTotalItems, is)) goto error; if (historyCursorPos > historyTotalItems) goto error; historyStartPos = 0; // read items int total = historyTotalItems; if (historyTotalItems > historySize) { // user can't afford that much undo levels, skip some items int num_items_to_skip = historyTotalItems - historySize; // first try to skip items over history_cursor_pos (future items), because "redo" is less important than "undo" int num_redo_items = historyTotalItems-1 - historyCursorPos; if (num_items_to_skip >= num_redo_items) { // skip all redo items historyTotalItems = historyCursorPos+1; num_items_to_skip -= num_redo_items; // and still need to skip some undo items for (i = 0; i < num_items_to_skip; ++i) { if (snap.skipLoad(is)) goto error; if (bookm.skipLoad(is)) goto error; if (is->fseek(1, SEEK_CUR)) goto error; // backup_current_branch } total -= num_items_to_skip; historyCursorPos -= num_items_to_skip; } historyTotalItems -= num_items_to_skip; } // load items for (i = 0; i < historyTotalItems; ++i) { if (snapshots[i].load(is)) goto error; if (bookmarkBackups[i].load(is)) goto error; if (is->fread(¤tBranchNumberBackups[i], 1) != 1) goto error; playback.setProgressbar(i, historyTotalItems); } // skip redo items if needed for (; i < total; ++i) { if (snap.skipLoad(is)) goto error; if (bookm.skipLoad(is)) goto error; if (is->fseek(1, SEEK_CUR)) goto error; // backup_current_branch } // everything went well // init vars undoHintPos = oldUndoHintPos = undoHintTimer = -1; oldShowUndoHint = showUndoHint = false; updateList(); redrawList(); return false; error: FCEU_printf("Error loading History\n"); reset(); return true; }
void GREENZONE::save(EMUFILE *os, int save_type) { if (save_type != GREENZONE_SAVING_MODE_NO) { collectCurrentState(); // in case the project is being saved before the greenzone.update() was called within current frame runGreenzoneCleaning(); if (greenzoneSize > (int)savestates.size()) greenzoneSize = savestates.size(); // write "GREENZONE" string os->fwrite(greenzone_save_id, GREENZONE_ID_LEN); // write LagLog lagLog.save(os); // write size write32le(greenzoneSize, os); // write Playback cursor position write32le(currFrameCounter, os); } int frame, size; int last_tick = 0; switch (save_type) { case GREENZONE_SAVING_MODE_ALL: { // write savestates for (frame = 0; frame < greenzoneSize; ++frame) { // update TASEditor progressbar from time to time if (frame / PROGRESSBAR_UPDATE_RATE > last_tick) { playback.setProgressbar(frame, greenzoneSize); last_tick = frame / PROGRESSBAR_UPDATE_RATE; } if (!savestates[frame].size()) continue; write32le(frame, os); // write savestate size = savestates[frame].size(); write32le(size, os); os->fwrite(&savestates[frame][0], size); } // write -1 as eof for greenzone write32le(-1, os); break; } case GREENZONE_SAVING_MODE_16TH: { // write savestates for (frame = 0; frame < greenzoneSize; ++frame) { if (!(frame & 0xF) || frame == currFrameCounter) { // update TASEditor progressbar from time to time if (frame / PROGRESSBAR_UPDATE_RATE > last_tick) { playback.setProgressbar(frame, greenzoneSize); last_tick = frame / PROGRESSBAR_UPDATE_RATE; } if (!savestates[frame].size()) continue; write32le(frame, os); // write savestate size = savestates[frame].size(); write32le(size, os); os->fwrite(&savestates[frame][0], size); } } // write -1 as eof for greenzone write32le(-1, os); break; } case GREENZONE_SAVING_MODE_MARKED: { // write savestates for (frame = 0; frame < greenzoneSize; ++frame) { if (markersManager.getMarkerAtFrame(frame) || frame == currFrameCounter) { // update TASEditor progressbar from time to time if (frame / PROGRESSBAR_UPDATE_RATE > last_tick) { playback.setProgressbar(frame, greenzoneSize); last_tick = frame / PROGRESSBAR_UPDATE_RATE; } if (!savestates[frame].size()) continue; write32le(frame, os); // write savestate size = savestates[frame].size(); write32le(size, os); os->fwrite(&savestates[frame][0], size); } } // write -1 as eof for greenzone write32le(-1, os); break; } case GREENZONE_SAVING_MODE_NO: { // write "GREENZONX" string os->fwrite(greenzone_skipsave_id, GREENZONE_ID_LEN); // write LagLog lagLog.save(os); // write Playback cursor position write32le(currFrameCounter, os); if (currFrameCounter > 0) { // write ONE savestate for currFrameCounter collectCurrentState(); int size = savestates[currFrameCounter].size(); write32le(size, os); os->fwrite(&savestates[currFrameCounter][0], size); } break; } } }