diff --git a/src/engine/level_script.c b/src/engine/level_script.c index dc1f6abf4..c25dffedf 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -426,6 +426,7 @@ static void level_cmd_23(void) { static void level_cmd_init_mario(void) { u32 behaviorArg = CMD_GET(u32, 4); + behaviorArg = behaviorArg; void* behaviorScript = CMD_GET(void*, 8); struct GraphNode* unk18 = gLoadedGraphNodes[CMD_GET(u8, 3)]; diff --git a/src/game/behaviors/chuckya.inc.c b/src/game/behaviors/chuckya.inc.c index 612901261..1d55389d2 100644 --- a/src/game/behaviors/chuckya.inc.c +++ b/src/game/behaviors/chuckya.inc.c @@ -82,7 +82,6 @@ s32 approach_forward_vel(f32 *arr, f32 spC, f32 sp10) { void chuckya_act_0(void) { struct Object* player = nearest_player_to_object(o); - int distanceToPlayer = dist_between_objects(o, player); int angleToPlayer = obj_angle_to_object(o, player); s32 sp3C; UNUSED u8 pad[16]; diff --git a/src/game/behaviors/sparkle_spawn_star.inc.c b/src/game/behaviors/sparkle_spawn_star.inc.c index bb06eb716..4ef83e1aa 100644 --- a/src/game/behaviors/sparkle_spawn_star.inc.c +++ b/src/game/behaviors/sparkle_spawn_star.inc.c @@ -51,7 +51,6 @@ void set_home_to_mario(void) { break; } } - struct Object* player = nearest_player_to_object(o); if (parentIsMario) { o->oHomeX = o->parentObj->oPosX; o->oHomeZ = o->parentObj->oPosZ; diff --git a/src/game/ingame_menu.h b/src/game/ingame_menu.h index dee0d3c47..73e136473 100644 --- a/src/game/ingame_menu.h +++ b/src/game/ingame_menu.h @@ -116,6 +116,7 @@ extern s8 gRedCoinsCollected; void create_dl_identity_matrix(void); void create_dl_translation_matrix(s8 pushOp, f32 x, f32 y, f32 z); void create_dl_ortho_matrix(void); +void render_generic_char(u8 c); void str_ascii_to_dialog(const char* string, u8* dialog, u16 length); f32 get_generic_dialog_width(u8* dialog); f32 get_generic_ascii_string_width(const char* ascii); diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 7ff16cd95..46f0fbcc8 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -103,8 +103,14 @@ void network_on_loaded_level(void) { // check for level change struct NetworkPlayer* np = gNetworkPlayerLocal; if (np != NULL) { - network_send_level_area(); - network_send_location_request(); + bool levelMatch = (np->currCourseNum == gCurrCourseNum + && np->currActNum == gCurrActNum + && np->currLevelNum == gCurrLevelNum); + if (np->currLevelSyncValid && levelMatch && np->currAreaIndex != gCurrAreaIndex) { + network_send_change_area(); + } else { + network_send_change_level(); + } } // request my chunk of reserved sync ids @@ -118,6 +124,9 @@ void network_send_to(u8 localIndex, struct Packet* p) { if (gNetworkType == NT_NONE) { LOG_ERROR("network type error none!"); return; } if (p->error) { LOG_ERROR("packet error!"); return; } if (gNetworkSystem == NULL) { LOG_ERROR("no network system attached"); return; } + if (p->buffer[0] != PACKET_JOIN_REQUEST && p->buffer[0] != PACKET_KICK && p->buffer[0] != PACKET_ACK && gNetworkPlayerLocal != NULL && gNetworkPlayerServer->localIndex != gNetworkPlayerLocal->localIndex) { + assert(localIndex != gNetworkPlayerLocal->localIndex); + } // set the flags again packet_set_flags(p); diff --git a/src/pc/network/network_player.c b/src/pc/network/network_player.c index cf7a016d1..12aa43658 100644 --- a/src/pc/network/network_player.c +++ b/src/pc/network/network_player.c @@ -33,10 +33,24 @@ struct NetworkPlayer* network_player_from_global_index(u8 globalIndex) { return NULL; } -struct NetworkPlayer* get_network_player_from_valid_location(s16 courseNum, s16 actNum, s16 levelNum, s16 areaIndex) { +struct NetworkPlayer* get_network_player_from_level(s16 courseNum, s16 actNum, s16 levelNum) { for (int i = 0; i < MAX_PLAYERS; i++) { struct NetworkPlayer* np = &gNetworkPlayers[i]; if (!np->connected) { continue; } + if (!np->currLevelSyncValid) { continue; } + if (np->currCourseNum != courseNum) { continue; } + if (np->currActNum != actNum) { continue; } + if (np->currLevelNum != levelNum) { continue; } + return np; + } + return NULL; +} + +struct NetworkPlayer* get_network_player_from_area(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->currLevelSyncValid) { continue; } if (!np->currAreaSyncValid) { continue; } if (np->currCourseNum != courseNum) { continue; } if (np->currActNum != actNum) { continue; } @@ -100,6 +114,10 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) { np->currAreaIndex = -1; np->currAreaSyncValid = false; gNetworkPlayerLocal = np; + + if (gNetworkType == NT_SERVER) { + gNetworkPlayerServer = gNetworkPlayerLocal; + } return 0; } diff --git a/src/pc/network/network_player.h b/src/pc/network/network_player.h index 950787465..6e5f7b231 100644 --- a/src/pc/network/network_player.h +++ b/src/pc/network/network_player.h @@ -28,6 +28,7 @@ struct NetworkPlayer { s16 currActNum; s16 currLevelNum; s16 currAreaIndex; + bool currLevelSyncValid; bool currAreaSyncValid; u8 fadeOpacity; u16 rxSeqIds[MAX_RX_SEQ_IDS]; @@ -41,7 +42,8 @@ extern struct NetworkPlayer* gNetworkPlayerServer; bool network_player_any_connected(void); u8 network_player_connected_count(void); struct NetworkPlayer* network_player_from_global_index(u8 globalIndex); -struct NetworkPlayer* get_network_player_from_valid_location(s16 courseNum, s16 actNum, s16 levelNum, s16 areaIndex); +struct NetworkPlayer* get_network_player_from_level(s16 courseNum, s16 actNum, s16 levelNum); +struct NetworkPlayer* get_network_player_from_area(s16 courseNum, s16 actNum, s16 levelNum, s16 areaIndex); void network_player_update(void); u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex); u8 network_player_disconnected(u8 globalIndex); diff --git a/src/pc/network/packets/packet.c b/src/pc/network/packets/packet.c index 6e227b517..5ec629aac 100644 --- a/src/pc/network/packets/packet.c +++ b/src/pc/network/packets/packet.c @@ -59,14 +59,21 @@ void packet_receive(struct Packet* p) { 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_LOCATION_REQUEST: network_receive_location_request(p); break; - case PACKET_LOCATION_REQUEST_CLIENT: network_receive_location_request_client(p); break; - case PACKET_LOCATION_RESPONSE: network_receive_location_response(p); break; - case PACKET_MACRO_DELETIONS: network_receive_macro_deletions(p); break; - case PACKET_SPAWN_INFO_DELETIONS: network_receive_spawn_info_deletions(p); break; - /// + + // location + case PACKET_CHANGE_LEVEL: network_receive_change_level(p); break; + case PACKET_CHANGE_AREA: network_receive_change_area(p); break; + case PACKET_LEVEL_AREA_REQUEST: network_receive_level_area_request(p); break; + case PACKET_LEVEL_REQUEST: network_receive_level_request(p); break; + case PACKET_LEVEL: network_receive_level(p); break; + case PACKET_AREA_REQUEST: network_receive_area_request(p); break; + case PACKET_AREA: network_receive_area(p); break; + case PACKET_SYNC_VALID: network_receive_sync_valid(p); break; + case PACKET_LEVEL_SPAWN_INFO: network_receive_level_spawn_info(p); break; + case PACKET_LEVEL_MACRO: network_receive_level_macro(p); break; + case PACKET_LEVEL_AREA_INFORM: network_receive_level_area_inform(p); break; + + // custom case PACKET_CUSTOM: network_receive_custom(p); break; default: LOG_ERROR("received unknown packet: %d", p->buffer[0]); } diff --git a/src/pc/network/packets/packet.h b/src/pc/network/packets/packet.h index 255bb4925..455fa555c 100644 --- a/src/pc/network/packets/packet.h +++ b/src/pc/network/packets/packet.h @@ -10,6 +10,8 @@ #define PACKET_LENGTH 1024 #define PACKET_DESTINATION_BROADCAST ((u8)-1) +struct NetworkPlayer; + enum PacketType { PACKET_ACK, PACKET_PLAYER, @@ -31,13 +33,19 @@ enum PacketType { PACKET_SAVE_FILE, PACKET_NETWORK_PLAYERS, PACKET_DEATH, - PACKET_LEVEL_AREA, - PACKET_LEVEL_AREA_VALID, - PACKET_LOCATION_REQUEST, - PACKET_LOCATION_REQUEST_CLIENT, - PACKET_LOCATION_RESPONSE, - PACKET_MACRO_DELETIONS, - PACKET_SPAWN_INFO_DELETIONS, + + PACKET_CHANGE_LEVEL, + PACKET_CHANGE_AREA, + PACKET_LEVEL_AREA_REQUEST, + PACKET_LEVEL_REQUEST, + PACKET_LEVEL, + PACKET_AREA_REQUEST, + PACKET_AREA, + PACKET_SYNC_VALID, + PACKET_LEVEL_SPAWN_INFO, + PACKET_LEVEL_MACRO, + PACKET_LEVEL_AREA_INFORM, + /// PACKET_CUSTOM = 255, }; @@ -74,6 +82,8 @@ u8 packet_initial_read(struct Packet* packet); void packet_read(struct Packet* packet, void* data, u16 length); u32 packet_hash(struct Packet* packet); bool packet_check_hash(struct Packet* packet); +void packet_ordered_begin(void); +void packet_ordered_end(void); // packet_reliable.c void network_forget_all_reliable(void); @@ -170,30 +180,48 @@ void network_receive_network_players(struct Packet* p); void network_send_death(void); void network_receive_death(struct Packet* p); -// 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_change_level.c +void network_send_change_level(void); +void network_receive_change_level(struct Packet* p); -// packet_location_request.c -void network_send_location_request(void); -void network_receive_location_request(struct Packet* p); +// packet_change_area.c +void network_send_change_area(void); +void network_receive_change_area(struct Packet* p); -// packet_location_request_client.c -void network_send_location_request_client(u8 destGlobalIndex, u8 srcGlobalIndex); -void network_receive_location_request_client(struct Packet* p); +// packet_level_area_request.c +void network_send_level_area_request(struct NetworkPlayer* fromNp, struct NetworkPlayer* toNp); +void network_receive_level_area_request(struct Packet* p); -// packet_location_response.c -void network_send_location_response(u8 destGlobalIndex); -void network_receive_location_response(struct Packet* p); +// packet_level_request.c +void network_send_level_request(struct NetworkPlayer* fromNp, struct NetworkPlayer* toNp); +void network_receive_level_request(struct Packet* p); -// packet_macro_deletions.c -void network_send_macro_deletions(u8 destGlobalIndex); -void network_receive_macro_deletions(struct Packet* p); +// packet_level.c +void network_send_level(struct NetworkPlayer* toNp, bool sendArea); +void network_receive_level(struct Packet* p); -// packet_spawn_info_deletions.c -void network_send_spawn_info_deletions(u8 destGlobalIndex); -void network_receive_spawn_info_deletions(struct Packet* p); +// packet_area_request.c +void network_send_area_request(struct NetworkPlayer* fromNp, struct NetworkPlayer* toNp); +void network_receive_area_request(struct Packet* p); + +// packet_area.c +void network_send_area(struct NetworkPlayer* toNp); +void network_receive_area(struct Packet* p); + +// packet_sync_valid.c +void network_send_sync_valid(struct NetworkPlayer* toNp); +void network_receive_sync_valid(struct Packet* p); + +// packet_level_spawn_info.c +void network_send_level_spawn_info(struct NetworkPlayer* destNp); +void network_receive_level_spawn_info(struct Packet* p); + +// packet_level_macro.c +void network_send_level_macro(struct NetworkPlayer* destNp); +void network_receive_level_macro(struct Packet* p); + +// packet_level_area_inform.c +void network_send_level_area_inform(struct NetworkPlayer* np); +void network_receive_level_area_inform(struct Packet* p); #endif diff --git a/src/pc/network/packets/packet_area.c b/src/pc/network/packets/packet_area.c new file mode 100644 index 000000000..2b08723b9 --- /dev/null +++ b/src/pc/network/packets/packet_area.c @@ -0,0 +1,156 @@ +#include +#include "../network.h" +#include "game/interaction.h" +#include "game/level_update.h" +#include "game/area.h" +#include "game/object_helpers.h" +#include "behavior_table.h" +#include "object_constants.h" +#include "object_fields.h" +#include "model_ids.h" +//#define DISABLE_MODULE_LOG 1 +#include "pc/debuglog.h" + +void network_send_area(struct NetworkPlayer* toNp) { + extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex; + + packet_ordered_begin(); + { + struct Packet p; + packet_init(&p, PACKET_AREA, true, false); + + // level location + packet_write(&p, &gCurrCourseNum, sizeof(s16)); + packet_write(&p, &gCurrActNum, sizeof(s16)); + packet_write(&p, &gCurrLevelNum, sizeof(s16)); + packet_write(&p, &gCurrAreaIndex, sizeof(s16)); + + // count respawners and write + u8 respawnerCount = 0; + for (int i = 0; i < MAX_SYNC_OBJECTS; i++) { + struct SyncObject* so = &gSyncObjects[i]; + if (so == NULL || so->o == NULL || so->o->behavior != bhvRespawner) { continue; } + respawnerCount++; + } + packet_write(&p, &respawnerCount, sizeof(u8)); + + // write respawners + for (int i = 0; i < MAX_SYNC_OBJECTS; i++) { + struct SyncObject* so = &gSyncObjects[i]; + if (so == NULL || so->o == NULL || so->o->behavior != bhvRespawner) { continue; } + u32 behaviorToRespawn = get_id_from_behavior(so->o->oRespawnerBehaviorToRespawn); + packet_write(&p, &so->o->oPosX, sizeof(f32)); + packet_write(&p, &so->o->oPosY, sizeof(f32)); + packet_write(&p, &so->o->oPosZ, sizeof(f32)); + packet_write(&p, &so->o->oBehParams, sizeof(s32)); + packet_write(&p, &so->o->oRespawnerModelToRespawn, sizeof(s32)); + packet_write(&p, &so->o->oRespawnerMinSpawnDist, sizeof(f32)); + packet_write(&p, &behaviorToRespawn, sizeof(s32)); + packet_write(&p, &so->o->oSyncID, sizeof(u32)); + LOG_INFO("tx respawner"); + } + + // send area packet + network_send_to(toNp->localIndex, &p); + + // send non-static objects + for (int i = 0; i < MAX_SYNC_OBJECTS; i++) { + struct SyncObject* so = &gSyncObjects[i]; + if (so == NULL || so->o == NULL || so->o->oSyncID != (u32)i) { continue; } + if (so->staticLevelSpawn) { continue; } + if (so->o->behavior == bhvRespawner) { continue; } + struct Object* spawn_objects[] = { so->o }; + + // TODO: move find model to a utility file/function + // find model + u32 model = 0; + for (int j = 0; j < 256; j++) { + if (so->o->header.gfx.sharedChild == gLoadedGraphNodes[j]) { + model = j; + break; + } + } + + u32 models[] = { model }; + network_send_spawn_objects_to(toNp->localIndex, spawn_objects, models, 1); + LOG_INFO("tx non-static"); + } + + // send last reliable ent packet + for (int i = 0; i < MAX_SYNC_OBJECTS; i++) { + struct SyncObject* so = &gSyncObjects[i]; + if (so == NULL || so->o == NULL) { continue; } + struct Packet* entPacket = get_last_sync_ent_reliable_packet(i); + if (entPacket->error) { continue; } + struct Packet p2 = { 0 }; + packet_duplicate(entPacket, &p2); + network_send_to(toNp->localIndex, &p2); + } + + // send sync valid + network_send_sync_valid(toNp); + } + packet_ordered_end(); + + LOG_INFO("tx area"); +} + +void network_receive_area(struct Packet* p) { + LOG_INFO("rx area"); + + // read level location + 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)); + + extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum; + if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) { + LOG_ERROR("rx area: received an improper location"); + return; + } + + // read respawner count + u8 respawnerCount = 0; + packet_read(p, &respawnerCount, sizeof(u8)); + + // read respawners + for (int i = 0; i < respawnerCount; i++) { + f32 posX, posY, posZ; + packet_read(p, &posX, sizeof(f32)); + packet_read(p, &posY, sizeof(f32)); + packet_read(p, &posZ, sizeof(f32)); + + s32 behParams, respawnerModelToRespawn; + packet_read(p, &behParams, sizeof(s32)); + packet_read(p, &respawnerModelToRespawn, sizeof(s32)); + + f32 respawnerMinSpawnDist; + packet_read(p, &respawnerMinSpawnDist, sizeof(f32)); + + u32 behaviorToRespawn, syncId; + packet_read(p, &behaviorToRespawn, sizeof(u32)); + packet_read(p, &syncId, sizeof(u32)); + + struct SyncObject* so = &gSyncObjects[syncId]; + + LOG_INFO("rx respawner"); + if (so->staticLevelSpawn) { + struct Object* respawner = spawn_object_abs_with_rot(gMarioStates[0].marioObj, 0, MODEL_NONE, bhvRespawner, posX, posY, posZ, 0, 0, 0); + respawner->parentObj = respawner; + respawner->oBehParams = behParams; + respawner->oRespawnerModelToRespawn = respawnerModelToRespawn; + respawner->oRespawnerMinSpawnDist = respawnerMinSpawnDist; + respawner->oRespawnerBehaviorToRespawn = get_behavior_from_id(behaviorToRespawn); + respawner->oSyncID = syncId; + + struct Object* o = so->o; + o->oSyncID = 0; + o->activeFlags = ACTIVE_FLAG_DEACTIVATED; + + so->o = respawner; + LOG_INFO("rx respawner replaced!"); + } + } +} diff --git a/src/pc/network/packets/packet_area_request.c b/src/pc/network/packets/packet_area_request.c new file mode 100644 index 000000000..152bb88c4 --- /dev/null +++ b/src/pc/network/packets/packet_area_request.c @@ -0,0 +1,49 @@ +#include +#include "../network.h" +//#define DISABLE_MODULE_LOG 1 +#include "pc/debuglog.h" + +void network_send_area_request(struct NetworkPlayer* fromNp, struct NetworkPlayer* toNp) { + if (gNetworkType == NT_SERVER && toNp == gNetworkPlayerLocal) { + // requesting server's area, send it immediately + network_send_area(fromNp); + return; + } + + struct Packet p; + packet_init(&p, PACKET_AREA_REQUEST, true, false); + packet_write(&p, &fromNp->globalIndex, sizeof(u8)); + packet_write(&p, &fromNp->currCourseNum, sizeof(s16)); + packet_write(&p, &fromNp->currActNum, sizeof(s16)); + packet_write(&p, &fromNp->currLevelNum, sizeof(s16)); + packet_write(&p, &fromNp->currAreaIndex, sizeof(s16)); + network_send_to(toNp->localIndex, &p); + LOG_INFO("tx area request"); +} + +void network_receive_area_request(struct Packet* p) { + LOG_INFO("rx area request"); + + u8 globalIndex; + s16 courseNum, actNum, levelNum, areaIndex; + packet_read(p, &globalIndex, 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)); + + struct NetworkPlayer* toNp = network_player_from_global_index(globalIndex); + if (toNp == NULL || toNp->localIndex == UNKNOWN_LOCAL_INDEX || !toNp->connected) { + LOG_ERROR("Receiving area request from inactive player!"); + return; + } + + extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex; + if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) { + LOG_ERROR("rx area request: received an improper location"); + return; + } + + // send area + network_send_area(toNp); +} diff --git a/src/pc/network/packets/packet_change_area.c b/src/pc/network/packets/packet_change_area.c new file mode 100644 index 000000000..213f3d345 --- /dev/null +++ b/src/pc/network/packets/packet_change_area.c @@ -0,0 +1,77 @@ +#include +#include "../network.h" +#include "level_table.h" +//#define DISABLE_MODULE_LOG 1 +#include "pc/debuglog.h" + +static void player_changed_area(struct NetworkPlayer* np, s16 courseNum, s16 actNum, s16 levelNum, s16 areaIndex) { + // set NetworkPlayer variables + np->currCourseNum = courseNum; + np->currActNum = actNum; + np->currLevelNum = levelNum; + np->currAreaIndex = areaIndex; + np->currAreaSyncValid = false; + network_send_level_area_inform(np); + + // find a NetworkPlayer at that area + struct NetworkPlayer* npLevelAreaMatch = get_network_player_from_area(courseNum, actNum, levelNum, areaIndex); + + if (npLevelAreaMatch == NULL) { + // no NetworkPlayer in the level + network_send_sync_valid(np); + return; + } + + // matching NetworkPlayer is client + network_send_area_request(np, npLevelAreaMatch); +} + +void network_send_change_area(void) { + extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex; + + // override castle act to 0 to prevent instancing of the hub + if (gCurrCourseNum == 0 && (gCurrLevelNum == LEVEL_CASTLE || gCurrLevelNum == LEVEL_CASTLE_GROUNDS || gCurrLevelNum == LEVEL_CASTLE_COURTYARD)) { + gCurrActNum = 0; + } + + if (gNetworkType == NT_SERVER) { + player_changed_area(gNetworkPlayerLocal, gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex); + return; + } + + struct Packet p; + packet_init(&p, PACKET_CHANGE_AREA, 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(gNetworkPlayerServer->localIndex, &p); + + struct NetworkPlayer* np = gNetworkPlayerLocal; + np->currCourseNum = gCurrCourseNum; + np->currActNum = gCurrActNum; + np->currLevelNum = gCurrLevelNum; + np->currAreaIndex = gCurrAreaIndex; + np->currAreaSyncValid = false; + + LOG_INFO("tx change area"); +} + +void network_receive_change_area(struct Packet* p) { + LOG_INFO("rx change area"); + + assert(gNetworkType == NT_SERVER); + struct NetworkPlayer* np = &gNetworkPlayers[p->localIndex]; + if (np == NULL || np->localIndex == UNKNOWN_LOCAL_INDEX || !np->connected) { + LOG_ERROR("Receiving change area 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)); + + player_changed_area(np, courseNum, actNum, levelNum, areaIndex); +} diff --git a/src/pc/network/packets/packet_change_level.c b/src/pc/network/packets/packet_change_level.c new file mode 100644 index 000000000..b4c42c01d --- /dev/null +++ b/src/pc/network/packets/packet_change_level.c @@ -0,0 +1,85 @@ +#include +#include "../network.h" +#include "level_table.h" +//#define DISABLE_MODULE_LOG 1 +#include "pc/debuglog.h" + +static void player_changed_level(struct NetworkPlayer* np, s16 courseNum, s16 actNum, s16 levelNum, s16 areaIndex) { + // set NetworkPlayer variables + np->currCourseNum = courseNum; + np->currActNum = actNum; + np->currLevelNum = levelNum; + np->currAreaIndex = areaIndex; + np->currLevelSyncValid = false; + np->currAreaSyncValid = false; + network_send_level_area_inform(np); + + // find a NetworkPlayer around that location + struct NetworkPlayer* npLevelAreaMatch = get_network_player_from_area(courseNum, actNum, levelNum, areaIndex); + struct NetworkPlayer* npLevelMatch = get_network_player_from_level(courseNum, actNum, levelNum); + struct NetworkPlayer* npAny = (npLevelAreaMatch == NULL) ? npLevelMatch : npLevelAreaMatch; + + if (npAny == NULL) { + // no NetworkPlayer in the level + network_send_sync_valid(np); + return; + } + + // matching NetworkPlayer is client + if (npAny == npLevelAreaMatch) { + network_send_level_area_request(np, npAny); + } else { + network_send_level_request(np, npAny); + } +} + +void network_send_change_level(void) { + extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex; + + // override castle act to 0 to prevent instancing of the hub + if (gCurrCourseNum == 0 && (gCurrLevelNum == LEVEL_CASTLE || gCurrLevelNum == LEVEL_CASTLE_GROUNDS || gCurrLevelNum == LEVEL_CASTLE_COURTYARD)) { + gCurrActNum = 0; + } + + if (gNetworkType == NT_SERVER) { + player_changed_level(gNetworkPlayerLocal, gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex); + return; + } + + struct Packet p; + packet_init(&p, PACKET_CHANGE_LEVEL, 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(gNetworkPlayerServer->localIndex, &p); + + struct NetworkPlayer* np = gNetworkPlayerLocal; + np->currCourseNum = gCurrCourseNum; + np->currActNum = gCurrActNum; + np->currLevelNum = gCurrLevelNum; + np->currAreaIndex = gCurrAreaIndex; + np->currAreaSyncValid = false; + np->currLevelSyncValid = false; + + LOG_INFO("tx change level"); +} + +void network_receive_change_level(struct Packet* p) { + LOG_INFO("rx change level"); + + assert(gNetworkType == NT_SERVER); + struct NetworkPlayer* np = &gNetworkPlayers[p->localIndex]; + if (np == NULL || np->localIndex == UNKNOWN_LOCAL_INDEX || !np->connected) { + LOG_ERROR("Receiving change level 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)); + + player_changed_level(np, courseNum, actNum, levelNum, areaIndex); +} diff --git a/src/pc/network/packets/packet_level.c b/src/pc/network/packets/packet_level.c new file mode 100644 index 000000000..5bacb6ea9 --- /dev/null +++ b/src/pc/network/packets/packet_level.c @@ -0,0 +1,67 @@ +#include +#include "../network.h" +#include "game/interaction.h" +#include "game/level_update.h" +//#define DISABLE_MODULE_LOG 1 +#include "pc/debuglog.h" + +void network_send_level(struct NetworkPlayer* toNp, bool sendArea) { + extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum; + + packet_ordered_begin(); + { + struct Packet p; + packet_init(&p, PACKET_LEVEL, true, false); + + // level location + packet_write(&p, &gCurrCourseNum, sizeof(s16)); + packet_write(&p, &gCurrActNum, sizeof(s16)); + packet_write(&p, &gCurrLevelNum, sizeof(s16)); + + // level variables + packet_write(&p, &gMarioStates[0].numCoins, sizeof(s16)); + packet_write(&p, &gPssSlideStarted, sizeof(u8)); + packet_write(&p, &gHudDisplay.timer, sizeof(u16)); + + // send level packet + network_send_to(toNp->localIndex, &p); + + // send macro deletions + network_send_level_macro(toNp); + + // send spawn info + network_send_level_spawn_info(toNp); + + if (sendArea) { + // send the area + network_send_area(toNp); + } else { + // send sync valid + network_send_sync_valid(toNp); + } + } + packet_ordered_end(); + + LOG_INFO("tx level"); +} + +void network_receive_level(struct Packet* p) { + LOG_INFO("rx level"); + + // read level location + s16 courseNum, actNum, levelNum; + packet_read(p, &courseNum, sizeof(s16)); + packet_read(p, &actNum, sizeof(s16)); + packet_read(p, &levelNum, sizeof(s16)); + + extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum; + if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum) { + LOG_ERROR("rx level: received an improper location"); + return; + } + + // read level variables + packet_write(p, &gMarioStates[0].numCoins, sizeof(s16)); + packet_write(p, &gPssSlideStarted, sizeof(u8)); + packet_write(p, &gHudDisplay.timer, sizeof(u16)); +} diff --git a/src/pc/network/packets/packet_level_area.c b/src/pc/network/packets/packet_level_area.c deleted file mode 100644 index a63d9a307..000000000 --- a/src/pc/network/packets/packet_level_area.c +++ /dev/null @@ -1,147 +0,0 @@ -#include -#include "level_table.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) { - // override castle act to 0 to prevent instancing of the hub - if (gCurrCourseNum == 0 && (gCurrLevelNum == LEVEL_CASTLE || gCurrLevelNum == LEVEL_CASTLE_GROUNDS || gCurrLevelNum == LEVEL_CASTLE_COURTYARD)) { - gCurrActNum = 0; - } - - 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(gNetworkPlayerServer->localIndex, &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); - } -} diff --git a/src/pc/network/packets/packet_level_area_inform.c b/src/pc/network/packets/packet_level_area_inform.c new file mode 100644 index 000000000..9cfc6ecd9 --- /dev/null +++ b/src/pc/network/packets/packet_level_area_inform.c @@ -0,0 +1,45 @@ +#include +#include "../network.h" +#include "level_table.h" +//#define DISABLE_MODULE_LOG 1 +#include "pc/debuglog.h" + +void network_send_level_area_inform(struct NetworkPlayer* np) { + assert(gNetworkType == NT_SERVER); + + struct Packet p; + packet_init(&p, PACKET_LEVEL_AREA_INFORM, true, false); + packet_write(&p, &np->globalIndex, sizeof(u8)); + 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(&p); + + LOG_INFO("tx level area inform"); +} + +void network_receive_level_area_inform(struct Packet* p) { + LOG_INFO("rx level area inform"); + + assert(gNetworkType != NT_SERVER); + + u8 globalIndex; + s16 courseNum, actNum, levelNum, areaIndex; + packet_read(p, &globalIndex, 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)); + + struct NetworkPlayer* np = network_player_from_global_index(globalIndex); + if (np == NULL || np->localIndex == UNKNOWN_LOCAL_INDEX || !np->connected) { + LOG_ERROR("Receiving level area inform from inactive player!"); + return; + } + + np->currCourseNum = courseNum; + np->currActNum = actNum; + np->currLevelNum = levelNum; + np->currAreaIndex = areaIndex; +} diff --git a/src/pc/network/packets/packet_level_area_request.c b/src/pc/network/packets/packet_level_area_request.c new file mode 100644 index 000000000..81b1e63cc --- /dev/null +++ b/src/pc/network/packets/packet_level_area_request.c @@ -0,0 +1,49 @@ +#include +#include "../network.h" +//#define DISABLE_MODULE_LOG 1 +#include "pc/debuglog.h" + +void network_send_level_area_request(struct NetworkPlayer* fromNp, struct NetworkPlayer* toNp) { + if (gNetworkType == NT_SERVER && toNp == gNetworkPlayerLocal) { + // requesting server's level area, send it immediately + network_send_level(fromNp, true); + return; + } + + struct Packet p; + packet_init(&p, PACKET_LEVEL_AREA_REQUEST, true, false); + packet_write(&p, &fromNp->globalIndex, sizeof(u8)); + packet_write(&p, &fromNp->currCourseNum, sizeof(s16)); + packet_write(&p, &fromNp->currActNum, sizeof(s16)); + packet_write(&p, &fromNp->currLevelNum, sizeof(s16)); + packet_write(&p, &fromNp->currAreaIndex, sizeof(s16)); + network_send_to(toNp->localIndex, &p); + LOG_INFO("tx level area request"); +} + +void network_receive_level_area_request(struct Packet* p) { + LOG_INFO("rx level area request"); + + u8 globalIndex; + s16 courseNum, actNum, levelNum, areaIndex; + packet_read(p, &globalIndex, 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)); + + struct NetworkPlayer* toNp = network_player_from_global_index(globalIndex); + if (toNp == NULL || toNp->localIndex == UNKNOWN_LOCAL_INDEX || !toNp->connected) { + LOG_ERROR("Receiving level area request from inactive player!"); + return; + } + + extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex; + if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) { + LOG_ERROR("rx level area request: received an improper location"); + return; + } + + // send level area + network_send_level(toNp, true); +} diff --git a/src/pc/network/packets/packet_macro_deletions.c b/src/pc/network/packets/packet_level_macro.c similarity index 82% rename from src/pc/network/packets/packet_macro_deletions.c rename to src/pc/network/packets/packet_level_macro.c index 54a02899b..45455a12b 100644 --- a/src/pc/network/packets/packet_macro_deletions.c +++ b/src/pc/network/packets/packet_level_macro.c @@ -25,23 +25,22 @@ static struct Object* get_object_matching_respawn_info(s16* respawnInfo) { //// -void network_send_macro_deletions_area(u8 destGlobalIndex, u8 areaIndex) { +static void network_send_level_macro_area(struct NetworkPlayer* destNp, u8 areaIndex) { // check that the area is active struct Area* area = &gAreaData[areaIndex]; if (area->unk04 == NULL) { return; } - struct NetworkPlayer* destNp = network_player_from_global_index(destGlobalIndex); if (destNp == NULL || !destNp->connected) { - LOG_ERROR("network_send_macro_deletions_area: dest np is invalid"); + LOG_ERROR("network_send_level_macro: dest np is invalid"); return; } // write header struct Packet p; - packet_init(&p, PACKET_MACRO_DELETIONS, true, false); + packet_init(&p, PACKET_LEVEL_MACRO, true, false); packet_write(&p, &gCurrCourseNum, sizeof(s16)); - packet_write(&p, &gCurrActNum, sizeof(s16)); - packet_write(&p, &gCurrLevelNum, sizeof(s16)); + packet_write(&p, &gCurrActNum, sizeof(s16)); + packet_write(&p, &gCurrLevelNum, sizeof(s16)); packet_write(&p, &gCurrAreaIndex, sizeof(s16)); // write this area's index @@ -54,7 +53,7 @@ void network_send_macro_deletions_area(u8 destGlobalIndex, u8 areaIndex) { // loop through macro objects for deletions s16* macroObjList = area->macroObjects; - while (*macroObjList != -1) { + while (macroObjList != NULL && *macroObjList != -1) { // grab preset ID s32 presetID = (*macroObjList & 0x1FF) - 31; // Preset identifier for MacroObjectPresets array if (presetID < 0) { break; } @@ -68,7 +67,7 @@ void network_send_macro_deletions_area(u8 destGlobalIndex, u8 areaIndex) { *macroDeletionCount = *macroDeletionCount + 1; u16 offset = respawnInfo - area->macroObjects; packet_write(&p, &offset, sizeof(u16)); - LOG_INFO("tx macro deletion: offset %d", offset); + LOG_INFO("tx macro: offset %d", offset); } } @@ -78,7 +77,7 @@ void network_send_macro_deletions_area(u8 destGlobalIndex, u8 areaIndex) { // loop through macro objects for special cases macroObjList = area->macroObjects; - while (*macroObjList != -1) { + while (macroObjList != NULL && *macroObjList != -1) { // grab preset ID s32 presetID = (*macroObjList & 0x1FF) - 31; // Preset identifier for MacroObjectPresets array if (presetID < 0) { break; } @@ -101,33 +100,32 @@ void network_send_macro_deletions_area(u8 destGlobalIndex, u8 areaIndex) { // send the packet if there are deletions if (*macroDeletionCount > 0 || *macroSpecialCount > 0) { network_send_to(destNp->localIndex, &p); - LOG_INFO("tx macro deletion for area %d (count %d)", areaIndex, *macroDeletionCount); + LOG_INFO("tx macro for area %d (count %d, %d)", areaIndex, *macroDeletionCount, *macroSpecialCount); } } -void network_send_macro_deletions(u8 destGlobalIndex) { - if (!gNetworkPlayerLocal->currAreaSyncValid) { +void network_send_level_macro(struct NetworkPlayer* destNp) { + if (!gNetworkPlayerLocal->currLevelSyncValid) { 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_macro_deletions: dest np is invalid"); + LOG_ERROR("network_send_level_macro: dest np is invalid"); return; } for (int i = 0; i < 8; i++) { - network_send_macro_deletions_area(destGlobalIndex, i); + network_send_level_macro_area(destNp, i); } } -void network_receive_macro_deletions(struct Packet* p) { +void network_receive_level_macro(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)); + 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) { LOG_ERROR("Receiving 'location response' with the wrong location!"); @@ -140,7 +138,7 @@ void network_receive_macro_deletions(struct Packet* p) { // read and execute macro deletions u8 macroDeletionCount; packet_read(p, ¯oDeletionCount, sizeof(u8)); - LOG_INFO("rx macro deletions (count %d)", macroDeletionCount); + LOG_INFO("rx macro (count %d)", macroDeletionCount); while (macroDeletionCount-- > 0) { u16 offset; @@ -166,7 +164,6 @@ void network_receive_macro_deletions(struct Packet* p) { } // read and execute macro specials - u8 macroSpecialCount; packet_read(p, ¯oSpecialCount, sizeof(u8)); while (macroSpecialCount-- > 0) { diff --git a/src/pc/network/packets/packet_level_request.c b/src/pc/network/packets/packet_level_request.c new file mode 100644 index 000000000..e18a7d47e --- /dev/null +++ b/src/pc/network/packets/packet_level_request.c @@ -0,0 +1,47 @@ +#include +#include "../network.h" +//#define DISABLE_MODULE_LOG 1 +#include "pc/debuglog.h" + +void network_send_level_request(struct NetworkPlayer* fromNp, struct NetworkPlayer* toNp) { + if (gNetworkType == NT_SERVER && toNp == gNetworkPlayerLocal) { + // requesting server's level, send it immediately + network_send_level(fromNp, false); + return; + } + + struct Packet p; + packet_init(&p, PACKET_LEVEL_REQUEST, true, false); + packet_write(&p, &fromNp->globalIndex, sizeof(u8)); + packet_write(&p, &fromNp->currCourseNum, sizeof(s16)); + packet_write(&p, &fromNp->currActNum, sizeof(s16)); + packet_write(&p, &fromNp->currLevelNum, sizeof(s16)); + network_send_to(toNp->localIndex, &p); + LOG_INFO("tx level request"); +} + +void network_receive_level_request(struct Packet* p) { + LOG_INFO("rx level request"); + + u8 globalIndex; + s16 courseNum, actNum, levelNum; + packet_read(p, &globalIndex, sizeof(u8)); + packet_read(p, &courseNum, sizeof(s16)); + packet_read(p, &actNum, sizeof(s16)); + packet_read(p, &levelNum, sizeof(s16)); + + struct NetworkPlayer* toNp = network_player_from_global_index(globalIndex); + if (toNp == NULL || toNp->localIndex == UNKNOWN_LOCAL_INDEX || !toNp->connected) { + LOG_ERROR("Receiving level request from inactive player!"); + return; + } + + extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum; + if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum) { + LOG_ERROR("rx level request: received an improper location"); + return; + } + + // send level + network_send_level(toNp, false); +} diff --git a/src/pc/network/packets/packet_spawn_info_deletions.c b/src/pc/network/packets/packet_level_spawn_info.c similarity index 81% rename from src/pc/network/packets/packet_spawn_info_deletions.c rename to src/pc/network/packets/packet_level_spawn_info.c index 384007541..179901568 100644 --- a/src/pc/network/packets/packet_spawn_info_deletions.c +++ b/src/pc/network/packets/packet_level_spawn_info.c @@ -13,7 +13,7 @@ #define DISABLE_MODULE_LOG 1 #include "pc/debuglog.h" -static struct Object* get_object_matching_respawn_info(s32* respawnInfo) { +static struct Object* get_object_matching_respawn_info(u32* respawnInfo) { for (int i = 0; i < OBJECT_POOL_CAPACITY; i++) { struct Object* o = &gObjectPool[i]; if (o->respawnInfo == respawnInfo) { return o; } @@ -24,20 +24,19 @@ static struct Object* get_object_matching_respawn_info(s32* respawnInfo) { //// -void network_send_spawn_info_deletions_area(u8 destGlobalIndex, u8 areaIndex) { +static void network_send_level_spawn_info_area(struct NetworkPlayer* destNp, u8 areaIndex) { // check that the area is active struct Area* area = &gAreaData[areaIndex]; if (area->unk04 == NULL) { return; } - struct NetworkPlayer* destNp = network_player_from_global_index(destGlobalIndex); if (destNp == NULL || !destNp->connected) { - LOG_ERROR("network_send_spawn_info_deletions_area: dest np is invalid"); + LOG_ERROR("network_send_level_spawn_info_area: dest np is invalid"); return; } // write header struct Packet p; - packet_init(&p, PACKET_SPAWN_INFO_DELETIONS, true, false); + packet_init(&p, PACKET_LEVEL_SPAWN_INFO, true, false); packet_write(&p, &gCurrCourseNum, sizeof(s16)); packet_write(&p, &gCurrActNum, sizeof(s16)); packet_write(&p, &gCurrLevelNum, sizeof(s16)); @@ -70,28 +69,27 @@ void network_send_spawn_info_deletions_area(u8 destGlobalIndex, u8 areaIndex) { // send the packet if there are deletions if (*spawnInfoDeletionCount > 0) { network_send_to(destNp->localIndex, &p); - LOG_INFO("tx spawn info deletion for area %d (count %d)", areaIndex, *spawnInfoDeletionCount); + LOG_INFO("tx spawn info for area %d (count %d)", areaIndex, *spawnInfoDeletionCount); } } -void network_send_spawn_info_deletions(u8 destGlobalIndex) { +void network_send_level_spawn_info(struct NetworkPlayer* destNp) { 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_spawn_info_deletions: dest np is invalid"); + LOG_ERROR("network_send_level_spawn_info: dest np is invalid"); return; } for (int i = 0; i < 8; i++) { - network_send_spawn_info_deletions_area(destGlobalIndex, i); + network_send_level_spawn_info_area(destNp, i); } } -void network_receive_spawn_info_deletions(struct Packet* p) { +void network_receive_level_spawn_info(struct Packet* p) { s16 courseNum, actNum, levelNum, areaIndex; packet_read(p, &courseNum, sizeof(s16)); packet_read(p, &actNum, sizeof(s16)); @@ -106,7 +104,7 @@ void network_receive_spawn_info_deletions(struct Packet* p) { u8 thisAreaIndex, spawnInfoDeletionCount; packet_read(p, &thisAreaIndex, sizeof(u8)); packet_read(p, &spawnInfoDeletionCount, sizeof(u8)); - LOG_INFO("rx spawn info deletions (count %d)", spawnInfoDeletionCount); + LOG_INFO("rx spawn info (count %d)", spawnInfoDeletionCount); if (spawnInfoDeletionCount <= 0) { return; } struct SpawnInfo* spawnInfo = gAreaData[thisAreaIndex].objectSpawnInfos; diff --git a/src/pc/network/packets/packet_location_request.c b/src/pc/network/packets/packet_location_request.c deleted file mode 100644 index 08f022e30..000000000 --- a/src/pc/network/packets/packet_location_request.c +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include "../network.h" -//#define DISABLE_MODULE_LOG 1 -#include "pc/debuglog.h" - -extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex; - -void network_send_location_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; - return; - } - network_send_location_request_client(gNetworkPlayerLocal->globalIndex, np->globalIndex); - return; - } - - struct Packet p; - packet_init(&p, PACKET_LOCATION_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); -} - -void network_receive_location_request(struct Packet* p) { - if (gNetworkType != NT_SERVER) { - LOG_ERROR("non-server is receiving a location request!"); - return; - } - - struct NetworkPlayer* np = &gNetworkPlayers[p->localIndex]; - if (np == NULL || np->localIndex == UNKNOWN_LOCAL_INDEX || !np->connected) { - LOG_ERROR("Receiving location 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; - - 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_location_response(np->globalIndex); - } else { - network_send_location_request_client(np->globalIndex, np2->globalIndex); - } -} diff --git a/src/pc/network/packets/packet_location_request_client.c b/src/pc/network/packets/packet_location_request_client.c deleted file mode 100644 index 3bb59d697..000000000 --- a/src/pc/network/packets/packet_location_request_client.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include "../network.h" -//#define DISABLE_MODULE_LOG 1 -#include "pc/debuglog.h" - -extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex; - -void network_send_location_request_client(u8 destGlobalIndex, u8 srcGlobalIndex) { - if (gNetworkType != NT_SERVER) { - LOG_ERROR("client can't send a 'client location request'"); - return; - } - - struct NetworkPlayer* destNp = network_player_from_global_index(destGlobalIndex); - if (destNp == NULL || !destNp->connected) { - LOG_ERROR("network_send_client_location_request: dest np is invalid (global %d)", destGlobalIndex); - return; - } - - struct Packet p; - packet_init(&p, PACKET_LOCATION_REQUEST_CLIENT, 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)); - - struct NetworkPlayer* srcNp = network_player_from_global_index(srcGlobalIndex); - if (srcNp == NULL || !srcNp->connected || !srcNp->currAreaSyncValid) { - LOG_ERROR("network_send_client_location_request: source np is invalid (global %d)", srcGlobalIndex); - return; - } - - network_send_to(srcNp->localIndex, &p); -} - -void network_receive_location_request_client(struct Packet* p) { - if (gNetworkType == NT_SERVER) { - LOG_ERROR("server is receiving a 'client location 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)); - - if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) { - LOG_ERROR("Receiving 'client location request' with the wrong location!"); - return; - } - - network_send_location_response(destGlobalIndex); -} diff --git a/src/pc/network/packets/packet_location_response.c b/src/pc/network/packets/packet_location_response.c deleted file mode 100644 index 0bb6f0cdb..000000000 --- a/src/pc/network/packets/packet_location_response.c +++ /dev/null @@ -1,189 +0,0 @@ -#include -#include "../network.h" -#include "game/interaction.h" -#include "game/object_list_processor.h" -#include "game/object_helpers.h" -#include "game/interaction.h" -#include "game/level_update.h" -#include "game/macro_special_objects.h" -#include "object_constants.h" -#include "object_fields.h" -#include "behavior_table.h" -#include "model_ids.h" -//#define DISABLE_MODULE_LOG 1 -#include "pc/debuglog.h" - -void network_send_location_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_location_response: dest np is invalid"); - return; - } - - struct Packet p; - packet_init(&p, PACKET_LOCATION_RESPONSE, 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)); - - // level variables - packet_write(&p, &gMarioStates[0].numCoins, sizeof(s16)); - packet_write(&p, &gPssSlideStarted, sizeof(u8)); - packet_write(&p, &gHudDisplay.timer, sizeof(u16)); - - // respawners - u8 respawnerCount = 0; - for (int i = 0; i < MAX_SYNC_OBJECTS; i++) { - struct SyncObject* so = &gSyncObjects[i]; - if (so == NULL || so->o == NULL || so->o->behavior != bhvRespawner) { continue; } - respawnerCount++; - } - - packet_write(&p, &respawnerCount, sizeof(u8)); - for (int i = 0; i < MAX_SYNC_OBJECTS; i++) { - struct SyncObject* so = &gSyncObjects[i]; - if (so == NULL || so->o == NULL || so->o->behavior != bhvRespawner) { continue; } - u32 behaviorToRespawn = get_id_from_behavior(so->o->oRespawnerBehaviorToRespawn); - packet_write(&p, &so->o->oPosX, sizeof(f32)); - packet_write(&p, &so->o->oPosY, sizeof(f32)); - packet_write(&p, &so->o->oPosZ, sizeof(f32)); - packet_write(&p, &so->o->oBehParams, sizeof(s32)); - packet_write(&p, &so->o->oRespawnerModelToRespawn, sizeof(s32)); - packet_write(&p, &so->o->oRespawnerMinSpawnDist, sizeof(f32)); - packet_write(&p, &behaviorToRespawn, sizeof(s32)); - packet_write(&p, &so->o->oSyncID, sizeof(u32)); - LOG_INFO("tx respawner"); - } - - network_send_to(destNp->localIndex, &p); - - // send macro deletions - network_send_macro_deletions(destGlobalIndex); - - // send spawn info - network_send_spawn_info_deletions(destGlobalIndex); - - // send non-static objects - for (int i = 0; i < MAX_SYNC_OBJECTS; i++) { - struct SyncObject* so = &gSyncObjects[i]; - if (so == NULL || so->o == NULL || so->o->oSyncID != i) { continue; } - if (so->staticLevelSpawn) { continue; } - if (so->o->behavior == bhvRespawner) { continue; } - struct Object* spawn_objects[] = { so->o }; - - // TODO: move find model to a utility file/function - // find model - u32 model = 0; - for (int j = 0; j < 256; j++) { - if (so->o->header.gfx.sharedChild == gLoadedGraphNodes[j]) { - model = j; - break; - } - } - - u32 models[] = { model }; - network_send_spawn_objects_to(destNp->localIndex, spawn_objects, models, 1); - LOG_INFO("tx non-static"); - } - - // send last reliable ent packet - for (int i = 0; i < MAX_SYNC_OBJECTS; i++) { - struct SyncObject* so = &gSyncObjects[i]; - if (so == NULL || so->o == NULL) { continue; } - struct Packet* entPacket = get_last_sync_ent_reliable_packet(i); - if (entPacket->error) { continue; } - struct Packet p2 = { 0 }; - packet_duplicate(entPacket, &p2); - network_send_to(destNp->localIndex, &p2); - } - - LOG_INFO("tx location response"); -} - -void network_receive_location_response(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("Receiving 'location response' with the wrong location!"); - return; - } - - if (gNetworkPlayerLocal->currAreaSyncValid) { - LOG_ERROR("Receiving 'location response' when our location is already valid!"); - return; - } - - s16 numCoins; - packet_read(p, &numCoins, sizeof(s16)); - - u8 pssSlideStarted; - u16 hudDisplayTimer; - packet_read(p, &pssSlideStarted, sizeof(u8)); - packet_read(p, &hudDisplayTimer, sizeof(u16)); - if (pssSlideStarted) { - level_control_timer(TIMER_CONTROL_SHOW); - level_control_timer(TIMER_CONTROL_START); - gPssSlideStarted = TRUE; - gHudDisplay.timer = hudDisplayTimer; - } - - // read respawners - u8 respawnerCount = 0; - packet_read(p, &respawnerCount, sizeof(u8)); - - for (int i = 0; i < respawnerCount; i++) { - f32 posX, posY, posZ; - packet_read(p, &posX, sizeof(f32)); - packet_read(p, &posY, sizeof(f32)); - packet_read(p, &posZ, sizeof(f32)); - - s32 behParams, respawnerModelToRespawn; - packet_read(p, &behParams, sizeof(s32)); - packet_read(p, &respawnerModelToRespawn, sizeof(s32)); - - f32 respawnerMinSpawnDist; - packet_read(p, &respawnerMinSpawnDist, sizeof(f32)); - - u32 behaviorToRespawn, syncId; - packet_read(p, &behaviorToRespawn, sizeof(u32)); - packet_read(p, &syncId, sizeof(u32)); - - struct SyncObject* so = &gSyncObjects[syncId]; - - LOG_INFO("rx respawner"); - if (so->staticLevelSpawn) { - struct Object* respawner = spawn_object_abs_with_rot(gMarioStates[0].marioObj, 0, MODEL_NONE, bhvRespawner, posX, posY, posZ, 0, 0, 0); - respawner->parentObj = respawner; - respawner->oBehParams = behParams; - respawner->oRespawnerModelToRespawn = respawnerModelToRespawn; - respawner->oRespawnerMinSpawnDist = respawnerMinSpawnDist; - respawner->oRespawnerBehaviorToRespawn = get_behavior_from_id(behaviorToRespawn); - respawner->oSyncID = syncId; - - struct Object* o = so->o; - o->oSyncID = 0; - o->activeFlags = ACTIVE_FLAG_DEACTIVATED; - - so->o = respawner; - LOG_INFO("rx respawner replaced!"); - } - } - - gMarioStates[0].numCoins = numCoins; - gNetworkPlayerLocal->currAreaSyncValid = true; - - if (gNetworkType != NT_SERVER) { - network_send_level_area_valid(0); - } - LOG_INFO("rx location response"); -} \ No newline at end of file diff --git a/src/pc/network/packets/packet_read_write.c b/src/pc/network/packets/packet_read_write.c index c44878048..9b7e73acd 100644 --- a/src/pc/network/packets/packet_read_write.c +++ b/src/pc/network/packets/packet_read_write.c @@ -140,3 +140,11 @@ bool packet_check_hash(struct Packet* packet) { memcpy(&packetHash, &packet->buffer[packet->dataLength], sizeof(u32)); return localHash == packetHash; } + +void packet_ordered_begin(void) { + // TODO: implement ordered packet streams +} + +void packet_ordered_end(void) { + // TODO: implement ordered packet streams +} diff --git a/src/pc/network/packets/packet_sync_valid.c b/src/pc/network/packets/packet_sync_valid.c new file mode 100644 index 000000000..427df3f3e --- /dev/null +++ b/src/pc/network/packets/packet_sync_valid.c @@ -0,0 +1,62 @@ +#include +#include "../network.h" +//#define DISABLE_MODULE_LOG 1 +#include "pc/debuglog.h" + +void network_send_sync_valid(struct NetworkPlayer* toNp) { + // set the NetworkPlayers sync valid + toNp->currLevelSyncValid = true; + toNp->currAreaSyncValid = true; + + if (toNp == gNetworkPlayerLocal) { + // the player is the server, no need to send it + return; + } + + u8 myGlobalIndex = gNetworkPlayerLocal->globalIndex; + struct Packet p; + packet_init(&p, PACKET_SYNC_VALID, true, false); + packet_write(&p, &toNp->currCourseNum, sizeof(s16)); + packet_write(&p, &toNp->currActNum, sizeof(s16)); + packet_write(&p, &toNp->currLevelNum, sizeof(s16)); + packet_write(&p, &toNp->currAreaIndex, sizeof(s16)); + packet_write(&p, &myGlobalIndex, sizeof(u8)); + network_send_to(toNp->localIndex, &p); + + LOG_INFO("tx sync valid"); +} + +void network_receive_sync_valid(struct Packet* p) { + LOG_INFO("rx sync valid"); + + s16 courseNum, actNum, levelNum, areaIndex; + u8 fromGlobalIndex; + packet_read(p, &courseNum, sizeof(s16)); + packet_read(p, &actNum, sizeof(s16)); + packet_read(p, &levelNum, sizeof(s16)); + packet_read(p, &areaIndex, sizeof(s16)); + packet_read(p, &fromGlobalIndex, sizeof(u8)); + + if (gNetworkType != NT_SERVER) { + extern s16 gCurrCourseNum, gCurrActNum, gCurrLevelNum, gCurrAreaIndex; + if (courseNum != gCurrCourseNum || actNum != gCurrActNum || levelNum != gCurrLevelNum || areaIndex != gCurrAreaIndex) { + LOG_ERROR("rx sync valid: received an improper location"); + return; + } + } + + struct NetworkPlayer* np = (gNetworkType != NT_SERVER) ? gNetworkPlayerLocal : &gNetworkPlayers[p->localIndex]; + if (np == NULL || np->localIndex == UNKNOWN_LOCAL_INDEX || !np->connected) { + LOG_ERROR("Receiving sync valid from inactive player!"); + return; + } + + np->currLevelSyncValid = true; + np->currAreaSyncValid = true; + + // inform server + if (fromGlobalIndex != gNetworkPlayerServer->globalIndex) { + LOG_INFO("informing server of sync valid"); + network_send_sync_valid(gNetworkPlayerServer); + } +}