summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2017-11-24 12:04:02 -0800
committerMichael Pavone <pavone@retrodev.com>2017-11-24 12:04:02 -0800
commit27b829ffc447758832cbd7ab2f9b7e427928d687 (patch)
tree6e4b2b813b40dbfb9200b7a9e85719aa47f78f1c
parentb21ebe75d412c72441be8a63c202641cc5ff4dfa (diff)
Refactored save slot related logic to reduce duplication and allow reuse in new UI. Get state loading/saving mostly working in new UI
--HG-- branch : nuklear_ui
-rw-r--r--Makefile2
-rw-r--r--blastem.h1
-rw-r--r--genesis.c18
-rw-r--r--io.c1
-rw-r--r--menu.c107
-rw-r--r--nuklear_ui/blastem_nuklear.c73
-rw-r--r--saves.c77
-rw-r--r--saves.h19
-rw-r--r--sms.c12
9 files changed, 173 insertions, 137 deletions
diff --git a/Makefile b/Makefile
index b0e5171..61b8203 100644
--- a/Makefile
+++ b/Makefile
@@ -130,7 +130,7 @@ NUKLEAROBJS=nuklear_ui/font.o nuklear_ui/blastem_nuklear.o
MAINOBJS=blastem.o system.o genesis.o debug.o gdb_remote.o vdp.o render_sdl.o ppm.o io.o romdb.o hash.o menu.o xband.o \
realtec.o i2c.o nor.o sega_mapper.o multi_game.o serialize.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) \
- $(TRANSOBJS) $(AUDIOOBJS) $(NUKLEAROBJS) paths.o
+ $(TRANSOBJS) $(AUDIOOBJS) $(NUKLEAROBJS) paths.o saves.o
ifeq ($(CPU),x86_64)
CFLAGS+=-DX86_64 -m64
diff --git a/blastem.h b/blastem.h
index 96fd879..b08075d 100644
--- a/blastem.h
+++ b/blastem.h
@@ -15,7 +15,6 @@ extern system_header *current_system;
extern char *save_state_path;
extern char *save_filename;
extern uint8_t use_native_states;
-#define QUICK_SAVE_SLOT 10
void reload_media(void);
void lockon_media(char *lock_on_path);
diff --git a/genesis.c b/genesis.c
index 4514b9e..16b3b6b 100644
--- a/genesis.c
+++ b/genesis.c
@@ -15,6 +15,7 @@
#include "util.h"
#include "debug.h"
#include "gdb_remote.h"
+#include "saves.h"
#define MCLKS_NTSC 53693175
#define MCLKS_PAL 53203395
@@ -359,18 +360,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80);
}
}
- char *save_path;
- if (slot == QUICK_SAVE_SLOT) {
- save_path = save_state_path;
- } else {
- char slotname[] = "slot_0.state";
- slotname[5] = '0' + slot;
- if (!use_native_states) {
- strcpy(slotname + 7, "gst");
- }
- char const *parts[] = {gen->header.save_dir, PATH_SEP, slotname};
- save_path = alloc_concat_m(3, parts);
- }
+ char *save_path = get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst");
if (use_native_states) {
serialize_buffer state;
init_serialize(&state);
@@ -381,9 +371,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
save_gst(gen, save_path, address);
}
printf("Saved state to %s\n", save_path);
- if (slot != QUICK_SAVE_SLOT) {
- free(save_path);
- }
+ free(save_path);
} else if(gen->header.save_state) {
context->sync_cycle = context->current_cycle + 1;
}
diff --git a/io.c b/io.c
index 22881c1..8cdb249 100644
--- a/io.c
+++ b/io.c
@@ -23,6 +23,7 @@
#include "render.h"
#include "util.h"
#include "menu.h"
+#include "saves.h"
#ifndef DISABLE_NUKLEAR
#include "nuklear_ui/blastem_nuklear.h"
#endif
diff --git a/menu.c b/menu.c
index be5090c..969b44a 100644
--- a/menu.c
+++ b/menu.c
@@ -9,7 +9,7 @@
#include "util.h"
#include "gst.h"
#include "paths.h"
-#include "m68k_internal.h" //needed for get_native_address_trans, should be eliminated once handling of PC is cleaned up
+#include "saves.h"
static menu_context *get_menu(genesis_context *gen)
{
@@ -94,18 +94,6 @@ void copy_to_guest(m68k_context *m68k, uint32_t guest_addr, char *src, size_t to
#define SAVE_INFO_BUFFER_SIZE (11*40)
-#ifdef _WIN32
-#define localtime_r(a,b) localtime(a)
-//windows inclues seem not to like certain single letter defines from m68k_internal.h
-//get rid of them here
-#undef X
-#undef N
-#undef Z
-#undef V
-#undef C
-#include <windows.h>
-#endif
-
uint32_t copy_dir_entry_to_guest(uint32_t dst, m68k_context *m68k, char *name, uint8_t is_dir)
{
uint8_t *dest = get_native_pointer(dst, (void **)m68k->mem_pointers, &m68k->options->gen);
@@ -307,63 +295,19 @@ void * menu_write_w(uint32_t address, void * context, uint16_t value)
char *cur = buffer;
if (gen->header.next_context && gen->header.next_context->save_dir) {
char *end = buffer + SAVE_INFO_BUFFER_SIZE;
- char slotfile[] = "slot_0.state";
- char slotfilegst[] = "slot_0.gst";
- char const * parts[3] = {gen->header.next_context->save_dir, PATH_SEP, slotfile};
- char const * partsgst[3] = {gen->header.next_context->save_dir, PATH_SEP, slotfilegst};
- struct tm ltime;
- char *fname;
- time_t modtime;
- for (int i = 0; i < 10 && cur < end; i++)
+ uint32_t num_slots;
+ save_slot_info *slots = get_slot_info(gen->header.next_context, &num_slots);
+ for (uint32_t i = 0; i < num_slots; i++)
{
- slotfile[5] = i + '0';
- fname = alloc_concat_m(3, parts);
- modtime = get_modification_time(fname);
- free(fname);
- if (modtime) {
- cur += snprintf(cur, end-cur, "Slot %d - ", i);
- cur += strftime(cur, end-cur, "%c", localtime_r(&modtime, &ltime));
-
- } else {
- slotfilegst[5] = i + '0';
- fname = alloc_concat_m(3, partsgst);
- modtime = get_modification_time(fname);
- free(fname);
- if (modtime) {
- cur += snprintf(cur, end-cur, "Slot %d - ", i);
- cur += strftime(cur, end-cur, "%c", localtime_r(&modtime, &ltime));
- } else {
- cur += snprintf(cur, end-cur, "Slot %d - EMPTY", i);
- }
- }
- //advance past the null terminator for this entry
- cur++;
- }
- if (cur < end) {
- parts[2] = "quicksave.state";
- fname = alloc_concat_m(3, parts);
- modtime = get_modification_time(fname);
- free(fname);
- if (modtime) {
- cur += strftime(cur, end-cur, "Quick - %c", localtime_r(&modtime, &ltime));
- } else {
- parts[2] = "quicksave.gst";
- fname = alloc_concat_m(3, parts);
- modtime = get_modification_time(fname);
- free(fname);
- if (modtime) {
- cur += strftime(cur, end-cur, "Quick - %c", localtime_r(&modtime, &ltime));
- } else if ((end-cur) > strlen("Quick - EMPTY")){
- cur += strlen(strcpy(cur, "Quick - EMPTY"));
- }
- }
- //advance past the null terminator for this entry
- cur++;
- if (cur < end) {
- //terminate the list
- *(cur++) = 0;
+ size_t desc_len = strlen(slots[i].desc) + 1;//+1 for string terminator
+ char *after = cur + desc_len + 1;//+1 for list terminator
+ if (after > cur) {
+ desc_len -= after - cur;
}
+ memcpy(cur, slots[i].desc, desc_len);
+ cur = after;
}
+ *cur = 0;//terminate list
} else {
*(cur++) = 0;
*(cur++) = 0;
@@ -383,36 +327,7 @@ void * menu_write_w(uint32_t address, void * context, uint16_t value)
if (gen->header.next_context && gen->header.next_context->save_dir) {
if (!gen->header.next_context->load_state(gen->header.next_context, dst)) {
break;
- }/*
- char numslotname[] = "slot_0.state";
- char *slotname;
- if (dst == QUICK_SAVE_SLOT) {
- slotname = "quicksave.state";
- } else {
- numslotname[5] = '0' + dst;
- slotname = numslotname;
- }
- char const *parts[] = {gen->header.next_context->save_dir, PATH_SEP, slotname};
- char *statepath = alloc_concat_m(3, parts);
- gen->header.next_context->load_state
- genesis_context *next = (genesis_context *)gen->header.next_context;
- deserialize_buffer state;
- uint32_t pc = 0;
- if (load_from_file(&state, statepath)) {
- genesis_deserialize(&state, next);
- free(state.data);
- //HACK
- pc = next->m68k->last_prefetch_address;
- } else {
- strcpy(statepath + strlen(statepath)-strlen("state"), "gst");
- pc = load_gst(next, statepath);
- }
- free(statepath);
- if (!pc) {
- break;
}
- next->m68k->resume_pc = get_native_address_trans(next->m68k, pc);
- */
}
m68k->should_return = 1;
break;
diff --git a/nuklear_ui/blastem_nuklear.c b/nuklear_ui/blastem_nuklear.c
index 2042402..a486a64 100644
--- a/nuklear_ui/blastem_nuklear.c
+++ b/nuklear_ui/blastem_nuklear.c
@@ -8,6 +8,7 @@
#include "../render_sdl.h"
#include "../util.h"
#include "../paths.h"
+#include "../saves.h"
#include "../blastem.h"
static struct nk_context *context;
@@ -78,6 +79,59 @@ typedef struct {
view_fun next_view;
} menu_item;
+static save_slot_info *slots;
+static uint32_t num_slots, selected_slot;
+
+void view_choose_state(struct nk_context *context, uint8_t is_load)
+{
+ uint32_t width = render_width();
+ uint32_t height = render_height();
+ if (nk_begin(context, "Slot Picker", nk_rect(0, 0, width, height), 0)) {
+ nk_layout_row_static(context, height - 100, width - 60, 1);
+ if (nk_group_begin(context, "Select Save Slot", NK_WINDOW_BORDER | NK_WINDOW_TITLE)) {
+ nk_layout_row_static(context, 28, width-100, 1);
+ if (!slots) {
+ slots = get_slot_info(current_system, &num_slots);
+ }
+ for (uint32_t i = 0; i < num_slots; i++)
+ {
+ int selected = i == selected_slot;
+ nk_selectable_label(context, slots[i].desc, NK_TEXT_ALIGN_LEFT, &selected);
+ if (selected && (slots[i].modification_time || !is_load)) {
+ selected_slot = i;
+ }
+ }
+ nk_group_end(context);
+ }
+ nk_layout_row_static(context, 52, width > 600 ? 300 : width / 2, 2);
+ if (nk_button_label(context, "Back")) {
+ current_view = previous_view;
+ }
+ if (is_load) {
+ if (nk_button_label(context, "Load")) {
+ current_system->load_state(current_system, selected_slot);
+ current_view = view_play;
+ }
+ } else {
+ if (nk_button_label(context, "Save")) {
+ current_system->save_state = selected_slot + 1;
+ current_view = view_play;
+ }
+ }
+ nk_end(context);
+ }
+}
+
+void view_save_state(struct nk_context *context)
+{
+ view_choose_state(context, 0);
+}
+
+void view_load_state(struct nk_context *context)
+{
+ view_choose_state(context, 1);
+}
+
static void menu(struct nk_context *context, uint32_t num_entries, const menu_item *items)
{
const uint32_t button_height = 52;
@@ -100,26 +154,15 @@ static void menu(struct nk_context *context, uint32_t num_entries, const menu_it
if (!current_view) {
exit(0);
}
+ if (current_view == view_save_state || current_view == view_load_state) {
+ free_slot_info(slots);
+ slots = NULL;
+ }
}
}
nk_layout_space_end(context);
}
-void view_choose_state(struct nk_context *context, uint8_t is_load)
-{
-
-}
-
-void view_save_state(struct nk_context *context)
-{
- view_choose_state(context, 0);
-}
-
-void view_load_state(struct nk_context *context)
-{
- view_choose_state(context, 1);
-}
-
void view_pause(struct nk_context *context)
{
static menu_item items[] = {
diff --git a/saves.c b/saves.c
new file mode 100644
index 0000000..955c959
--- /dev/null
+++ b/saves.c
@@ -0,0 +1,77 @@
+#include <string.h>
+#include <stdlib.h>
+#include "saves.h"
+#include "util.h"
+
+#ifdef _WIN32
+#define localtime_r(a,b) localtime(a)
+#include <windows.h>
+#endif
+//0123456789012345678901234678
+//Slot N - December 31st, XXXX
+#define MAX_DESC_SIZE 40
+
+char *get_slot_name(system_header *system, uint32_t slot_index, char *ext)
+{
+ if (!system->save_dir) {
+ return NULL;
+ }
+ char *fname;
+ if (slot_index < 10) {
+ size_t name_len = strlen("slot_N.") + strlen(ext) + 1;
+ fname = malloc(name_len);
+ snprintf(fname, name_len, "slot_%d.%s", slot_index, ext);
+ } else {
+ size_t name_len = strlen("quicksave.") + strlen(ext) + 1;
+ fname = malloc(name_len);
+ snprintf(fname, name_len, "quicksave.%s", ext);
+ }
+ char const *parts[] = {system->save_dir, PATH_SEP, fname};
+ char *ret = alloc_concat_m(3, parts);
+ free(fname);
+ return ret;
+}
+
+save_slot_info *get_slot_info(system_header *system, uint32_t *num_out)
+{
+ save_slot_info *dst = calloc(11, sizeof(save_slot_info));
+ time_t modtime;
+ struct tm ltime;
+ for (uint32_t i = 0; i <= QUICK_SAVE_SLOT; i++)
+ {
+ char * cur = dst[i].desc = malloc(MAX_DESC_SIZE);
+ char * fname = get_slot_name(system, i, "state");
+ modtime = get_modification_time(fname);
+ free(fname);
+ if (!modtime && system->type == SYSTEM_GENESIS) {
+ fname = get_slot_name(system, i, "gst");
+ modtime = get_modification_time(fname);
+ free(fname);
+ }
+ if (i == QUICK_SAVE_SLOT) {
+ cur += snprintf(cur, MAX_DESC_SIZE, "Quick - ");
+ } else {
+ cur += snprintf(cur, MAX_DESC_SIZE, "Slot %d - ", i);
+ }
+ if (modtime) {
+ strftime(cur, MAX_DESC_SIZE - (cur - dst->desc), "%c", localtime_r(&modtime, &ltime));
+ } else {
+ strcpy(cur, "EMPTY");
+ }
+ dst[i].modification_time;
+ }
+ *num_out = QUICK_SAVE_SLOT + 1;
+ return dst;
+}
+
+void free_slot_info(save_slot_info *slots)
+{
+ if (!slots) {
+ return;
+ }
+ for (uint32_t i = 0; i <= QUICK_SAVE_SLOT; i++)
+ {
+ free(slots[i].desc);
+ }
+ free(slots);
+}
diff --git a/saves.h b/saves.h
new file mode 100644
index 0000000..6964e82
--- /dev/null
+++ b/saves.h
@@ -0,0 +1,19 @@
+#ifndef SAVES_H_
+#define SAVES_H_
+
+#include <time.h>
+#include <stdint.h>
+#include "system.h"
+
+#define QUICK_SAVE_SLOT 10
+
+typedef struct {
+ char *desc;
+ time_t modification_time;
+} save_slot_info;
+
+char *get_slot_name(system_header *system, uint32_t slot_index, char *ext);
+save_slot_info *get_slot_info(system_header *system, uint32_t *num_out);
+void free_slot_info(save_slot_info *slots);
+
+#endif //SAVES_H_
diff --git a/sms.c b/sms.c
index 45b950c..9bbad17 100644
--- a/sms.c
+++ b/sms.c
@@ -6,6 +6,7 @@
#include "render.h"
#include "util.h"
#include "debug.h"
+#include "saves.h"
static void *memory_io_write(uint32_t location, void *vcontext, uint8_t value)
{
@@ -292,20 +293,13 @@ void sms_deserialize(deserialize_buffer *buf, sms_context *sms)
static void save_state(sms_context *sms, uint8_t slot)
{
- char *save_path;
- if (slot == QUICK_SAVE_SLOT) {
- save_path = save_state_path;
- } else {
- char slotname[] = "slot_0.state";
- slotname[5] = '0' + slot;
- char const *parts[] = {sms->header.save_dir, PATH_SEP, slotname};
- save_path = alloc_concat_m(3, parts);
- }
+ char *save_path = get_slot_name(&sms->header, slot, "state");
serialize_buffer state;
init_serialize(&state);
sms_serialize(sms, &state);
save_to_file(&state, save_path);
printf("Saved state to %s\n", save_path);
+ free(save_path);
free(state.data);
}