Complete rewrite of level-change/area-change system

Now level changes and area changes are separated. Entity deletions are
properly tracked on level change or area change. Late entity
synchronization is now triggered on any area change.
This commit is contained in:
MysterD 2021-06-11 01:42:20 -07:00
parent 0b3a97d405
commit 6bfdcbcb7b
25 changed files with 779 additions and 528 deletions

View file

@ -426,6 +426,7 @@ static void level_cmd_23(void) {
static void level_cmd_init_mario(void) { static void level_cmd_init_mario(void) {
u32 behaviorArg = CMD_GET(u32, 4); u32 behaviorArg = CMD_GET(u32, 4);
behaviorArg = behaviorArg;
void* behaviorScript = CMD_GET(void*, 8); void* behaviorScript = CMD_GET(void*, 8);
struct GraphNode* unk18 = gLoadedGraphNodes[CMD_GET(u8, 3)]; struct GraphNode* unk18 = gLoadedGraphNodes[CMD_GET(u8, 3)];

View file

@ -82,7 +82,6 @@ s32 approach_forward_vel(f32 *arr, f32 spC, f32 sp10) {
void chuckya_act_0(void) { void chuckya_act_0(void) {
struct Object* player = nearest_player_to_object(o); struct Object* player = nearest_player_to_object(o);
int distanceToPlayer = dist_between_objects(o, player);
int angleToPlayer = obj_angle_to_object(o, player); int angleToPlayer = obj_angle_to_object(o, player);
s32 sp3C; s32 sp3C;
UNUSED u8 pad[16]; UNUSED u8 pad[16];

View file

@ -51,7 +51,6 @@ void set_home_to_mario(void) {
break; break;
} }
} }
struct Object* player = nearest_player_to_object(o);
if (parentIsMario) { if (parentIsMario) {
o->oHomeX = o->parentObj->oPosX; o->oHomeX = o->parentObj->oPosX;
o->oHomeZ = o->parentObj->oPosZ; o->oHomeZ = o->parentObj->oPosZ;

View file

@ -116,6 +116,7 @@ extern s8 gRedCoinsCollected;
void create_dl_identity_matrix(void); void create_dl_identity_matrix(void);
void create_dl_translation_matrix(s8 pushOp, f32 x, f32 y, f32 z); void create_dl_translation_matrix(s8 pushOp, f32 x, f32 y, f32 z);
void create_dl_ortho_matrix(void); void create_dl_ortho_matrix(void);
void render_generic_char(u8 c);
void str_ascii_to_dialog(const char* string, u8* dialog, u16 length); void str_ascii_to_dialog(const char* string, u8* dialog, u16 length);
f32 get_generic_dialog_width(u8* dialog); f32 get_generic_dialog_width(u8* dialog);
f32 get_generic_ascii_string_width(const char* ascii); f32 get_generic_ascii_string_width(const char* ascii);

View file

@ -103,8 +103,14 @@ void network_on_loaded_level(void) {
// check for level change // check for level change
struct NetworkPlayer* np = gNetworkPlayerLocal; struct NetworkPlayer* np = gNetworkPlayerLocal;
if (np != NULL) { if (np != NULL) {
network_send_level_area(); bool levelMatch = (np->currCourseNum == gCurrCourseNum
network_send_location_request(); && 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 // 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 (gNetworkType == NT_NONE) { LOG_ERROR("network type error none!"); return; }
if (p->error) { LOG_ERROR("packet error!"); return; } if (p->error) { LOG_ERROR("packet error!"); return; }
if (gNetworkSystem == NULL) { LOG_ERROR("no network system attached"); 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 // set the flags again
packet_set_flags(p); packet_set_flags(p);

View file

@ -33,10 +33,24 @@ struct NetworkPlayer* network_player_from_global_index(u8 globalIndex) {
return NULL; 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++) { for (int i = 0; i < MAX_PLAYERS; i++) {
struct NetworkPlayer* np = &gNetworkPlayers[i]; struct NetworkPlayer* np = &gNetworkPlayers[i];
if (!np->connected) { continue; } 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->currAreaSyncValid) { continue; }
if (np->currCourseNum != courseNum) { continue; } if (np->currCourseNum != courseNum) { continue; }
if (np->currActNum != actNum) { continue; } if (np->currActNum != actNum) { continue; }
@ -100,6 +114,10 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
np->currAreaIndex = -1; np->currAreaIndex = -1;
np->currAreaSyncValid = false; np->currAreaSyncValid = false;
gNetworkPlayerLocal = np; gNetworkPlayerLocal = np;
if (gNetworkType == NT_SERVER) {
gNetworkPlayerServer = gNetworkPlayerLocal;
}
return 0; return 0;
} }

View file

@ -28,6 +28,7 @@ struct NetworkPlayer {
s16 currActNum; s16 currActNum;
s16 currLevelNum; s16 currLevelNum;
s16 currAreaIndex; s16 currAreaIndex;
bool currLevelSyncValid;
bool currAreaSyncValid; bool currAreaSyncValid;
u8 fadeOpacity; u8 fadeOpacity;
u16 rxSeqIds[MAX_RX_SEQ_IDS]; u16 rxSeqIds[MAX_RX_SEQ_IDS];
@ -41,7 +42,8 @@ extern struct NetworkPlayer* gNetworkPlayerServer;
bool network_player_any_connected(void); bool network_player_any_connected(void);
u8 network_player_connected_count(void); u8 network_player_connected_count(void);
struct NetworkPlayer* network_player_from_global_index(u8 globalIndex); 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); void network_player_update(void);
u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex); u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex);
u8 network_player_disconnected(u8 globalIndex); u8 network_player_disconnected(u8 globalIndex);

View file

@ -59,14 +59,21 @@ void packet_receive(struct Packet* p) {
case PACKET_SAVE_FILE: network_receive_save_file(p); break; case PACKET_SAVE_FILE: network_receive_save_file(p); break;
case PACKET_NETWORK_PLAYERS: network_receive_network_players(p); break; case PACKET_NETWORK_PLAYERS: network_receive_network_players(p); break;
case PACKET_DEATH: network_receive_death(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; // location
case PACKET_LOCATION_REQUEST: network_receive_location_request(p); break; case PACKET_CHANGE_LEVEL: network_receive_change_level(p); break;
case PACKET_LOCATION_REQUEST_CLIENT: network_receive_location_request_client(p); break; case PACKET_CHANGE_AREA: network_receive_change_area(p); break;
case PACKET_LOCATION_RESPONSE: network_receive_location_response(p); break; case PACKET_LEVEL_AREA_REQUEST: network_receive_level_area_request(p); break;
case PACKET_MACRO_DELETIONS: network_receive_macro_deletions(p); break; case PACKET_LEVEL_REQUEST: network_receive_level_request(p); break;
case PACKET_SPAWN_INFO_DELETIONS: network_receive_spawn_info_deletions(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; case PACKET_CUSTOM: network_receive_custom(p); break;
default: LOG_ERROR("received unknown packet: %d", p->buffer[0]); default: LOG_ERROR("received unknown packet: %d", p->buffer[0]);
} }

View file

@ -10,6 +10,8 @@
#define PACKET_LENGTH 1024 #define PACKET_LENGTH 1024
#define PACKET_DESTINATION_BROADCAST ((u8)-1) #define PACKET_DESTINATION_BROADCAST ((u8)-1)
struct NetworkPlayer;
enum PacketType { enum PacketType {
PACKET_ACK, PACKET_ACK,
PACKET_PLAYER, PACKET_PLAYER,
@ -31,13 +33,19 @@ enum PacketType {
PACKET_SAVE_FILE, PACKET_SAVE_FILE,
PACKET_NETWORK_PLAYERS, PACKET_NETWORK_PLAYERS,
PACKET_DEATH, PACKET_DEATH,
PACKET_LEVEL_AREA,
PACKET_LEVEL_AREA_VALID, PACKET_CHANGE_LEVEL,
PACKET_LOCATION_REQUEST, PACKET_CHANGE_AREA,
PACKET_LOCATION_REQUEST_CLIENT, PACKET_LEVEL_AREA_REQUEST,
PACKET_LOCATION_RESPONSE, PACKET_LEVEL_REQUEST,
PACKET_MACRO_DELETIONS, PACKET_LEVEL,
PACKET_SPAWN_INFO_DELETIONS, PACKET_AREA_REQUEST,
PACKET_AREA,
PACKET_SYNC_VALID,
PACKET_LEVEL_SPAWN_INFO,
PACKET_LEVEL_MACRO,
PACKET_LEVEL_AREA_INFORM,
/// ///
PACKET_CUSTOM = 255, PACKET_CUSTOM = 255,
}; };
@ -74,6 +82,8 @@ u8 packet_initial_read(struct Packet* packet);
void packet_read(struct Packet* packet, void* data, u16 length); void packet_read(struct Packet* packet, void* data, u16 length);
u32 packet_hash(struct Packet* packet); u32 packet_hash(struct Packet* packet);
bool packet_check_hash(struct Packet* packet); bool packet_check_hash(struct Packet* packet);
void packet_ordered_begin(void);
void packet_ordered_end(void);
// packet_reliable.c // packet_reliable.c
void network_forget_all_reliable(void); 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_send_death(void);
void network_receive_death(struct Packet* p); void network_receive_death(struct Packet* p);
// packet_level_area.c // packet_change_level.c
void network_send_level_area(void); void network_send_change_level(void);
void network_receive_level_area(struct Packet* p); void network_receive_change_level(struct Packet* p);
void network_send_level_area_valid(u8 toGlobalIndex);
void network_receive_level_area_valid(struct Packet* p);
// packet_location_request.c // packet_change_area.c
void network_send_location_request(void); void network_send_change_area(void);
void network_receive_location_request(struct Packet* p); void network_receive_change_area(struct Packet* p);
// packet_location_request_client.c // packet_level_area_request.c
void network_send_location_request_client(u8 destGlobalIndex, u8 srcGlobalIndex); void network_send_level_area_request(struct NetworkPlayer* fromNp, struct NetworkPlayer* toNp);
void network_receive_location_request_client(struct Packet* p); void network_receive_level_area_request(struct Packet* p);
// packet_location_response.c // packet_level_request.c
void network_send_location_response(u8 destGlobalIndex); void network_send_level_request(struct NetworkPlayer* fromNp, struct NetworkPlayer* toNp);
void network_receive_location_response(struct Packet* p); void network_receive_level_request(struct Packet* p);
// packet_macro_deletions.c // packet_level.c
void network_send_macro_deletions(u8 destGlobalIndex); void network_send_level(struct NetworkPlayer* toNp, bool sendArea);
void network_receive_macro_deletions(struct Packet* p); void network_receive_level(struct Packet* p);
// packet_spawn_info_deletions.c // packet_area_request.c
void network_send_spawn_info_deletions(u8 destGlobalIndex); void network_send_area_request(struct NetworkPlayer* fromNp, struct NetworkPlayer* toNp);
void network_receive_spawn_info_deletions(struct Packet* p); 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 #endif

View file

@ -0,0 +1,156 @@
#include <stdio.h>
#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!");
}
}
}

View file

@ -0,0 +1,49 @@
#include <stdio.h>
#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);
}

View file

@ -0,0 +1,77 @@
#include <stdio.h>
#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);
}

View file

@ -0,0 +1,85 @@
#include <stdio.h>
#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);
}

View file

@ -0,0 +1,67 @@
#include <stdio.h>
#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));
}

View file

@ -1,147 +0,0 @@
#include <stdio.h>
#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);
}
}

