diff --git a/command.c b/command.c index 8676b49c6d..abff46c982 100644 --- a/command.c +++ b/command.c @@ -286,6 +286,7 @@ static const struct cmd_map map[] = { { "MUTE", RARCH_MUTE }, { "OSK", RARCH_OSK }, { "NETPLAY_FLIP", RARCH_NETPLAY_FLIP }, + { "NETPLAY_GAME_WATCH", RARCH_NETPLAY_GAME_WATCH }, { "SLOWMOTION", RARCH_SLOWMOTION }, { "VOLUME_UP", RARCH_VOLUME_UP }, { "VOLUME_DOWN", RARCH_VOLUME_DOWN }, @@ -2369,6 +2370,11 @@ bool command_event(enum event_command cmd, void *data) case CMD_EVENT_NETPLAY_FLIP_PLAYERS: #ifdef HAVE_NETWORKING netplay_driver_ctl(RARCH_NETPLAY_CTL_FLIP_PLAYERS, NULL); +#endif + break; + case CMD_EVENT_NETPLAY_GAME_WATCH: +#ifdef HAVE_NETWORKING + netplay_driver_ctl(RARCH_NETPLAY_CTL_GAME_WATCH, NULL); #endif break; case CMD_EVENT_FULLSCREEN_TOGGLE: diff --git a/command.h b/command.h index 4c47cd5224..3131915d0a 100644 --- a/command.h +++ b/command.h @@ -173,6 +173,8 @@ enum event_command CMD_EVENT_NETPLAY_DEINIT, /* Flip netplay players. */ CMD_EVENT_NETPLAY_FLIP_PLAYERS, + /* Switch between netplay gaming and watching. */ + CMD_EVENT_NETPLAY_GAME_WATCH, /* Initializes BSV movie. */ CMD_EVENT_BSV_MOVIE_INIT, /* Deinitializes BSV movie. */ diff --git a/config.def.h b/config.def.h index cc7fd22b1f..d44acd7f50 100644 --- a/config.def.h +++ b/config.def.h @@ -987,7 +987,8 @@ static const struct retro_keybind retro_keybinds_1[] = { { true, RARCH_SCREENSHOT, MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, RETROK_F8, NO_BTN, 0, AXIS_NONE }, { true, RARCH_MUTE, MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, RETROK_F9, NO_BTN, 0, AXIS_NONE }, { true, RARCH_OSK, MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, RETROK_F12, NO_BTN, 0, AXIS_NONE }, - { true, RARCH_NETPLAY_FLIP, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FLIP, RETROK_i, NO_BTN, 0, AXIS_NONE }, + { true, RARCH_NETPLAY_FLIP, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FLIP, RETROK_UNKNOWN, NO_BTN, 0, AXIS_NONE }, + { true, RARCH_NETPLAY_GAME_WATCH, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, RETROK_i, NO_BTN, 0, AXIS_NONE }, { true, RARCH_SLOWMOTION, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION, RETROK_e, NO_BTN, 0, AXIS_NONE }, { true, RARCH_ENABLE_HOTKEY, MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, RETROK_UNKNOWN, NO_BTN, 0, AXIS_NONE }, { true, RARCH_VOLUME_UP, MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, RETROK_KP_PLUS, NO_BTN, 0, AXIS_NONE }, diff --git a/input/input_config.c b/input/input_config.c index eb6861afcf..a978d0af36 100644 --- a/input/input_config.c +++ b/input/input_config.c @@ -125,7 +125,8 @@ const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL] = { DECLARE_META_BIND(2, screenshot, RARCH_SCREENSHOT, MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT), DECLARE_META_BIND(2, audio_mute, RARCH_MUTE, MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE), DECLARE_META_BIND(2, osk_toggle, RARCH_OSK, MENU_ENUM_LABEL_VALUE_INPUT_META_OSK), - DECLARE_META_BIND(2, netplay_flip_players, RARCH_NETPLAY_FLIP, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FLIP), + DECLARE_META_BIND(2, netplay_flip_players_1_2, RARCH_NETPLAY_FLIP, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FLIP), + DECLARE_META_BIND(2, netplay_game_watch, RARCH_NETPLAY_GAME_WATCH, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH), DECLARE_META_BIND(2, slowmotion, RARCH_SLOWMOTION, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION), DECLARE_META_BIND(2, enable_hotkey, RARCH_ENABLE_HOTKEY, MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY), DECLARE_META_BIND(2, volume_up, RARCH_VOLUME_UP, MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP), diff --git a/input/input_defines.h b/input/input_defines.h index 9040d6df7b..c626512773 100644 --- a/input/input_defines.h +++ b/input/input_defines.h @@ -72,6 +72,7 @@ enum RARCH_MUTE, RARCH_OSK, RARCH_NETPLAY_FLIP, + RARCH_NETPLAY_GAME_WATCH, RARCH_SLOWMOTION, RARCH_ENABLE_HOTKEY, RARCH_VOLUME_UP, diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index e364b1723f..ace43f647f 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -91,6 +91,10 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) snprintf(s, len, "Netplay flip users."); break; + case RARCH_NETPLAY_GAME_WATCH: + snprintf(s, len, + "Netplay toggle play/spectate mode."); + break; case RARCH_SLOWMOTION: snprintf(s, len, "Hold for slowmotion."); @@ -1787,6 +1791,10 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) snprintf(s, len, "Netplay flip users."); break; + case MENU_ENUM_LABEL_NETPLAY_GAME_WATCH: + snprintf(s, len, + "Netplay toggle play/spectate mode."); + break; case MENU_ENUM_LABEL_CHEAT_INDEX_PLUS: snprintf(s, len, "Increment cheat index.\n"); diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index cb1271d5fd..5b84cfa9aa 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -714,6 +714,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, "Audio mute toggle") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FLIP, "Netplay flip users") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, + "Netplay toggle play/spectate mode") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, "On-screen keyboard toggle") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, diff --git a/msg_hash.h b/msg_hash.h index 0ca9835b8a..3f975fc885 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -530,6 +530,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FLIP, + MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION, MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, @@ -940,6 +941,7 @@ enum msg_hash_enums MENU_LABEL(UNDO_SAVE_STATE), MENU_LABEL(NETPLAY_FLIP_PLAYERS), + MENU_LABEL(NETPLAY_GAME_WATCH), MENU_LABEL(CHEAT_INDEX_MINUS), MENU_LABEL(CHEAT_INDEX_PLUS), MENU_LABEL(SHADER_NEXT), diff --git a/network/netplay/netplay.c b/network/netplay/netplay.c index c4a244c578..50a4d5eaec 100644 --- a/network/netplay/netplay.c +++ b/network/netplay/netplay.c @@ -831,6 +831,7 @@ static bool netplay_get_cmd(netplay_t *netplay, /* Mark them as not playing anymore */ connection->mode = NETPLAY_CONNECTION_SPECTATING; + netplay->connected_players &= ~(1<player); /* Tell everyone */ payload[1] = htonl(connection->player); @@ -924,8 +925,6 @@ static bool netplay_get_cmd(netplay_t *netplay, return netplay_cmd_nak(netplay, connection); frame = ntohl(payload[0]); - if (frame != netplay->server_frame_count) - return netplay_cmd_nak(netplay, connection); /* We're changing past input, so must replay it */ if (frame < netplay->self_frame_count) @@ -941,6 +940,9 @@ static bool netplay_get_cmd(netplay_t *netplay, /* A change to me! */ if (mode & NETPLAY_CMD_MODE_BIT_PLAYING) { + if (frame != netplay->server_frame_count) + return netplay_cmd_nak(netplay, connection); + /* Hooray, I get to play now! */ if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING) return netplay_cmd_nak(netplay, connection); @@ -992,6 +994,9 @@ static bool netplay_get_cmd(netplay_t *netplay, /* Somebody else is joining or parting */ if (mode & NETPLAY_CMD_MODE_BIT_PLAYING) { + if (frame != netplay->server_frame_count) + return netplay_cmd_nak(netplay, connection); + netplay->connected_players |= (1<read_ptr[player] = netplay->server_ptr; @@ -1978,6 +1983,35 @@ static void netplay_flip_users(netplay_t *netplay) netplay->flip_frame = flip_frame; } +/* Toggle between play mode and spectate mode */ +static void netplay_toggle_play_spectate(netplay_t *netplay) +{ + uint32_t cmd; + size_t i; + + if (netplay->is_server) + { + /* FIXME */ + return; + } + + if (netplay->self_mode == NETPLAY_CONNECTION_PLAYING) + { + /* Switch to spectator mode immediately */ + netplay->self_mode = NETPLAY_CONNECTION_SPECTATING; + cmd = NETPLAY_CMD_SPECTATE; + } + else if (netplay->self_mode == NETPLAY_CONNECTION_SPECTATING) + { + /* Switch only after getting permission */ + cmd = NETPLAY_CMD_PLAY; + } + else return; + + netplay_send_raw_cmd_all(netplay, NULL, cmd, NULL, 0); +} + + /** * netplay_free: * @netplay : pointer to netplay object @@ -2426,6 +2460,9 @@ bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data) netplay_flip_users(netplay_data); } break; + case RARCH_NETPLAY_CTL_GAME_WATCH: + netplay_toggle_play_spectate(netplay_data); + break; case RARCH_NETPLAY_CTL_PAUSE: netplay_frontend_paused(netplay_data, true); break; diff --git a/network/netplay/netplay.h b/network/netplay/netplay.h index ec84805c97..61e63a24a5 100644 --- a/network/netplay/netplay.h +++ b/network/netplay/netplay.h @@ -33,6 +33,7 @@ enum rarch_netplay_ctl_state { RARCH_NETPLAY_CTL_NONE = 0, RARCH_NETPLAY_CTL_FLIP_PLAYERS, + RARCH_NETPLAY_CTL_GAME_WATCH, RARCH_NETPLAY_CTL_POST_FRAME, RARCH_NETPLAY_CTL_PRE_FRAME, RARCH_NETPLAY_CTL_ENABLE_SERVER, diff --git a/runloop.c b/runloop.c index 29e413d7fe..c05f34aa65 100644 --- a/runloop.c +++ b/runloop.c @@ -922,6 +922,9 @@ static enum runloop_state runloop_check_state( #ifdef HAVE_NETWORKING tmp = runloop_cmd_triggered(trigger_input, RARCH_NETPLAY_FLIP); netplay_driver_ctl(RARCH_NETPLAY_CTL_FLIP_PLAYERS, &tmp); + tmp = runloop_cmd_triggered(trigger_input, RARCH_NETPLAY_GAME_WATCH); + if (tmp) + netplay_driver_ctl(RARCH_NETPLAY_CTL_GAME_WATCH, NULL); tmp = runloop_cmd_triggered(trigger_input, RARCH_FULLSCREEN_TOGGLE_KEY); #endif