From ff6177a56ab93e9ee1d4282b04770f745994147f Mon Sep 17 00:00:00 2001 From: MysterD Date: Thu, 3 Sep 2020 18:11:42 -0700 Subject: [PATCH] Prevented softlock and entity duplication when both grab at the same time As reported by somario360: After grabbing the small box at the same time, one of two results can happen. There will be a fake cloned box that will only be visually in the other player's hands, or one player will be stuck in the punching animation until the other player lets go of the box, in which the box goes into the stuck player's hands. Now escapes from action if the grab fails, preventing a softlock. And now if both players report having the same object, the client will drop their copy. Fixes #14 --- src/game/mario.c | 8 ++++++++ src/game/mario_actions_object.c | 12 ++++++++++++ src/game/mario_actions_stationary.c | 2 ++ 3 files changed, 22 insertions(+) diff --git a/src/game/mario.c b/src/game/mario.c index 6f720bf0..de02da8b 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -1854,6 +1854,14 @@ s32 execute_mario_action(UNUSED struct Object *o) { if (gFreezeMario < 1 && gDialogID != -1) { gFreezeMario = 1; } } + // two-player hack: drop held object if server is holding it + if (networkType == NT_CLIENT && gMarioState->playerIndex == 0 && gMarioState->heldObj != NULL) { + u8 inCutscene = ((gMarioState->action & ACT_GROUP_MASK) != ACT_GROUP_CUTSCENE); + if (!inCutscene && gMarioState->heldObj == gMarioStates[0].heldObj) { + drop_and_set_mario_action(gMarioState, ACT_IDLE, 0); + } + } + u32 hangPreventionActions[MAX_HANG_PREVENTION]; u8 hangPreventionIndex = 0; diff --git a/src/game/mario_actions_object.c b/src/game/mario_actions_object.c index 664ecd71..56543ce3 100644 --- a/src/game/mario_actions_object.c +++ b/src/game/mario_actions_object.c @@ -11,6 +11,7 @@ #include "engine/math_util.h" #include "thread6.h" #include "behavior_data.h" +#include "pc/network/network.h" /** * Used by act_punching() to determine Mario's forward velocity during each @@ -191,6 +192,9 @@ s32 act_picking_up(struct MarioState *m) { if (m->heldObj != NULL) { play_sound_if_no_flag(m, SOUND_MARIO_HRMM, MARIO_MARIO_SOUND_PLAYED); m->actionState = 1; + } else { + set_mario_action(m, ACT_IDLE, 0); + return FALSE; } } @@ -326,6 +330,9 @@ s32 act_picking_up_bowser(struct MarioState *m) { play_sound(SOUND_MARIO_HRMM, m->marioObj->header.gfx.cameraToObject); if (m->playerIndex == 0) { network_send_object(m->heldObj); + } else { + set_mario_action(m, ACT_IDLE, 0); + return FALSE; } } } @@ -350,6 +357,9 @@ s32 act_holding_bowser(struct MarioState *m) { if (m->heldObj != NULL) { queue_rumble_data_mario(m, 5, 80); play_sound(SOUND_MARIO_HRMM, m->marioObj->header.gfx.cameraToObject); + } else { + set_mario_action(m, ACT_IDLE, 0); + return FALSE; } } } @@ -451,6 +461,8 @@ s32 act_releasing_bowser(struct MarioState *m) { } s32 check_common_object_cancels(struct MarioState *m) { + if (m->playerIndex != 0) { return FALSE; } + f32 waterSurface = m->waterLevel - 100; if (m->pos[1] < waterSurface) { return set_water_plunge_action(m); diff --git a/src/game/mario_actions_stationary.c b/src/game/mario_actions_stationary.c index 7ce9fb72..d95cf4c9 100644 --- a/src/game/mario_actions_stationary.c +++ b/src/game/mario_actions_stationary.c @@ -1108,6 +1108,8 @@ s32 act_first_person(struct MarioState *m) { } s32 check_common_stationary_cancels(struct MarioState *m) { + if (m->playerIndex != 0) { return FALSE; } + if (m->pos[1] < m->waterLevel - 100) { if (m->action == ACT_SPAWN_SPIN_LANDING) { load_level_init_text(0);