View file

@ -0,0 +1,45 @@
#include <stdio.h>
#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;
}

View file

@ -0,0 +1,49 @@
#include <stdio.h>
#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);
}

View file

@ -25,20 +25,19 @@ 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 // check that the area is active
struct Area* area = &gAreaData[areaIndex]; struct Area* area = &gAreaData[areaIndex];
if (area->unk04 == NULL) { return; } if (area->unk04 == NULL) { return; }
struct NetworkPlayer* destNp = network_player_from_global_index(destGlobalIndex);
if (destNp == NULL || !destNp->connected) { 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; return;
} }
// write header // write header
struct Packet p; 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, &gCurrCourseNum, sizeof(s16));
packet_write(&p, &gCurrActNum, sizeof(s16)); packet_write(&p, &gCurrActNum, sizeof(s16));
packet_write(&p, &gCurrLevelNum, sizeof(s16)); packet_write(&p, &gCurrLevelNum, sizeof(s16));
@ -54,7 +53,7 @@ void network_send_macro_deletions_area(u8 destGlobalIndex, u8 areaIndex) {
// loop through macro objects for deletions // loop through macro objects for deletions
s16* macroObjList = area->macroObjects; s16* macroObjList = area->macroObjects;
while (*macroObjList != -1) { while (macroObjList != NULL && *macroObjList != -1) {
// grab preset ID // grab preset ID
s32 presetID = (*macroObjList & 0x1FF) - 31; // Preset identifier for MacroObjectPresets array s32 presetID = (*macroObjList & 0x1FF) - 31; // Preset identifier for MacroObjectPresets array
if (presetID < 0) { break; } if (presetID < 0) { break; }
@ -68,7 +67,7 @@ void network_send_macro_deletions_area(u8 destGlobalIndex, u8 areaIndex) {
*macroDeletionCount = *macroDeletionCount + 1; *macroDeletionCount = *macroDeletionCount + 1;
u16 offset = respawnInfo - area->macroObjects; u16 offset = respawnInfo - area->macroObjects;
packet_write(&p, &offset, sizeof(u16)); 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 // loop through macro objects for special cases
macroObjList = area->macroObjects; macroObjList = area->macroObjects;
while (*macroObjList != -1) { while (macroObjList != NULL && *macroObjList != -1) {
// grab preset ID // grab preset ID
s32 presetID = (*macroObjList & 0x1FF) - 31; // Preset identifier for MacroObjectPresets array s32 presetID = (*macroObjList & 0x1FF) - 31; // Preset identifier for MacroObjectPresets array
if (presetID < 0) { break; } if (presetID < 0) { break; }
@ -101,28 +100,27 @@ void network_send_macro_deletions_area(u8 destGlobalIndex, u8 areaIndex) {
// send the packet if there are deletions // send the packet if there are deletions
if (*macroDeletionCount > 0 || *macroSpecialCount > 0) { if (*macroDeletionCount > 0 || *macroSpecialCount > 0) {
network_send_to(destNp->localIndex, &p); 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) { void network_send_level_macro(struct NetworkPlayer* destNp) {
if (!gNetworkPlayerLocal->currAreaSyncValid) { if (!gNetworkPlayerLocal->currLevelSyncValid) {
LOG_ERROR("my area is invalid"); LOG_ERROR("my area is invalid");
return; return;
} }
struct NetworkPlayer* destNp = network_player_from_global_index(destGlobalIndex);
if (destNp == NULL || !destNp->connected) { 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; return;
} }
for (int i = 0; i < 8; i++) { 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; s16 courseNum, actNum, levelNum, areaIndex;
packet_read(p, &courseNum, sizeof(s16)); packet_read(p, &courseNum, sizeof(s16));
packet_read(p, &actNum, sizeof(s16)); packet_read(p, &actNum, sizeof(s16));
@ -140,7 +138,7 @@ void network_receive_macro_deletions(struct Packet* p) {
// read and execute macro deletions // read and execute macro deletions
u8 macroDeletionCount; u8 macroDeletionCount;
packet_read(p, &macroDeletionCount, sizeof(u8)); packet_read(p, &macroDeletionCount, sizeof(u8));
LOG_INFO("rx macro deletions (count %d)", macroDeletionCount); LOG_INFO("rx macro (count %d)", macroDeletionCount);
while (macroDeletionCount-- > 0) { while (macroDeletionCount-- > 0) {
u16 offset; u16 offset;
@ -166,7 +164,6 @@ void network_receive_macro_deletions(struct Packet* p) {
} }
// read and execute macro specials // read and execute macro specials
u8 macroSpecialCount; u8 macroSpecialCount;
packet_read(p, &macroSpecialCount, sizeof(u8)); packet_read(p, &macroSpecialCount, sizeof(u8));
while (macroSpecialCount-- > 0) { while (macroSpecialCount-- > 0) {

View file

@ -0,0 +1,47 @@
#include <stdio.h>
#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);
}

View file

@ -13,7 +13,7 @@
#define DISABLE_MODULE_LOG 1 #define DISABLE_MODULE_LOG 1
#include "pc/debuglog.h" #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++) { for (int i = 0; i < OBJECT_POOL_CAPACITY; i++) {
struct Object* o = &gObjectPool[i]; struct Object* o = &gObjectPool[i];
if (o->respawnInfo == respawnInfo) { return o; } 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 // check that the area is active
struct Area* area = &gAreaData[areaIndex]; struct Area* area = &gAreaData[areaIndex];
if (area->unk04 == NULL) { return; } if (area->unk04 == NULL) { return; }
struct NetworkPlayer* destNp = network_player_from_global_index(destGlobalIndex);
if (destNp == NULL || !destNp->connected) { 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; return;
} }
// write header // write header
struct Packet p; 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, &gCurrCourseNum, sizeof(s16));
packet_write(&p, &gCurrActNum, sizeof(s16)); packet_write(&p, &gCurrActNum, sizeof(s16));
packet_write(&p, &gCurrLevelNum, 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 // send the packet if there are deletions
if (*spawnInfoDeletionCount > 0) { if (*spawnInfoDeletionCount > 0) {
network_send_to(destNp->localIndex, &p); 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) { if (!gNetworkPlayerLocal->currAreaSyncValid) {
LOG_ERROR("my area is invalid"); LOG_ERROR("my area is invalid");
return; return;
} }
struct NetworkPlayer* destNp = network_player_from_global_index(destGlobalIndex);
if (destNp == NULL || !destNp->connected) { 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; return;
} }
for (int i = 0; i < 8; i++) { 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; s16 courseNum, actNum, levelNum, areaIndex;
packet_read(p, &courseNum, sizeof(s16)); packet_read(p, &courseNum, sizeof(s16));
packet_read(p, &actNum, sizeof(s16)); packet_read(p, &actNum, sizeof(s16));
@ -106,7 +104,7 @@ void network_receive_spawn_info_deletions(struct Packet* p) {
u8 thisAreaIndex, spawnInfoDeletionCount; u8 thisAreaIndex, spawnInfoDeletionCount;
packet_read(p, &thisAreaIndex, sizeof(u8)); packet_read(p, &thisAreaIndex, sizeof(u8));
packet_read(p, &spawnInfoDeletionCount, 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; } if (spawnInfoDeletionCount <= 0) { return; }
struct SpawnInfo* spawnInfo = gAreaData[thisAreaIndex].objectSpawnInfos; struct SpawnInfo* spawnInfo = gAreaData[thisAreaIndex].objectSpawnInfos;

View file

@ -1,60 +0,0 @@
#include <stdio.h>
#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);
}
}

View file

@ -1,57 +0,0 @@
#include <stdio.h>
#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);
}

View file

@ -1,189 +0,0 @@
#include <stdio.h>
#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");
}

View file

@ -140,3 +140,11 @@ bool packet_check_hash(struct Packet* packet) {
memcpy(&packetHash, &packet->buffer[packet->dataLength], sizeof(u32)); memcpy(&packetHash, &packet->buffer[packet->dataLength], sizeof(u32));
return localHash == packetHash; return localHash == packetHash;
} }
void packet_ordered_begin(void) {
// TODO: implement ordered packet streams
}
void packet_ordered_end(void) {
// TODO: implement ordered packet streams
}

View file

@ -0,0 +1,62 @@
#include <stdio.h>
#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);
}
}