mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2025-10-30 08:01:01 +00:00
Synchronized chain chomp, adjustments to Koopa
Added entity event syncing system. Made sure old events don't override new events.
This commit is contained in:
parent
0a2c76c76e
commit
0a3b0623a5
8 changed files with 87 additions and 25 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
#include <assert.h>
|
||||
#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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue