Basic rewind works!
This commit is contained in:
parent
c5f825eaa5
commit
351e098da1
|
@ -1,6 +1,6 @@
|
||||||
TARGET = ssnes.exe
|
TARGET = ssnes.exe
|
||||||
JTARGET = ssnes-joyconfig.exe
|
JTARGET = ssnes-joyconfig.exe
|
||||||
OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o message.o
|
OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o message.o rewind.o
|
||||||
JOBJ = conf/config_file.o tools/main-stub.o tools/ssnes-joyconfig.o
|
JOBJ = conf/config_file.o tools/main-stub.o tools/ssnes-joyconfig.o
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
|
|
|
@ -184,6 +184,7 @@ static const struct snes_keybind snes_keybinds_1[] = {
|
||||||
{ SSNES_STATE_SLOT_PLUS, SDLK_F7, NO_BTN, AXIS_NONE },
|
{ SSNES_STATE_SLOT_PLUS, SDLK_F7, NO_BTN, AXIS_NONE },
|
||||||
{ SSNES_AUDIO_INPUT_RATE_PLUS, SDLK_KP_PLUS, NO_BTN, AXIS_NONE },
|
{ SSNES_AUDIO_INPUT_RATE_PLUS, SDLK_KP_PLUS, NO_BTN, AXIS_NONE },
|
||||||
{ SSNES_AUDIO_INPUT_RATE_MINUS, SDLK_KP_MINUS, NO_BTN, AXIS_NONE },
|
{ SSNES_AUDIO_INPUT_RATE_MINUS, SDLK_KP_MINUS, NO_BTN, AXIS_NONE },
|
||||||
|
{ SSNES_REWIND, SDLK_r, NO_BTN, AXIS_NONE },
|
||||||
{ -1 }
|
{ -1 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
1
driver.h
1
driver.h
|
@ -36,6 +36,7 @@ enum
|
||||||
SSNES_STATE_SLOT_MINUS,
|
SSNES_STATE_SLOT_MINUS,
|
||||||
SSNES_AUDIO_INPUT_RATE_PLUS,
|
SSNES_AUDIO_INPUT_RATE_PLUS,
|
||||||
SSNES_AUDIO_INPUT_RATE_MINUS,
|
SSNES_AUDIO_INPUT_RATE_MINUS,
|
||||||
|
SSNES_REWIND,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct snes_keybind
|
struct snes_keybind
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "record/ffemu.h"
|
#include "record/ffemu.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
|
#include "rewind.h"
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
@ -35,7 +36,7 @@
|
||||||
|
|
||||||
|
|
||||||
#define MAX_PLAYERS 5
|
#define MAX_PLAYERS 5
|
||||||
#define MAX_BINDS 22 // Needs to be increased every time there are new binds added.
|
#define MAX_BINDS 23 // Needs to be increased every time there are new binds added.
|
||||||
#define SSNES_NO_JOYPAD 0xFFFF
|
#define SSNES_NO_JOYPAD 0xFFFF
|
||||||
struct settings
|
struct settings
|
||||||
{
|
{
|
||||||
|
@ -145,6 +146,10 @@ struct global
|
||||||
|
|
||||||
msg_queue_t *msg_queue;
|
msg_queue_t *msg_queue;
|
||||||
|
|
||||||
|
state_manager_t *state_manager;
|
||||||
|
void *state_buf;
|
||||||
|
bool rewind_enable;
|
||||||
|
|
||||||
#ifdef HAVE_FFMPEG
|
#ifdef HAVE_FFMPEG
|
||||||
ffemu_t *rec;
|
ffemu_t *rec;
|
||||||
char record_path[256];
|
char record_path[256];
|
||||||
|
|
6
rewind.c
6
rewind.c
|
@ -21,6 +21,8 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
//#include <stdio.h>
|
||||||
|
|
||||||
struct state_manager
|
struct state_manager
|
||||||
{
|
{
|
||||||
uint64_t *buffer;
|
uint64_t *buffer;
|
||||||
|
@ -120,6 +122,7 @@ static void reassign_bottom(state_manager_t *state)
|
||||||
|
|
||||||
static void generate_delta(state_manager_t *state, const void *data, bool aligned)
|
static void generate_delta(state_manager_t *state, const void *data, bool aligned)
|
||||||
{
|
{
|
||||||
|
unsigned patch_size = 0;
|
||||||
bool crossed = false;
|
bool crossed = false;
|
||||||
const uint32_t *old_state = state->tmp_state;
|
const uint32_t *old_state = state->tmp_state;
|
||||||
uint32_t *new_state = aligned ? (uint32_t*)data : state->scratch_buf;
|
uint32_t *new_state = aligned ? (uint32_t*)data : state->scratch_buf;
|
||||||
|
@ -138,6 +141,7 @@ static void generate_delta(state_manager_t *state, const void *data, bool aligne
|
||||||
// This, if states don't really differ much, we'll save lots of space :) Hopefully this will work really well with save states.
|
// This, if states don't really differ much, we'll save lots of space :) Hopefully this will work really well with save states.
|
||||||
if (xor)
|
if (xor)
|
||||||
{
|
{
|
||||||
|
patch_size++;
|
||||||
state->buffer[state->top_ptr] = (i << 32) | xor;
|
state->buffer[state->top_ptr] = (i << 32) | xor;
|
||||||
state->top_ptr = (state->top_ptr + 1) % state->buf_size;
|
state->top_ptr = (state->top_ptr + 1) % state->buf_size;
|
||||||
|
|
||||||
|
@ -148,6 +152,8 @@ static void generate_delta(state_manager_t *state, const void *data, bool aligne
|
||||||
|
|
||||||
if (crossed)
|
if (crossed)
|
||||||
reassign_bottom(state);
|
reassign_bottom(state);
|
||||||
|
|
||||||
|
//fprintf(stderr, "DELTA SIZE: %u, ORIG SIZE: %u\n", (unsigned)patch_size << 3, (unsigned)state->state_size << 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool state_manager_push(state_manager_t *state, const void *data, bool aligned)
|
bool state_manager_push(state_manager_t *state, const void *data, bool aligned)
|
||||||
|
|
38
ssnes.c
38
ssnes.c
|
@ -28,6 +28,7 @@
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "dynamic.h"
|
#include "dynamic.h"
|
||||||
#include "record/ffemu.h"
|
#include "record/ffemu.h"
|
||||||
|
#include "rewind.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#ifdef HAVE_SRC
|
#ifdef HAVE_SRC
|
||||||
#include <samplerate.h>
|
#include <samplerate.h>
|
||||||
|
@ -636,6 +637,22 @@ static void deinit_msg_queue(void)
|
||||||
msg_queue_free(g_extern.msg_queue);
|
msg_queue_free(g_extern.msg_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void init_rewind(void)
|
||||||
|
{
|
||||||
|
size_t serial_size = snes_serialize_size();
|
||||||
|
g_extern.state_buf = malloc(serial_size);
|
||||||
|
snes_serialize(g_extern.state_buf, serial_size);
|
||||||
|
g_extern.state_manager = state_manager_new(serial_size, 10 << 20, g_extern.state_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deinit_rewind(void)
|
||||||
|
{
|
||||||
|
if (g_extern.state_manager)
|
||||||
|
state_manager_free(g_extern.state_manager);
|
||||||
|
if (g_extern.state_buf)
|
||||||
|
free(g_extern.state_buf);
|
||||||
|
}
|
||||||
|
|
||||||
static void fill_pathnames(void)
|
static void fill_pathnames(void)
|
||||||
{
|
{
|
||||||
switch (g_extern.game_type)
|
switch (g_extern.game_type)
|
||||||
|
@ -773,6 +790,24 @@ static void check_input_rate(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_rewind(void)
|
||||||
|
{
|
||||||
|
if (!g_extern.state_manager)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (driver.input->key_pressed(driver.input_data, SSNES_REWIND))
|
||||||
|
{
|
||||||
|
void *buf;
|
||||||
|
if (state_manager_pop(g_extern.state_manager, &buf))
|
||||||
|
snes_unserialize(buf, snes_serialize_size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snes_serialize(g_extern.state_buf, snes_serialize_size());
|
||||||
|
state_manager_push(g_extern.state_manager, g_extern.state_buf, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void do_state_checks(void)
|
static void do_state_checks(void)
|
||||||
{
|
{
|
||||||
set_fast_forward_button(driver.input->key_pressed(driver.input_data, SSNES_FAST_FORWARD_KEY));
|
set_fast_forward_button(driver.input->key_pressed(driver.input_data, SSNES_FAST_FORWARD_KEY));
|
||||||
|
@ -781,6 +816,7 @@ static void do_state_checks(void)
|
||||||
check_savestates();
|
check_savestates();
|
||||||
check_fullscreen();
|
check_fullscreen();
|
||||||
check_input_rate();
|
check_input_rate();
|
||||||
|
check_rewind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -817,6 +853,7 @@ int main(int argc, char *argv[])
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
init_msg_queue();
|
init_msg_queue();
|
||||||
|
init_rewind();
|
||||||
|
|
||||||
// Main loop
|
// Main loop
|
||||||
for(;;)
|
for(;;)
|
||||||
|
@ -833,6 +870,7 @@ int main(int argc, char *argv[])
|
||||||
psnes_run();
|
psnes_run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deinit_rewind();
|
||||||
deinit_msg_queue();
|
deinit_msg_queue();
|
||||||
#ifdef HAVE_FFMPEG
|
#ifdef HAVE_FFMPEG
|
||||||
deinit_recording();
|
deinit_recording();
|
||||||
|
|
Loading…
Reference in New Issue