# HG changeset patch # User Michael Pavone # Date 1511553842 28800 # Node ID da1dce39e8462386eb24f0ee9d071bef08711fbe # Parent 1cdd7f492af8aa672f255024c93c17abfe489212 Refactored save slot related logic to reduce duplication and allow reuse in new UI. Get state loading/saving mostly working in new UI diff -r 1cdd7f492af8 -r da1dce39e846 Makefile --- a/Makefile Wed Nov 22 11:18:36 2017 -0800 +++ b/Makefile Fri Nov 24 12:04:02 2017 -0800 @@ -130,7 +130,7 @@ 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 -r 1cdd7f492af8 -r da1dce39e846 blastem.h --- a/blastem.h Wed Nov 22 11:18:36 2017 -0800 +++ b/blastem.h Fri Nov 24 12:04:02 2017 -0800 @@ -15,7 +15,6 @@ 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 -r 1cdd7f492af8 -r da1dce39e846 genesis.c --- a/genesis.c Wed Nov 22 11:18:36 2017 -0800 +++ b/genesis.c Fri Nov 24 12:04:02 2017 -0800 @@ -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 @@ 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 @@ 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 -r 1cdd7f492af8 -r da1dce39e846 io.c --- a/io.c Wed Nov 22 11:18:36 2017 -0800 +++ b/io.c Fri Nov 24 12:04:02 2017 -0800 @@ -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 -r 1cdd7f492af8 -r da1dce39e846 menu.c --- a/menu.c Wed Nov 22 11:18:36 2017 -0800 +++ b/menu.c Fri Nov 24 12:04:02 2017 -0800 @@ -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 @@ #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 -#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 @@ 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, <ime)); - - } 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, <ime)); - } else { - cur += snprintf(cur, end-cur, "Slot %d - EMPTY", i); - } + 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; } - //advance past the null terminator for this entry - cur++; + memcpy(cur, slots[i].desc, desc_len); + cur = after; } - 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, <ime)); - } 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, <ime)); - } 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; - } - } + *cur = 0;//terminate list } else { *(cur++) = 0; *(cur++) = 0; @@ -383,36 +327,7 @@ 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 -r 1cdd7f492af8 -r da1dce39e846 nuklear_ui/blastem_nuklear.c --- a/nuklear_ui/blastem_nuklear.c Wed Nov 22 11:18:36 2017 -0800 +++ b/nuklear_ui/blastem_nuklear.c Fri Nov 24 12:04:02 2017 -0800 @@ -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 @@ 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 @@ 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 -r 1cdd7f492af8 -r da1dce39e846 saves.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/saves.c Fri Nov 24 12:04:02 2017 -0800 @@ -0,0 +1,77 @@ +#include +#include +#include "saves.h" +#include "util.h" + +#ifdef _WIN32 +#define localtime_r(a,b) localtime(a) +#include +#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, <ime)); + } 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 -r 1cdd7f492af8 -r da1dce39e846 saves.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/saves.h Fri Nov 24 12:04:02 2017 -0800 @@ -0,0 +1,19 @@ +#ifndef SAVES_H_ +#define SAVES_H_ + +#include +#include +#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 -r 1cdd7f492af8 -r da1dce39e846 sms.c --- a/sms.c Wed Nov 22 11:18:36 2017 -0800 +++ b/sms.c Fri Nov 24 12:04:02 2017 -0800 @@ -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 @@ 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); }