Synchronized breakable boxes

Added maximum sync distance, special cases for infinite distance and
only synchronizing entity deaths.

Started mocking out reliable packets for entity deaths.
This commit is contained in:
MysterD 2020-08-04 22:42:28 -07:00
parent 4452b38848
commit 6d3a90031c
9 changed files with 49 additions and 12 deletions

View file

@ -125,7 +125,7 @@
#define /*0x198*/ oNumLootCoins OBJECT_FIELD_S32(0x44)
#define /*0x19C*/ oDrawingDistance OBJECT_FIELD_F32(0x45)
#define /*0x1A0*/ oRoom OBJECT_FIELD_S32(0x46)
// 0x1A4 is unused, possibly related to 0x1A8 in removed macro purposes.
#define /*0x1A4*/ oSyncDeath OBJECT_FIELD_U32(0x47)
#define /*0x1A8*/ oUnk1A8 OBJECT_FIELD_U32(0x48)
// 0x1AC-0x1B2 (0x48-0x4A) are object specific and defined below the common fields.
#define /*0x1B4*/ oWallAngle OBJECT_FIELD_S32(0x4B)

View file

@ -43,6 +43,7 @@
#include "spawn_object.h"
#include "spawn_sound.h"
#include "thread6.h"
#include "src/pc/network/network.h"
#define o gCurrentObject

View file

@ -17,7 +17,7 @@ void bhv_bobomb_init(void) {
o->oFriction = 0.8;
o->oBuoyancy = 1.3;
o->oInteractionSubtype = INT_SUBTYPE_KICKABLE;
network_init_object(o);
network_init_object(o, 4000);
}
void bobomb_spawn_coin(void) {

View file

@ -5,7 +5,7 @@ void bhv_breakable_box_loop(void) {
cur_obj_set_model(MODEL_BREAKABLE_BOX_SMALL);
if (o->oTimer == 0)
breakable_box_init();
if (cur_obj_was_attacked_or_ground_pounded() != 0) {
if (cur_obj_was_attacked_or_ground_pounded() != 0 || o->oSyncDeath) {
obj_explode_and_spawn_coins(46.0f, 1);
create_sound_spawner(SOUND_GENERAL_BREAK_BOX);
}

View file

@ -20,6 +20,7 @@ void bhv_breakable_box_small_init(void) {
obj_set_hitbox(o, &sBreakableBoxSmallHitbox);
o->oAnimState = 1;
o->activeFlags |= ACTIVE_FLAG_UNK9;
network_init_object(o, 500);
}
void small_breakable_box_spawn_dust(void) {

View file

@ -127,7 +127,7 @@ void bhv_goomba_init(void) {
o->oGravity = -8.0f / 3.0f * o->oGoombaScale;
network_init_object(o);
network_init_object(o, 4000);
network_init_object_field(o, &o->oGoombaTargetYaw);
network_init_object_field(o, &o->oGoombaWalkTimer);
}

View file

@ -29,6 +29,8 @@ void breakable_box_init(void) {
cur_obj_scale(1.5f);
break;
}
network_init_object(o, SYNC_DISTANCE_ONLY_DEATH);
network_init_object_field(o, &o->oInteractStatus);
}
void hidden_breakable_box_actions(void) {

View file

@ -6,6 +6,8 @@
#include <assert.h>
#include "../cliopts.h"
#define SYNC_DISTANCE_ONLY_DEATH -1
#define SYNC_DISTANCE_INFINITE 0
#define MAX_SYNC_OBJECTS 256
#define MAX_SYNC_OBJECT_FIELDS 16
#define PACKET_LENGTH 1024
@ -21,11 +23,14 @@ enum PacketType {
struct Packet {
int cursor;
bool error;
bool reliable;
u16 seqId;
char buffer[PACKET_LENGTH];
};
struct SyncObject {
struct Object* o;
float maxSyncDistance;
bool owned;
unsigned int ticksSinceUpdate;
unsigned int syncDeactive;
@ -40,7 +45,7 @@ extern enum NetworkType networkType;
extern struct SyncObject syncObjects[];
void network_init(enum NetworkType networkType);
void network_init_object(struct Object *object);
void network_init_object(struct Object *object, float maxSyncDistance);
void network_send(struct Packet* p);
void network_update(void);
void network_shutdown(void);

View file

@ -6,16 +6,17 @@
u32 nextSyncID = 1;
struct SyncObject syncObjects[MAX_SYNC_OBJECTS] = { 0 };
void network_init_object(struct Object *o) {
void network_init_object(struct Object *o, float maxSyncDistance) {
if (o->oSyncID == 0) {
o->oSyncID = nextSyncID++;
}
assert(o->oSyncID < MAX_SYNC_OBJECTS);
struct SyncObject* so = &syncObjects[o->oSyncID];
so->o = o;
so->maxSyncDistance = maxSyncDistance;
so->owned = false;
so->ticksSinceUpdate = -1;
so->syncDeactive = 0;
so->syncDeactive = false;
so->extraFieldCount = 0;
memset(so->extraFields, 0, sizeof(void*) * MAX_SYNC_OBJECT_FIELDS);
}
@ -45,7 +46,11 @@ void network_send_object(struct SyncObject* so) {
packet_write(&p, so->extraFields[i], 4);
}
if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) { so->syncDeactive++; }
if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) {
so->syncDeactive = true;
p.reliable = true;
}
so->ticksSinceUpdate = 0;
network_send(&p);
}
@ -64,6 +69,22 @@ void network_receive_object(struct Packet* p) {
struct Object* o = syncObjects[syncId].o;
if (o == NULL) { printf("%s failed to receive object!\n", NETWORKTYPESTR); return; }
// make sure it's active
if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) {
return;
}
// sync only death
if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) {
s16 activeFlags;
packet_read(p, &activeFlags, 2);
if (activeFlags == ACTIVE_FLAG_DEACTIVATED) {
so->o->oSyncDeath = 1;
so->syncDeactive = true;
}
return;
}
// write object flags
packet_read(p, &o->activeFlags, 2);
packet_read(p, &o->oPosX, 28);
@ -80,7 +101,6 @@ void network_receive_object(struct Packet* p) {
packet_read(p, so->extraFields[i], 4);
}
if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) { so->syncDeactive++; }
}
float player_distance(struct MarioState* marioState, struct Object* o) {
@ -104,7 +124,7 @@ void forget_sync_object(struct SyncObject* so) {
so->o = NULL;
so->owned = false;
so->ticksSinceUpdate = -1;
so->syncDeactive = 0;
so->syncDeactive = false;
}
void network_update_objects(void) {
@ -113,7 +133,7 @@ void network_update_objects(void) {
if (so->o == NULL) { continue; }
// check for stale sync object
if (so->o->oSyncID != i || so->syncDeactive > 10) {
if (so->o->oSyncID != i || so->syncDeactive) {
forget_sync_object(so);
continue;
}
@ -123,7 +143,15 @@ void network_update_objects(void) {
if (!should_own_object(so)) { continue; }
// check update rate
int updateRate = player_distance(&gMarioStates[0], so->o) / 50;
if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) {
if (so->o->activeFlags != ACTIVE_FLAG_DEACTIVATED) { continue; }
network_send_object(&syncObjects[i]);
continue;
}
float dist = player_distance(&gMarioStates[0], so->o);
if (so->maxSyncDistance != SYNC_DISTANCE_INFINITE && dist > so->maxSyncDistance) { continue; }
int updateRate = dist / 50;
if (gMarioStates[0].heldObj == so->o) { updateRate = 0; }
if (so->ticksSinceUpdate < updateRate) { continue; }