mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2026-04-28 04:51:40 +00:00
Completely rewrote level transition synchronization code
Should be snappier and less prone to crashes. I tested as many scenarios as I could think of and it has been rock solid. But time will tell. Also created a new debug log system, just so I could understand what the hell was going on with this code.
This commit is contained in:
parent
e48a9c25ab
commit
1e6c734ced
15 changed files with 274 additions and 174 deletions
|
|
@ -4305,6 +4305,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\include\behavior_table.h" />
|
<ClInclude Include="..\include\behavior_table.h" />
|
||||||
|
<ClInclude Include="..\src\pc\debuglog.h" />
|
||||||
<ClInclude Include="..\src\pc\network\network.h" />
|
<ClInclude Include="..\src\pc\network\network.h" />
|
||||||
<ClInclude Include="..\src\pc\network\socket\socket.h" />
|
<ClInclude Include="..\src\pc\network\socket\socket.h" />
|
||||||
<ClInclude Include="..\src\pc\network\socket\socket_linux.h" />
|
<ClInclude Include="..\src\pc\network\socket\socket_linux.h" />
|
||||||
|
|
|
||||||
|
|
@ -15928,5 +15928,8 @@
|
||||||
<ClInclude Include="..\include\behavior_table.h">
|
<ClInclude Include="..\include\behavior_table.h">
|
||||||
<Filter>Header Files\include</Filter>
|
<Filter>Header Files\include</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\pc\debuglog.h">
|
||||||
|
<Filter>Source Files\src\pc</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -12,6 +12,8 @@ if [ ! -f "$FILE" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$FILE --server 27015 --configfile sm64config_server.txt &
|
$FILE --server 27015 --configfile sm64config_server.txt &
|
||||||
|
#$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt &
|
||||||
|
#exit
|
||||||
|
|
||||||
# debug if cgdb exists
|
# debug if cgdb exists
|
||||||
if ! [ -x "$(command -v cgdb)" ]; then
|
if ! [ -x "$(command -v cgdb)" ]; then
|
||||||
|
|
|
||||||
|
|
@ -254,6 +254,7 @@ void load_area(s32 index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void unload_area(void) {
|
void unload_area(void) {
|
||||||
|
network_clear_sync_objects();
|
||||||
if (gCurrentArea != NULL) {
|
if (gCurrentArea != NULL) {
|
||||||
unload_objects_from_area(0, gCurrentArea->index);
|
unload_objects_from_area(0, gCurrentArea->index);
|
||||||
geo_call_global_function_nodes(&gCurrentArea->unk04->node, GEO_CONTEXT_AREA_UNLOAD);
|
geo_call_global_function_nodes(&gCurrentArea->unk04->node, GEO_CONTEXT_AREA_UNLOAD);
|
||||||
|
|
|
||||||
|
|
@ -3123,12 +3123,6 @@ s16 render_course_complete_screen(void) {
|
||||||
gInGameLanguage = eu_get_language();
|
gInGameLanguage = eu_get_language();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// if we went into a painting, no more save menu!
|
|
||||||
if (gInsidePainting == TRUE) {
|
|
||||||
gMenuMode = -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (gDialogBoxState) {
|
switch (gDialogBoxState) {
|
||||||
case DIALOG_STATE_OPENING:
|
case DIALOG_STATE_OPENING:
|
||||||
render_course_complete_lvl_info_and_hud_str();
|
render_course_complete_lvl_info_and_hud_str();
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,10 @@
|
||||||
|
|
||||||
#define WARP_NODE_CREDITS_MIN 0xF8
|
#define WARP_NODE_CREDITS_MIN 0xF8
|
||||||
|
|
||||||
|
u8 gControlledWarp = 0;
|
||||||
|
u8 gReceiveWarp = 0;
|
||||||
|
struct WarpDest gReceiveWarpDest = { 0 };
|
||||||
|
|
||||||
#ifdef VERSION_JP
|
#ifdef VERSION_JP
|
||||||
const char *credits01[] = { "1GAME DIRECTOR", "SHIGERU MIYAMOTO" };
|
const char *credits01[] = { "1GAME DIRECTOR", "SHIGERU MIYAMOTO" };
|
||||||
const char *credits02[] = { "2ASSISTANT DIRECTORS", "YOSHIAKI KOIZUMI", "TAKASHI TEZUKA" };
|
const char *credits02[] = { "2ASSISTANT DIRECTORS", "YOSHIAKI KOIZUMI", "TAKASHI TEZUKA" };
|
||||||
|
|
@ -169,11 +173,6 @@ s8 D_8032C9E0 = 0;
|
||||||
u8 unused3[4];
|
u8 unused3[4];
|
||||||
u8 unused4[2];
|
u8 unused4[2];
|
||||||
|
|
||||||
u8 gInsidePainting = false;
|
|
||||||
u8 gControlPainting = false;
|
|
||||||
u8 gWaitingForRemotePainting = false;
|
|
||||||
struct WarpNode gPaintingWarpNode = { 0 };
|
|
||||||
|
|
||||||
u16 level_control_timer(s32 timerOp) {
|
u16 level_control_timer(s32 timerOp) {
|
||||||
switch (timerOp) {
|
switch (timerOp) {
|
||||||
case TIMER_CONTROL_SHOW:
|
case TIMER_CONTROL_SHOW:
|
||||||
|
|
@ -361,7 +360,17 @@ void set_mario_initial_action(struct MarioState *m, u32 spawnType, u32 actionArg
|
||||||
set_mario_initial_cap_powerup(m);
|
set_mario_initial_cap_powerup(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
void init_mario_after_warp(void) {
|
void init_mario_after_warp(void) {
|
||||||
|
printf("===== init mario =====\n");
|
||||||
|
printf("areaIdx = %d\n", sWarpDest.areaIdx);
|
||||||
|
printf("arg = %d\n", sWarpDest.arg);
|
||||||
|
printf("levelNum = %d\n", sWarpDest.levelNum);
|
||||||
|
printf("nodeId = %d\n", sWarpDest.nodeId);
|
||||||
|
printf("type = %d\n", sWarpDest.type);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
struct ObjectWarpNode *spawnNode = area_get_warp_node(sWarpDest.nodeId);
|
struct ObjectWarpNode *spawnNode = area_get_warp_node(sWarpDest.nodeId);
|
||||||
u32 marioSpawnType = get_mario_spawn_type(spawnNode->object);
|
u32 marioSpawnType = get_mario_spawn_type(spawnNode->object);
|
||||||
|
|
||||||
|
|
@ -671,35 +680,7 @@ struct WarpNode *get_painting_warp_node(void) {
|
||||||
return warpNode;
|
return warpNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void initiate_painting_warp_node(struct WarpNode *pWarpNode, u8 instant) {
|
||||||
* Check is Mario has entered a painting, and if so, initiate a warp.
|
|
||||||
*/
|
|
||||||
void initiate_painting_warp(void) {
|
|
||||||
if (gCurrentArea->paintingWarpNodes != NULL && gMarioState->floor != NULL) {
|
|
||||||
struct WarpNode *pWarpNode = get_painting_warp_node();
|
|
||||||
|
|
||||||
if (pWarpNode != NULL) {
|
|
||||||
if (gMarioState->action & ACT_FLAG_INTANGIBLE) {
|
|
||||||
play_painting_eject_sound();
|
|
||||||
} else if (pWarpNode->id != 0) {
|
|
||||||
initiate_painting_warp_node(pWarpNode, false);
|
|
||||||
gControlPainting = true;
|
|
||||||
gWaitingForRemotePainting = (gNetworkType != NT_NONE);
|
|
||||||
set_mario_action(gMarioState, ACT_DISAPPEARED, 0);
|
|
||||||
gMarioState->marioObj->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void initiate_painting_warp_node(struct WarpNode *pWarpNode, u8 instant) {
|
|
||||||
if (pWarpNode->id == 0) { return; }
|
|
||||||
|
|
||||||
gControlPainting = false;
|
|
||||||
gWaitingForRemotePainting = false;
|
|
||||||
gInsidePainting = true;
|
|
||||||
|
|
||||||
gPaintingWarpNode = *pWarpNode;
|
|
||||||
struct WarpNode warpNode = *pWarpNode;
|
struct WarpNode warpNode = *pWarpNode;
|
||||||
|
|
||||||
if (!(warpNode.destLevel & 0x80)) {
|
if (!(warpNode.destLevel & 0x80)) {
|
||||||
|
|
@ -718,6 +699,26 @@ void initiate_painting_warp_node(struct WarpNode *pWarpNode, u8 instant) {
|
||||||
func_sh_8024C89C(1);
|
func_sh_8024C89C(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check is Mario has entered a painting, and if so, initiate a warp.
|
||||||
|
*/
|
||||||
|
void initiate_painting_warp(void) {
|
||||||
|
if (gCurrentArea->paintingWarpNodes != NULL && gMarioState->floor != NULL) {
|
||||||
|
struct WarpNode *pWarpNode = get_painting_warp_node();
|
||||||
|
|
||||||
|
if (pWarpNode != NULL) {
|
||||||
|
if (gMarioState->action & ACT_FLAG_INTANGIBLE) {
|
||||||
|
play_painting_eject_sound();
|
||||||
|
} else if (pWarpNode->id != 0) {
|
||||||
|
initiate_painting_warp_node(pWarpNode, false);
|
||||||
|
set_mario_action(gMarioState, ACT_DISAPPEARED, 0);
|
||||||
|
gMarioState->marioObj->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If there is not already a delayed warp, schedule one. The source node is
|
* If there is not already a delayed warp, schedule one. The source node is
|
||||||
* based on the warp operation and sometimes Mario's used object.
|
* based on the warp operation and sometimes Mario's used object.
|
||||||
|
|
@ -727,7 +728,6 @@ s16 level_trigger_warp(struct MarioState *m, s32 warpOp) {
|
||||||
// only allow for local player
|
// only allow for local player
|
||||||
if (m != &gMarioStates[0]) { return 0; }
|
if (m != &gMarioStates[0]) { return 0; }
|
||||||
|
|
||||||
gControlPainting = TRUE;
|
|
||||||
s32 val04 = TRUE;
|
s32 val04 = TRUE;
|
||||||
|
|
||||||
if (sDelayedWarpOp == WARP_OP_NONE) {
|
if (sDelayedWarpOp == WARP_OP_NONE) {
|
||||||
|
|
@ -996,6 +996,29 @@ void basic_update(UNUSED s16 *arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_for_received_warp(void) {
|
||||||
|
if (!gReceiveWarp) { return; }
|
||||||
|
gReceiveWarp = FALSE;
|
||||||
|
sWarpDest = gReceiveWarpDest;
|
||||||
|
|
||||||
|
if (!gControlledWarp) {
|
||||||
|
// force well behaved state
|
||||||
|
extern s16 gMenuMode;
|
||||||
|
reset_dialog_render_state();
|
||||||
|
level_set_transition(0, 0);
|
||||||
|
sTransitionUpdate = NULL;
|
||||||
|
gMenuMode = -1;
|
||||||
|
gPauseScreenMode = 1;
|
||||||
|
gSaveOptSelectIndex = 0;
|
||||||
|
gMarioStates[0].action = (gMarioStates[0].pos[1] <= gMarioStates[0].waterLevel) ? ACT_WATER_IDLE : ACT_IDLE;
|
||||||
|
gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_play_mode((sWarpDest.type == WARP_TYPE_CHANGE_LEVEL)
|
||||||
|
? PLAY_MODE_CHANGE_LEVEL
|
||||||
|
: PLAY_MODE_CHANGE_AREA);
|
||||||
|
}
|
||||||
|
|
||||||
int gPressedStart = 0;
|
int gPressedStart = 0;
|
||||||
|
|
||||||
s32 play_mode_normal(void) {
|
s32 play_mode_normal(void) {
|
||||||
|
|
@ -1036,14 +1059,14 @@ s32 play_mode_normal(void) {
|
||||||
set_play_mode(PLAY_MODE_CHANGE_LEVEL);
|
set_play_mode(PLAY_MODE_CHANGE_LEVEL);
|
||||||
} else {
|
} else {
|
||||||
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_LEVEL);
|
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_LEVEL);
|
||||||
network_send_level_warp();
|
network_send_level_warp(FALSE);
|
||||||
}
|
}
|
||||||
} else if (sTransitionTimer != 0) {
|
} else if (sTransitionTimer != 0) {
|
||||||
if (sWarpDest.type == WARP_TYPE_NOT_WARPING || gCurrentArea->index == sWarpDest.areaIdx) {
|
if (sWarpDest.type == WARP_TYPE_NOT_WARPING || gCurrentArea->index == sWarpDest.areaIdx) {
|
||||||
set_play_mode(PLAY_MODE_CHANGE_AREA);
|
set_play_mode(PLAY_MODE_CHANGE_AREA);
|
||||||
} else {
|
} else {
|
||||||
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_AREA);
|
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_AREA);
|
||||||
network_send_level_warp();
|
network_send_level_warp(FALSE);
|
||||||
}
|
}
|
||||||
} else if (pressed_pause()) {
|
} else if (pressed_pause()) {
|
||||||
lower_background_noise(1);
|
lower_background_noise(1);
|
||||||
|
|
@ -1053,6 +1076,8 @@ s32 play_mode_normal(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_for_received_warp();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1073,7 +1098,7 @@ s32 play_mode_paused(void) {
|
||||||
gSavedCourseNum = COURSE_NONE;
|
gSavedCourseNum = COURSE_NONE;
|
||||||
}
|
}
|
||||||
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_LEVEL);
|
set_play_mode((gNetworkType != NT_NONE) ? PLAY_MODE_SYNC_LEVEL : PLAY_MODE_CHANGE_LEVEL);
|
||||||
network_send_level_warp();
|
network_send_level_warp(FALSE);
|
||||||
} else if (gPauseScreenMode == 3) {
|
} else if (gPauseScreenMode == 3) {
|
||||||
// We should only be getting "int 3" to here
|
// We should only be getting "int 3" to here
|
||||||
initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0);
|
initiate_warp(LEVEL_CASTLE, 1, 0x1F, 0);
|
||||||
|
|
@ -1087,6 +1112,7 @@ s32 play_mode_paused(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 play_mode_sync_level(void) {
|
s32 play_mode_sync_level(void) {
|
||||||
|
check_for_received_warp();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1123,8 +1149,6 @@ void level_set_transition(s16 length, void (*updateFunction)(s16 *)) {
|
||||||
* Play the transition and then return to normal play mode.
|
* Play the transition and then return to normal play mode.
|
||||||
*/
|
*/
|
||||||
s32 play_mode_change_area(void) {
|
s32 play_mode_change_area(void) {
|
||||||
network_on_init_level();
|
|
||||||
|
|
||||||
//! This maybe was supposed to be sTransitionTimer == -1? sTransitionUpdate
|
//! This maybe was supposed to be sTransitionTimer == -1? sTransitionUpdate
|
||||||
// is never set to -1.
|
// is never set to -1.
|
||||||
if (sTransitionUpdate == (void (*)(s16 *)) - 1) {
|
if (sTransitionUpdate == (void (*)(s16 *)) - 1) {
|
||||||
|
|
@ -1222,7 +1246,6 @@ s32 update_level(void) {
|
||||||
|
|
||||||
s32 init_level(void) {
|
s32 init_level(void) {
|
||||||
reset_dialog_render_state();
|
reset_dialog_render_state();
|
||||||
network_on_init_level();
|
|
||||||
|
|
||||||
s32 val4 = 0;
|
s32 val4 = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,10 +69,6 @@ extern struct CreditsEntry *gCurrCreditsEntry;
|
||||||
|
|
||||||
extern struct MarioState gMarioStates[];
|
extern struct MarioState gMarioStates[];
|
||||||
extern struct MarioState *gMarioState;
|
extern struct MarioState *gMarioState;
|
||||||
extern u8 gInsidePainting;
|
|
||||||
extern u8 gControlPainting;
|
|
||||||
extern u8 gWaitingForRemotePainting;
|
|
||||||
extern struct WarpNode gPaintingWarpNode;
|
|
||||||
|
|
||||||
extern s16 sCurrPlayMode;
|
extern s16 sCurrPlayMode;
|
||||||
extern u16 D_80339ECA;
|
extern u16 D_80339ECA;
|
||||||
|
|
@ -140,7 +136,6 @@ void basic_update(UNUSED s16 *arg);
|
||||||
|
|
||||||
s32 init_level(void);
|
s32 init_level(void);
|
||||||
|
|
||||||
void initiate_painting_warp_node(struct WarpNode *pWarpNode, u8 instant);
|
|
||||||
void star_select_finish_selection(void);
|
void star_select_finish_selection(void);
|
||||||
|
|
||||||
#endif // LEVEL_UPDATE_H
|
#endif // LEVEL_UPDATE_H
|
||||||
|
|
|
||||||
|
|
@ -2083,8 +2083,6 @@ static void init_single_mario(struct MarioState* m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_mario(void) {
|
void init_mario(void) {
|
||||||
gInsidePainting = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < MAX_PLAYERS; i++) {
|
for (int i = 0; i < MAX_PLAYERS; i++) {
|
||||||
gMarioStates[i].playerIndex = i;
|
gMarioStates[i].playerIndex = i;
|
||||||
init_single_mario(&gMarioStates[i]);
|
init_single_mario(&gMarioStates[i]);
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
static struct Object *sStarSelectorModels[8];
|
static struct Object *sStarSelectorModels[8];
|
||||||
|
|
||||||
// The act the course is loaded as, affects whether some objects spawn.
|
// The act the course is loaded as, affects whether some objects spawn.
|
||||||
static s8 sLoadedActNum;
|
s8 sLoadedActNum;
|
||||||
|
|
||||||
// Number of obtained stars, excluding the coin star.
|
// Number of obtained stars, excluding the coin star.
|
||||||
static u8 sObtainedStars;
|
static u8 sObtainedStars;
|
||||||
|
|
@ -54,6 +54,8 @@ s8 sSelectableStarIndex = 0;
|
||||||
// Act Selector menu timer that keeps counting until you choose an act.
|
// Act Selector menu timer that keeps counting until you choose an act.
|
||||||
static s32 sActSelectorMenuTimer = 0;
|
static s32 sActSelectorMenuTimer = 0;
|
||||||
|
|
||||||
|
extern u8 gControlledWarp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Act Selector Star Type Loop Action
|
* Act Selector Star Type Loop Action
|
||||||
* Defines a select type for a star in the act selector.
|
* Defines a select type for a star in the act selector.
|
||||||
|
|
@ -156,7 +158,10 @@ void bhv_act_selector_init(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
render_100_coin_star(stars);
|
render_100_coin_star(stars);
|
||||||
gInsidePainting = TRUE;
|
|
||||||
|
if (gControlledWarp) {
|
||||||
|
network_send_inside_painting(TRUE, FALSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -175,7 +180,11 @@ void bhv_act_selector_loop(void) {
|
||||||
// Sometimes, stars are not selectable even if they appear on the screen.
|
// Sometimes, stars are not selectable even if they appear on the screen.
|
||||||
// This code filters selectable and non-selectable stars.
|
// This code filters selectable and non-selectable stars.
|
||||||
sSelectedActIndex = 0;
|
sSelectedActIndex = 0;
|
||||||
if (gControlPainting) { handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sObtainedStars); }
|
if (gControlledWarp) {
|
||||||
|
s8 oldIndex = sSelectableStarIndex;
|
||||||
|
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sObtainedStars);
|
||||||
|
if (oldIndex != sSelectableStarIndex) { network_send_inside_painting(FALSE, FALSE); }
|
||||||
|
}
|
||||||
starIndexCounter = sSelectableStarIndex;
|
starIndexCounter = sSelectableStarIndex;
|
||||||
for (i = 0; i < sVisibleStars; i++) {
|
for (i = 0; i < sVisibleStars; i++) {
|
||||||
// Can the star be selected (is it either already completed or the first non-completed mission)
|
// Can the star be selected (is it either already completed or the first non-completed mission)
|
||||||
|
|
@ -189,7 +198,11 @@ void bhv_act_selector_loop(void) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If all stars are collected then they are all selectable.
|
// If all stars are collected then they are all selectable.
|
||||||
if (gControlPainting) { handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sVisibleStars - 1); }
|
if (gControlledWarp) {
|
||||||
|
s8 oldIndex = sSelectableStarIndex;
|
||||||
|
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sVisibleStars - 1);
|
||||||
|
if (oldIndex != sSelectableStarIndex) { network_send_inside_painting(FALSE, FALSE); }
|
||||||
|
}
|
||||||
sSelectedActIndex = sSelectableStarIndex;
|
sSelectedActIndex = sSelectableStarIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,7 +302,7 @@ void print_act_selector_strings(void) {
|
||||||
create_dl_ortho_matrix();
|
create_dl_ortho_matrix();
|
||||||
|
|
||||||
// display disclaimer that the other player has to select
|
// display disclaimer that the other player has to select
|
||||||
if (!gControlPainting || gWaitingForRemotePainting) {
|
if (!gControlledWarp) {
|
||||||
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
|
||||||
u8 a = ((gGlobalTimer % 24) >= 12) ? 160 : 130;
|
u8 a = ((gGlobalTimer % 24) >= 12) ? 160 : 130;
|
||||||
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, a);
|
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, a);
|
||||||
|
|
@ -426,8 +439,7 @@ s32 lvl_init_act_selector_values_and_stars(UNUSED s32 arg, UNUSED s32 unused) {
|
||||||
* Also updates objects and returns act number selected after is chosen.
|
* Also updates objects and returns act number selected after is chosen.
|
||||||
*/
|
*/
|
||||||
s32 lvl_update_obj_and_load_act_button_actions(UNUSED s32 arg, UNUSED s32 unused) {
|
s32 lvl_update_obj_and_load_act_button_actions(UNUSED s32 arg, UNUSED s32 unused) {
|
||||||
u8 allowSelection = (gControlPainting && !gWaitingForRemotePainting);
|
if (gControlledWarp && sActSelectorMenuTimer >= 11) {
|
||||||
if (sActSelectorMenuTimer >= 11 && allowSelection) {
|
|
||||||
// If any of these buttons are pressed, play sound and go to course act
|
// If any of these buttons are pressed, play sound and go to course act
|
||||||
#ifndef VERSION_EU
|
#ifndef VERSION_EU
|
||||||
if ((gPlayer3Controller->buttonPressed & A_BUTTON)
|
if ((gPlayer3Controller->buttonPressed & A_BUTTON)
|
||||||
|
|
@ -458,8 +470,5 @@ void star_select_finish_selection(void) {
|
||||||
}
|
}
|
||||||
gDialogCourseActNum = sSelectedActIndex + 1;
|
gDialogCourseActNum = sSelectedActIndex + 1;
|
||||||
|
|
||||||
gInsidePainting = FALSE;
|
if (gControlledWarp) { network_send_inside_painting(FALSE, TRUE); }
|
||||||
if (gControlPainting) {
|
|
||||||
network_send_inside_painting(TRUE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
src/pc/debuglog.h
Normal file
34
src/pc/debuglog.h
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "pc/network/network.h"
|
||||||
|
|
||||||
|
#if defined(DEBUG) && !defined(DISABLE_MODULE_LOG)
|
||||||
|
static void debuglog_print_timestamp(void) {
|
||||||
|
time_t ltime = time(NULL);
|
||||||
|
char* str = asctime(localtime(<ime));
|
||||||
|
printf("%.*s", (int)strlen(str) - 1, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debuglog_print_network_type(void) {
|
||||||
|
printf(" [%s] ", NETWORKTYPESTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debuglog_print_short_filename(char* filename) {
|
||||||
|
char* last = strrchr(filename, '/');
|
||||||
|
if (last != NULL) {
|
||||||
|
printf("%s: ", last + 1);
|
||||||
|
} else {
|
||||||
|
printf("???: ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debuglog_print_log(char* filename) {
|
||||||
|
debuglog_print_timestamp();
|
||||||
|
debuglog_print_network_type();
|
||||||
|
debuglog_print_short_filename(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOG_INFO(...) ( debuglog_print_log(__FILE__), printf(__VA_ARGS__), printf("\n") )
|
||||||
|
#else
|
||||||
|
#define LOG_INFO(...)
|
||||||
|
#endif
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
#include "pc/configfile.h"
|
#include "pc/configfile.h"
|
||||||
|
|
||||||
// Mario 64 specific externs
|
// Mario 64 specific externs
|
||||||
extern u8 gInsidePainting;
|
|
||||||
extern s16 sCurrPlayMode;
|
extern s16 sCurrPlayMode;
|
||||||
|
|
||||||
enum NetworkType gNetworkType = NT_NONE;
|
enum NetworkType gNetworkType = NT_NONE;
|
||||||
|
|
@ -105,9 +104,7 @@ void network_update(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// figure out which update loop to run
|
// figure out which update loop to run
|
||||||
if (gInsidePainting && sCurrPlayMode == PLAY_MODE_CHANGE_LEVEL) {
|
if (sCurrPlayMode == PLAY_MODE_NORMAL || sCurrPlayMode == PLAY_MODE_PAUSED) {
|
||||||
network_update_inside_painting();
|
|
||||||
} else if (sCurrPlayMode == PLAY_MODE_NORMAL || sCurrPlayMode == PLAY_MODE_PAUSED) {
|
|
||||||
network_update_player();
|
network_update_player();
|
||||||
network_update_objects();
|
network_update_objects();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -131,12 +131,11 @@ void network_send_spawn_star(struct Object* o, u8 starType, f32 x, f32 y, f32 z,
|
||||||
void network_receive_spawn_star(struct Packet* p);
|
void network_receive_spawn_star(struct Packet* p);
|
||||||
|
|
||||||
// packet_level_warp.c
|
// packet_level_warp.c
|
||||||
void network_send_level_warp(void);
|
void network_send_level_warp(u8 done);
|
||||||
void network_receive_level_warp(struct Packet* p);
|
void network_receive_level_warp(struct Packet* p);
|
||||||
|
|
||||||
// packet_inside_painting.c
|
// packet_inside_painting.c
|
||||||
void network_update_inside_painting(void);
|
void network_send_inside_painting(u8 startOfEvent, u8 endOfEvent);
|
||||||
void network_send_inside_painting(bool reliable);
|
|
||||||
void network_receive_inside_painting(struct Packet* p);
|
void network_receive_inside_painting(struct Packet* p);
|
||||||
|
|
||||||
// packet_collect_star.c
|
// packet_collect_star.c
|
||||||
|
|
|
||||||
|
|
@ -2,81 +2,83 @@
|
||||||
#include "../network.h"
|
#include "../network.h"
|
||||||
#include "src/game/level_update.h"
|
#include "src/game/level_update.h"
|
||||||
#include "src/game/area.h"
|
#include "src/game/area.h"
|
||||||
|
#define DISABLE_MODULE_LOG
|
||||||
|
#include "pc/debuglog.h"
|
||||||
|
|
||||||
|
extern u8 gControlledWarp;
|
||||||
|
|
||||||
extern struct WarpNode gPaintingWarpNode;
|
|
||||||
extern u8 sSelectableStarIndex;
|
extern u8 sSelectableStarIndex;
|
||||||
extern u8 sSelectedActIndex;
|
extern u8 sSelectedActIndex;
|
||||||
|
extern s8 sLoadedActNum;
|
||||||
|
|
||||||
struct PacketDataInsidePainting {
|
#pragma pack(1)
|
||||||
u8 insidePainting;
|
struct PacketInsidePaintingData {
|
||||||
u8 controlPainting;
|
u8 seqId;
|
||||||
|
u8 eventId;
|
||||||
u8 starIndex;
|
u8 starIndex;
|
||||||
u8 actIndex;
|
u8 actIndex;
|
||||||
|
u8 loadedActNum;
|
||||||
};
|
};
|
||||||
|
|
||||||
static clock_t lastSentTime = 0;
|
static u8 eventId = 0;
|
||||||
static float minUpdateRate = 5.0f;
|
static u8 remoteFinishedEventId = (u8)-1;
|
||||||
static struct PacketDataInsidePainting lastSentData = { 0 };
|
|
||||||
|
|
||||||
static void populate_packet_data(struct PacketDataInsidePainting* data) {
|
static u8 seqId = 0;
|
||||||
data->insidePainting = gInsidePainting;
|
static u8 remoteLastSeqId = (u8)-1;
|
||||||
data->controlPainting = gControlPainting;
|
|
||||||
|
static void populate_packet_data(struct PacketInsidePaintingData* data) {
|
||||||
|
data->seqId = seqId;
|
||||||
|
data->eventId = eventId;
|
||||||
data->starIndex = sSelectableStarIndex;
|
data->starIndex = sSelectableStarIndex;
|
||||||
data->actIndex = sSelectedActIndex;
|
data->actIndex = sSelectedActIndex;
|
||||||
|
data->loadedActNum = sLoadedActNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_send_inside_painting(bool reliable) {
|
void network_send_inside_painting(u8 startOfEvent, u8 endOfEvent) {
|
||||||
struct PacketDataInsidePainting data = { 0 };
|
if (startOfEvent) { eventId++; }
|
||||||
|
struct PacketInsidePaintingData data = { 0 };
|
||||||
populate_packet_data(&data);
|
populate_packet_data(&data);
|
||||||
|
|
||||||
struct Packet p;
|
struct Packet p;
|
||||||
packet_init(&p, PACKET_INSIDE_PAINTING, reliable);
|
packet_init(&p, PACKET_INSIDE_PAINTING, true);
|
||||||
packet_write(&p, &data, sizeof(struct PacketDataInsidePainting));
|
packet_write(&p, &data, sizeof(struct PacketInsidePaintingData));
|
||||||
network_send(&p);
|
network_send(&p);
|
||||||
|
seqId++;
|
||||||
lastSentData = data;
|
|
||||||
lastSentTime = clock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_receive_inside_painting(struct Packet* p) {
|
void network_receive_inside_painting(struct Packet* p) {
|
||||||
struct PacketDataInsidePainting remote = { 0 };
|
struct PacketInsidePaintingData local = { 0 };
|
||||||
packet_read(p, &remote, sizeof(struct PacketDataInsidePainting));
|
populate_packet_data(&local);
|
||||||
|
|
||||||
if (gNetworkType == NT_CLIENT && gControlPainting && remote.controlPainting) {
|
struct PacketInsidePaintingData remote = { 0 };
|
||||||
// we both think we should control the painting, host wins the tie
|
packet_read(p, &remote, sizeof(struct PacketInsidePaintingData));
|
||||||
gControlPainting = false;
|
|
||||||
|
// de-dup
|
||||||
|
if (remote.seqId == remoteLastSeqId) {
|
||||||
|
LOG_INFO("we've seen this packet, escape!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
remoteLastSeqId = remote.seqId;
|
||||||
|
if (remote.eventId == remoteFinishedEventId || (remote.eventId == remoteFinishedEventId - 1)) {
|
||||||
|
LOG_INFO("we've finished this event, escape!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gControlPainting && remote.controlPainting) {
|
// two-player hack: gControlledWarp is a bool instead of an index
|
||||||
// update star/act index to show the one in control's selection
|
if (gControlledWarp) {
|
||||||
sSelectableStarIndex = remote.starIndex;
|
LOG_INFO("this should never happen, received inside_painting when gControlledWarp");
|
||||||
sSelectedActIndex = remote.actIndex;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gControlPainting && !remote.controlPainting) {
|
LOG_INFO("received update");
|
||||||
// remote is well behaved now, we can control the painting
|
eventId = remote.eventId;
|
||||||
gWaitingForRemotePainting = false;
|
sSelectableStarIndex = remote.starIndex;
|
||||||
}
|
sSelectedActIndex = remote.actIndex;
|
||||||
|
sLoadedActNum = remote.loadedActNum;
|
||||||
|
|
||||||
if (gControlPainting && !remote.controlPainting && !gInsidePainting && remote.insidePainting) {
|
if (sLoadedActNum != 0) {
|
||||||
// we're in control and no longer in the painting, let remote know
|
LOG_INFO("finished with painting");
|
||||||
network_send_inside_painting(false);
|
remoteFinishedEventId = remote.eventId;
|
||||||
}
|
|
||||||
|
|
||||||
if (!gControlPainting && remote.controlPainting && !remote.insidePainting) {
|
|
||||||
// remote is in control and in game, we should be too
|
|
||||||
star_select_finish_selection();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_update_inside_painting(void) {
|
|
||||||
struct PacketDataInsidePainting data = { 0 };
|
|
||||||
populate_packet_data(&data);
|
|
||||||
int compareData = memcmp(&data, &lastSentData, sizeof(struct PacketDataInsidePainting));
|
|
||||||
|
|
||||||
float timeSinceSend = (clock() - lastSentTime) / CLOCKS_PER_SEC;
|
|
||||||
|
|
||||||
if (compareData != 0 || timeSinceSend > minUpdateRate) {
|
|
||||||
network_send_inside_painting(timeSinceSend > 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,73 +1,114 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "../network.h"
|
|
||||||
#include "src/game/level_update.h"
|
|
||||||
#include "src/game/area.h"
|
|
||||||
#include "src/game/ingame_menu.h"
|
|
||||||
#include "sm64.h"
|
#include "sm64.h"
|
||||||
|
#include "../network.h"
|
||||||
|
#include "game/level_update.h"
|
||||||
|
#include "game/area.h"
|
||||||
|
#include "game/ingame_menu.h"
|
||||||
|
#define DISABLE_MODULE_LOG
|
||||||
|
#include "pc/debuglog.h"
|
||||||
|
|
||||||
int matchCount = 0;
|
static u8 eventId = 0;
|
||||||
|
static u8 remoteFinishedEventId = (u8)-1;
|
||||||
|
|
||||||
extern s16 gMenuMode;
|
static u8 seqId = 0;
|
||||||
|
static u8 remoteLastSeqId = (u8)-1;
|
||||||
|
|
||||||
void network_send_level_warp(void) {
|
extern u8 gControlledWarp; // two-player hack
|
||||||
struct Packet p;
|
extern u8 gReceiveWarp;
|
||||||
packet_init(&p, PACKET_LEVEL_WARP, true);
|
extern struct WarpDest gReceiveWarpDest;
|
||||||
packet_write(&p, &sCurrPlayMode, sizeof(s16));
|
|
||||||
packet_write(&p, &sWarpDest, sizeof(struct WarpDest));
|
|
||||||
|
|
||||||
network_send(&p);
|
struct WarpDest savedWarpNode = { 0 };
|
||||||
|
|
||||||
|
#pragma pack(1)
|
||||||
|
struct PacketLevelWarpData {
|
||||||
|
u8 seqId;
|
||||||
|
u8 eventId;
|
||||||
|
u8 done;
|
||||||
|
u8 controlledWarp;
|
||||||
|
struct WarpDest warpDest;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void populate_packet_data(struct PacketLevelWarpData* data, bool done) {
|
||||||
|
data->seqId = seqId;
|
||||||
|
data->eventId = eventId;
|
||||||
|
data->done = done;
|
||||||
|
data->controlledWarp = gControlledWarp;
|
||||||
|
data->warpDest = savedWarpNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void force_well_behaved_state(void) {
|
void network_send_level_warp(u8 done) {
|
||||||
reset_dialog_render_state();
|
if (!done) {
|
||||||
level_set_transition(0, 0);
|
savedWarpNode = sWarpDest;
|
||||||
gMenuMode = -1;
|
gControlledWarp = true;
|
||||||
gPauseScreenMode = 1;
|
eventId++;
|
||||||
gSaveOptSelectIndex = 0;
|
LOG_INFO("new event [%d]!", eventId);
|
||||||
gMarioStates[0].action = (gMarioStates[0].pos[1] <= (gMarioStates[0].waterLevel - 100)) ? ACT_WATER_IDLE : ACT_IDLE;
|
}
|
||||||
gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN;
|
|
||||||
|
struct PacketLevelWarpData data = { 0 };
|
||||||
|
populate_packet_data(&data, done);
|
||||||
|
|
||||||
|
struct Packet p;
|
||||||
|
packet_init(&p, PACKET_LEVEL_WARP, true);
|
||||||
|
packet_write(&p, &data, sizeof(struct PacketLevelWarpData));
|
||||||
|
network_send(&p);
|
||||||
|
|
||||||
|
seqId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_warp(void) {
|
||||||
|
gReceiveWarpDest = savedWarpNode;
|
||||||
|
gReceiveWarp = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_receive_level_warp(struct Packet* p) {
|
void network_receive_level_warp(struct Packet* p) {
|
||||||
s16 remotePlayMode;
|
struct PacketLevelWarpData remote = { 0 };
|
||||||
struct WarpDest remoteWarpDest;
|
packet_read(p, &remote, sizeof(struct PacketLevelWarpData));
|
||||||
|
|
||||||
packet_read(p, &remotePlayMode, sizeof(s16));
|
// de-dup
|
||||||
packet_read(p, &remoteWarpDest, sizeof(struct WarpDest));
|
if (remote.seqId == remoteLastSeqId) {
|
||||||
|
LOG_INFO("we've seen this packet, escape!");
|
||||||
bool matchingDest = memcmp(&remoteWarpDest, &sWarpDest, sizeof(struct WarpDest)) == 0;
|
return;
|
||||||
|
}
|
||||||
if (remotePlayMode == PLAY_MODE_SYNC_LEVEL && (sCurrPlayMode == PLAY_MODE_NORMAL || sCurrPlayMode == PLAY_MODE_PAUSED)) {
|
remoteLastSeqId = remote.seqId;
|
||||||
if (remoteWarpDest.type == WARP_TYPE_NOT_WARPING) { return; }
|
LOG_INFO("rx event [%d] last [%d]!", remote.eventId, remoteFinishedEventId);
|
||||||
sCurrPlayMode = PLAY_MODE_SYNC_LEVEL;
|
if (remote.eventId == remoteFinishedEventId || (remote.eventId == remoteFinishedEventId - 1)) {
|
||||||
sWarpDest = remoteWarpDest;
|
LOG_INFO("we've finished this event, escape!");
|
||||||
force_well_behaved_state();
|
|
||||||
network_send_level_warp();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remotePlayMode == PLAY_MODE_SYNC_LEVEL && sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) {
|
if (gNetworkType == NT_SERVER) {
|
||||||
if (matchingDest) {
|
if (sCurrPlayMode != PLAY_MODE_SYNC_LEVEL) {
|
||||||
switch (sWarpDest.type) {
|
// client initiated warp
|
||||||
case WARP_TYPE_CHANGE_AREA: sCurrPlayMode = PLAY_MODE_CHANGE_AREA; break;
|
LOG_INFO("client initiated warp!");
|
||||||
case WARP_TYPE_CHANGE_LEVEL: sCurrPlayMode = PLAY_MODE_CHANGE_LEVEL; break;
|
gControlledWarp = FALSE;
|
||||||
}
|
savedWarpNode = remote.warpDest;
|
||||||
|
eventId = remote.eventId;
|
||||||
|
remoteFinishedEventId = remote.eventId;
|
||||||
|
LOG_INFO("finished event [%d]!", remote.eventId);
|
||||||
|
do_warp();
|
||||||
|
network_send_level_warp(TRUE);
|
||||||
|
return;
|
||||||
|
} else if (remote.done) {
|
||||||
|
// client done with warp
|
||||||
|
LOG_INFO("client is done with warp, lets-a-go!");
|
||||||
|
remoteFinishedEventId = remote.eventId;
|
||||||
|
do_warp();
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (gNetworkType == NT_CLIENT) {
|
LOG_INFO("client initiated warp, but server is already warping!");
|
||||||
if (remoteWarpDest.type == WARP_TYPE_NOT_WARPING) { return; }
|
return;
|
||||||
// two-player hack: would need to use player index as priority
|
|
||||||
sWarpDest = remoteWarpDest;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
network_send_level_warp();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((remotePlayMode == PLAY_MODE_CHANGE_LEVEL || remotePlayMode == PLAY_MODE_CHANGE_AREA) && sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) {
|
assert(gNetworkType == NT_CLIENT);
|
||||||
if (remoteWarpDest.type == WARP_TYPE_NOT_WARPING) { return; }
|
|
||||||
switch (sWarpDest.type) {
|
// server initiated warp
|
||||||
case WARP_TYPE_CHANGE_AREA: sCurrPlayMode = PLAY_MODE_CHANGE_AREA; break;
|
LOG_INFO("server initiated warp!");
|
||||||
case WARP_TYPE_CHANGE_LEVEL: sCurrPlayMode = PLAY_MODE_CHANGE_LEVEL; break;
|
gControlledWarp = !remote.controlledWarp; // two-player hack
|
||||||
}
|
savedWarpNode = remote.warpDest;
|
||||||
}
|
eventId = remote.eventId;
|
||||||
|
remoteFinishedEventId = remote.eventId;
|
||||||
|
LOG_INFO("finished event [%d]!", remote.eventId);
|
||||||
|
do_warp();
|
||||||
|
network_send_level_warp(TRUE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ bool network_sync_object_initialized(struct Object* o) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_clear_sync_objects(void) {
|
void network_clear_sync_objects(void) {
|
||||||
|
network_on_init_level();
|
||||||
for (u16 i = 0; i < MAX_SYNC_OBJECTS; i++) {
|
for (u16 i = 0; i < MAX_SYNC_OBJECTS; i++) {
|
||||||
network_forget_sync_object(&gSyncObjects[i]);
|
network_forget_sync_object(&gSyncObjects[i]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue