From 6d3a90031ca63065d3fd3e371c0d1a19fafacefa Mon Sep 17 00:00:00 2001 From: MysterD Date: Tue, 4 Aug 2020 22:42:28 -0700 Subject: [PATCH] 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. --- include/object_fields.h | 2 +- src/game/behavior_actions.c | 1 + src/game/behaviors/bobomb.inc.c | 2 +- src/game/behaviors/breakable_box.inc.c | 2 +- src/game/behaviors/breakable_box_small.inc.c | 1 + src/game/behaviors/goomba.inc.c | 2 +- .../behaviors/switch_hidden_objects.inc.c | 2 + src/pc/network/network.h | 7 +++- src/pc/network/packets/packet_object.c | 42 +++++++++++++++---- 9 files changed, 49 insertions(+), 12 deletions(-) diff --git a/include/object_fields.h b/include/object_fields.h index 23fd63b3..9ec8935d 100644 --- a/include/object_fields.h +++ b/include/object_fields.h @@ -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) diff --git a/src/game/behavior_actions.c b/src/game/behavior_actions.c index b40408b3..7948e249 100644 --- a/src/game/behavior_actions.c +++ b/src/game/behavior_actions.c @@ -43,6 +43,7 @@ #include "spawn_object.h" #include "spawn_sound.h" #include "thread6.h" +#include "src/pc/network/network.h" #define o gCurrentObject diff --git a/src/game/behaviors/bobomb.inc.c b/src/game/behaviors/bobomb.inc.c index 5c032c9d..2770a336 100644 --- a/src/game/behaviors/bobomb.inc.c +++ b/src/game/behaviors/bobomb.inc.c @@ -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) { diff --git a/src/game/behaviors/breakable_box.inc.c b/src/game/behaviors/breakable_box.inc.c index f46954c3..a4f90d34 100644 --- a/src/game/behaviors/breakable_box.inc.c +++ b/src/game/behaviors/breakable_box.inc.c @@ -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); } diff --git a/src/game/behaviors/breakable_box_small.inc.c b/src/game/behaviors/breakable_box_small.inc.c index 3acf2d56..639c96da 100644 --- a/src/game/behaviors/breakable_box_small.inc.c +++ b/src/game/behaviors/breakable_box_small.inc.c @@ -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) { diff --git a/src/game/behaviors/goomba.inc.c b/src/game/behaviors/goomba.inc.c index eb41fda9..5f93f277 100644 --- a/src/game/behaviors/goomba.inc.c +++ b/src/game/behaviors/goomba.inc.c @@ -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); } diff --git a/src/game/behaviors/switch_hidden_objects.inc.c b/src/game/behaviors/switch_hidden_objects.inc.c index e159700f..ae4a6983 100644 --- a/src/game/behaviors/switch_hidden_objects.inc.c +++ b/src/game/behaviors/switch_hidden_objects.inc.c @@ -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) { diff --git a/src/pc/network/network.h b/src/pc/network/network.h index a9b1e897..55bfd52a 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -6,6 +6,8 @@ #include #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); diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index 517efde5..88f8015e 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -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; }