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:
MysterD 2020-08-05 23:44:43 -07:00
parent 0a2c76c76e
commit 0a3b0623a5
8 changed files with 87 additions and 25 deletions

View file

@ -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;
}
}

View file

@ -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);
}
/**

View file

@ -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;

View file

@ -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) {

View file

@ -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

View file

@ -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);

View file

@ -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) {

View file

@ -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;
}