From bd7bc68b856fff6b3d601cce1c9b723ff238ee51 Mon Sep 17 00:00:00 2001 From: cadmic Date: Sun, 22 Oct 2023 11:06:12 -0700 Subject: [PATCH 1/3] Zero out unused settings for forward compatibility --- src/gz/settings.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gz/settings.c b/src/gz/settings.c index 9cde88e1..4c646218 100644 --- a/src/gz/settings.c +++ b/src/gz/settings.c @@ -31,6 +31,7 @@ static _Bool settings_validate(struct settings *settings) void settings_load_default(void) { + memset(&settings_store, 0, sizeof(settings_store)); settings_store.header.version = SETTINGS_VERSION; settings_store.header.data_size = sizeof(settings_store.data); struct settings_data *d = &settings_store.data; From 65c2ef0fd254033b169ca276c2b36882f67be97e Mon Sep 17 00:00:00 2001 From: cadmic Date: Sun, 22 Oct 2023 12:10:54 -0700 Subject: [PATCH 2/3] Display timer in hundredths of a second --- src/gz/gz.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gz/gz.c b/src/gz/gz.c index a7178489..56a28a97 100644 --- a/src/gz/gz.c +++ b/src/gz/gz.c @@ -371,23 +371,23 @@ static void main_hook(void) gz.timer_counter_prev = gz.cpu_counter; if (settings->bits.timer) { int64_t count = gz.cpu_counter + gz.timer_counter_offset; - int tenths = count * 10 / gz.cpu_counter_freq; - int seconds = tenths / 10; + int hundredths = count * 100 / gz.cpu_counter_freq; + int seconds = hundredths / 100; int minutes = seconds / 60; int hours = minutes / 60; - tenths %= 10; + hundredths %= 100; seconds %= 60; minutes %= 60; int x = settings->timer_x; int y = settings->timer_y; gfx_mode_set(GFX_MODE_COLOR, GPACK_RGBA8888(0xC0, 0xC0, 0xC0, alpha)); if (hours > 0) - gfx_printf(font, x, y, "%d:%02d:%02d.%d", - hours, minutes, seconds, tenths); + gfx_printf(font, x, y, "%d:%02d:%02d.%02d", + hours, minutes, seconds, hundredths); else if (minutes > 0) - gfx_printf(font, x, y, "%d:%02d.%d", minutes, seconds, tenths); + gfx_printf(font, x, y, "%d:%02d.%02d", minutes, seconds, hundredths); else - gfx_printf(font, x, y, "%d.%d", seconds, tenths); + gfx_printf(font, x, y, "%d.%02d", seconds, hundredths); } /* draw menus */ From 4947076535364903b38bba9b64d3c23c79b8760b Mon Sep 17 00:00:00 2001 From: cadmic Date: Sun, 22 Oct 2023 12:34:27 -0700 Subject: [PATCH 3/3] Implement settings to help with macro timing --- USAGE.md | 39 +++++++++++++++++++++++---------------- src/gz/gz.c | 22 +++++++++++++++++----- src/gz/gz.h | 1 + src/gz/gz_macro.c | 45 ++++++++++++++++++++++++++++++++++++++++----- src/gz/settings.c | 2 ++ src/gz/settings.h | 2 ++ 6 files changed, 85 insertions(+), 26 deletions(-) diff --git a/USAGE.md b/USAGE.md index 435ec6ac..455a63d2 100644 --- a/USAGE.md +++ b/USAGE.md @@ -341,22 +341,29 @@ _Note:_ States can not be used in the file select menu or on the n64 logo. _See also:_ [4 Issues with savestates](#4-issues-with-savestates). #### 2.7.1 Settings -This menu provides advanced settings for savestates and macro recording. gz -implements certain hacks to keep macros in sync (See -[5 About frame advancing and recording](#5-about-frame-advancing-and-recording)). -All hacks are enabled by default. Disabling the hacks can cause issues and -desyncs, and should only be done if required. For example, when recording a -setup that is sensitive to room loading lag. For such use cases, the hacks -should not be kept disabled longer than necessary (i.e. disable only when -recording that particular section). - -The **wii vc camera** setting enables a camera quirk that is present on the Wii -VC versions of the game. This setting can be used to sync macros that were made -on Wii VC when played back on N64, or vice versa. It is enabled by default on -Wii VC versions of gz. The **ignore state's z-target** option will keep the -current z-targetting mode when loading states that have a different setting, -which is useful for practicing with savestates made by someone with different -preferences. +This menu provides advanced settings for savestates and macro recording: + +- **recording settings**: gz implements certain hacks to keep macros in sync + (See + [5 About frame advancing and recording](#5-about-frame-advancing-and-recording) + ). All hacks are enabled by default. Disabling the hacks can cause issues + and desyncs, and should only be done if required (for example, when + recording a setup that is sensitive to room loading lag). For such use + cases, the hacks should not be kept disabled longer than necessary (i.e. + disable only when recording that particular section). +- **playback settings**: The **pause when playback ends** setting will + automatically freeze gameplay when macro playback completes, instead of + letting the game continue to run. The **start/stop timer automatically** + setting will start or stop the timer when gameplay is unpaused or paused + respectively, which can be useful for timing macros especially when + combined with **pause when playback ends**. +- **game settings**: The **wii vc camera** setting enables a camera quirk + that is present on the Wii VC versions of the game. This setting can be + used to sync macros that were made on Wii VC when played back on N64, or + vice versa. It is enabled by default on Wii VC versions of gz. The + **ignore state's z-target** option will keep the current z-targeting mode + when loading states that have a different setting, which is useful for + practicing with savestates made by someone with different preferences. #### 2.7.2 Virtual controller Press the checkbox next to the controller number to override the game's input diff --git a/src/gz/gz.c b/src/gz/gz.c index 56a28a97..735c8f93 100644 --- a/src/gz/gz.c +++ b/src/gz/gz.c @@ -39,7 +39,6 @@ static void update_cpu_counter(void) static void main_hook(void) { - update_cpu_counter(); input_update(); gfx_mode_init(); @@ -365,10 +364,7 @@ static void main_hook(void) } gz.frame_counter += z64_file.gameinfo->update_rate; - /* execute and draw timer */ - if (!gz.timer_active) - gz.timer_counter_offset -= gz.cpu_counter - gz.timer_counter_prev; - gz.timer_counter_prev = gz.cpu_counter; + /* draw timer */ if (settings->bits.timer) { int64_t count = gz.cpu_counter + gz.timer_counter_offset; int hundredths = count * 100 / gz.cpu_counter_freq; @@ -651,6 +647,9 @@ HOOK void input_hook(void) } else gz.reset_flag = reset; + if (settings->bits.macro_pause_done && + gz.movie_frame == gz.movie_input.size) + gz.frames_queued = 1; } } } @@ -684,7 +683,16 @@ HOOK void disp_hook(z64_disp_buf_t *disp_buf, Gfx *buf, uint32_t size) static void state_main_hook(void) { + /* update timer */ + update_cpu_counter(); + if (!gz.timer_active) + gz.timer_counter_offset -= gz.cpu_counter - gz.timer_counter_prev; + gz.timer_counter_prev = gz.cpu_counter; + if (gz.frames_queued != 0) { + if (settings->bits.macro_sync_timer && !gz.game_running) + gz.timer_active = 1; + gz.game_running = 1; if (gz.frames_queued > 0) --gz.frames_queued; /* reset sync event flags */ @@ -719,6 +727,9 @@ static void state_main_hook(void) } } else { + if (settings->bits.macro_sync_timer && gz.game_running) + gz.timer_active = 0; + gz.game_running = 0; z64_gfx_t *gfx = z64_ctxt.gfx; if (z64_ctxt.state_frames != 0) { /* copy gfx buffer from previous frame */ @@ -1065,6 +1076,7 @@ static void init(void) gz.day_time_prev = z64_file.day_time; gz.target_day_time = -1; gz.frames_queued = -1; + gz.game_running = 1; gz.movie_state = MOVIE_IDLE; vector_init(&gz.movie_input, sizeof(struct movie_input)); vector_init(&gz.movie_seed, sizeof(struct movie_seed)); diff --git a/src/gz/gz.h b/src/gz/gz.h index 4369d7b5..69c83e88 100644 --- a/src/gz/gz.h +++ b/src/gz/gz.h @@ -154,6 +154,7 @@ struct gz uint16_t day_time_prev; int target_day_time; int32_t frames_queued; + _Bool game_running; struct zu_disp_p z_disp_p; uint32_t disp_hook_size[4]; uint32_t disp_hook_p[4]; diff --git a/src/gz/gz_macro.c b/src/gz/gz_macro.c index 5ea3b3dd..ecd08c63 100644 --- a/src/gz/gz_macro.c +++ b/src/gz/gz_macro.c @@ -586,6 +586,36 @@ static int hack_room_load_proc(struct menu_item *item, return 0; } +static int macro_pause_done_proc(struct menu_item *item, + enum menu_callback_reason reason, + void *data) +{ + if (reason == MENU_CALLBACK_SWITCH_ON) + settings->bits.macro_pause_done = 1; + else if (reason == MENU_CALLBACK_SWITCH_OFF) + settings->bits.macro_pause_done = 0; + else if (reason == MENU_CALLBACK_THINK) { + if (menu_checkbox_get(item) != settings->bits.macro_pause_done) + menu_checkbox_set(item, settings->bits.macro_pause_done); + } + return 0; +} + +static int macro_sync_timer_proc(struct menu_item *item, + enum menu_callback_reason reason, + void *data) +{ + if (reason == MENU_CALLBACK_SWITCH_ON) + settings->bits.macro_sync_timer = 1; + else if (reason == MENU_CALLBACK_SWITCH_OFF) + settings->bits.macro_sync_timer = 0; + else if (reason == MENU_CALLBACK_THINK) { + if (menu_checkbox_get(item) != settings->bits.macro_sync_timer) + menu_checkbox_set(item, settings->bits.macro_sync_timer); + } + return 0; +} + static int wiivc_cam_proc(struct menu_item *item, enum menu_callback_reason reason, void *data) @@ -792,11 +822,16 @@ struct menu *gz_macro_menu(void) menu_add_static(&menu_settings, 4, 3, "ocarina sync hack", 0xC0C0C0); menu_add_checkbox(&menu_settings, 2, 4, hack_room_load_proc, NULL); menu_add_static(&menu_settings, 4, 4, "room load hack", 0xC0C0C0); - menu_add_static(&menu_settings, 0, 5, "game settings", 0xC0C0C0); - menu_add_checkbox(&menu_settings, 2, 6, wiivc_cam_proc, NULL); - menu_add_static(&menu_settings, 4, 6, "wii vc camera", 0xC0C0C0); - menu_add_checkbox(&menu_settings, 2, 7, byte_ztarget_proc, NULL); - menu_add_static(&menu_settings, 4, 7, "ignore state's z-target", 0xC0C0C0); + menu_add_static(&menu_settings, 0, 5, "playback settings", 0xC0C0C0); + menu_add_checkbox(&menu_settings, 2, 6, macro_pause_done_proc, NULL); + menu_add_static(&menu_settings, 4, 6, "pause when playback ends", 0xC0C0C0); + menu_add_checkbox(&menu_settings, 2, 7, macro_sync_timer_proc, NULL); + menu_add_static(&menu_settings, 4, 7, "start/stop timer automatically", 0xC0C0C0); + menu_add_static(&menu_settings, 0, 8, "game settings", 0xC0C0C0); + menu_add_checkbox(&menu_settings, 2, 9, wiivc_cam_proc, NULL); + menu_add_static(&menu_settings, 4, 9, "wii vc camera", 0xC0C0C0); + menu_add_checkbox(&menu_settings, 2, 10, byte_ztarget_proc, NULL); + menu_add_static(&menu_settings, 4, 10, "ignore state's z-target", 0xC0C0C0); /* populate virtual pad menu */ menu_vcont.selector = menu_add_submenu(&menu_vcont, 0, 0, NULL, "return"); diff --git a/src/gz/settings.c b/src/gz/settings.c index 4c646218..22620bd3 100644 --- a/src/gz/settings.c +++ b/src/gz/settings.c @@ -76,6 +76,8 @@ void settings_load_default(void) d->bits.holl_view_xlu = 1; d->bits.holl_view_all = 0; d->bits.watches_visible = 1; + d->bits.macro_pause_done = 0; + d->bits.macro_sync_timer = 0; d->menu_x = 20; d->menu_y = 64; d->input_display_x = 20; diff --git a/src/gz/settings.h b/src/gz/settings.h index 05eb4239..0353e55f 100644 --- a/src/gz/settings.h +++ b/src/gz/settings.h @@ -137,6 +137,8 @@ struct settings_bits uint32_t holl_view_xlu : 1; uint32_t holl_view_all : 1; uint32_t watches_visible : 1; + uint32_t macro_pause_done : 1; + uint32_t macro_sync_timer : 1; }; struct settings_data