diff --git a/src/game/behaviors/chain_chomp.inc.c b/src/game/behaviors/chain_chomp.inc.c index 9b9c3423b..669e2c2ea 100644 --- a/src/game/behaviors/chain_chomp.inc.c +++ b/src/game/behaviors/chain_chomp.inc.c @@ -30,7 +30,7 @@ static struct ObjectHitbox sChainChompHitbox = { void bhv_chain_chomp_chain_part_update(void) { struct ChainSegment *segment; - if (o->parentObj->oAction == CHAIN_CHOMP_ACT_UNLOAD_CHAIN) { + if (o->parentObj->behavior != &bhvChainChomp || o->parentObj->oAction == CHAIN_CHOMP_ACT_UNLOAD_CHAIN) { obj_mark_for_deletion(o); } else if (o->oBehParams2ndByte != CHAIN_CHOMP_CHAIN_PART_BP_PIVOT) { segment = &o->parentObj->oChainChompSegments[o->oBehParams2ndByte]; @@ -54,7 +54,9 @@ static void chain_chomp_act_uninitialized(void) { s32 i; #ifndef NODRAWINGDISTANCE - if (o->oDistanceToMario < 3000.0f) { + struct Object* player = nearest_player_to_object(o); + int distanceToPlayer = dist_between_objects(o, player); + if (distanceToPlayer < 3000.0f) { #endif segments = mem_pool_alloc(gObjectMemoryPool, 5 * sizeof(struct ChainSegment)); if (segments != NULL) { @@ -177,9 +179,13 @@ static void chain_chomp_sub_act_turn(void) { chain_chomp_restore_normal_chain_lengths(); obj_move_pitch_approach(0, 0x100); + struct Object* player = nearest_player_to_object(o); + int distanceToPlayer = dist_between_objects(o, player); + int angleToPlayer = obj_angle_to_object(o, player); + if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) { - cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x400); - if (abs_angle_diff(o->oAngleToMario, o->oMoveAngleYaw) < 0x800) { + cur_obj_rotate_yaw_toward(angleToPlayer, 0x400); + if (abs_angle_diff(angleToPlayer, o->oMoveAngleYaw) < 0x800 && distanceToPlayer < 3000) { if (o->oTimer > 30) { if (cur_obj_check_anim_frame(0)) { cur_obj_reverse_animation(); @@ -208,7 +214,7 @@ static void chain_chomp_sub_act_turn(void) { o->oVelY = 20.0f; } } else { - cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x190); + cur_obj_rotate_yaw_toward(angleToPlayer, 0x190); o->oTimer = 0; } } @@ -280,9 +286,12 @@ static void chain_chomp_released_lunge_around(void) { // Finish bounce if (o->oMoveFlags & OBJ_MOVE_MASK_ON_GROUND) { + struct Object* player = nearest_player_to_object(o); + int angleToPlayer = obj_angle_to_object(o, player); + // Before first bounce, turn toward mario and wait 2 seconds if (o->oChainChompNumLunges == 0) { - if (cur_obj_rotate_yaw_toward(o->oAngleToMario, 0x320)) { + if (cur_obj_rotate_yaw_toward(angleToPlayer, 0x320)) { if (o->oTimer > 60) { o->oChainChompNumLunges += 1; // enable wall collision @@ -294,7 +303,7 @@ static void chain_chomp_released_lunge_around(void) { } else { if (++o->oChainChompNumLunges <= 5) { cur_obj_play_sound_2(SOUND_GENERAL_CHAIN_CHOMP1); - o->oMoveAngleYaw = o->oAngleToMario + random_sign() * 0x2000; + o->oMoveAngleYaw = angleToPlayer + random_sign() * 0x2000; o->oForwardVel = 30.0f; o->oVelY = 50.0f; } else { @@ -364,7 +373,9 @@ static void chain_chomp_act_move(void) { // Unload chain if mario is far enough #ifndef NODRAWINGDISTANCE - if (o->oChainChompReleaseStatus == CHAIN_CHOMP_NOT_RELEASED && o->oDistanceToMario > 4000.0f) { + struct Object* player = nearest_player_to_object(o); + int distanceToPlayer = dist_between_objects(o, player); + if (o->oChainChompReleaseStatus == CHAIN_CHOMP_NOT_RELEASED && distanceToPlayer > 4000.0f) { o->oAction = CHAIN_CHOMP_ACT_UNLOAD_CHAIN; o->oForwardVel = o->oVelY = 0.0f; } else { @@ -468,7 +479,11 @@ static void chain_chomp_act_unload_chain(void) { o->oAction = CHAIN_CHOMP_ACT_UNINITIALIZED; if (o->oChainChompReleaseStatus != CHAIN_CHOMP_NOT_RELEASED) { + for (u8 i = 0; i < 5; i++) { + obj_mark_for_deletion(&o->oChainChompSegments[i]); + } obj_mark_for_deletion(o); + obj_mark_for_deletion(o->parentObj); } } @@ -476,6 +491,10 @@ static void chain_chomp_act_unload_chain(void) { * Update function for chain chomp. */ void bhv_chain_chomp_update(void) { + if (o->oSyncID == 0) { + network_init_object(o, 1000.0f); + } + switch (o->oAction) { case CHAIN_CHOMP_ACT_UNINITIALIZED: chain_chomp_act_uninitialized(); @@ -493,11 +512,21 @@ void bhv_chain_chomp_update(void) { * Update function for wooden post. */ void bhv_wooden_post_update(void) { + if (o->oSyncID == 0) { + network_init_object(o, SYNC_DISTANCE_ONLY_EVENTS); + network_init_object_field(o, &o->oWoodenPostMarioPounding); + network_init_object_field(o, &o->oWoodenPostOffsetY); + network_init_object_field(o, &o->oWoodenPostSpeedY); + network_init_object_field(o, &o->oWoodenPostTotalMarioAngle); + network_init_object_field(o, &o->oTimer); + } + // When ground pounded by mario, drop by -45 + -20 if (!o->oWoodenPostMarioPounding) { if ((o->oWoodenPostMarioPounding = cur_obj_is_mario_ground_pounding_platform())) { cur_obj_play_sound_2(SOUND_GENERAL_POUND_WOOD_POST); o->oWoodenPostSpeedY = -70.0f; + if (network_owns_object(o)) { network_send_object(o); } } } else if (approach_f32_ptr(&o->oWoodenPostSpeedY, 0.0f, 25.0f)) { // Stay still until mario is done ground pounding @@ -516,20 +545,25 @@ void bhv_wooden_post_update(void) { if (o->oWoodenPostOffsetY != 0.0f) { o->oPosY = o->oHomeY + o->oWoodenPostOffsetY; } else if (!(o->oBehParams & WOODEN_POST_BP_NO_COINS_MASK)) { + struct Object* player = nearest_player_to_object(o); + int distanceToPlayer = dist_between_objects(o, player); + int angleToPlayer = obj_angle_to_object(o, player); + // Reset the timer once mario is far enough - if (o->oDistanceToMario > 400.0f) { + if (distanceToPlayer > 400.0f) { o->oTimer = o->oWoodenPostTotalMarioAngle = 0; } else { // When mario runs around the post 3 times within 200 frames, spawn // coins - o->oWoodenPostTotalMarioAngle += (s16)(o->oAngleToMario - o->oWoodenPostPrevAngleToMario); + o->oWoodenPostTotalMarioAngle += (s16)(angleToPlayer - o->oWoodenPostPrevAngleToMario); if (absi(o->oWoodenPostTotalMarioAngle) > 0x30000 && o->oTimer < 200) { + if (network_owns_object(o)) { network_send_object(o); } obj_spawn_loot_yellow_coins(o, 5, 20.0f); set_object_respawn_info_bits(o, 1); } } - o->oWoodenPostPrevAngleToMario = o->oAngleToMario; + o->oWoodenPostPrevAngleToMario = angleToPlayer; } } diff --git a/src/game/behaviors/koopa.inc.c b/src/game/behaviors/koopa.inc.c index 6eb05f774..3dd6a6be4 100644 --- a/src/game/behaviors/koopa.inc.c +++ b/src/game/behaviors/koopa.inc.c @@ -86,10 +86,10 @@ void bhv_koopa_init(void) { } network_init_object(o, 4000.0f); - network_init_object_field(o, &o->oSubAction); network_init_object_field(o, &o->oKoopaTargetYaw); network_init_object_field(o, &o->oKoopaCountdown); network_init_object_field(o, &o->oKoopaMovementType); + network_init_object_field(o, &o->oKoopaUnshelledTimeUntilTurn); } /** diff --git a/src/game/behaviors/koopa_shell.inc.c b/src/game/behaviors/koopa_shell.inc.c index 7c4237bd7..d62f103e3 100644 --- a/src/game/behaviors/koopa_shell.inc.c +++ b/src/game/behaviors/koopa_shell.inc.c @@ -54,8 +54,6 @@ void koopa_shell_spawn_sparkles(f32 a) { void bhv_koopa_shell_loop(void) { if (o->oSyncID == 0) { network_init_object(o, 500.0f); - network_init_object_field(o, &o->oInteractStatus); - network_init_object_field(o, &o->oAction); } struct Surface *sp34; diff --git a/src/game/behaviors/switch_hidden_objects.inc.c b/src/game/behaviors/switch_hidden_objects.inc.c index ae4a69835..c7de751f1 100644 --- a/src/game/behaviors/switch_hidden_objects.inc.c +++ b/src/game/behaviors/switch_hidden_objects.inc.c @@ -30,7 +30,6 @@ void breakable_box_init(void) { break; } network_init_object(o, SYNC_DISTANCE_ONLY_DEATH); - network_init_object_field(o, &o->oInteractStatus); } void hidden_breakable_box_actions(void) { diff --git a/src/game/obj_behaviors_2.c b/src/game/obj_behaviors_2.c index a7dd244a9..7ee925abc 100644 --- a/src/game/obj_behaviors_2.c +++ b/src/game/obj_behaviors_2.c @@ -44,6 +44,7 @@ #include "save_file.h" #include "seq_ids.h" #include "spawn_sound.h" +#include "pc/network/network.h" #define POS_OP_SAVE_POSITION 0 #define POS_OP_COMPUTE_VELOCITY 1 diff --git a/src/pc/network/network.h b/src/pc/network/network.h index 22af5d3f6..82af23b4f 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -6,7 +6,8 @@ #include #include "../cliopts.h" -#define SYNC_DISTANCE_ONLY_DEATH -1 +#define SYNC_DISTANCE_ONLY_DEATH -1.0f +#define SYNC_DISTANCE_ONLY_EVENTS -2.0f #define SYNC_DISTANCE_INFINITE 0 #define MAX_SYNC_OBJECTS 256 #define MAX_SYNC_OBJECT_FIELDS 16 @@ -36,6 +37,7 @@ struct SyncObject { bool owned; unsigned int ticksSinceUpdate; void* behavior; + u16 onEventId; u8 extraFieldCount; void* extraFields[MAX_SYNC_OBJECT_FIELDS]; }; @@ -66,6 +68,7 @@ void network_update_reliable(void); void network_update_player(void); void network_receive_player(struct Packet* p); +bool network_owns_object(struct Object* o); void network_update_objects(void); void network_receive_object(struct Packet* p); diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index a627a9d6d..183b9206f 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -24,6 +24,7 @@ void network_init_object(struct Object *o, float maxSyncDistance) { so->ticksSinceUpdate = -1; so->extraFieldCount = 0; so->behavior = o->behavior; + so->onEventId = 0; memset(so->extraFields, 0, sizeof(void*) * MAX_SYNC_OBJECT_FIELDS); } @@ -34,18 +35,29 @@ void network_init_object_field(struct Object *o, void* field) { so->extraFields[index] = field; } +bool network_owns_object(struct Object* o) { + struct SyncObject* so = &syncObjects[o->oSyncID]; + if (so == NULL) { return false; } + return so->owned; +} + void network_send_object(struct Object* o) { struct SyncObject* so = &syncObjects[o->oSyncID]; if (so == NULL) { return; } - bool reliable = (o->activeFlags == ACTIVE_FLAG_DEACTIVATED); + so->onEventId++; + + bool reliable = (o->activeFlags == ACTIVE_FLAG_DEACTIVATED || so->maxSyncDistance == SYNC_DISTANCE_ONLY_EVENTS); struct Packet p; packet_init(&p, PACKET_OBJECT, reliable); packet_write(&p, &o->oSyncID, 4); + packet_write(&p, &so->onEventId, 2); packet_write(&p, &so->behavior, sizeof(void*)); packet_write(&p, &o->activeFlags, 2); packet_write(&p, &o->oPosX, 28); packet_write(&p, &o->oAction, 4); + packet_write(&p, &o->oSubAction, 4); + packet_write(&p, &o->oInteractStatus, 4); packet_write(&p, &o->oHeldState, 4); packet_write(&p, &o->oMoveAngleYaw, 4); @@ -61,6 +73,8 @@ void network_send_object(struct Object* o) { if (o->behavior != so->behavior) { printf("network_send_object() BEHAVIOR MISMATCH!\n"); + forget_sync_object(so); + return; } network_send(&p); @@ -85,6 +99,20 @@ void network_receive_object(struct Packet* p) { return; } + // make sure this is the newest event possible + volatile u16 eventId = 0; + packet_read(p, &eventId, 2); + if (so->onEventId > eventId && (u16)abs(eventId - so->onEventId) < USHRT_MAX / 2) { return; } + so->onEventId = eventId; + + // make sure the behaviors match + packet_read(p, &so->behavior, sizeof(void*)); + if (o->behavior != so->behavior) { + printf("network_receive_object() BEHAVIOR MISMATCH!\n"); + forget_sync_object(so); + return; + } + // sync only death if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) { s16 activeFlags; @@ -97,10 +125,11 @@ void network_receive_object(struct Packet* p) { } // write object flags - packet_read(p, &so->behavior, sizeof(void*)); packet_read(p, &o->activeFlags, 2); packet_read(p, &o->oPosX, 28); packet_read(p, &o->oAction, 4); + packet_read(p, &o->oSubAction, 4); + packet_read(p, &o->oInteractStatus, 4); packet_read(p, &o->oHeldState, 4); packet_read(p, &o->oMoveAngleYaw, 4); @@ -113,10 +142,6 @@ void network_receive_object(struct Packet* p) { packet_read(p, so->extraFields[i], 4); } - if (o->behavior != so->behavior) { - printf("network_receive_object() BEHAVIOR MISMATCH!\n"); - } - // deactivated if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) { forget_sync_object(so); @@ -161,7 +186,8 @@ void network_update_objects(void) { so->ticksSinceUpdate++; // check if we should be the one syncing this object - if (!should_own_object(so)) { continue; } + so->owned = should_own_object(so); + if (!so->owned) { continue; } // check update rate if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) { diff --git a/src/pc/network/packets/packet_read_write.c b/src/pc/network/packets/packet_read_write.c index 878412be8..7033897ee 100644 --- a/src/pc/network/packets/packet_read_write.c +++ b/src/pc/network/packets/packet_read_write.c @@ -24,6 +24,7 @@ void packet_write(struct Packet* packet, void* data, int length) { void packet_read(struct Packet* packet, void* data, int length) { if (data == NULL) { packet->error = true; return; } - memcpy(data, &packet->buffer[packet->cursor], length); - packet->cursor += length; + int cursor = packet->cursor; + memcpy(data, &packet->buffer[cursor], length); + packet->cursor = cursor + length; }