mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2025-10-30 08:01:01 +00:00
Refactor packet_object + misc cleanup
This commit is contained in:
parent
9036336f42
commit
d307fc3f30
5 changed files with 223 additions and 127 deletions
|
|
@ -949,7 +949,7 @@ static BhvCommandProc BehaviorCmdTable[] = {
|
||||||
bhv_cmd_set_int_unused, //36
|
bhv_cmd_set_int_unused, //36
|
||||||
bhv_cmd_spawn_water_droplet, //37
|
bhv_cmd_spawn_water_droplet, //37
|
||||||
bhv_cmd_cylboard, //38
|
bhv_cmd_cylboard, //38
|
||||||
bhv_cmd_id //38
|
bhv_cmd_id //39
|
||||||
};
|
};
|
||||||
|
|
||||||
// Execute the behavior script of the current object, process the object flags, and other miscellaneous code for updating objects.
|
// Execute the behavior script of the current object, process the object flags, and other miscellaneous code for updating objects.
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ int matchCount = 0;
|
||||||
void network_send_level_warp(void) {
|
void network_send_level_warp(void) {
|
||||||
struct Packet p;
|
struct Packet p;
|
||||||
packet_init(&p, PACKET_LEVEL_WARP, false);
|
packet_init(&p, PACKET_LEVEL_WARP, false);
|
||||||
packet_write(&p, &sCurrPlayMode, 2);
|
packet_write(&p, &sCurrPlayMode, sizeof(s16));
|
||||||
packet_write(&p, &gCurrLevelNum, 2);
|
packet_write(&p, &gCurrLevelNum, sizeof(s16));
|
||||||
packet_write(&p, &sDelayedWarpArg, 4);
|
packet_write(&p, &sDelayedWarpArg, sizeof(s32));
|
||||||
packet_write(&p, &sSourceWarpNodeId, 2);
|
packet_write(&p, &sSourceWarpNodeId, sizeof(s16));
|
||||||
|
|
||||||
network_send(&p);
|
network_send(&p);
|
||||||
}
|
}
|
||||||
|
|
@ -22,10 +22,10 @@ void network_receive_level_warp(struct Packet* p) {
|
||||||
s32 remoteWarpArg;
|
s32 remoteWarpArg;
|
||||||
s16 remoteWarpNodeId;
|
s16 remoteWarpNodeId;
|
||||||
|
|
||||||
packet_read(p, &remotePlayMode, 2);
|
packet_read(p, &remotePlayMode, sizeof(s16));
|
||||||
packet_read(p, &remoteLevelNum, 2);
|
packet_read(p, &remoteLevelNum, sizeof(s16));
|
||||||
packet_read(p, &remoteWarpArg, 4);
|
packet_read(p, &remoteWarpArg, sizeof(s32));
|
||||||
packet_read(p, &remoteWarpNodeId, 2);
|
packet_read(p, &remoteWarpNodeId, sizeof(s16));
|
||||||
|
|
||||||
bool matching = (remoteLevelNum == gCurrLevelNum)
|
bool matching = (remoteLevelNum == gCurrLevelNum)
|
||||||
&& (remoteWarpArg == sDelayedWarpArg)
|
&& (remoteWarpArg == sDelayedWarpArg)
|
||||||
|
|
@ -62,4 +62,4 @@ void network_receive_level_warp(struct Packet* p) {
|
||||||
|
|
||||||
void network_update_level_warp(void) {
|
void network_update_level_warp(void) {
|
||||||
network_send_level_warp();
|
network_send_level_warp();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,20 @@
|
||||||
u8 nextSyncID = 1;
|
u8 nextSyncID = 1;
|
||||||
struct SyncObject syncObjects[MAX_SYNC_OBJECTS] = { 0 };
|
struct SyncObject syncObjects[MAX_SYNC_OBJECTS] = { 0 };
|
||||||
|
|
||||||
|
// todo: move this to somewhere more general
|
||||||
|
float player_distance(struct MarioState* marioState, struct Object* o) {
|
||||||
|
if (marioState->marioObj == NULL) { return 0; }
|
||||||
|
f32 mx = marioState->marioObj->header.gfx.pos[0] - o->oPosX;
|
||||||
|
f32 my = marioState->marioObj->header.gfx.pos[1] - o->oPosY;
|
||||||
|
f32 mz = marioState->marioObj->header.gfx.pos[2] - o->oPosZ;
|
||||||
|
mx *= mx;
|
||||||
|
my *= my;
|
||||||
|
mz *= mz;
|
||||||
|
return sqrt(mx + my + mz);
|
||||||
|
}
|
||||||
|
|
||||||
void network_init_object(struct Object *o, float maxSyncDistance) {
|
void network_init_object(struct Object *o, float maxSyncDistance) {
|
||||||
|
// generate new sync ID
|
||||||
if (o->oSyncID == 0) {
|
if (o->oSyncID == 0) {
|
||||||
for (int i = 0; i < MAX_SYNC_OBJECTS; i++) {
|
for (int i = 0; i < MAX_SYNC_OBJECTS; i++) {
|
||||||
if (syncObjects[nextSyncID].o == NULL) { break; }
|
if (syncObjects[nextSyncID].o == NULL) { break; }
|
||||||
|
|
@ -20,6 +33,8 @@ void network_init_object(struct Object *o, float maxSyncDistance) {
|
||||||
nextSyncID = (nextSyncID + 1) % MAX_SYNC_OBJECTS;
|
nextSyncID = (nextSyncID + 1) % MAX_SYNC_OBJECTS;
|
||||||
}
|
}
|
||||||
assert(o->oSyncID < MAX_SYNC_OBJECTS);
|
assert(o->oSyncID < MAX_SYNC_OBJECTS);
|
||||||
|
|
||||||
|
// set default values for sync object
|
||||||
struct SyncObject* so = &syncObjects[o->oSyncID];
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
so->o = o;
|
so->o = o;
|
||||||
so->maxSyncDistance = maxSyncDistance;
|
so->maxSyncDistance = maxSyncDistance;
|
||||||
|
|
@ -37,6 +52,7 @@ void network_init_object(struct Object *o, float maxSyncDistance) {
|
||||||
|
|
||||||
void network_object_settings(struct Object *o, bool fullObjectSync, float maxUpdateRate, bool keepRandomSeed, u8 ignore_if_true(struct Object*)) {
|
void network_object_settings(struct Object *o, bool fullObjectSync, float maxUpdateRate, bool keepRandomSeed, u8 ignore_if_true(struct Object*)) {
|
||||||
assert(o->oSyncID != 0);
|
assert(o->oSyncID != 0);
|
||||||
|
// override default settings for sync object
|
||||||
struct SyncObject* so = &syncObjects[o->oSyncID];
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
so->fullObjectSync = fullObjectSync;
|
so->fullObjectSync = fullObjectSync;
|
||||||
so->maxUpdateRate = maxUpdateRate;
|
so->maxUpdateRate = maxUpdateRate;
|
||||||
|
|
@ -46,6 +62,7 @@ void network_object_settings(struct Object *o, bool fullObjectSync, float maxUpd
|
||||||
|
|
||||||
void network_init_object_field(struct Object *o, void* field) {
|
void network_init_object_field(struct Object *o, void* field) {
|
||||||
assert(o->oSyncID != 0);
|
assert(o->oSyncID != 0);
|
||||||
|
// remember to synchronize this extra field
|
||||||
struct SyncObject* so = &syncObjects[o->oSyncID];
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
int index = so->extraFieldCount++;
|
int index = so->extraFieldCount++;
|
||||||
so->extraFields[index] = field;
|
so->extraFields[index] = field;
|
||||||
|
|
@ -57,84 +74,51 @@ bool network_owns_object(struct Object* o) {
|
||||||
return so->owned;
|
return so->owned;
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_send_object(struct Object* o) {
|
// ----- header ----- //
|
||||||
|
|
||||||
|
static void packet_write_object_header(struct Packet* p, struct Object* o) {
|
||||||
struct SyncObject* so = &syncObjects[o->oSyncID];
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
if (so == NULL) { return; }
|
|
||||||
|
|
||||||
so->onEventId++;
|
|
||||||
|
|
||||||
enum BehaviorId behaviorId = get_id_from_behavior(o->behavior);
|
enum BehaviorId behaviorId = get_id_from_behavior(o->behavior);
|
||||||
bool reliable = (o->activeFlags == ACTIVE_FLAG_DEACTIVATED || so->maxSyncDistance == SYNC_DISTANCE_ONLY_EVENTS);
|
|
||||||
|
|
||||||
struct Packet p;
|
packet_write(p, &o->oSyncID, sizeof(u32));
|
||||||
packet_init(&p, PACKET_OBJECT, reliable);
|
packet_write(p, &so->onEventId, sizeof(u16));
|
||||||
packet_write(&p, &o->oSyncID, 4);
|
packet_write(p, &behaviorId, sizeof(enum BehaviorId));
|
||||||
packet_write(&p, &so->onEventId, sizeof(u16));
|
|
||||||
packet_write(&p, &behaviorId, sizeof(enum BehaviorId));
|
|
||||||
|
|
||||||
if (so->maxSyncDistance != SYNC_DISTANCE_ONLY_EVENTS) {
|
|
||||||
packet_write(&p, &o->activeFlags, sizeof(s16));
|
|
||||||
packet_write(&p, &o->header.gfx.node.flags, sizeof(s16));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (so->fullObjectSync) {
|
|
||||||
packet_write(&p, o->rawData.asU32, sizeof(u32) * 80);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (so->maxSyncDistance != SYNC_DISTANCE_ONLY_EVENTS) {
|
|
||||||
packet_write(&p, &o->oPosX, sizeof(u32) * 7);
|
|
||||||
packet_write(&p, &o->oAction, sizeof(u32));
|
|
||||||
packet_write(&p, &o->oSubAction, sizeof(u32));
|
|
||||||
packet_write(&p, &o->oInteractStatus, sizeof(u32));
|
|
||||||
packet_write(&p, &o->oHeldState, sizeof(u32));
|
|
||||||
packet_write(&p, &o->oMoveAngleYaw, sizeof(u32));
|
|
||||||
packet_write(&p, &o->oTimer, sizeof(u32));
|
|
||||||
}
|
|
||||||
|
|
||||||
packet_write(&p, &so->extraFieldCount, sizeof(u8));
|
|
||||||
for (int i = 0; i < so->extraFieldCount; i++) {
|
|
||||||
assert(so->extraFields[i] != NULL);
|
|
||||||
packet_write(&p, so->extraFields[i], sizeof(u32));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
so->clockSinceUpdate = clock();
|
|
||||||
|
|
||||||
if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) { forget_sync_object(so); }
|
|
||||||
|
|
||||||
if (o->behavior != so->behavior) {
|
|
||||||
printf("network_send_object() BEHAVIOR MISMATCH!\n");
|
|
||||||
forget_sync_object(so);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
network_send(&p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_receive_object(struct Packet* p) {
|
static struct SyncObject* packet_read_object_header(struct Packet* p) {
|
||||||
// get sync ID
|
// get sync ID, sanity check
|
||||||
u32 syncId;
|
u32 syncId = 0;
|
||||||
packet_read(p, &syncId, sizeof(u32));
|
packet_read(p, &syncId, sizeof(u32));
|
||||||
assert(syncId < MAX_SYNC_OBJECTS);
|
if (syncId == 0 || syncId >= MAX_SYNC_OBJECTS) {
|
||||||
|
printf("%s invalid SyncID!\n", NETWORKTYPESTR, syncId);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// retrieve SyncObject
|
// retrieve SyncObject, check if we should update using callback
|
||||||
struct SyncObject* so = &syncObjects[syncId];
|
struct SyncObject* so = &syncObjects[syncId];
|
||||||
|
if (so->ignore_if_true != NULL && (*so->ignore_if_true)(so->o)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
so->clockSinceUpdate = clock();
|
so->clockSinceUpdate = clock();
|
||||||
if (so->ignore_if_true != NULL && (*so->ignore_if_true)(so->o)) { return; }
|
|
||||||
|
|
||||||
// extract Object
|
// extract object, sanity check
|
||||||
struct Object* o = syncObjects[syncId].o;
|
struct Object* o = syncObjects[syncId].o;
|
||||||
if (o == NULL) { printf("%s failed to receive object!\n", NETWORKTYPESTR); return; }
|
if (o == NULL) {
|
||||||
|
printf("%s invalid SyncObject!\n", NETWORKTYPESTR);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// make sure it's active
|
// make sure it's active
|
||||||
if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) {
|
if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) {
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure this is the newest event possible
|
// make sure this is the newest event possible
|
||||||
volatile u16 eventId = 0;
|
u16 eventId = 0;
|
||||||
packet_read(p, &eventId, sizeof(u16));
|
packet_read(p, &eventId, sizeof(u16));
|
||||||
if (so->onEventId > eventId && (u16)abs(eventId - so->onEventId) < USHRT_MAX / 2) { return; }
|
if (so->onEventId > eventId && (u16)abs(eventId - so->onEventId) < USHRT_MAX / 2) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
so->onEventId = eventId;
|
so->onEventId = eventId;
|
||||||
|
|
||||||
// make sure the behaviors match
|
// make sure the behaviors match
|
||||||
|
|
@ -142,56 +126,175 @@ void network_receive_object(struct Packet* p) {
|
||||||
packet_read(p, &behaviorId, sizeof(enum BehaviorId));
|
packet_read(p, &behaviorId, sizeof(enum BehaviorId));
|
||||||
so->behavior = get_behavior_from_id(behaviorId);
|
so->behavior = get_behavior_from_id(behaviorId);
|
||||||
if (o->behavior != so->behavior) {
|
if (o->behavior != so->behavior) {
|
||||||
printf("network_receive_object() BEHAVIOR MISMATCH!\n");
|
printf("network_receive_object() behavior mismatch!\n");
|
||||||
|
forget_sync_object(so);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return so;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- full sync ----- //
|
||||||
|
|
||||||
|
static void packet_write_object_full_sync(struct Packet* p, struct Object* o) {
|
||||||
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
|
if (!so->fullObjectSync) { return; }
|
||||||
|
|
||||||
|
// write all of raw data
|
||||||
|
packet_write(p, o->rawData.asU32, sizeof(u32) * 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void packet_read_object_full_sync(struct Packet* p, struct Object* o) {
|
||||||
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
|
if (!so->fullObjectSync) { return; }
|
||||||
|
|
||||||
|
// read all of raw data
|
||||||
|
packet_read(p, o->rawData.asU32, sizeof(u32) * 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- standard fields ----- //
|
||||||
|
|
||||||
|
static void packet_write_object_standard_fields(struct Packet* p, struct Object* o) {
|
||||||
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
|
if (so->fullObjectSync) { return; }
|
||||||
|
if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) { return; }
|
||||||
|
if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_EVENTS) { return; }
|
||||||
|
|
||||||
|
// write the standard fields
|
||||||
|
packet_write(p, &o->oPosX, sizeof(u32) * 7);
|
||||||
|
packet_write(p, &o->oAction, sizeof(u32));
|
||||||
|
packet_write(p, &o->oSubAction, sizeof(u32));
|
||||||
|
packet_write(p, &o->oInteractStatus, sizeof(u32));
|
||||||
|
packet_write(p, &o->oHeldState, sizeof(u32));
|
||||||
|
packet_write(p, &o->oMoveAngleYaw, sizeof(u32));
|
||||||
|
packet_write(p, &o->oTimer, sizeof(u32));
|
||||||
|
packet_write(p, &o->activeFlags, sizeof(s16));
|
||||||
|
packet_write(p, &o->header.gfx.node.flags, sizeof(s16));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void packet_read_object_standard_fields(struct Packet* p, struct Object* o) {
|
||||||
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
|
if (so->fullObjectSync) { return; }
|
||||||
|
if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) { return; }
|
||||||
|
if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_EVENTS) { return; }
|
||||||
|
|
||||||
|
// read the standard fields
|
||||||
|
packet_read(p, &o->oPosX, sizeof(u32) * 7);
|
||||||
|
packet_read(p, &o->oAction, sizeof(u32));
|
||||||
|
packet_read(p, &o->oSubAction, sizeof(u32));
|
||||||
|
packet_read(p, &o->oInteractStatus, sizeof(u32));
|
||||||
|
packet_read(p, &o->oHeldState, sizeof(u32));
|
||||||
|
packet_read(p, &o->oMoveAngleYaw, sizeof(u32));
|
||||||
|
packet_read(p, &o->oTimer, sizeof(u32));
|
||||||
|
packet_read(p, &o->activeFlags, sizeof(u16));
|
||||||
|
packet_read(p, &o->header.gfx.node.flags, sizeof(s16));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- extra fields ----- //
|
||||||
|
|
||||||
|
static void packet_write_object_extra_fields(struct Packet* p, struct Object* o) {
|
||||||
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
|
if (so->fullObjectSync) { return; }
|
||||||
|
if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) { return; }
|
||||||
|
|
||||||
|
// write the count
|
||||||
|
packet_write(p, &so->extraFieldCount, sizeof(u8));
|
||||||
|
|
||||||
|
// write the extra field
|
||||||
|
for (int i = 0; i < so->extraFieldCount; i++) {
|
||||||
|
assert(so->extraFields[i] != NULL);
|
||||||
|
packet_write(p, so->extraFields[i], sizeof(u32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void packet_read_object_extra_fields(struct Packet* p, struct Object* o) {
|
||||||
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
|
if (so->fullObjectSync) { return; }
|
||||||
|
if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) { return; }
|
||||||
|
|
||||||
|
// read the count and sanity check
|
||||||
|
u8 extraFieldsCount = 0;
|
||||||
|
packet_read(p, &extraFieldsCount, sizeof(u8));
|
||||||
|
assert(extraFieldsCount == so->extraFieldCount);
|
||||||
|
|
||||||
|
// read the extra fields
|
||||||
|
for (int i = 0; i < extraFieldsCount; i++) {
|
||||||
|
assert(so->extraFields[i] != NULL);
|
||||||
|
packet_read(p, so->extraFields[i], sizeof(u32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- only death ----- //
|
||||||
|
|
||||||
|
static void packet_write_object_only_death(struct Packet* p, struct Object* o) {
|
||||||
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
|
if (so->maxSyncDistance != SYNC_DISTANCE_ONLY_DEATH) { return; }
|
||||||
|
packet_write(p, &o->activeFlags, sizeof(s16));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void packet_read_object_only_death(struct Packet* p, struct Object* o) {
|
||||||
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
|
if (so->maxSyncDistance != SYNC_DISTANCE_ONLY_DEATH) { return; }
|
||||||
|
s16 activeFlags;
|
||||||
|
packet_read(p, &activeFlags, sizeof(u16));
|
||||||
|
if (activeFlags == ACTIVE_FLAG_DEACTIVATED) {
|
||||||
|
// flag the object as dead, the behavior is responsible for clean up
|
||||||
|
so->o->oSyncDeath = 1;
|
||||||
|
forget_sync_object(so);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- main send/receive ----- //
|
||||||
|
|
||||||
|
void network_send_object(struct Object* o) {
|
||||||
|
// sanity check SyncObject
|
||||||
|
struct SyncObject* so = &syncObjects[o->oSyncID];
|
||||||
|
if (so == NULL) { return; }
|
||||||
|
if (o->behavior != so->behavior) {
|
||||||
|
printf("network_send_object() BEHAVIOR MISMATCH!\n");
|
||||||
forget_sync_object(so);
|
forget_sync_object(so);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sync only death
|
// always send a new event ID
|
||||||
if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) {
|
so->onEventId++;
|
||||||
s16 activeFlags;
|
so->clockSinceUpdate = clock();
|
||||||
packet_read(p, &activeFlags, sizeof(u16));
|
|
||||||
if (activeFlags == ACTIVE_FLAG_DEACTIVATED) {
|
// reliable packets when sending a dead object or event
|
||||||
so->o->oSyncDeath = 1;
|
bool reliable = (o->activeFlags == ACTIVE_FLAG_DEACTIVATED || so->maxSyncDistance == SYNC_DISTANCE_ONLY_EVENTS);
|
||||||
forget_sync_object(so);
|
|
||||||
}
|
// write the packet data
|
||||||
return;
|
struct Packet p;
|
||||||
|
packet_init(&p, PACKET_OBJECT, reliable);
|
||||||
|
packet_write_object_header(&p, o);
|
||||||
|
packet_write_object_full_sync(&p, o);
|
||||||
|
packet_write_object_standard_fields(&p, o);
|
||||||
|
packet_write_object_extra_fields(&p, o);
|
||||||
|
packet_write_object_only_death(&p, o);
|
||||||
|
|
||||||
|
// check for object death
|
||||||
|
if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) {
|
||||||
|
forget_sync_object(so);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gMarioStates[0].heldObj == o) {
|
// send the packet out
|
||||||
return;
|
network_send(&p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// write object flags
|
void network_receive_object(struct Packet* p) {
|
||||||
if (so->maxSyncDistance != SYNC_DISTANCE_ONLY_EVENTS) {
|
// read the header and sanity check the packet
|
||||||
packet_read(p, &o->activeFlags, sizeof(u16));
|
struct SyncObject* so = packet_read_object_header(p);
|
||||||
packet_read(p, &o->header.gfx.node.flags, sizeof(s16));
|
if (so == NULL) { return; }
|
||||||
}
|
struct Object* o = so->o;
|
||||||
|
|
||||||
if (so->fullObjectSync) {
|
// make sure no one can update an object we're holding
|
||||||
packet_read(p, o->rawData.asU32, sizeof(u32) * 80);
|
if (gMarioStates[0].heldObj == o) { return; }
|
||||||
} else {
|
|
||||||
|
|
||||||
if (so->maxSyncDistance != SYNC_DISTANCE_ONLY_EVENTS) {
|
// read the rest of the packet data
|
||||||
packet_read(p, &o->oPosX, sizeof(u32) * 7);
|
packet_read_object_full_sync(p, o);
|
||||||
packet_read(p, &o->oAction, sizeof(u32));
|
packet_read_object_standard_fields(p, o);
|
||||||
packet_read(p, &o->oSubAction, sizeof(u32));
|
packet_read_object_extra_fields(p, o);
|
||||||
packet_read(p, &o->oInteractStatus, sizeof(u32));
|
packet_read_object_only_death(p, o);
|
||||||
packet_read(p, &o->oHeldState, sizeof(u32));
|
|
||||||
packet_read(p, &o->oMoveAngleYaw, sizeof(u32));
|
|
||||||
packet_read(p, &o->oTimer, sizeof(u32));
|
|
||||||
}
|
|
||||||
|
|
||||||
// write extra fields
|
|
||||||
u8 extraFields = 0;
|
|
||||||
packet_read(p, &extraFields, sizeof(u8));
|
|
||||||
assert(extraFields == so->extraFieldCount);
|
|
||||||
for (int i = 0; i < extraFields; i++) {
|
|
||||||
assert(so->extraFields[i] != NULL);
|
|
||||||
packet_read(p, so->extraFields[i], sizeof(u32));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// deactivated
|
// deactivated
|
||||||
if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) {
|
if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) {
|
||||||
|
|
@ -199,17 +302,6 @@ void network_receive_object(struct Packet* p) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float player_distance(struct MarioState* marioState, struct Object* o) {
|
|
||||||
if (marioState->marioObj == NULL) { return 0; }
|
|
||||||
f32 mx = marioState->marioObj->header.gfx.pos[0] - o->oPosX;
|
|
||||||
f32 my = marioState->marioObj->header.gfx.pos[1] - o->oPosY;
|
|
||||||
f32 mz = marioState->marioObj->header.gfx.pos[2] - o->oPosZ;
|
|
||||||
mx *= mx;
|
|
||||||
my *= my;
|
|
||||||
mz *= mz;
|
|
||||||
return sqrt(mx + my + mz);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool should_own_object(struct SyncObject* so) {
|
bool should_own_object(struct SyncObject* so) {
|
||||||
if (so->o->oHeldState == HELD_HELD && so->o->heldByPlayerIndex == 0) { return true; }
|
if (so->o->oHeldState == HELD_HELD && so->o->heldByPlayerIndex == 0) { return true; }
|
||||||
if (player_distance(&gMarioStates[0], so->o) > player_distance(&gMarioStates[1], so->o)) { return false; }
|
if (player_distance(&gMarioStates[0], so->o) > player_distance(&gMarioStates[1], so->o)) { return false; }
|
||||||
|
|
@ -238,24 +330,28 @@ void network_update_objects(void) {
|
||||||
so->owned = should_own_object(so);
|
so->owned = should_own_object(so);
|
||||||
if (!so->owned) { continue; }
|
if (!so->owned) { continue; }
|
||||||
|
|
||||||
// check update rate
|
// check for 'only death' event
|
||||||
if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) {
|
if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) {
|
||||||
if (so->o->activeFlags != ACTIVE_FLAG_DEACTIVATED) { continue; }
|
if (so->o->activeFlags != ACTIVE_FLAG_DEACTIVATED) { continue; }
|
||||||
network_send_object(syncObjects[i].o);
|
network_send_object(syncObjects[i].o);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calculate the update rate
|
||||||
float dist = player_distance(&gMarioStates[0], so->o);
|
float dist = player_distance(&gMarioStates[0], so->o);
|
||||||
if (so->maxSyncDistance != SYNC_DISTANCE_INFINITE && dist > so->maxSyncDistance) { continue; }
|
if (so->maxSyncDistance != SYNC_DISTANCE_INFINITE && dist > so->maxSyncDistance) { continue; }
|
||||||
float updateRate = dist / 1000.0f;
|
float updateRate = dist / 1000.0f;
|
||||||
if (gMarioStates[0].heldObj == so->o) { updateRate = 0; }
|
if (gMarioStates[0].heldObj == so->o) { updateRate = 0; }
|
||||||
|
|
||||||
|
// set max and min update rate
|
||||||
if (so->maxUpdateRate > 0 && updateRate < so->maxUpdateRate) { updateRate = so->maxUpdateRate; }
|
if (so->maxUpdateRate > 0 && updateRate < so->maxUpdateRate) { updateRate = so->maxUpdateRate; }
|
||||||
if (updateRate < 0.33f) { updateRate = 0.33f; }
|
if (updateRate < 0.33f) { updateRate = 0.33f; }
|
||||||
|
|
||||||
|
// see if we should update
|
||||||
float timeSinceUpdate = ((float)clock() - (float)so->clockSinceUpdate) / (float)CLOCKS_PER_SEC;
|
float timeSinceUpdate = ((float)clock() - (float)so->clockSinceUpdate) / (float)CLOCKS_PER_SEC;
|
||||||
if (timeSinceUpdate < updateRate) { continue; }
|
if (timeSinceUpdate < updateRate) { continue; }
|
||||||
|
|
||||||
|
// update!
|
||||||
network_send_object(syncObjects[i].o);
|
network_send_object(syncObjects[i].o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,14 +37,14 @@ void network_send_ack(struct Packet* p) {
|
||||||
// send back the ACK
|
// send back the ACK
|
||||||
struct Packet ack = { 0 };
|
struct Packet ack = { 0 };
|
||||||
packet_init(&ack, PACKET_ACK, false);
|
packet_init(&ack, PACKET_ACK, false);
|
||||||
packet_write(&ack, &seqId, 2);
|
packet_write(&ack, &seqId, sizeof(u16));
|
||||||
network_send(&ack);
|
network_send(&ack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void network_receive_ack(struct Packet* p) {
|
void network_receive_ack(struct Packet* p) {
|
||||||
// grab seq num
|
// grab seq num
|
||||||
u16 seqId = 0;
|
u16 seqId = 0;
|
||||||
packet_read(p, &seqId, 2);
|
packet_read(p, &seqId, sizeof(u16));
|
||||||
|
|
||||||
// find in list and remove
|
// find in list and remove
|
||||||
struct PacketLinkedList* node = head;
|
struct PacketLinkedList* node = head;
|
||||||
|
|
@ -94,4 +94,4 @@ void network_update_reliable(void) {
|
||||||
}
|
}
|
||||||
node = node->next;
|
node = node->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ void network_receive_spawn_objects(struct Packet* p) {
|
||||||
packet_read(p, &remoteSpawnId, sizeof(u8));
|
packet_read(p, &remoteSpawnId, sizeof(u8));
|
||||||
packet_read(p, &objectCount, sizeof(u8));
|
packet_read(p, &objectCount, sizeof(u8));
|
||||||
|
|
||||||
// check if remote coin id has already been seen
|
// check if remote spawn id has already been seen
|
||||||
for (int i = 0; i < MAX_REMOTE_SPAWN_IDS; i++) {
|
for (int i = 0; i < MAX_REMOTE_SPAWN_IDS; i++) {
|
||||||
if (remoteSpawnIds[i] == remoteSpawnId) {
|
if (remoteSpawnIds[i] == remoteSpawnId) {
|
||||||
// we already saw this event!
|
// we already saw this event!
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue