Ripped out level synchronization/warp code

Began writing new system that synchronizes course/act/level/area per
player and 'ownership' of that location.
This commit is contained in:
MysterD 2021-06-07 12:19:59 -07:00
parent 48c2d91eef
commit bbdc942501
34 changed files with 552 additions and 728 deletions

View file

@ -3967,14 +3967,11 @@
<ClCompile Include="..\src\pc\network\packets\packet_collect_item.c" />
<ClCompile Include="..\src\pc\network\packets\packet_collect_star.c" />
<ClCompile Include="..\src\pc\network\packets\packet_custom.c" />
<ClCompile Include="..\src\pc\network\packets\packet_instant_warp.c" />
<ClCompile Include="..\src\pc\network\packets\packet_death.c" />
<ClCompile Include="..\src\pc\network\packets\packet_kick.c" />
<ClCompile Include="..\src\pc\network\packets\packet_inside_painting.c" />
<ClCompile Include="..\src\pc\network\packets\packet_join.c" />
<ClCompile Include="..\src\pc\network\packets\packet_keep_alive.c" />
<ClCompile Include="..\src\pc\network\packets\packet_leaving.c" />
<ClCompile Include="..\src\pc\network\packets\packet_level_warp.c" />
<ClCompile Include="..\src\pc\network\packets\packet_level_warp_2.c" />
<ClCompile Include="..\src\pc\network\packets\packet_network_players.c" />
<ClCompile Include="..\src\pc\network\packets\packet_object.c" />
<ClCompile Include="..\src\pc\network\packets\packet_player.c" />

View file

@ -14967,15 +14967,9 @@
<ClCompile Include="..\src\pc\network\packets\packet_read_write.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_level_warp.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_reliable.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_inside_painting.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_collect_star.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
@ -15069,9 +15063,6 @@
<ClCompile Include="..\src\pc\network\packets\packet_leaving.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_instant_warp.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\utils\string_linked_list.c">
<Filter>Source Files\src\pc\utils</Filter>
</ClCompile>
@ -15087,7 +15078,7 @@
<ClCompile Include="..\src\game\characters.c">
<Filter>Source Files\src\game</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_level_warp_2.c">
<ClCompile Include="..\src\pc\network\packets\packet_death.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
</ItemGroup>

View file

@ -19,6 +19,7 @@ fi
# no debug, direct
$FILE --server 27015 --configfile sm64config_server.txt &
sleep 7
$FILE --client 127.0.0.1 27015 --configfile sm64config_client.txt &
exit

View file

@ -13,7 +13,7 @@ if [ ! -f "$FILE" ]; then
fi
$FILE --server 27015 --configfile sm64config_p1.txt &
sleep 2
sleep 4
$FILE --client 127.0.0.1 27015 --configfile sm64config_p2.txt &
sleep 2
$FILE --client 127.0.0.1 27015 --configfile sm64config_p3.txt &

View file

@ -386,7 +386,6 @@ struct MarioState
#define PLAY_MODE_CHANGE_AREA 3
#define PLAY_MODE_CHANGE_LEVEL 4
#define PLAY_MODE_FRAME_ADVANCE 5
#define PLAY_MODE_SYNC_LEVEL 6
// NOTE: this defines the maximum number of players...
// HOWEVER, simply increasing this to 3 will not magically work

View file

@ -257,15 +257,6 @@ void load_area(s32 index) {
load_obj_warp_nodes();
geo_call_global_function_nodes(&gCurrentArea->unk04->node, GEO_CONTEXT_AREA_LOAD);
}
if (!network_is_warp_2_duplicate()) {
if (gNetworkType != NT_NONE) {
network_send_level_warp_2(TRUE, gNetworkPlayerLocal->globalIndex);
}
if (gNetworkType == NT_CLIENT) {
sCurrPlayMode = PLAY_MODE_SYNC_LEVEL;
}
}
}
void unload_area(void) {
@ -450,11 +441,6 @@ void render_game(void) {
}
}
// only render 'synchronizing' text if we've been waiting for a while
if (sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) {
render_sync_level_screen();
}
D_8032CE74 = NULL;
D_8032CE78 = 0;
}

View file

@ -2823,50 +2823,6 @@ s16 render_pause_courses_and_castle(void) {
return 0;
}
s16 render_sync_level_screen(void) {
char* message;
if (gNetworkType == NT_SERVER) {
message = network_player_any_connected() ? "Waiting for player..." : "Waiting for player to connect...";
} else {
message = network_player_any_connected() ? "Waiting for player..." : "Not connected to anyone.\nPlease restart the game.";
}
static f32 alphaScalar = 0.0f;
static clock_t lastDisplay = 0;
f32 elapsed = (clock() - lastDisplay) / (f32)CLOCKS_PER_SEC;
if (elapsed > 1.0f) {
alphaScalar = 0;
} else if (alphaScalar < 1.0f) {
alphaScalar += 0.3f;
if (alphaScalar > 1) { alphaScalar = 1; }
}
u8 alpha = (((f32)fabs(sin(gGlobalTimer / 20.0f)) * alphaScalar) * 255);
lastDisplay = clock();
// black screen
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 240.0f, 0);
create_dl_scale_matrix(MENU_MTX_NOPUSH, GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_HEIGHT / 130.0f, 3.0f, 1.0f);
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
// print text
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
f32 textWidth = get_generic_ascii_string_width(message);
f32 textHeight = get_generic_ascii_string_height(message);
f32 xPos = (SCREEN_WIDTH - textWidth) / 2.0f;
f32 yPos = (SCREEN_HEIGHT + textHeight) / 2.0f;
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, alpha);
print_generic_ascii_string(xPos, yPos, message);
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
return 0;
}
#if defined(VERSION_JP) || defined(VERSION_SH)
#define TXT_HISCORE_X 112
#define TXT_HISCORE_Y 48

View file

@ -153,7 +153,6 @@ void do_cutscene_handler(void);
void render_hud_cannon_reticle(void);
void reset_red_coins_collected(void);
s16 render_menus_and_dialogs(void);
s16 render_sync_level_screen(void);
void create_dl_scale_matrix(s8 pushOp, f32 x, f32 y, f32 z);
#endif // INGAME_MENU_H

View file

