Removed two-player hacks from cannon and object packets

Increased error checking of get_behavior_from_id
Made failure logging for packet_object a lot better
Changed debug logging to show global index instead of "Server/Client"
Changed debug keyboard binds to support more keyboard types
Made SyncObject's rxEventId de-duplication per-player instead of one-player
Removed sizeof(enum) from packet_read/packet_write
This commit is contained in:
MysterD 2020-10-13 21:44:27 -07:00
parent aaa7e65b65
commit c8a45235ca
15 changed files with 117 additions and 90 deletions

View file

@ -524,5 +524,8 @@ enum BehaviorId get_id_from_behavior(const BehaviorScript* behavior) {
} }
const BehaviorScript* get_behavior_from_id(enum BehaviorId id) { const BehaviorScript* get_behavior_from_id(enum BehaviorId id) {
if (id < 0 || id >= id_bhv_max_count) {
return NULL;
}
return gBehaviorTable[id]; return gBehaviorTable[id];
} }

View file

@ -350,10 +350,10 @@
#define /*0x1AC*/ oTripletButterflyScalePhase OBJECT_FIELD_S32(0x49) #define /*0x1AC*/ oTripletButterflyScalePhase OBJECT_FIELD_S32(0x49)
/* Cannon */ /* Cannon */
#define /*0x0F4*/ oCannonUnkF4 OBJECT_FIELD_S32(0x1B) #define /*0x0F4*/ oCannonUnkF4 OBJECT_FIELD_S32(0x1B)
#define /*0x0F8*/ oCannonUnkF8 OBJECT_FIELD_S32(0x1C) #define /*0x0F8*/ oCannonUnkF8 OBJECT_FIELD_S32(0x1C)
#define /*0x10C*/ oCannonUnk10C OBJECT_FIELD_S32(0x21) #define /*0x10C*/ oCannonUnk10C OBJECT_FIELD_S32(0x21)
#define /*0x110*/ oCannonIsLocal OBJECT_FIELD_S32(0x22) #define /*0x110*/ oCannonPlayerIndex OBJECT_FIELD_S32(0x22)
/* Cap */ /* Cap */
#define /*0x0F4*/ oCapUnkF4 OBJECT_FIELD_S32(0x1B) #define /*0x0F4*/ oCapUnkF4 OBJECT_FIELD_S32(0x1B)

View file

