From 47f5e2315ecf069741962d66077164e36ecf24e4 Mon Sep 17 00:00:00 2001 From: MysterD Date: Tue, 22 Sep 2020 18:25:17 -0700 Subject: [PATCH] Synchronized LLL puzzle --- src/game/behaviors/bowser_puzzle_piece.inc.c | 78 ++++++++++++++++++- src/game/behaviors/cannon.inc.c | 2 +- src/game/behaviors/mips.inc.c | 4 +- src/pc/controller/controller_keyboard_debug.c | 2 +- src/pc/network/network.h | 4 +- src/pc/network/network_player.c | 8 ++ src/pc/network/network_player.h | 1 + src/pc/network/packets/packet_object.c | 4 +- 8 files changed, 93 insertions(+), 10 deletions(-) diff --git a/src/game/behaviors/bowser_puzzle_piece.inc.c b/src/game/behaviors/bowser_puzzle_piece.inc.c index 14db4de62..f984dbb4e 100644 --- a/src/game/behaviors/bowser_puzzle_piece.inc.c +++ b/src/game/behaviors/bowser_puzzle_piece.inc.c @@ -114,19 +114,87 @@ void bhv_lll_bowser_puzzle_spawn_pieces(f32 pieceWidth) { o->oAction++; } +static u8 bowserPuzzleTimer = 0; +static u8 bowserPuzzleOnAction = 0; +static u8 bowserPuzzleServerAction = 0; +static u32 bowserPuzzleTxRxAction = 0; +static u8 bowserPuzzleRx[MAX_PLAYERS] = { 0 }; + +static void bhv_lll_bowser_puzzle_networking_received(u8 fromLocalIndex) { + if (gNetworkType == NT_CLIENT) { + if (bowserPuzzleTxRxAction != (u8)(bowserPuzzleOnAction + 1)) { return; } + bowserPuzzleServerAction = bowserPuzzleTxRxAction; + return; + } + if (bowserPuzzleTxRxAction != bowserPuzzleOnAction) { return; } + bowserPuzzleRx[fromLocalIndex] = bowserPuzzleTxRxAction; +} + +static void bhv_lll_bowser_puzzle_networking(void) { + if (!network_sync_object_initialized(o)) { + bowserPuzzleTimer = 0; + bowserPuzzleOnAction = 0; + bowserPuzzleServerAction = 0; + bowserPuzzleTxRxAction = 0; + for (int i = 0; i < MAX_PLAYERS; i++) { bowserPuzzleRx[i] = 0; } + + struct SyncObject* so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); + network_init_object_field(o, &bowserPuzzleTxRxAction); + so->on_received_post = bhv_lll_bowser_puzzle_networking_received; + } + + if (bowserPuzzleTimer < 24) { + bowserPuzzleTimer++; + return; + } + + if (gNetworkType == NT_SERVER) { + if (bowserPuzzleTimer == 24) { + bowserPuzzleTimer++; + bowserPuzzleOnAction++; + bowserPuzzleTxRxAction = bowserPuzzleOnAction; + network_send_object(o); + return; + } + + for (int i = 1; i < MAX_PLAYERS; i++) { + if (gNetworkPlayers[i].connected && bowserPuzzleRx[i] != bowserPuzzleOnAction) { return; } + } + + // received from all, continue + bowserPuzzleTimer = 0; + return; + } + + if (gNetworkType == NT_CLIENT) { + if (bowserPuzzleServerAction == (u8)(bowserPuzzleOnAction + 1)) { + bowserPuzzleOnAction++; + bowserPuzzleTimer = 0; + bowserPuzzleTxRxAction = bowserPuzzleServerAction; + network_send_object(o); + } + return; + } +} + /* * Does the initial spawn of the puzzle pieces and then waits to spawn 5 coins. */ void bhv_lll_bowser_puzzle_loop(void) { s32 i; UNUSED struct Object *sp28; + struct Object* player = nearest_player_to_object(o); + int distanceToPlayer = dist_between_objects(o, player); + + bhv_lll_bowser_puzzle_networking(); + switch (o->oAction) { case BOWSER_PUZZLE_ACT_SPAWN_PIECES: bhv_lll_bowser_puzzle_spawn_pieces(480.0f); break; case BOWSER_PUZZLE_ACT_WAIT_FOR_COMPLETE: // If both completion flags are set and Mario is within 1000 units... - if (o->oBowserPuzzleCompletionFlags == 3 && o->oDistanceToMario < 1000.0f) { + if (o->oBowserPuzzleCompletionFlags == 3 && distanceToPlayer < 1000.0f) { // Spawn 5 coins. for (i = 0; i < 5; i++) sp28 = spawn_object(o, MODEL_YELLOW_COIN, bhvSingleCoinGetsSpawned); @@ -164,11 +232,17 @@ void bhv_lll_bowser_puzzle_piece_update(void) { s8 *nextAction = o->oBowserPuzzlePieceNextAction; // If Mario is standing on this puzzle piece, set a flag in the parent. - if (gMarioObject->platform == o) + if (cur_obj_is_any_player_on_platform()) o->parentObj->oBowserPuzzleCompletionFlags = 1; // If we should advance to the next action... if (o->oBowserPuzzlePieceContinuePerformingAction == 0) { + // if we haven't received an event from everyone, do not continue execution + if (bowserPuzzleTimer >= 24) { + cur_obj_change_action(0); + return; + } + // Start doing the next action. cur_obj_change_action(*nextAction); diff --git a/src/game/behaviors/cannon.inc.c b/src/game/behaviors/cannon.inc.c index e0a072645..15877cec9 100644 --- a/src/game/behaviors/cannon.inc.c +++ b/src/game/behaviors/cannon.inc.c @@ -151,7 +151,7 @@ u8 cannon_ignore_remote_updates(void) { return ((gNetworkType == NT_SERVER) && o->oCannonIsLocal); } -static void cannon_on_received_pos(void) { +static void cannon_on_received_pos(u8 fromLocalIndex) { // check if we're on in the cannon too struct MarioState* m = &gMarioStates[0]; if (m->action != ACT_IN_CANNON) { return; } diff --git a/src/game/behaviors/mips.inc.c b/src/game/behaviors/mips.inc.c index 39e7ebdf0..33b2543df 100644 --- a/src/game/behaviors/mips.inc.c +++ b/src/game/behaviors/mips.inc.c @@ -4,11 +4,11 @@ static u32 mipsPrevHeldState = 0; -static void bhv_mips_on_received_pre(void) { +static void bhv_mips_on_received_pre(u8 fromLocalIndex) { mipsPrevHeldState = o->oHeldState; } -static void bhv_mips_on_received_post(void) { +static void bhv_mips_on_received_post(u8 fromLocalIndex) { if (mipsPrevHeldState == HELD_HELD && o->oHeldState == HELD_FREE) { cur_obj_init_animation(0); } diff --git a/src/pc/controller/controller_keyboard_debug.c b/src/pc/controller/controller_keyboard_debug.c index 5075b2503..1ddba6dd2 100644 --- a/src/pc/controller/controller_keyboard_debug.c +++ b/src/pc/controller/controller_keyboard_debug.c @@ -5,7 +5,7 @@ #ifdef DEBUG -static u8 warpToLevel = LEVEL_BOB; +static u8 warpToLevel = LEVEL_LLL; #define SCANCODE_0 0x0B #define SCANCODE_3 0x04 diff --git a/src/pc/network/network.h b/src/pc/network/network.h index 12c6ea1c7..29c76854e 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -52,8 +52,8 @@ struct SyncObject { bool hasStandardFields; float maxUpdateRate; u8 (*ignore_if_true)(void); - void (*on_received_pre)(void); - void (*on_received_post)(void); + void (*on_received_pre)(u8 fromLocalIndex); + void (*on_received_post)(u8 fromLocalIndex); void* extraFields[MAX_SYNC_OBJECT_FIELDS]; }; diff --git a/src/pc/network/network_player.c b/src/pc/network/network_player.c index 18c2dd3ae..2b48d83fa 100644 --- a/src/pc/network/network_player.c +++ b/src/pc/network/network_player.c @@ -14,6 +14,14 @@ bool network_player_any_connected(void) { return false; } +u8 network_player_connected_count(void) { + u8 count = 0; + for (int i = 1; i < MAX_PLAYERS; i++) { + if (gNetworkPlayers[i].connected) { count++; } + } + return count; +} + void network_player_update(void) { float elapsed = (clock() - gLastNetworkSend) / (float)CLOCKS_PER_SEC; if (elapsed > NETWORK_PLAYER_TIMEOUT / 3.0f) { diff --git a/src/pc/network/network_player.h b/src/pc/network/network_player.h index 1a7941be6..22e599396 100644 --- a/src/pc/network/network_player.h +++ b/src/pc/network/network_player.h @@ -29,6 +29,7 @@ extern struct NetworkPlayer* gNetworkPlayerLocal; extern struct NetworkPlayer* gNetworkPlayerServer; bool network_player_any_connected(void); +u8 network_player_connected_count(void); void network_player_update(void); u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex); u8 network_player_disconnected(u8 globalIndex); diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index 785a6ce9e..84cb79f2f 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -378,7 +378,7 @@ void network_receive_object(struct Packet* p) { extern struct Object* gCurrentObject; struct Object* tmp = gCurrentObject; gCurrentObject = so->o; - (*so->on_received_pre)(); + (*so->on_received_pre)(p->localIndex); gCurrentObject = tmp; } @@ -398,7 +398,7 @@ void network_receive_object(struct Packet* p) { extern struct Object* gCurrentObject; struct Object* tmp = gCurrentObject; gCurrentObject = so->o; - (*so->on_received_post)(); + (*so->on_received_post)(p->localIndex); gCurrentObject = tmp; } }