@ -1277,12 +1277,14 @@ u8 player_is_sliding(struct MarioState* m) {
}
u32 interact_player(struct MarioState* m, UNUSED u32 interactType, struct Object* o) {
if (!is_player_active(m)) { return FALSE; }
if (gServerSettings.playerInteractions == PLAYER_INTERACTIONS_NONE) { return FALSE; }
if (m->action == ACT_JUMBO_STAR_CUTSCENE) { return FALSE; }
struct MarioState* m2 = NULL;
for (int i = 0; i < MAX_PLAYERS; i++) {
if (o == gMarioStates[i].marioObj) {
if (!is_player_active(&gMarioStates[i])) { return FALSE; }
m2 = &gMarioStates[i];
break;
}

View file

@ -49,7 +49,6 @@
#define WARP_NODE_CREDITS_MIN 0xF8
struct SavedWarpValues gReceiveWarp = { 0 };
u8 gControlledWarpGlobalIndex = 0;
extern s8 sReceivedLoadedActNum;
u8 gRejectInstantWarp = 0;
@ -603,13 +602,6 @@ void check_instant_warp(void) {
warp_camera(warp->displacement[0], warp->displacement[1], warp->displacement[2]);
gMarioStates[0].area->camera->yaw = cameraAngle;
// don't force synchronize the slide in TTM
u8 ignoreSyncingArea = (gCurrLevelNum == LEVEL_TTM && (gCurrAreaIndex == 3 || gCurrAreaIndex == 4));
if (changeOfArea && !ignoreSyncingArea) {
set_play_mode(PLAY_MODE_SYNC_LEVEL);
network_send_instant_warp();
}
return;
}
}
@ -1020,36 +1012,6 @@ void basic_update(UNUSED s16 *arg) {
}
}
static void check_received_warp(void) {
extern float gPaintingMarioYEntry;
if (!gReceiveWarp.received) { return; }
gReceiveWarp.received = FALSE;
// keep do_warp(void) in sync with this
sWarpDest = gReceiveWarp.warpDest;
gInWarpCheckpoint = gReceiveWarp.inWarpCheckpoint;
gTTCSpeedSetting = gReceiveWarp.ttcSpeedSetting;
D_80339EE0 = gReceiveWarp.D_80339EE0;
gPaintingMarioYEntry = gReceiveWarp.paintingMarioYEntry;
if (gControlledWarpGlobalIndex != gNetworkPlayerLocal->globalIndex) {
// force well behaved state
extern s16 gMenuMode;
gMenuMode = -1;
reset_dialog_render_state();
reset_screen_transition_timers();
}
set_play_mode((sWarpDest.type == WARP_TYPE_CHANGE_LEVEL)
? PLAY_MODE_CHANGE_LEVEL
: PLAY_MODE_CHANGE_AREA);
s8 warpCourse = gLevelToCourseNumTable[sWarpDest.levelNum - 1];
if (sWarpDest.type == WARP_TYPE_CHANGE_LEVEL && warpCourse == COURSE_NONE) {
sReceivedLoadedActNum = 0;
}
}
int gPressedStart = 0;
s32 play_mode_normal(void) {
@ -1104,7 +1066,6 @@ s32 play_mode_normal(void) {
set_play_mode(PLAY_MODE_PAUSED);
}
}
check_received_warp();
}
@ -1136,18 +1097,6 @@ s32 play_mode_paused(void) {
}
gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN;
check_received_warp();
return 0;
}
s32 play_mode_sync_level(void) {
// force unpause state
raise_background_noise(1);
set_menu_mode(-1);
gCameraMovementFlags &= ~CAM_MOVE_PAUSE_SCREEN;
//check_received_warp();
return 0;
}
@ -1289,9 +1238,6 @@ s32 update_level(void) {
case PLAY_MODE_FRAME_ADVANCE:
changeLevel = play_mode_frame_advance();
break;
case PLAY_MODE_SYNC_LEVEL:
changeLevel = play_mode_sync_level();
break;
}
if (changeLevel) {

View file

@ -1868,7 +1868,13 @@ s32 execute_mario_action(UNUSED struct Object *o) {
// hide inactive players
struct NetworkPlayer* np = &gNetworkPlayers[gMarioState->playerIndex];
if (np->type != NPT_LOCAL) {
if (!np->connected || np->currLevelNum != gCurrLevelNum || np->currAreaIndex != gCurrAreaIndex) {
bool levelAreaMismatch =
(np->currCourseNum != gCurrCourseNum
|| np->currActNum != gCurrActNum
|| np->currLevelNum != gCurrLevelNum
|| np->currAreaIndex != gCurrAreaIndex);
if (!np->connected || levelAreaMismatch) {
gMarioState->marioObj->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE;
gMarioState->marioObj->oIntangibleTimer = -1;
return 0;

View file

@ -517,7 +517,12 @@ u8 is_player_active(struct MarioState* m) {
struct NetworkPlayer* np = &gNetworkPlayers[m->playerIndex];
if (np->type != NPT_LOCAL) {
if (!np->connected) { return FALSE; }
if (np->currLevelNum != gCurrLevelNum || np->currAreaIndex != gCurrAreaIndex) { return FALSE; }
bool levelAreaMismatch =
(np->currCourseNum != gCurrCourseNum
|| np->currActNum != gCurrActNum
|| np->currLevelNum != gCurrLevelNum
|| np->currAreaIndex != gCurrAreaIndex);
if (levelAreaMismatch) { return FALSE; }
}
return TRUE;
}

View file

@ -55,8 +55,6 @@ s8 sSelectableStarIndex = 0;
// Act Selector menu timer that keeps counting until you choose an act.
static s32 sActSelectorMenuTimer = 0;
extern u8 gControlledWarpGlobalIndex;
/**
* Act Selector Star Type Loop Action
* Defines a select type for a star in the act selector.
@ -177,11 +175,10 @@ void bhv_act_selector_loop(void) {
// Sometimes, stars are not selectable even if they appear on the screen.
// This code filters selectable and non-selectable stars.
sSelectedActIndex = 0;
if (gControlledWarpGlobalIndex == gNetworkPlayerLocal->globalIndex) {
s8 oldIndex = sSelectableStarIndex;
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sObtainedStars);
if (oldIndex != sSelectableStarIndex) { network_send_inside_painting(); }
}
s8 oldIndex = sSelectableStarIndex;
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sObtainedStars);
starIndexCounter = sSelectableStarIndex;
for (i = 0; i < sVisibleStars; i++) {
// Can the star be selected (is it either already completed or the first non-completed mission)
@ -195,11 +192,8 @@ void bhv_act_selector_loop(void) {
}
} else {
// If all stars are collected then they are all selectable.
if (gControlledWarpGlobalIndex == gNetworkPlayerLocal->globalIndex) {
s8 oldIndex = sSelectableStarIndex;
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sVisibleStars - 1);
if (oldIndex != sSelectableStarIndex) { network_send_inside_painting(); }
}
s8 oldIndex = sSelectableStarIndex;
handle_menu_scrolling(MENU_SCROLL_HORIZONTAL, &sSelectableStarIndex, 0, sVisibleStars - 1);
sSelectedActIndex = sSelectableStarIndex;
}
@ -298,15 +292,6 @@ void print_act_selector_strings(void) {
create_dl_ortho_matrix();
// display disclaimer that the other player has to select
if (gControlledWarpGlobalIndex != gNetworkPlayerLocal->globalIndex) {
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
u8 a = ((gGlobalTimer % 24) >= 12) ? 160 : 130;
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, a);
print_generic_ascii_string(66, 212, "Waiting for other player's selection...");
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
}
#ifdef VERSION_EU
switch (language) {
case LANGUAGE_ENGLISH:
@ -436,7 +421,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.
*/
s32 lvl_update_obj_and_load_act_button_actions(UNUSED s32 arg, UNUSED s32 unused) {
if ((gControlledWarpGlobalIndex == gNetworkPlayerLocal->globalIndex) && sActSelectorMenuTimer >= 11) {
if (sActSelectorMenuTimer >= 11) {
// If any of these buttons are pressed, play sound and go to course act
#ifndef VERSION_EU
if ((gPlayer3Controller->buttonPressed & A_BUTTON)
@ -472,6 +457,4 @@ void star_select_finish_selection(void) {
sLoadedActNum = sInitSelectedActNum;
}
gDialogCourseActNum = sSelectedActIndex + 1;
if (gControlledWarpGlobalIndex == gNetworkPlayerLocal->globalIndex) { network_send_inside_painting(); }
}

View file

@ -7,7 +7,7 @@
#ifdef DEBUG
static u8 warpToLevel = LEVEL_WF;
static u8 warpToLevel = LEVEL_BOB;
#define SCANCODE_0 0x0B
#define SCANCODE_1 0x02
@ -26,7 +26,6 @@ static void debug_breakpoint_here(void) {
static void debug_warp_level(u8 level) {
if (sCurrPlayMode == PLAY_MODE_CHANGE_LEVEL) { return; }
if (sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) { return; }
// find level from painting
for (int i = 0; i < 45; i++) {
@ -39,8 +38,7 @@ static void debug_warp_level(u8 level) {
sWarpDest.nodeId = node->destNode;
sWarpDest.arg = 0;
sCurrPlayMode = PLAY_MODE_SYNC_LEVEL;
network_send_level_warp_begin();
sCurrPlayMode = PLAY_MODE_CHANGE_LEVEL;
return;
}
}
@ -55,8 +53,7 @@ static void debug_warp_level(u8 level) {
sWarpDest.nodeId = node->destNode;
sWarpDest.arg = 0;
sCurrPlayMode = PLAY_MODE_SYNC_LEVEL;
network_send_level_warp_begin();
sCurrPlayMode = PLAY_MODE_CHANGE_LEVEL;
return;
}
objectNode = objectNode->next;
@ -68,19 +65,15 @@ static void debug_warp_level(u8 level) {
sWarpDest.areaIdx = 1;
sWarpDest.nodeId = 0x1F;
sWarpDest.arg = 0;
sCurrPlayMode = PLAY_MODE_SYNC_LEVEL;
sCurrPlayMode = PLAY_MODE_CHANGE_LEVEL;
D_80339ECA = 0;
D_80339EE0 = 0;
extern s16 gSavedCourseNum;
gSavedCourseNum = 0;
network_send_level_warp_begin();
}
static void debug_warp_area() {
/*level_trigger_warp(&gMarioStates[0], WARP_OP_CREDITS_START);
return;*/
if (sCurrPlayMode == PLAY_MODE_CHANGE_LEVEL) { return; }
if (sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) { return; }
struct ObjectWarpNode* objectNode = gCurrentArea->warpNodes;
while (objectNode != NULL) {
@ -92,8 +85,7 @@ static void debug_warp_area() {
sWarpDest.nodeId = node->destNode;
sWarpDest.arg = 0;
sCurrPlayMode = PLAY_MODE_SYNC_LEVEL;
network_send_level_warp_begin();
sCurrPlayMode = PLAY_MODE_CHANGE_LEVEL;
return;
}
objectNode = objectNode->next;

View file

@ -11,6 +11,7 @@
// Mario 64 specific externs
extern s16 sCurrPlayMode;
extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex;
enum NetworkType gNetworkType = NT_NONE;
#ifdef DISCORD_SDK
@ -87,6 +88,18 @@ void network_on_init_level(void) {
}
void network_on_loaded_level(void) {
// set all sync objects as staticLevelSpawn
for (int i = 0; i < MAX_SYNC_OBJECTS; i++) {
gSyncObjects[i].staticLevelSpawn = true;
}
// check for level change
struct NetworkPlayer* np = gNetworkPlayerLocal;
if (np != NULL) {
network_send_level_area();
network_send_entities_request();
}
// request my chunk of reserved sync ids
if (gNetworkType == NT_CLIENT) {
network_send_reservation_request();

View file

@ -46,6 +46,7 @@ struct SyncObject {
u16 reserved;
float maxSyncDistance;
bool owned;
bool staticLevelSpawn;
clock_t clockSinceUpdate;
void* behavior;
u16 txEventId;

View file

@ -17,14 +17,14 @@ bool network_player_any_connected(void) {
u8 network_player_connected_count(void) {
u8 count = 0;
for (int i = 1; i < MAX_PLAYERS; i++) {
for (int i = 0; i < MAX_PLAYERS; i++) {
if (gNetworkPlayers[i].connected) { count++; }
}
return count;
}
struct NetworkPlayer* network_player_from_global_index(u8 globalIndex) {
for (int i = 1; i < MAX_PLAYERS; i++) {
for (int i = 0; i < MAX_PLAYERS; i++) {
if (!gNetworkPlayers[i].connected) { continue; }
if (gNetworkPlayers[i].globalIndex == globalIndex) {
return &gNetworkPlayers[i];
@ -69,12 +69,23 @@ void network_player_update(void) {
u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
if (type == NPT_LOCAL) {
memset(&gNetworkPlayers[0], 0, sizeof(struct NetworkPlayer));
gNetworkPlayers[0].connected = true;
gNetworkPlayers[0].type = type;
gNetworkPlayers[0].localIndex = 0;
gNetworkPlayers[0].globalIndex = globalIndex;
gNetworkPlayerLocal = &gNetworkPlayers[0];
struct NetworkPlayer* np = &gNetworkPlayers[0];
if (np->connected) {
np->globalIndex = globalIndex;
return 0;
}
memset(np, 0, sizeof(struct NetworkPlayer));
np->connected = true;
np->type = type;
np->localIndex = 0;
np->globalIndex = globalIndex;
np->currLevelAreaSeqId = 0;
np->currCourseNum = -1;
np->currActNum = -1;
np->currLevelNum = -1;
np->currAreaIndex = -1;
np->currAreaSyncValid = false;
gNetworkPlayerLocal = np;
return 0;
}
@ -96,8 +107,12 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
if (np->connected) { continue; }
memset(np, 0, sizeof(struct NetworkPlayer));
np->connected = true;
np->currLevelAreaSeqId = 0;
np->currCourseNum = -1;
np->currActNum = -1;
np->currLevelNum = -1;
np->currAreaIndex = -1;
np->currAreaSyncValid = false;
np->fadeOpacity = 0;
np->localIndex = i;
np->globalIndex = (gNetworkType == NT_SERVER) ? i : globalIndex;
@ -108,10 +123,6 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
if (type == NPT_SERVER) { gNetworkPlayerServer = np; }
else { chat_add_message_ext("player connected", CMT_SYSTEM, get_player_color(np->globalIndex, 0)); }
LOG_INFO("player connected, local %d, global %d", i, np->globalIndex);
extern s16 sCurrPlayMode;
if (gNetworkType == NT_SERVER && sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) {
network_send_level_warp_repeat();
}
return i;
}

View file

@ -23,8 +23,12 @@ struct NetworkPlayer {
u8 localIndex;
u8 globalIndex;
clock_t lastReceived;
u16 currLevelAreaSeqId;
s16 currCourseNum;
s16 currActNum;
s16 currLevelNum;
s16 currAreaIndex;
bool currAreaSyncValid;
u8 fadeOpacity;
u16 rxSeqIds[MAX_RX_SEQ_IDS];
u8 onRxSeqId;

View file

@ -29,37 +29,40 @@ void packet_receive(struct Packet* p) {
if (np->onRxSeqId >= MAX_RX_SEQ_IDS) { np->onRxSeqId = 0; }
}
// check if we should drop packet
if (!packet_initial_read(p)) { LOG_ERROR("initial read failed (%d - %d)", packetType, p->levelAreaMustMatch); return; }
switch (packetType) {
case PACKET_ACK: network_receive_ack(p); break;
case PACKET_PLAYER: network_receive_player(p); break;
case PACKET_OBJECT: network_receive_object(p); break;
case PACKET_SPAWN_OBJECTS: network_receive_spawn_objects(p); break;
case PACKET_SPAWN_STAR: network_receive_spawn_star(p); break;
case PACKET_SPAWN_STAR_NLE: network_receive_spawn_star_nle(p); break;
case PACKET_LEVEL_WARP: network_receive_level_warp(p); break;
case PACKET_INSIDE_PAINTING: network_receive_inside_painting(p); break;
case PACKET_COLLECT_STAR: network_receive_collect_star(p); break;
case PACKET_COLLECT_COIN: network_receive_collect_coin(p); break;
case PACKET_COLLECT_ITEM: network_receive_collect_item(p); break;
case PACKET_RESERVATION_REQUEST: network_receive_reservation_request(p); break;
case PACKET_RESERVATION: network_receive_reservation(p); break;
case PACKET_JOIN_REQUEST: network_receive_join_request(p); break;
case PACKET_JOIN: network_receive_join(p); break;
case PACKET_CHAT: network_receive_chat(p); break;
case PACKET_KICK: network_receive_kick(p); break;
case PACKET_KEEP_ALIVE: network_receive_keep_alive(p); break;
case PACKET_LEAVING: network_receive_leaving(p); break;
case PACKET_SAVE_FILE: network_receive_save_file(p); break;
case PACKET_INSTANT_WARP: network_receive_instant_warp(p); break;
case PACKET_NETWORK_PLAYERS: network_receive_network_players(p); break;
case PACKET_DEATH: network_receive_death(p); break;
case PACKET_LEVEL_WARP_2: network_receive_level_warp_2(p); break;
///
case PACKET_CUSTOM: network_receive_custom(p); break;
default: LOG_ERROR("received unknown packet: %d", p->buffer[0]);
// check if we should process the packet
if (packet_initial_read(p)) {
switch (packetType) {
case PACKET_ACK: network_receive_ack(p); break;
case PACKET_PLAYER: network_receive_player(p); break;
case PACKET_OBJECT: network_receive_object(p); break;
case PACKET_SPAWN_OBJECTS: network_receive_spawn_objects(p); break;
case PACKET_SPAWN_STAR: network_receive_spawn_star(p); break;
case PACKET_SPAWN_STAR_NLE: network_receive_spawn_star_nle(p); break;
case PACKET_COLLECT_STAR: network_receive_collect_star(p); break;
case PACKET_COLLECT_COIN: network_receive_collect_coin(p); break;
case PACKET_COLLECT_ITEM: network_receive_collect_item(p); break;
case PACKET_RESERVATION_REQUEST: network_receive_reservation_request(p); break;
case PACKET_RESERVATION: network_receive_reservation(p); break;
case PACKET_JOIN_REQUEST: network_receive_join_request(p); break;
case PACKET_JOIN: network_receive_join(p); break;
case PACKET_CHAT: network_receive_chat(p); break;
case PACKET_KICK: network_receive_kick(p); break;
case PACKET_KEEP_ALIVE: network_receive_keep_alive(p); break;
case PACKET_LEAVING: network_receive_leaving(p); break;
case PACKET_SAVE_FILE: network_receive_save_file(p); break;
case PACKET_NETWORK_PLAYERS: network_receive_network_players(p); break;
case PACKET_DEATH: network_receive_death(p); break;
case PACKET_LEVEL_AREA: network_receive_level_area(p); break;
case PACKET_LEVEL_AREA_VALID: network_receive_level_area_valid(p); break;
case PACKET_ENTITIES_REQUEST: network_receive_entities_request(p); break;
case PACKET_CLIENT_ENTITIES_REQUEST: network_receive_client_entities_request(p); break;
case PACKET_ENTITIES_RESPONSE: network_receive_entities_response(p); break;
///
case PACKET_CUSTOM: network_receive_custom(p); break;
default: LOG_ERROR("received unknown packet: %d", p->buffer[0]);
}
} else {
//LOG_ERROR("initial read failed (%d - %d)", packetType, p->levelAreaMustMatch);
}
// broadcast packet

View file

@ -16,8 +16,6 @@ enum PacketType {
PACKET_SPAWN_OBJECTS,
PACKET_SPAWN_STAR,
PACKET_SPAWN_STAR_NLE,
PACKET_LEVEL_WARP,
PACKET_INSIDE_PAINTING,
PACKET_COLLECT_STAR,
PACKET_COLLECT_COIN,
PACKET_COLLECT_ITEM,
@ -30,10 +28,13 @@ enum PacketType {
PACKET_KEEP_ALIVE,
PACKET_LEAVING,
PACKET_SAVE_FILE,
PACKET_INSTANT_WARP,
PACKET_NETWORK_PLAYERS,
PACKET_DEATH,
PACKET_LEVEL_WARP_2,
PACKET_LEVEL_AREA,
PACKET_LEVEL_AREA_VALID,
PACKET_ENTITIES_REQUEST,
PACKET_CLIENT_ENTITIES_REQUEST,
PACKET_ENTITIES_RESPONSE,
///
PACKET_CUSTOM = 255,
};
@ -102,15 +103,6 @@ void network_receive_spawn_star(struct Packet* p);
void network_send_spawn_star_nle(struct Object* o, u32 params);
void network_receive_spawn_star_nle(struct Packet* p);
// packet_level_warp.c
void network_send_level_warp_begin(void);
void network_send_level_warp_repeat(void);
void network_receive_level_warp(struct Packet* p);
// packet_inside_painting.c
void network_send_inside_painting(void);
void network_receive_inside_painting(struct Packet* p);
// packet_collect_star.c
void network_send_collect_star(struct Object* o, s16 coinScore, s16 starIndex);
void network_receive_collect_star(struct Packet* p);
@ -160,10 +152,6 @@ void network_receive_leaving(struct Packet* p);
void network_send_save_file(s32 fileIndex);
void network_receive_save_file(struct Packet* p);
// packet_instant_warp.c
void network_send_instant_warp(void);
void network_receive_instant_warp(struct Packet* p);
// packet_network_players.c
void network_send_network_players(void);
void network_receive_network_players(struct Packet* p);
@ -172,9 +160,18 @@ void network_receive_network_players(struct Packet* p);
void network_send_death(void);
void network_receive_death(struct Packet* p);
// packet_level_warp_2.c
void network_send_level_warp_2(u8 eventBegins, u8 controlledGlobalIndex);
void network_receive_level_warp_2(struct Packet* p);
u8 network_is_warp_2_duplicate(void);
// packet_level_area.c
void network_send_level_area(void);
void network_receive_level_area(struct Packet* p);
void network_send_level_area_valid(u8 toGlobalIndex);
void network_receive_level_area_valid(struct Packet* p);
// packet_entities_request.c
void network_send_entities_request(void);
void network_receive_entities_request(struct Packet* p);
void network_send_client_entities_request(u8 destGlobalIndex, u8 srcGlobalIndex);
void network_receive_client_entities_request(struct Packet* p);
void network_send_entities_response(u8 destGlobalIndex);
void network_receive_entities_response(struct Packet* p);
#endif

View file

@ -15,6 +15,17 @@ static void print_sync_object_table(void) {
}
LOG_INFO(" ");
}
static void print_network_player_table(void) {
LOG_INFO("Network Player Table");
LOG_INFO("%5s %8s %8s %8s %8s %8s", "id", "course", "act", "level", "area", "valid");
for (int i = 0; i < MAX_PLAYERS; i++) {
struct NetworkPlayer* np = &gNetworkPlayers[i];
if (!np->connected) { continue; }
LOG_INFO("%5d %8d %8d %8d %8d %8d", np->globalIndex, np->currCourseNum, np->currActNum, np->currLevelNum, np->currAreaIndex, np->currAreaSyncValid);
}
LOG_INFO(" ");
}
#endif
void network_send_chat(char* message, u8 rgb[3]) {
@ -28,7 +39,7 @@ void network_send_chat(char* message, u8 rgb[3]) {
LOG_INFO("tx chat: %s", message);
#ifdef DEVELOPMENT
print_sync_object_table();
print_network_player_table();
#endif
}
@ -47,6 +58,6 @@ void network_receive_chat(struct Packet* p) {
LOG_INFO("rx chat: %s", remoteMessage);
#ifdef DEVELOPMENT
print_sync_object_table();
print_network_player_table();
#endif
}

View file

@ -0,0 +1,229 @@
#include <stdio.h>
#include "../network.h"
#include "menu/custom_menu_system.h"
//#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex;
struct NetworkPlayer* get_network_player_from_valid_location(s16 courseNum, s16 actNum, s16 levelNum, s16 areaIndex) {
for (int i = 0; i < MAX_PLAYERS; i++) {
struct NetworkPlayer* np = &gNetworkPlayers[i];
if (!np->connected) { continue; }
if (!np->currAreaSyncValid) { continue; }
if (np->currCourseNum != courseNum) { continue; }
if (np->currActNum != actNum) { continue; }
if (np->currLevelNum != levelNum) { continue; }
if (np->currAreaIndex != areaIndex) { continue; }
return np;
}
return NULL;
}
///////////////////////////////////////////////////////////////////////////////
void network_send_entities_request(void) {
if (gNetworkType == NT_SERVER) {
struct NetworkPlayer* np = get_network_player_from_valid_location(gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex);
if (np == NULL) {
gNetworkPlayerLocal->currAreaSyncValid = true;
LOG_INFO("set currAreaSyncValid to true (1)");
return;
}
//LOG_INFO("network_send_entities_request()");
network_send_client_entities_request(gNetworkPlayerLocal->globalIndex, np->globalIndex);
return;
}
struct Packet p;
packet_init(&p, PACKET_ENTITIES_REQUEST, true, false);
packet_write(&p, &gCurrCourseNum, sizeof(s16));
packet_write(&p, &gCurrActNum, sizeof(s16));
packet_write(&p, &gCurrLevelNum, sizeof(s16));
packet_write(&p, &gCurrAreaIndex, sizeof(s16));
network_send_to(0, &p);
//LOG_INFO("network_send_entities_request() { %d, %d, %d, %d }", gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex);
}
void network_receive_entities_request(struct Packet* p) {
if (gNetworkType != NT_SERVER) {
LOG_ERROR("non-server is receiving an entities request!");
return;
}
struct NetworkPlayer* np = &gNetworkPlayers[p->localIndex];
if (np == NULL || np->localIndex == UNKNOWN_LOCAL_INDEX || !np->connected) {
LOG_ERROR("Receiving entities request from inactive player!");
return;
}
s16 courseNum, actNum, levelNum, areaIndex;
packet_read(p, &courseNum, sizeof(s16));
packet_read(p, &actNum, sizeof(s16));
packet_read(p, &levelNum, sizeof(s16));
packet_read(p, &areaIndex, sizeof(s16));
np->currCourseNum = courseNum;
np->currActNum = actNum;
np->currLevelNum = levelNum;
np->currAreaIndex = areaIndex;
np->currAreaSyncValid = false;
LOG_INFO("set global %d's currAreaSyncValid to false", np->globalIndex);
//LOG_INFO("network_receive_entities_request() { %d, %d, %d, %d }", courseNum, actNum, levelNum, areaIndex);
struct NetworkPlayer* np2 = get_network_player_from_valid_location(courseNum, actNum, levelNum, areaIndex);
if (np2 == NULL) {
network_send_level_area_valid(np->globalIndex);
} else if (np2 == gNetworkPlayerLocal) {
network_send_entities_response(np->globalIndex);
} else {
network_send_client_entities_request(np->globalIndex, np2->globalIndex);
}
}
///////////////////////////////////////////////////////////////////////////////
void network_send_client_entities_request(u8 destGlobalIndex, u8 srcGlobalIndex) {
if (gNetworkType != NT_SERVER) {
LOG_ERROR("client can't send a 'client entities request'");
return;
}
struct NetworkPlayer* destNp = network_player_from_global_index(destGlobalIndex);
if (destNp == NULL || !destNp->connected) {
LOG_ERROR("network_send_client_entities_request: dest np is invalid (global %d)", destGlobalIndex);
return;
}
struct Packet p;
packet_init(&p, PACKET_CLIENT_ENTITIES_REQUEST, true, false);
packet_write(&p, &destGlobalIndex, sizeof(u8));
packet_write(&p, &destNp->currCourseNum, sizeof(s16));
packet_write(&p, &destNp->currActNum, sizeof(s16));
packet_write(&p, &destNp->currLevelNum, sizeof(s16));
packet_write(&p, &destNp->currAreaIndex, sizeof(s16));
//LOG_INFO("network_send_client_entities_request() { %d, %d, %d, %d, %d }", destGlobalIndex, destNp->currCourseNum, destNp->currActNum, destNp->currLevelNum, destNp->currAreaIndex);
struct NetworkPlayer* srcNp = network_player_from_global_index(srcGlobalIndex);
if (srcNp == NULL || !srcNp->connected || !srcNp->currAreaSyncValid) {
LOG_ERROR("network_send_client_entities_request: source np is invalid (global %d)", srcGlobalIndex);
return;
}
network_send_to(srcNp->localIndex, &p);
}
void network_receive_client_entities_request(struct Packet* p) {
if (gNetworkType == NT_SERVER) {
LOG_ERROR("server is receiving a 'client entities request'!");
return;
}
u8 destGlobalIndex;
s16 courseNum, actNum, levelNum, areaIndex;
packet_read(p, &destGlobalIndex, sizeof(u8));
packet_read(p, &courseNum, sizeof(s16));
packet_read(p, &actNum, sizeof(s16));
packet_read(p, &levelNum, sizeof(s16));
packet_read(p, &areaIndex, sizeof(s16));
//LOG_INFO("network_receive_client_entities_request() { %d, %d, %d, %d, %d }", destGlobalIndex, courseNum, actNum, levelNum, areaIndex);
if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) {
LOG_ERROR("Receiving 'client entities request' with the wrong location!");
return;
}
network_send_entities_response(destGlobalIndex);
}
///////////////////////////////////////////////////////////////////////////////
void network_send_entities_response(u8 destGlobalIndex) {
if (!gNetworkPlayerLocal->currAreaSyncValid) {
LOG_ERROR("my area is invalid");
return;
}
struct NetworkPlayer* destNp = network_player_from_global_index(destGlobalIndex);
if (destNp == NULL || !destNp->connected) {
LOG_ERROR("network_send_entities_response: dest np is invalid");
return;
}
struct Packet p;
packet_init(&p, PACKET_ENTITIES_RESPONSE, true, false);
packet_write(&p, &destGlobalIndex, sizeof(u8));
packet_write(&p, &gCurrCourseNum, sizeof(s16));
packet_write(&p, &gCurrActNum, sizeof(s16));
packet_write(&p, &gCurrLevelNum, sizeof(s16));
packet_write(&p, &gCurrAreaIndex, sizeof(s16));
// TODO: write entities here!
//LOG_INFO("network_send_entities_response() { %d, %d, %d, %d, %d } to: %d", destGlobalIndex, gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex, (gNetworkType == NT_SERVER) ? destNp->localIndex : 0);
network_send_to((gNetworkType == NT_SERVER) ? destNp->localIndex : 0, &p);
if (gNetworkType == NT_SERVER) {
LOG_INFO("sending response from global %d to global %d", gNetworkPlayerLocal->globalIndex, destNp->globalIndex);
}
}
void network_receive_entities_response(struct Packet* p) {
u8 destGlobalIndex;
s16 courseNum, actNum, levelNum, areaIndex;
packet_read(p, &destGlobalIndex, sizeof(u8));
packet_read(p, &courseNum, sizeof(s16));
packet_read(p, &actNum, sizeof(s16));
packet_read(p, &levelNum, sizeof(s16));
packet_read(p, &areaIndex, sizeof(s16));
// TODO: read entities here!
//LOG_INFO("network_receive_entities_response() { %d, %d, %d, %d, %d }", destGlobalIndex, courseNum, actNum, levelNum, areaIndex);
if (gNetworkType == NT_SERVER && gNetworkPlayerLocal->globalIndex != destGlobalIndex) {
// recreate packet and send to destination
struct Packet p2;
packet_init(&p2, PACKET_ENTITIES_RESPONSE, true, false);
packet_write(&p2, &destGlobalIndex, sizeof(u8));
packet_write(&p2, &courseNum, sizeof(s16));
packet_write(&p2, &actNum, sizeof(s16));
packet_write(&p2, &levelNum, sizeof(s16));
packet_write(&p2, &areaIndex, sizeof(s16));
// TODO: write entities here!
struct NetworkPlayer* destNp = network_player_from_global_index(destGlobalIndex);
if (destNp == NULL || !destNp->connected) {
LOG_ERROR("network_receive_entities_response: dest np is invalid");
return;
}
struct NetworkPlayer* srcNp = &gNetworkPlayers[p->localIndex];
LOG_INFO("sending response from global %d to global %d", srcNp->globalIndex, destNp->globalIndex);
network_send_to(destNp->localIndex, &p2);
return;
} else if (gNetworkPlayerLocal->globalIndex != destGlobalIndex) {
LOG_ERROR("Receiving 'entities response' meant for someone else!");
return;
}
if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) {
LOG_ERROR("Receiving 'entities response' with the wrong location!");
return;
}
// TODO: apply entities!
if (gNetworkType == NT_SERVER) {
struct NetworkPlayer* srcNp = &gNetworkPlayers[p->localIndex];
LOG_INFO("sending response from global %d to global %d", srcNp->globalIndex, gNetworkPlayerLocal->globalIndex);
}
gNetworkPlayerLocal->currAreaSyncValid = true;
LOG_INFO("set currAreaSyncValid to true (2)");
if (gNetworkType != NT_SERVER) {
network_send_level_area_valid(0);
}
//LOG_INFO("network_receive_entities_response() ==> valid");
}

View file

@ -1,62 +0,0 @@
#include <stdio.h>
#include "../network.h"
#include "src/game/level_update.h"
#include "src/game/area.h"
#define DISABLE_MODULE_LOG
#include "pc/debuglog.h"
extern u8 gControlledWarpGlobalIndex;
extern u8 sSelectableStarIndex;
extern u8 sSelectedActIndex;
extern s8 sLoadedActNum;
extern s8 sReceivedLoadedActNum;
#pragma pack(1)
struct PacketInsidePaintingData {
u8 starIndex;
u8 actIndex;
u8 loadedActNum;
};
static void populate_packet_data(struct PacketInsidePaintingData* data) {
data->starIndex = sSelectableStarIndex;
data->actIndex = sSelectedActIndex;
data->loadedActNum = sLoadedActNum;
}
void network_send_inside_painting(void) {
struct PacketInsidePaintingData data = { 0 };
populate_packet_data(&data);
struct Packet p;
packet_init(&p, PACKET_INSIDE_PAINTING, true, false);
packet_write(&p, &data, sizeof(struct PacketInsidePaintingData));
network_send(&p);
}
void network_receive_inside_painting(struct Packet* p) {
struct PacketInsidePaintingData local = { 0 };
populate_packet_data(&local);
struct PacketInsidePaintingData remote = { 0 };
packet_read(p, &remote, sizeof(struct PacketInsidePaintingData));
if (gControlledWarpGlobalIndex == gNetworkPlayerLocal->globalIndex) {
LOG_ERROR("this should never happen, received inside_painting when gControlledWarp");
return;
}
LOG_INFO("received update");
sSelectableStarIndex = remote.starIndex;
sSelectedActIndex = remote.actIndex;
if (sReceivedLoadedActNum == 0) {
sReceivedLoadedActNum = remote.loadedActNum;
}
if (sReceivedLoadedActNum != 0) {
LOG_INFO("finished with painting");
}
}

View file

@ -1,82 +0,0 @@
#include <stdio.h>
#include "sm64.h"
#include "../network.h"
#include "engine/math_util.h"
#include "game/level_update.h"
#include "game/area.h"
#include "game/ingame_menu.h"
#include "game/mario.h"
#define DISABLE_MODULE_LOG
#include "pc/debuglog.h"
extern u8 gRejectInstantWarp;
#pragma pack(1)
struct PacketInstantWarpData {
Vec3f pos;
s16 areaIndex;
s16 yaw;
};
static void populate_packet_data(struct PacketInstantWarpData* data) {
data->pos[0] = gMarioStates[0].pos[0];
data->pos[1] = gMarioStates[0].pos[1];
data->pos[2] = gMarioStates[0].pos[2];
data->yaw = gMarioStates[0].faceAngle[1];
data->areaIndex = gCurrAreaIndex;
}
void network_send_instant_warp(void) {
struct PacketInstantWarpData data = { 0 };
populate_packet_data(&data);
struct Packet p;
packet_init(&p, PACKET_INSTANT_WARP, true, false);
packet_write(&p, &data, sizeof(struct PacketInstantWarpData));
network_send(&p);
LOG_INFO("tx %d", data.areaIndex);
gRejectInstantWarp = 120;
}
void network_receive_instant_warp(struct Packet* p) {
struct PacketInstantWarpData remote = { 0 };
packet_read(p, &remote, sizeof(struct PacketInstantWarpData));
LOG_INFO("rx instant warp");
if (gCurrAreaIndex == remote.areaIndex) {
if (sCurrPlayMode == PLAY_MODE_SYNC_LEVEL) { sCurrPlayMode = PLAY_MODE_NORMAL; }
LOG_INFO("instant warp done %d", remote.areaIndex);
return;
}
gMarioStates[0].pos[0] = remote.pos[0];
gMarioStates[0].pos[1] = remote.pos[1];
gMarioStates[0].pos[2] = remote.pos[2];
vec3f_copy(gMarioStates[0].nonInstantWarpPos, gMarioStates[0].pos);
gMarioStates[0].marioObj->oPosX = gMarioStates[0].pos[0];
gMarioStates[0].marioObj->oPosY = gMarioStates[0].pos[1];
gMarioStates[0].marioObj->oPosZ = gMarioStates[0].pos[2];
/*gMarioStates[0].faceAngle[1] = remote.yaw;
gMarioStates[0].intendedYaw = remote.yaw;
gMarioStates[0].marioObj->oMoveAngleYaw = remote.yaw;
gMarioStates[0].marioObj->oFaceAngleYaw = remote.yaw;*/
for (int i = 0; i < MAX_PLAYERS; i++) {
gMarioStates[i].marioObj->oIntangibleTimer = 30;
force_idle_state(&gMarioStates[i]);
}
//s16 cameraAngle = gMarioStates[0].area->camera->yaw;
change_area(remote.areaIndex);
for (int i = 0; i < MAX_PLAYERS; i++) { gMarioStates[i].area = gCurrentArea; }
//warp_camera(warp->displacement[0], warp->displacement[1], warp->displacement[2]);
//gMarioStates[0].area->camera->yaw = cameraAngle;
LOG_INFO("instant warp applied %d", remote.areaIndex);
network_send_instant_warp();
}

View file

@ -11,8 +11,10 @@
#include "src/pc/fs/fs.h"
#include "PR/os_eeprom.h"
#include "pc/network/version.h"
#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
extern u8* gOverrideEeprom;
static u8 eeprom[512] = { 0 };

View file

@ -0,0 +1,141 @@
#include <stdio.h>
#include "../network.h"
#include "menu/custom_menu_system.h"
//#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex;
static u16 currLevelAreaSeqId = 0;
void network_send_level_area(void) {
struct Packet p;
currLevelAreaSeqId++;
packet_init(&p, PACKET_LEVEL_AREA, true, false);
packet_write(&p, &gNetworkPlayerLocal->globalIndex, sizeof(u8));
packet_write(&p, &currLevelAreaSeqId, sizeof(u16));
packet_write(&p, &gCurrCourseNum, sizeof(s16));
packet_write(&p, &gCurrActNum, sizeof(s16));
packet_write(&p, &gCurrLevelNum, sizeof(s16));
packet_write(&p, &gCurrAreaIndex, sizeof(s16));
network_send(&p);
struct NetworkPlayer* np = gNetworkPlayerLocal;
if (np != NULL) {
np->currLevelAreaSeqId = currLevelAreaSeqId;
np->currCourseNum = gCurrCourseNum;
np->currActNum = gCurrActNum;
np->currLevelNum = gCurrLevelNum;
np->currAreaIndex = gCurrAreaIndex;
np->currAreaSyncValid = false;
LOG_INFO("set currAreaSyncValid to false");
}
//LOG_INFO("tx location: [%d, %d, %d, %d]", gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex);
}
void network_receive_level_area(struct Packet* p) {
u8 globalIndex;
u16 levelAreaSeqId;
s16 courseNum, actNum, levelNum, areaIndex;
packet_read(p, &globalIndex, sizeof(u8));
packet_read(p, &levelAreaSeqId, sizeof(u16));
packet_read(p, &courseNum, sizeof(s16));
packet_read(p, &actNum, sizeof(s16));
packet_read(p, &levelNum, sizeof(s16));
packet_read(p, &areaIndex, sizeof(s16));
struct NetworkPlayer* np = network_player_from_global_index(globalIndex);
if (np == gNetworkPlayerLocal) {
LOG_ERROR("Receiving level area from myself!");
return;
}
if (np == NULL || np->localIndex == UNKNOWN_LOCAL_INDEX || !np->connected) {
LOG_ERROR("Receiving level area from inactive player global %d!", np->globalIndex);
return;
}
if (levelAreaSeqId <= np->currLevelAreaSeqId) {
LOG_ERROR("Receiving old level area (%d <= %d) from local %d, global %d!", levelAreaSeqId, np->currLevelAreaSeqId, p->localIndex, np->globalIndex);
return;
}
np->currLevelAreaSeqId = levelAreaSeqId;
np->currCourseNum = courseNum;
np->currActNum = actNum;
np->currLevelNum = levelNum;
np->currAreaIndex = areaIndex;
//LOG_INFO("rx location: [%d, %d, %d, %d] from local %d, global %d", courseNum, actNum, levelNum, areaIndex, p->localIndex, np->globalIndex);
}
///////////////////////////////////////////////////////////////////////////////
static void network_send_level_area_valid_server(u8 toGlobalIndex) {
struct NetworkPlayer* np = network_player_from_global_index(toGlobalIndex);
if (np == NULL || !np->connected) {
LOG_ERROR("tried to send level area valid to invalid player");
return;
}
struct Packet p;
packet_init(&p, PACKET_LEVEL_AREA_VALID, true, false);
packet_write(&p, &np->currCourseNum, sizeof(s16));
packet_write(&p, &np->currActNum, sizeof(s16));
packet_write(&p, &np->currLevelNum, sizeof(s16));
packet_write(&p, &np->currAreaIndex, sizeof(s16));
network_send_to(np->localIndex, &p);
}
static void network_send_level_area_valid_client() {
struct Packet p;
packet_init(&p, PACKET_LEVEL_AREA_VALID, true, false);
network_send_to(0, &p);
}
void network_send_level_area_valid(u8 toGlobalIndex) {
if (gNetworkType == NT_SERVER) {
network_send_level_area_valid_server(toGlobalIndex);
} else if (toGlobalIndex != 0) {
LOG_ERROR("client tried to send 'level area valid' to non-server");
} else {
network_send_level_area_valid_client();
}
}
static void network_receive_level_area_valid_server(struct Packet* p) {
struct NetworkPlayer* np = &gNetworkPlayers[p->localIndex];
if (np == NULL || !np->connected) {
LOG_ERROR("network_receive_level_area_valid_server(): invalid network player");
return;
}
np->currAreaSyncValid = true;
LOG_INFO("set global %d's currAreaSyncValid to true", np->globalIndex);
}
static void network_receive_level_area_valid_client(struct Packet* p) {
s16 courseNum, actNum, levelNum, areaIndex;
packet_read(p, &courseNum, sizeof(s16));
packet_read(p, &actNum, sizeof(s16));
packet_read(p, &levelNum, sizeof(s16));
packet_read(p, &areaIndex, sizeof(s16));
if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) {
LOG_ERROR("tried to validate a level area that isn't current");
return;
}
gNetworkPlayerLocal->currAreaSyncValid = true;
network_send_level_area_valid_client();
LOG_INFO("set currAreaSyncValid to true (3)");
}
void network_receive_level_area_valid(struct Packet* p) {
if (gNetworkType == NT_SERVER) {
network_receive_level_area_valid_server(p);
} else {
network_receive_level_area_valid_client(p);
}
}

View file

@ -1,182 +0,0 @@
#include <stdio.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"
// two-player hack
// this entire system needs to be ripped out and replaced
static u8 eventId = 0;
static u8 remoteFinishedEventId[2] = { (u8)-1, (u8)-1 };
extern s16 gTTCSpeedSetting;
extern s16 D_80339EE0;
extern float gPaintingMarioYEntry;
extern u8 gControlledWarpGlobalIndex;
extern struct SavedWarpValues gReceiveWarp;
struct SavedWarpValues saved = { 0 };
static clock_t lastDoneEvent = 0;
static bool isInWarp = FALSE;
#pragma pack(1)
struct PacketLevelWarpData {
u8 eventId;
u8 done;
u8 controlledWarp;
struct WarpDest warpDest;
s8 inWarpCheckpoint;
s16 ttcSpeedSetting;
s16 D_80339EE0;
f32 paintingMarioYEntry;
};
static void populate_packet_data(struct PacketLevelWarpData* data, bool done, u8 packetEventId) {
data->eventId = packetEventId;
data->done = done;
data->controlledWarp = gControlledWarpGlobalIndex;
data->warpDest = saved.warpDest;
data->inWarpCheckpoint = saved.inWarpCheckpoint;
data->ttcSpeedSetting = saved.ttcSpeedSetting;
data->D_80339EE0 = saved.D_80339EE0;
data->paintingMarioYEntry = saved.paintingMarioYEntry;
}
void network_send_level_warp_begin(void) {
isInWarp = TRUE;
saved.warpDest = sWarpDest;
saved.inWarpCheckpoint = gInWarpCheckpoint;
saved.ttcSpeedSetting = gTTCSpeedSetting;
saved.D_80339EE0 = D_80339EE0;
saved.paintingMarioYEntry = gPaintingMarioYEntry;
float elapsedSinceDone = (clock() - lastDoneEvent) / CLOCKS_PER_SEC;
gControlledWarpGlobalIndex = (elapsedSinceDone < 1.0f)
? 0
: gNetworkPlayerLocal->globalIndex;
eventId++;
if (eventId == (u8)-1) { eventId++; }
LOG_INFO("new event [%d]!", eventId);
struct PacketLevelWarpData data = { 0 };
populate_packet_data(&data, false, eventId);
struct Packet p;
packet_init(&p, PACKET_LEVEL_WARP, true, false);
packet_write(&p, &data, sizeof(struct PacketLevelWarpData));
network_send(&p);
}
void network_send_level_warp_repeat(void) {
if (!isInWarp) {
network_send_level_warp_begin();
LOG_ERROR("sending repeat, but we're not warping!");
return;
}
struct PacketLevelWarpData data = { 0 };
populate_packet_data(&data, false, eventId);
struct Packet p;
packet_init(&p, PACKET_LEVEL_WARP, false, false);
packet_write(&p, &data, sizeof(struct PacketLevelWarpData));
network_send(&p);
}
static void network_send_level_warp_done(u8 remoteEventId) {
lastDoneEvent = clock();
isInWarp = FALSE;
struct PacketLevelWarpData data = { 0 };
populate_packet_data(&data, true, remoteEventId);
struct Packet p;
packet_init(&p, PACKET_LEVEL_WARP, true, false);
packet_write(&p, &data, sizeof(struct PacketLevelWarpData));
network_send(&p);
}
static void do_warp(void) {
// keep check_received_warp(void) in sync with this
gReceiveWarp = saved;
gReceiveWarp.received = TRUE;
gInWarpCheckpoint = saved.inWarpCheckpoint;
gTTCSpeedSetting = saved.ttcSpeedSetting;
D_80339EE0 = saved.D_80339EE0;
gPaintingMarioYEntry = saved.paintingMarioYEntry;
}
void network_receive_level_warp(struct Packet* p) {
struct PacketLevelWarpData remote = { 0 };
packet_read(p, &remote, sizeof(struct PacketLevelWarpData));
LOG_INFO("rx event [%d] last [%d, %d]", remote.eventId, remoteFinishedEventId[0], remoteFinishedEventId[1]);
if (remote.done && remote.eventId != eventId) {
LOG_INFO("remote has finished the wrong id!");
return;
}
if (!remote.done) {
if (remote.eventId == remoteFinishedEventId[0] || remote.eventId == remoteFinishedEventId[1]) {
LOG_INFO("we've finished this event, escape!");
return;
}
remoteFinishedEventId[1] = remoteFinishedEventId[0];
remoteFinishedEventId[0] = remote.eventId;
}
if (gNetworkType == NT_SERVER) {
if (!isInWarp && remote.done) {
LOG_INFO("client is done with warp, but so are we!");
return;
} else if (!isInWarp) {
// client initiated warp
LOG_INFO("client initiated warp!");
gControlledWarpGlobalIndex = remote.controlledWarp;
saved.warpDest = remote.warpDest;
saved.inWarpCheckpoint = remote.inWarpCheckpoint;
saved.ttcSpeedSetting = remote.ttcSpeedSetting;
saved.D_80339EE0 = remote.D_80339EE0;
saved.paintingMarioYEntry = remote.paintingMarioYEntry;
do_warp();
network_send_level_warp_done(remote.eventId);
return;
} else if (remote.done && remote.eventId == eventId) {
// client done with warp
LOG_INFO("client is done with warp, lets-a-go!");
do_warp();
isInWarp = FALSE;
return;
} else {
LOG_INFO("client initiated warp, but server is already warping!");
LOG_INFO("remote.done: %d, remote.eventId: %d!", remote.done, remote.eventId);
network_send_level_warp_repeat();
return;
}
}
assert(gNetworkType == NT_CLIENT);
// server initiated warp
LOG_INFO("server initiated warp!");
gControlledWarpGlobalIndex = remote.controlledWarp;
saved.warpDest = remote.warpDest;
saved.inWarpCheckpoint = remote.inWarpCheckpoint;
saved.ttcSpeedSetting = remote.ttcSpeedSetting;
saved.D_80339EE0 = remote.D_80339EE0;
saved.paintingMarioYEntry = remote.paintingMarioYEntry;
LOG_INFO("finished event [%d]!", remote.eventId);
do_warp();
network_send_level_warp_done(remote.eventId);
}

View file

@ -1,143 +0,0 @@
#include "../network.h"
#include "game/level_update.h"
#include "game/object_list_processor.h"
//#define DISABLE_MODULE_LOG
#include "pc/debuglog.h"
#define SERVER_RETAIN_WARP_SECONDS 1
extern u8 gControlledWarpGlobalIndex;
extern float gPaintingMarioYEntry;
#pragma pack(1)
struct PacketLevelWarp2Data {
s16 levelNum;
s16 areaIndex;
s16 actNum;
u8 warpType;
u8 warpLevelNum;
u8 warpAreaIdx;
u8 warpNodeId;
u32 warpArg;
s8 inWarpCheckpoint;
s16 ttcSpeedSetting;
s16 D_80339EE0;
f32 paintingMarioYEntry;
u8 controlledWarpGlobalIndex;
};
struct PacketLevelWarp2Data sSavedLevelWarp2Data = { 0 };
static clock_t sSavedClockTime = 0;
static void populate_packet_data(struct PacketLevelWarp2Data* data) {
data->levelNum = gCurrLevelNum;
data->areaIndex = gCurrAreaIndex;
data->actNum = gCurrActNum;
data->warpType = sWarpDest.type;
data->warpLevelNum = sWarpDest.levelNum;
data->warpAreaIdx = sWarpDest.areaIdx;
data->warpNodeId = sWarpDest.nodeId;
data->warpArg = sWarpDest.arg;
data->inWarpCheckpoint = gInWarpCheckpoint;
data->ttcSpeedSetting = gTTCSpeedSetting;
data->D_80339EE0 = D_80339EE0;
data->paintingMarioYEntry = gPaintingMarioYEntry;
data->controlledWarpGlobalIndex = gControlledWarpGlobalIndex;
}
void network_send_level_warp_2(u8 eventBegins, u8 controlledGlobalIndex) {
struct PacketLevelWarp2Data data = { 0 };
if (eventBegins) {
gControlledWarpGlobalIndex = controlledGlobalIndex;
populate_packet_data(&data);
if (gNetworkType == NT_SERVER) {
sSavedLevelWarp2Data = data;
sSavedClockTime = clock();
}
} else {
data = sSavedLevelWarp2Data;
}
struct Packet p;
packet_init(&p, PACKET_LEVEL_WARP_2, true, false);
packet_write(&p, &data, sizeof(struct PacketLevelWarp2Data));
if (gNetworkType == NT_SERVER) {
network_send(&p);
} else {
network_send_to(gNetworkPlayerServer->localIndex, &p);
}
LOG_INFO("send warp: %d, %d, %d", gCurrLevelNum, gCurrAreaIndex, gCurrActNum);
}
static void do_warp(struct PacketLevelWarp2Data* data) {
if (gCurrLevelNum != data->levelNum ) { gChangeLevel = data->levelNum; }
sWarpDest.type = data->warpType;
sWarpDest.levelNum = data->warpLevelNum;
sWarpDest.areaIdx = data->warpAreaIdx;
sWarpDest.nodeId = data->warpNodeId;
sWarpDest.arg = data->warpArg;
gInWarpCheckpoint = data->inWarpCheckpoint;
gTTCSpeedSetting = data->ttcSpeedSetting;
D_80339EE0 = data->D_80339EE0;
gPaintingMarioYEntry = data->paintingMarioYEntry;
gControlledWarpGlobalIndex = data->controlledWarpGlobalIndex;
gCurrLevelNum = data->levelNum;
gCurrAreaIndex = data->areaIndex;
gCurrActNum = data->actNum;
LOG_INFO("do warp: %d, %d, %d", gCurrLevelNum, gCurrAreaIndex, gCurrActNum);
}
void network_receive_level_warp_2(struct Packet* p) {
struct PacketLevelWarp2Data remote = { 0 };
packet_read(p, &remote, sizeof(struct PacketLevelWarp2Data));
LOG_INFO("rx warp: %d, %d, %d", remote.levelNum, remote.areaIndex, remote.actNum);
u8 levelOrAreaDifference = (gCurrLevelNum != remote.levelNum) || (gCurrAreaIndex != remote.areaIndex);
if (gNetworkType == NT_SERVER) {
f32 elapsed = (clock() - sSavedClockTime) / (f32)CLOCKS_PER_SEC;
if (elapsed < SERVER_RETAIN_WARP_SECONDS || !levelOrAreaDifference) {
network_send_level_warp_2(FALSE, gNetworkPlayerLocal->globalIndex);
return;
}
}
if (levelOrAreaDifference) {
do_warp(&remote);
}
if (gNetworkType == NT_CLIENT) {
sSavedLevelWarp2Data = remote;
sSavedClockTime = clock();
}
if (gNetworkType == NT_SERVER) {
network_send_level_warp_2(TRUE, remote.controlledWarpGlobalIndex);
} else {
sCurrPlayMode = PLAY_MODE_NORMAL;
network_on_init_level();
}
}
u8 network_is_warp_2_duplicate(void) {
struct PacketLevelWarp2Data data = { 0 };
populate_packet_data(&data);
if (data.levelNum == 1 && data.areaIndex == 1) { return TRUE; }
if (gNetworkType == NT_SERVER) {
f32 elapsed = (clock() - sSavedClockTime) / (f32)CLOCKS_PER_SEC;
if (elapsed >= SERVER_RETAIN_WARP_SECONDS) { return FALSE; }
}
return (memcmp(&sSavedLevelWarp2Data, &data, sizeof(struct PacketLevelWarp2Data)) == 0);
}

View file

@ -14,13 +14,18 @@ static void network_send_to_network_players(u8 sendToLocalIndex) {
struct Packet p;
packet_init(&p, PACKET_NETWORK_PLAYERS, true, false);
packet_write(&p, &connectedCount, sizeof(u8));
for (int i = 1; i < MAX_PLAYERS; i++) {
for (int i = 0; i < MAX_PLAYERS; i++) {
if (!gNetworkPlayers[i].connected) { continue; }
u8 npType = gNetworkPlayers[i].type;
if (npType == NPT_LOCAL) { npType = NPT_SERVER; }
else if (i == sendToLocalIndex) { npType = NPT_LOCAL; }
packet_write(&p, &npType, sizeof(u8));
packet_write(&p, &gNetworkPlayers[i].globalIndex, sizeof(u8));
packet_write(&p, &gNetworkPlayers[i].globalIndex, sizeof(u8));
packet_write(&p, &gNetworkPlayers[i].currLevelAreaSeqId, sizeof(u16));
packet_write(&p, &gNetworkPlayers[i].currCourseNum, sizeof(s16));
packet_write(&p, &gNetworkPlayers[i].currActNum, sizeof(s16));
packet_write(&p, &gNetworkPlayers[i].currLevelNum, sizeof(s16));
packet_write(&p, &gNetworkPlayers[i].currAreaIndex, sizeof(s16));
LOG_INFO("send network player [%d == %d]", gNetworkPlayers[i].globalIndex, npType);
}
@ -47,9 +52,26 @@ void network_receive_network_players(struct Packet* p) {
packet_read(p, &connectedCount, sizeof(u8));
for (int i = 0; i < connectedCount; i++) {
u8 npType, globalIndex;
packet_read(p, &npType, sizeof(u8));
packet_read(p, &globalIndex, sizeof(u8));
network_player_connected(npType, globalIndex);
LOG_INFO("received network player [%d == %d]", globalIndex, npType);
u16 levelAreaSeqId;
s16 courseNum, actNum, levelNum, areaIndex;
packet_read(p, &npType, sizeof(u8));
packet_read(p, &globalIndex, sizeof(u8));
packet_read(p, &levelAreaSeqId, sizeof(u16));
packet_read(p, &courseNum, sizeof(s16));
packet_read(p, &actNum, sizeof(s16));
packet_read(p, &levelNum, sizeof(s16));
packet_read(p, &areaIndex, sizeof(s16));
u8 localIndex = network_player_connected(npType, globalIndex);
LOG_INFO("received network player [%d == %d] (%d)", globalIndex, npType, localIndex);
if (localIndex != UNKNOWN_GLOBAL_INDEX && localIndex != 0) {
struct NetworkPlayer* np = &gNetworkPlayers[localIndex];
np->currLevelAreaSeqId = levelAreaSeqId;
np->currCourseNum = courseNum;
np->currActNum = actNum;
np->currLevelNum = levelNum;
np->currAreaIndex = areaIndex;
LOG_INFO("received network player location (%d, %d, %d, %d)", courseNum, actNum, levelNum, areaIndex);
}
}
}

View file

@ -472,6 +472,7 @@ void network_forget_sync_object(struct SyncObject* so) {
so->behavior = NULL;
so->reserved = 0;
so->owned = false;
so->staticLevelSpawn = false;
}
void network_update_objects(void) {

View file

@ -65,9 +65,6 @@ struct PacketPlayerData {
u8 interactSyncID;
u8 usedSyncID;
u8 platformSyncID;
s16 currLevelNum;
s16 currAreaIndex;
};
static void read_packet_data(struct PacketPlayerData* data, struct MarioState* m) {
@ -129,9 +126,6 @@ static void read_packet_data(struct PacketPlayerData* data, struct MarioState* m
data->interactSyncID = interactSyncID;
data->usedSyncID = usedSyncID;
data->platformSyncID = platformSyncID;
data->currLevelNum = gCurrLevelNum;
data->currAreaIndex = gCurrAreaIndex;
}
static void write_packet_data(struct PacketPlayerData* data, struct MarioState* m,
@ -226,13 +220,6 @@ void network_receive_player(struct Packet* p) {
return;
}
// check player level/area
u8 levelAreaMismatch = TRUE;
np->currLevelNum = data.currLevelNum;
np->currAreaIndex = data.currAreaIndex;
levelAreaMismatch = (data.currLevelNum != gCurrLevelNum || data.currAreaIndex != gCurrAreaIndex);
if (levelAreaMismatch) { np->fadeOpacity = 0; return; }
// apply data from packet to mario state
u8 heldSyncID = 0;
u8 heldBySyncID = 0;

View file

@ -31,6 +31,8 @@ void packet_init(struct Packet* packet, enum PacketType packetType, bool reliabl
packet_set_flags(packet);
if (levelAreaMustMatch) {
packet_write(packet, &gCurrCourseNum, sizeof(s16));
packet_write(packet, &gCurrActNum, sizeof(s16));
packet_write(packet, &gCurrLevelNum, sizeof(s16));
packet_write(packet, &gCurrAreaIndex, sizeof(s16));
}
@ -58,14 +60,18 @@ u8 packet_initial_read(struct Packet* packet) {
packet->requestBroadcast = GET_BIT(flags, 1);
if (packet->levelAreaMustMatch) {
s16 currLevelNum;
s16 currAreaIndex;
s16 currCourseNum, currActNum, currLevelNum, currAreaIndex;
packet_read(packet, &currCourseNum, sizeof(s16));
packet_read(packet, &currActNum, sizeof(s16));
packet_read(packet, &currLevelNum, sizeof(s16));
packet_read(packet, &currAreaIndex, sizeof(s16));
if (currLevelNum != gCurrLevelNum || currAreaIndex != gCurrAreaIndex) {
// drop packet
return FALSE;
}
bool levelAreaMismatch =
(currCourseNum != gCurrCourseNum
|| currActNum != gCurrActNum
|| currLevelNum != gCurrLevelNum
|| currAreaIndex != gCurrAreaIndex);
// drop packet
if (levelAreaMismatch) { return FALSE; }
}
// don't drop packet

View file

@ -6,6 +6,7 @@
#include "course_table.h"
#include "src/game/interaction.h"
#include "src/engine/math_util.h"
#define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h"
#define RESERVATION_COUNT 10

View file

@ -8,6 +8,7 @@
#define MAX_SPAWN_OBJECTS_PER_PACKET 8
#pragma pack(1)
struct SpawnObjectData {
u8 parentId;
u32 model;