@ -29,7 +29,7 @@ void opened_cannon_act_0(void) {
o->oAction = 4; o->oAction = 4;
o->oCannonUnk10C = 1; o->oCannonUnk10C = 1;
o->oCannonUnkF8 = 1; o->oCannonUnkF8 = 1;
o->oCannonIsLocal = TRUE; o->oCannonPlayerIndex = 0;
network_send_object(o); network_send_object(o);
} else { } else {
o->oInteractStatus = 0; o->oInteractStatus = 0;
@ -53,10 +53,12 @@ void opened_cannon_act_4(void) {
o->oPosZ += (f32)((o->oTimer / 2 & 1) - 0.5) * 4; o->oPosZ += (f32)((o->oTimer / 2 & 1) - 0.5) * 4;
o->oAction = 6; o->oAction = 6;
} }
if (!o->oCannonIsLocal) { if (o->oCannonPlayerIndex != 0) {
// two-player hack struct MarioState* controlledBy = &gMarioStates[o->oCannonPlayerIndex];
gMarioStates[1].marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw; if (controlledBy->marioObj != NULL) {
gMarioStates[1].marioObj->oMarioCannonInputYaw = 0; controlledBy->marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw;
controlledBy->marioObj->oMarioCannonInputYaw = 0;
}
} }
} }
@ -74,16 +76,12 @@ void opened_cannon_act_6(void) {
o->oCannonUnkF4 += 0x400; o->oCannonUnkF4 += 0x400;
} else if (o->oTimer < 26) { } else if (o->oTimer < 26) {
} else { } else {
if (o->oCannonIsLocal) { struct MarioState* controlledBy = &gMarioStates[o->oCannonPlayerIndex];
gMarioStates[0].marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw; if (controlledBy->marioObj != NULL) {
gMarioStates[0].marioObj->oMarioCannonInputYaw = 0; controlledBy->marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw;
gMarioStates[0].faceAngle[0] = 8192; controlledBy->marioObj->oMarioCannonInputYaw = 0;
} else {
// two-player hack
gMarioStates[1].marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw;
gMarioStates[1].marioObj->oMarioCannonInputYaw = 0;
gMarioStates[1].faceAngle[0] = 8192;
} }
controlledBy->faceAngle[0] = 8192;
o->oCannonUnkF4 = 0; o->oCannonUnkF4 = 0;
o->oAction = 5; o->oAction = 5;
@ -109,16 +107,18 @@ void opened_cannon_act_5(void) {
void opened_cannon_act_1(void) { void opened_cannon_act_1(void) {
UNUSED s32 unused; UNUSED s32 unused;
if (o->oCannonIsLocal) { // two-player hack if (o->oCannonPlayerIndex == 0) {
cur_obj_become_intangible(); cur_obj_become_intangible();
cur_obj_disable_rendering(); cur_obj_disable_rendering();
} else { } else {
struct MarioState* marioState = &gMarioStates[1]; // two-player hack struct MarioState* controlledBy = &gMarioStates[o->oCannonPlayerIndex];
o->oMoveAnglePitch = 14563 + marioState->faceAngle[0] * -0.5f; o->oMoveAnglePitch = 14563 + controlledBy->faceAngle[0] * -0.5f;
o->oMoveAngleYaw = marioState->marioObj->oMarioCannonObjectYaw + marioState->marioObj->oMarioCannonInputYaw; if (controlledBy->marioObj != NULL) {
o->oMoveAngleYaw = controlledBy->marioObj->oMarioCannonObjectYaw + controlledBy->marioObj->oMarioCannonInputYaw;
}
} }
o->oCannonUnk10C = 0; o->oCannonUnk10C = 0;
if (o->oCannonIsLocal) { if (o->oCannonPlayerIndex == 0) {
gMarioShotFromCannon = 1; gMarioShotFromCannon = 1;
} }
} }
@ -131,7 +131,6 @@ void opened_cannon_act_3(void) {
UNUSED s32 unused; UNUSED s32 unused;
if (o->oTimer > 3) { if (o->oTimer > 3) {
o->oAction = 0; o->oAction = 0;
o->oCannonIsLocal = FALSE;
if (o->heldByPlayerIndex == 0) { network_send_object(o); } if (o->heldByPlayerIndex == 0) { network_send_object(o); }
} }
} }
@ -144,39 +143,37 @@ u8 unused0EA1FC[] = { 2, 0, 0, 0, 0, 0, 0, 0, 63, 128, 0, 0, 2, 0, 0, 0
63, 128, 0, 0, 2, 0, 0, 0, 65, 160, 0, 0, 63, 128, 0, 0, 2, 0, 0, 0, 63, 128, 0, 0, 2, 0, 0, 0, 65, 160, 0, 0, 63, 128, 0, 0, 2, 0, 0, 0,
65, 160, 0, 0, 63, 128, 0, 0, 8, 0, 0, 0, 65, 32, 0, 0, 63, 128, 0, 0 }; 65, 160, 0, 0, 63, 128, 0, 0, 8, 0, 0, 0, 65, 32, 0, 0, 63, 128, 0, 0 };
u8 cannon_ignore_remote_updates(void) {
// two-player hack
return ((gNetworkType == NT_SERVER) && o->oCannonIsLocal);
}
static void cannon_on_received_post(u8 fromLocalIndex) { static void cannon_on_received_post(u8 fromLocalIndex) {
// check if we're on in the cannon too // check if we're on in the cannon too
struct MarioState* m = &gMarioStates[0]; struct MarioState* m = &gMarioStates[0];
if (m->action != ACT_IN_CANNON) { return; } u8 shouldEject = (m->action == ACT_IN_CANNON)
if (m->interactObj != o) { return; } && (m->interactObj == o)
// two-player hack && gNetworkPlayers[fromLocalIndex].globalIndex < gNetworkPlayerLocal->globalIndex;
if (gNetworkType == NT_SERVER) { return; }
// eject the player by shooting out of the cannon weakly if (shouldEject) {
m->forwardVel = 10.0f * coss(m->faceAngle[0]); // eject the player by shooting out of the cannon weakly
m->vel[1] = 10.0f * sins(m->faceAngle[0]); m->forwardVel = 10.0f * coss(m->faceAngle[0]);
m->pos[0] += 120.0f * coss(m->faceAngle[0]) * sins(m->faceAngle[1]); m->vel[1] = 10.0f * sins(m->faceAngle[0]);
m->pos[1] += 120.0f * sins(m->faceAngle[0]); m->pos[0] += 120.0f * coss(m->faceAngle[0]) * sins(m->faceAngle[1]);
m->pos[2] += 120.0f * coss(m->faceAngle[0]) * coss(m->faceAngle[1]); m->pos[1] += 120.0f * sins(m->faceAngle[0]);
set_mario_action(m, ACT_SHOT_FROM_CANNON, 0); m->pos[2] += 120.0f * coss(m->faceAngle[0]) * coss(m->faceAngle[1]);
set_mario_action(m, ACT_SHOT_FROM_CANNON, 0);
// reset things that got messed up // reset things that got messed up
m->marioObj->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE; m->marioObj->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE;
reset_camera(gCamera); reset_camera(gCamera);
o->oCannonIsLocal = FALSE; o->oCannonPlayerIndex = fromLocalIndex;
cur_obj_become_tangible(); cur_obj_become_tangible();
cur_obj_enable_rendering(); cur_obj_enable_rendering();
} else {
o->oCannonPlayerIndex = fromLocalIndex;
}
} }
static void bhv_cannon_base_sanity_check(void) { static void bhv_cannon_base_sanity_check(void) {
// figure out if it's still in use // figure out if it's still in use
u8 inUse = FALSE; u8 inUse = FALSE;
if (o->oCannonIsLocal) { if (o->oCannonPlayerIndex == 0) {
inUse = (gMarioStates[0].action == ACT_IN_CANNON && gMarioStates[0].interactObj == o); inUse = (gMarioStates[0].action == ACT_IN_CANNON && gMarioStates[0].interactObj == o);
} else { } else {
for (int i = 0; i < MAX_PLAYERS; i++) { for (int i = 0; i < MAX_PLAYERS; i++) {
@ -208,11 +205,18 @@ static void bhv_cannon_base_sanity_check(void) {
} }
} }
void bhv_cannon_override_ownership(u8* shouldOverride, u8* shouldOwn) {
if ((o->oAction != 0) && (o->oCannonPlayerIndex == 0)) {
*shouldOverride = TRUE;
*shouldOwn = TRUE;
}
}
void bhv_cannon_base_loop(void) { void bhv_cannon_base_loop(void) {
if (!network_sync_object_initialized(o)) { if (!network_sync_object_initialized(o)) {
struct SyncObject* so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); struct SyncObject* so = network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS);
so->ignore_if_true = cannon_ignore_remote_updates;
so->on_received_post = cannon_on_received_post; so->on_received_post = cannon_on_received_post;
so->override_ownership = bhv_cannon_override_ownership;
network_init_object_field(o, &o->oAction); network_init_object_field(o, &o->oAction);
network_init_object_field(o, &o->oPrevAction); network_init_object_field(o, &o->oPrevAction);
network_init_object_field(o, &o->oTimer); network_init_object_field(o, &o->oTimer);
@ -227,7 +231,7 @@ void bhv_cannon_base_loop(void) {
bhv_cannon_base_sanity_check(); bhv_cannon_base_sanity_check();
if (o->oAction != 0 && !o->oCannonIsLocal) { if ((o->oAction != 0) && (o->oCannonPlayerIndex != 0)) {
cur_obj_push_mario_away_from_cylinder(220, 300); cur_obj_push_mario_away_from_cylinder(220, 300);
} }

View file

@ -59,6 +59,7 @@ void bhv_koopa_shell_loop(void) {
struct Surface *sp34; struct Surface *sp34;
obj_set_hitbox(o, &sKoopaShellHitbox); obj_set_hitbox(o, &sKoopaShellHitbox);
cur_obj_scale(1.0f); cur_obj_scale(1.0f);
struct MarioState* marioState = nearest_mario_state_to_object(o);
struct Object* player = NULL; struct Object* player = NULL;
switch (o->oAction) { switch (o->oAction) {
case 0: case 0:
@ -66,8 +67,7 @@ void bhv_koopa_shell_loop(void) {
cur_obj_if_hit_wall_bounce_away(); cur_obj_if_hit_wall_bounce_away();
if (o->oInteractStatus & INT_STATUS_INTERACTED) { if (o->oInteractStatus & INT_STATUS_INTERACTED) {
o->oAction++; o->oAction++;
player = nearest_player_to_object(o); o->heldByPlayerIndex = marioState->playerIndex;
o->heldByPlayerIndex = (player == gMarioObject) ? 0 : 1;
} }
o->oFaceAngleYaw += 0x1000; o->oFaceAngleYaw += 0x1000;
cur_obj_move_standard(-20); cur_obj_move_standard(-20);

View file

@ -1188,10 +1188,12 @@ u32 interact_door(struct MarioState *m, UNUSED u32 interactType, struct Object *
u32 interact_cannon_base(struct MarioState *m, UNUSED u32 interactType, struct Object *o) { u32 interact_cannon_base(struct MarioState *m, UNUSED u32 interactType, struct Object *o) {
if (o->oAction != 0) { return FALSE; } if (o->oAction != 0) { return FALSE; }
if (m->playerIndex != 0) { return FALSE; }
if (m->action != ACT_IN_CANNON) { if (m->action != ACT_IN_CANNON) {
mario_stop_riding_and_holding(m); mario_stop_riding_and_holding(m);
o->oInteractStatus = INT_STATUS_INTERACTED; o->oInteractStatus = INT_STATUS_INTERACTED;
o->oCannonPlayerIndex = 0;
m->interactObj = o; m->interactObj = o;
m->usedObj = o; m->usedObj = o;
return set_mario_action(m, ACT_IN_CANNON, 0); return set_mario_action(m, ACT_IN_CANNON, 0);

View file

@ -117,7 +117,7 @@ static void debug_suicide(void) {
void debug_keyboard_on_key_down(int scancode) { void debug_keyboard_on_key_down(int scancode) {
scancode = scancode; scancode = scancode;
switch (scancode) { switch (scancode & 0xFF) {
case SCANCODE_3: debug_breakpoint_here(); break; case SCANCODE_3: debug_breakpoint_here(); break;
#ifdef DEVELOPMENT #ifdef DEVELOPMENT
case SCANCODE_6: debug_warp_level(warpToLevel); break; case SCANCODE_6: debug_warp_level(warpToLevel); break;

View file

@ -10,7 +10,7 @@
} }
static void debuglog_print_network_type(void) { static void debuglog_print_network_type(void) {
printf(" [%s] ", NETWORKTYPESTR); printf(" [%02d] ", (gNetworkPlayerLocal != NULL) ? gNetworkPlayerLocal->globalIndex : -1);
} }
static void debuglog_print_log_type(char* logType) { static void debuglog_print_log_type(char* logType) {

View file

@ -49,7 +49,7 @@ struct SyncObject {
clock_t clockSinceUpdate; clock_t clockSinceUpdate;
void* behavior; void* behavior;
u16 txEventId; u16 txEventId;
u16 rxEventId; u16 rxEventId[MAX_PLAYERS];
u16 randomSeed; u16 randomSeed;
u8 extraFieldCount; u8 extraFieldCount;
bool fullObjectSync; bool fullObjectSync;

View file

@ -103,6 +103,7 @@ u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex) {
np->type = type; np->type = type;
np->lastReceived = clock(); np->lastReceived = clock();
gNetworkSystem->save_id(i); gNetworkSystem->save_id(i);
for (int j = 0; j < MAX_SYNC_OBJECTS; j++) { gSyncObjects[j].rxEventId[i] = 0; }
if (type == NPT_SERVER) { gNetworkPlayerServer = np; } if (type == NPT_SERVER) { gNetworkPlayerServer = np; }
else { chat_add_message("player connected", CMT_SYSTEM); } else { chat_add_message("player connected", CMT_SYSTEM); }
LOG_INFO("player connected, local %d, global %d", i, np->globalIndex); LOG_INFO("player connected, local %d, global %d", i, np->globalIndex);
@ -139,6 +140,7 @@ u8 network_player_disconnected(u8 globalIndex) {
if (gNetworkType == NT_SERVER) { network_send_leaving(np->globalIndex); } if (gNetworkType == NT_SERVER) { network_send_leaving(np->globalIndex); }
np->connected = false; np->connected = false;
gNetworkSystem->clear_id(i); gNetworkSystem->clear_id(i);
for (int j = 0; j < MAX_SYNC_OBJECTS; j++) { gSyncObjects[j].rxEventId[i] = 0; }
LOG_INFO("player disconnected, local %d, global %d", i, globalIndex); LOG_INFO("player disconnected, local %d, global %d", i, globalIndex);
chat_add_message("player disconnected", CMT_SYSTEM); chat_add_message("player disconnected", CMT_SYSTEM);
return i; return i;

View file

@ -48,7 +48,7 @@ void network_send_collect_coin(struct Object* o) {
struct Packet p; struct Packet p;
packet_init(&p, PACKET_COLLECT_COIN, true, true); packet_init(&p, PACKET_COLLECT_COIN, true, true);
packet_write(&p, &behaviorId, sizeof(enum BehaviorId)); packet_write(&p, &behaviorId, sizeof(u16));
packet_write(&p, &o->oPosX, sizeof(f32) * 3); packet_write(&p, &o->oPosX, sizeof(f32) * 3);
packet_write(&p, &gMarioStates[0].numCoins, sizeof(s16)); packet_write(&p, &gMarioStates[0].numCoins, sizeof(s16));
packet_write(&p, &o->oDamageOrCoinValue, sizeof(s32)); packet_write(&p, &o->oDamageOrCoinValue, sizeof(s32));
@ -62,7 +62,7 @@ void network_receive_collect_coin(struct Packet* p) {
s16 numCoins = 0; s16 numCoins = 0;
s32 coinValue = 0; s32 coinValue = 0;
packet_read(p, &behaviorId, sizeof(enum BehaviorId)); packet_read(p, &behaviorId, sizeof(u16));
packet_read(p, &pos, sizeof(f32) * 3); packet_read(p, &pos, sizeof(f32) * 3);
packet_read(p, &numCoins, sizeof(s16)); packet_read(p, &numCoins, sizeof(s16));
packet_read(p, &coinValue, sizeof(s32)); packet_read(p, &coinValue, sizeof(s32));
@ -88,7 +88,7 @@ void network_receive_collect_coin(struct Packet* p) {
if (COURSE_IS_MAIN_COURSE(gCurrCourseNum) if (COURSE_IS_MAIN_COURSE(gCurrCourseNum)
&& gMarioStates[0].numCoins - coin->oDamageOrCoinValue < 100 && gMarioStates[0].numCoins - coin->oDamageOrCoinValue < 100
&& gMarioStates[0].numCoins >= 100) { && gMarioStates[0].numCoins >= 100) {
bhv_spawn_star_no_level_exit(gMarioStates[1].marioObj, 6, FALSE); bhv_spawn_star_no_level_exit(gMarioStates[p->localIndex].marioObj, 6, FALSE);
} }
return; return;
@ -102,6 +102,6 @@ SANITY_CHECK_COINS:;
if (COURSE_IS_MAIN_COURSE(gCurrCourseNum) if (COURSE_IS_MAIN_COURSE(gCurrCourseNum)
&& oldCoinCount < 100 && oldCoinCount < 100
&& gMarioStates[0].numCoins >= 100) { && gMarioStates[0].numCoins >= 100) {
bhv_spawn_star_no_level_exit(gMarioStates[1].marioObj, 6, FALSE); bhv_spawn_star_no_level_exit(gMarioStates[p->localIndex].marioObj, 6, FALSE);
} }
} }

View file

@ -45,7 +45,7 @@ void network_send_collect_item(struct Object* o) {
struct Packet p; struct Packet p;
packet_init(&p, PACKET_COLLECT_ITEM, true, true); packet_init(&p, PACKET_COLLECT_ITEM, true, true);
packet_write(&p, &behaviorId, sizeof(enum BehaviorId)); packet_write(&p, &behaviorId, sizeof(u16));
packet_write(&p, &o->oPosX, sizeof(f32) * 3); packet_write(&p, &o->oPosX, sizeof(f32) * 3);
network_send(&p); network_send(&p);
@ -55,7 +55,7 @@ void network_receive_collect_item(struct Packet* p) {
enum BehaviorId behaviorId; enum BehaviorId behaviorId;
f32 pos[3] = { 0 }; f32 pos[3] = { 0 };
packet_read(p, &behaviorId, sizeof(enum BehaviorId)); packet_read(p, &behaviorId, sizeof(u16));
packet_read(p, &pos, sizeof(f32) * 3); packet_read(p, &pos, sizeof(f32) * 3);
const void* behavior = get_behavior_from_id(behaviorId); const void* behavior = get_behavior_from_id(behaviorId);

View file

@ -52,7 +52,7 @@ void network_send_collect_star(struct Object* o, s16 coinScore, s16 starIndex) {
packet_write(&p, &gCurrSaveFileNum, sizeof(s16)); packet_write(&p, &gCurrSaveFileNum, sizeof(s16));
packet_write(&p, &gCurrCourseNum, sizeof(s16)); packet_write(&p, &gCurrCourseNum, sizeof(s16));
packet_write(&p, &o->oPosX, sizeof(f32) * 3); packet_write(&p, &o->oPosX, sizeof(f32) * 3);
packet_write(&p, &behaviorId, sizeof(enum BehaviorId)); packet_write(&p, &behaviorId, sizeof(u16));
packet_write(&p, &coinScore, sizeof(s16)); packet_write(&p, &coinScore, sizeof(s16));
packet_write(&p, &starIndex, sizeof(s16)); packet_write(&p, &starIndex, sizeof(s16));
@ -69,7 +69,7 @@ void network_receive_collect_star(struct Packet* p) {
packet_read(p, &gCurrSaveFileNum, sizeof(s16)); packet_read(p, &gCurrSaveFileNum, sizeof(s16));
packet_read(p, &gCurrCourseNum, sizeof(s16)); packet_read(p, &gCurrCourseNum, sizeof(s16));
packet_read(p, &pos, sizeof(f32) * 3); packet_read(p, &pos, sizeof(f32) * 3);
packet_read(p, &behaviorId, sizeof(enum BehaviorId)); packet_read(p, &behaviorId, sizeof(u16));
packet_read(p, &coinScore, sizeof(s16)); packet_read(p, &coinScore, sizeof(s16));
packet_read(p, &starIndex, sizeof(s16)); packet_read(p, &starIndex, sizeof(s16));

View file

@ -6,7 +6,7 @@
void network_send_kick(enum KickReasonType kickReason) { void network_send_kick(enum KickReasonType kickReason) {
struct Packet p; struct Packet p;
packet_init(&p, PACKET_KICK, false, false); packet_init(&p, PACKET_KICK, false, false);
packet_write(&p, &kickReason, sizeof(enum KickReasonType)); packet_write(&p, &kickReason, sizeof(u8));
network_send_to(0, &p); network_send_to(0, &p);
} }
@ -22,7 +22,7 @@ void network_receive_kick(struct Packet* p) {
} }
enum KickReasonType kickReason; enum KickReasonType kickReason;
packet_read(p, &kickReason, sizeof(enum KickReasonType)); packet_read(p, &kickReason, sizeof(u8));
switch (kickReason) { switch (kickReason) {
case EKT_FULL_PARTY: custom_menu_error("The party is full."); break; case EKT_FULL_PARTY: custom_menu_error("The party is full."); break;
default: custom_menu_error("Host has closed the connection."); break; default: custom_menu_error("Host has closed the connection."); break;

View file

@ -8,6 +8,7 @@
#include "src/game/memory.h" #include "src/game/memory.h"
#include "src/game/object_helpers.h" #include "src/game/object_helpers.h"
#include "src/game/obj_behaviors.h" #include "src/game/obj_behaviors.h"
#include "pc/debuglog.h"
static u8 nextSyncID = 1; static u8 nextSyncID = 1;
struct SyncObject gSyncObjects[MAX_SYNC_OBJECTS] = { 0 }; struct SyncObject gSyncObjects[MAX_SYNC_OBJECTS] = { 0 };
@ -42,7 +43,10 @@ static bool should_own_object(struct SyncObject* so) {
if (gMarioStates[i].heldByObj == so->o) { return false; } if (gMarioStates[i].heldByObj == so->o) { return false; }
} }
if (so->o->oHeldState == HELD_HELD && so->o->heldByPlayerIndex == 0) { return true; } if (so->o->oHeldState == HELD_HELD && so->o->heldByPlayerIndex == 0) { return true; }
if (player_distance(&gMarioStates[0], so->o) > player_distance(&gMarioStates[1], so->o)) { return false; } for (int i = 0; i < MAX_PLAYERS; i++) {
if (!is_player_active(&gMarioStates[i])) { continue; }
if (player_distance(&gMarioStates[0], so->o) > player_distance(&gMarioStates[i], so->o)) { return false; }
}
if (so->o->oHeldState == HELD_HELD && so->o->heldByPlayerIndex != 0) { return false; } if (so->o->oHeldState == HELD_HELD && so->o->heldByPlayerIndex != 0) { return false; }
return true; return true;
} }
@ -60,7 +64,9 @@ struct SyncObject* network_init_object(struct Object *o, float maxSyncDistance)
so->clockSinceUpdate = clock(); so->clockSinceUpdate = clock();
so->extraFieldCount = 0; so->extraFieldCount = 0;
so->behavior = (BehaviorScript*)o->behavior; so->behavior = (BehaviorScript*)o->behavior;
so->rxEventId = 0; for (int i = 0; i < MAX_PLAYERS; i++) {
so->rxEventId[i] = 0;
}
so->txEventId = 0; so->txEventId = 0;
so->fullObjectSync = false; so->fullObjectSync = false;
so->hasStandardFields = (maxSyncDistance >= 0); so->hasStandardFields = (maxSyncDistance >= 0);
@ -141,10 +147,11 @@ static void packet_write_object_header(struct Packet* p, struct Object* o) {
struct SyncObject* so = &gSyncObjects[o->oSyncID]; struct SyncObject* so = &gSyncObjects[o->oSyncID];
enum BehaviorId behaviorId = get_id_from_behavior(o->behavior); enum BehaviorId behaviorId = get_id_from_behavior(o->behavior);
packet_write(p, &gNetworkPlayerLocal->globalIndex, sizeof(u8));
packet_write(p, &o->oSyncID, sizeof(u32)); packet_write(p, &o->oSyncID, sizeof(u32));
packet_write(p, &so->txEventId, sizeof(u16)); packet_write(p, &so->txEventId, sizeof(u16));
packet_write(p, &so->randomSeed, sizeof(u16)); packet_write(p, &so->randomSeed, sizeof(u16));
packet_write(p, &behaviorId, sizeof(enum BehaviorId)); packet_write(p, &behaviorId, sizeof(u16));
} }
static bool allowable_behavior_change(struct SyncObject* so, BehaviorScript* behavior) { static bool allowable_behavior_change(struct SyncObject* so, BehaviorScript* behavior) {
@ -162,19 +169,25 @@ static bool allowable_behavior_change(struct SyncObject* so, BehaviorScript* beh
return true; return true;
} }
static struct SyncObject* packet_read_object_header(struct Packet* p) { static struct SyncObject* packet_read_object_header(struct Packet* p, u8* fromLocalIndex) {
// figure out where the packet came from
u8 fromGlobalIndex = 0;
packet_read(p, &fromGlobalIndex, sizeof(u8));
struct NetworkPlayer* np = network_player_from_global_index(fromGlobalIndex);
*fromLocalIndex = (np != NULL) ? np->localIndex : p->localIndex;
// get sync ID, sanity check // get sync ID, sanity check
u32 syncId = 0; u32 syncId = 0;
packet_read(p, &syncId, sizeof(u32)); packet_read(p, &syncId, sizeof(u32));
if (syncId == 0 || syncId >= MAX_SYNC_OBJECTS) { if (syncId == 0 || syncId >= MAX_SYNC_OBJECTS) {
printf("%s invalid SyncID %d!\n", NETWORKTYPESTR, syncId); LOG_ERROR("invalid SyncID: %d", syncId);
return NULL; return NULL;
} }
// extract object, sanity check // extract object, sanity check
struct Object* o = gSyncObjects[syncId].o; struct Object* o = gSyncObjects[syncId].o;
if (o == NULL) { if (o == NULL) {
printf("%s invalid SyncObject!\n", NETWORKTYPESTR); LOG_ERROR("invalid SyncObject for %d", syncId);
return NULL; return NULL;
} }
@ -193,20 +206,23 @@ static struct SyncObject* packet_read_object_header(struct Packet* p) {
// make sure this is the newest event possible // make sure this is the newest event possible
u16 eventId = 0; u16 eventId = 0;
packet_read(p, &eventId, sizeof(u16)); packet_read(p, &eventId, sizeof(u16));
if (so->rxEventId > eventId && (u16)abs(eventId - so->rxEventId) < USHRT_MAX / 2) { if (so->rxEventId[*fromLocalIndex] > eventId && (u16)abs(eventId - so->rxEventId[*fromLocalIndex]) < USHRT_MAX / 2) {
return NULL; return NULL;
} }
so->rxEventId = eventId; so->rxEventId[*fromLocalIndex] = eventId;
// update the random seed // update the random seed
packet_read(p, &so->randomSeed, sizeof(u16)); packet_read(p, &so->randomSeed, sizeof(u16));
// make sure the behaviors match // make sure the behaviors match
enum BehaviorId behaviorId; enum BehaviorId behaviorId;
packet_read(p, &behaviorId, sizeof(enum BehaviorId)); packet_read(p, &behaviorId, sizeof(u16));
BehaviorScript* behavior = (BehaviorScript*)get_behavior_from_id(behaviorId); BehaviorScript* behavior = (BehaviorScript*)get_behavior_from_id(behaviorId);
if (o->behavior != behavior && !allowable_behavior_change(so, behavior)) { if (behavior == NULL) {
printf("network_receive_object() behavior mismatch!\n"); LOG_ERROR("unable to find behavior %04X for id %d", behaviorId, syncId);
return NULL;
} if (o->behavior != behavior && !allowable_behavior_change(so, behavior)) {
LOG_ERROR("behavior mismatch for %d: %04X vs %04X", syncId, get_id_from_behavior(o->behavior), get_id_from_behavior(behavior));
network_forget_sync_object(so); network_forget_sync_object(so);
return NULL; return NULL;
} }
@ -337,13 +353,13 @@ void network_send_object(struct Object* o) {
if (!network_sync_object_initialized(o)) { return; } if (!network_sync_object_initialized(o)) { return; }
struct SyncObject* so = &gSyncObjects[o->oSyncID]; struct SyncObject* so = &gSyncObjects[o->oSyncID];
if (so == NULL) { return; } if (so == NULL) { return; }
if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) { if (o != so->o) {
printf("network_send_object() BEHAVIOR MISMATCH!\n"); LOG_ERROR("object mismatch for %d", o->oSyncID);
network_forget_sync_object(so); network_forget_sync_object(so);
return; return;
} }
if (o != so->o) { if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) {
printf("network_send_object() OBJECT MISMATCH!\n"); LOG_ERROR("behavior mismatch for %d: %04X vs %04X", o->oSyncID, get_id_from_behavior(o->behavior), get_id_from_behavior(so->behavior));
network_forget_sync_object(so); network_forget_sync_object(so);
return; return;
} }
@ -357,14 +373,13 @@ void network_send_object_reliability(struct Object* o, bool reliable) {
if (!network_sync_object_initialized(o)) { return; } if (!network_sync_object_initialized(o)) { return; }
struct SyncObject* so = &gSyncObjects[o->oSyncID]; struct SyncObject* so = &gSyncObjects[o->oSyncID];
if (so == NULL) { return; } if (so == NULL) { return; }
if (o != so->o) {
if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) { LOG_ERROR("object mismatch for %d", o->oSyncID);
printf("network_send_object() BEHAVIOR MISMATCH!\n");
network_forget_sync_object(so); network_forget_sync_object(so);
return; return;
} }
if (o != so->o) { if (o->behavior != so->behavior && !allowable_behavior_change(so, so->behavior)) {
printf("network_send_object() OBJECT MISMATCH!\n"); LOG_ERROR("behavior mismatch for %d: %04X vs %04X", o->oSyncID, get_id_from_behavior(o->behavior), get_id_from_behavior(so->behavior));
network_forget_sync_object(so); network_forget_sync_object(so);
return; return;
} }
@ -393,7 +408,8 @@ void network_send_object_reliability(struct Object* o, bool reliable) {
void network_receive_object(struct Packet* p) { void network_receive_object(struct Packet* p) {
// read the header and sanity check the packet // read the header and sanity check the packet
struct SyncObject* so = packet_read_object_header(p); u8 fromLocalIndex = 0;
struct SyncObject* so = packet_read_object_header(p, &fromLocalIndex);
if (so == NULL) { return; } if (so == NULL) { return; }
struct Object* o = so->o; struct Object* o = so->o;
if (!network_sync_object_initialized(o)) { return; } if (!network_sync_object_initialized(o)) { return; }
@ -412,7 +428,7 @@ void network_receive_object(struct Packet* p) {
extern struct Object* gCurrentObject; extern struct Object* gCurrentObject;
struct Object* tmp = gCurrentObject; struct Object* tmp = gCurrentObject;
gCurrentObject = so->o; gCurrentObject = so->o;
(*so->on_received_pre)(p->localIndex); (*so->on_received_pre)(fromLocalIndex);
gCurrentObject = tmp; gCurrentObject = tmp;
} }
@ -432,7 +448,7 @@ void network_receive_object(struct Packet* p) {
extern struct Object* gCurrentObject; extern struct Object* gCurrentObject;
struct Object* tmp = gCurrentObject; struct Object* tmp = gCurrentObject;
gCurrentObject = so->o; gCurrentObject = so->o;
(*so->on_received_post)(p->localIndex); (*so->on_received_post)(fromLocalIndex);
gCurrentObject = tmp; gCurrentObject = tmp;
} }
@ -464,7 +480,7 @@ void network_update_objects(void) {
// check for stale sync object // check for stale sync object
if (so->o->oSyncID != i) { if (so->o->oSyncID != i) {
printf("ERROR! Sync ID mismatch!\n"); LOG_ERROR("sync id mismatch: %d vs %d", so->o->oSyncID, i);
network_forget_sync_object(so); network_forget_sync_object(so);
continue; continue;
} }

View file

@ -57,7 +57,7 @@ void network_send_spawn_objects(struct Object* objects[], u32 models[], u8 objec
enum BehaviorId behaviorId = get_id_from_behavior(o->behavior); enum BehaviorId behaviorId = get_id_from_behavior(o->behavior);
packet_write(&p, &parentId, sizeof(u8)); packet_write(&p, &parentId, sizeof(u8));
packet_write(&p, &model, sizeof(u32)); packet_write(&p, &model, sizeof(u32));
packet_write(&p, &behaviorId, sizeof(enum BehaviorId)); packet_write(&p, &behaviorId, sizeof(u16));
packet_write(&p, &o->activeFlags, sizeof(s16)); packet_write(&p, &o->activeFlags, sizeof(s16));
packet_write(&p, o->rawData.asU32, sizeof(s32) * 80); packet_write(&p, o->rawData.asU32, sizeof(s32) * 80);
packet_write(&p, &o->header.gfx.scale[0], sizeof(f32)); packet_write(&p, &o->header.gfx.scale[0], sizeof(f32));
@ -99,7 +99,7 @@ void network_receive_spawn_objects(struct Packet* p) {
Vec3f scale = { 0 }; Vec3f scale = { 0 };
packet_read(p, &data.parentId, sizeof(u8)); packet_read(p, &data.parentId, sizeof(u8));
packet_read(p, &data.model, sizeof(u32)); packet_read(p, &data.model, sizeof(u32));
packet_read(p, &data.behaviorId, sizeof(enum BehaviorId)); packet_read(p, &data.behaviorId, sizeof(u16));
packet_read(p, &data.activeFlags, sizeof(s16)); packet_read(p, &data.activeFlags, sizeof(s16));
packet_read(p, &data.rawData, sizeof(s32) * 80); packet_read(p, &data.rawData, sizeof(s32) * 80);
packet_read(p, &scale[0], sizeof(f32)); packet_read(p, &scale[0], sizeof(f32));