From e61b1371603809177d4c0b2885cbc0fce3e27a9e Mon Sep 17 00:00:00 2001 From: MysterD Date: Wed, 5 Aug 2020 01:01:50 -0700 Subject: [PATCH] Refactored entity death sync + reliable packets Embedded an immediate packet send whenever a synced entity is unloaded from the game. Added reliable packet sending. --- src/game/spawn_object.c | 3 + src/pc/network/network.c | 11 ++- src/pc/network/network.h | 10 +- .../network/packets/packet_inside_painting.c | 2 +- src/pc/network/packets/packet_level_warp.c | 2 +- src/pc/network/packets/packet_object.c | 43 +++++--- src/pc/network/packets/packet_player.c | 2 +- src/pc/network/packets/packet_read_write.c | 13 ++- src/pc/network/packets/packet_reliable.c | 97 +++++++++++++++++++ 9 files changed, 159 insertions(+), 24 deletions(-) create mode 100644 src/pc/network/packets/packet_reliable.c diff --git a/src/game/spawn_object.c b/src/game/spawn_object.c index 6337486fc..843739ddc 100644 --- a/src/game/spawn_object.c +++ b/src/game/spawn_object.c @@ -184,6 +184,7 @@ static void unused_delete_leaf_nodes(struct Object *obj) { * Free the given object. */ void unload_object(struct Object *obj) { + obj->activeFlags = ACTIVE_FLAG_DEACTIVATED; obj->prevObj = NULL; @@ -196,6 +197,8 @@ void unload_object(struct Object *obj) { obj->header.gfx.node.flags &= ~GRAPH_RENDER_CYLBOARD; obj->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE; + if (obj->oSyncID != 0) { network_send_object(obj); } + deallocate_object(&gFreeObjectList, &obj->header); } diff --git a/src/pc/network/network.c b/src/pc/network/network.c index 051f3a014..9c37e48c9 100644 --- a/src/pc/network/network.c +++ b/src/pc/network/network.c @@ -66,11 +66,15 @@ void network_send(struct Packet* p) { txAddr.sin_port = txPort; txAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + network_remember_reliable(p); + int rc = sendto(gSocket, p->buffer, p->cursor, 0, (SOCKADDR *)& txAddr, sizeof(txAddr)); if (rc == SOCKET_ERROR) { wprintf(L"%s sendto failed with error: %d\n", NETWORKTYPESTR, WSAGetLastError()); return; } + + p->sent = true; } void network_update(void) { @@ -89,7 +93,7 @@ void network_update(void) { do { struct sockaddr_in rxAddr; int rxAddrSize = sizeof(rxAddr); - struct Packet p = { .cursor = 1 }; + struct Packet p = { .cursor = 3 }; int rc = recvfrom(gSocket, p.buffer, PACKET_LENGTH, 0, (SOCKADDR *)&rxAddr, &rxAddrSize); if (rc == SOCKET_ERROR) { int error = WSAGetLastError(); @@ -101,6 +105,7 @@ void network_update(void) { if (rc == 0) { break; } switch (p.buffer[0]) { + case PACKET_ACK: network_receive_ack(&p); break; case PACKET_PLAYER: network_receive_player(&p); break; case PACKET_OBJECT: network_receive_object(&p); break; case PACKET_LEVEL_WARP: network_receive_level_warp(&p); break; @@ -108,8 +113,12 @@ void network_update(void) { default: printf("%s received unknown packet: %d\n", NETWORKTYPESTR, p.buffer[0]); } + // send an ACK if requested + network_send_ack(&p); + } while (1); + network_update_reliable(); } void network_shutdown(void) { diff --git a/src/pc/network/network.h b/src/pc/network/network.h index 55bfd52a8..dcb43668b 100644 --- a/src/pc/network/network.h +++ b/src/pc/network/network.h @@ -14,6 +14,7 @@ #define NETWORKTYPESTR (networkType == NT_CLIENT ? "Client" : "Server") enum PacketType { + PACKET_ACK, PACKET_PLAYER, PACKET_OBJECT, PACKET_LEVEL_WARP, @@ -25,6 +26,7 @@ struct Packet { bool error; bool reliable; u16 seqId; + bool sent; char buffer[PACKET_LENGTH]; }; @@ -33,7 +35,6 @@ struct SyncObject { float maxSyncDistance; bool owned; unsigned int ticksSinceUpdate; - unsigned int syncDeactive; u8 extraFieldCount; void* extraFields[MAX_SYNC_OBJECT_FIELDS]; }; @@ -51,11 +52,16 @@ void network_update(void); void network_shutdown(void); // packet read / write -void packet_init(struct Packet* packet, enum PacketType packetType); +void packet_init(struct Packet* packet, enum PacketType packetType, bool reliable); void packet_write(struct Packet* packet, void* data, int length); void packet_read(struct Packet* packet, void* data, int length); // packet headers +void network_send_ack(struct Packet* p); +void network_receive_ack(struct Packet* p); +void network_remember_reliable(struct Packet* p); +void network_update_reliable(void); + void network_update_player(void); void network_receive_player(struct Packet* p); diff --git a/src/pc/network/packets/packet_inside_painting.c b/src/pc/network/packets/packet_inside_painting.c index f8a00ae75..40fb80759 100644 --- a/src/pc/network/packets/packet_inside_painting.c +++ b/src/pc/network/packets/packet_inside_painting.c @@ -32,7 +32,7 @@ void network_send_inside_painting(void) { populate_packet_data(&data); struct Packet p; - packet_init(&p, PACKET_INSIDE_PAINTING); + packet_init(&p, PACKET_INSIDE_PAINTING, false); packet_write(&p, &data, sizeof(struct PacketDataInsidePainting)); network_send(&p); diff --git a/src/pc/network/packets/packet_level_warp.c b/src/pc/network/packets/packet_level_warp.c index ee84023af..eb387261d 100644 --- a/src/pc/network/packets/packet_level_warp.c +++ b/src/pc/network/packets/packet_level_warp.c @@ -7,7 +7,7 @@ int warpTimeout = 0; void network_send_level_warp(void) { struct Packet p; - packet_init(&p, PACKET_LEVEL_WARP); + packet_init(&p, PACKET_LEVEL_WARP, false); packet_write(&p, &sCurrPlayMode, 2); packet_write(&p, &gCurrLevelNum, 2); packet_write(&p, &sDelayedWarpArg, 4); diff --git a/src/pc/network/packets/packet_object.c b/src/pc/network/packets/packet_object.c index 88f8015ee..20b8341f4 100644 --- a/src/pc/network/packets/packet_object.c +++ b/src/pc/network/packets/packet_object.c @@ -3,12 +3,18 @@ #include "object_fields.h" #include "object_constants.h" -u32 nextSyncID = 1; +u8 nextSyncID = 1; struct SyncObject syncObjects[MAX_SYNC_OBJECTS] = { 0 }; void network_init_object(struct Object *o, float maxSyncDistance) { if (o->oSyncID == 0) { - o->oSyncID = nextSyncID++; + for (int i = 0; i < MAX_SYNC_OBJECTS; i++) { + if (syncObjects[nextSyncID].o == NULL) { break; } + nextSyncID = (nextSyncID + 1) % MAX_SYNC_OBJECTS; + } + assert(syncObjects[nextSyncID].o == NULL); + o->oSyncID = nextSyncID; + nextSyncID = (nextSyncID + 1) % MAX_SYNC_OBJECTS; } assert(o->oSyncID < MAX_SYNC_OBJECTS); struct SyncObject* so = &syncObjects[o->oSyncID]; @@ -16,7 +22,6 @@ void network_init_object(struct Object *o, float maxSyncDistance) { so->maxSyncDistance = maxSyncDistance; so->owned = false; so->ticksSinceUpdate = -1; - so->syncDeactive = false; so->extraFieldCount = 0; memset(so->extraFields, 0, sizeof(void*) * MAX_SYNC_OBJECT_FIELDS); } @@ -28,11 +33,13 @@ void network_init_object_field(struct Object *o, void* field) { so->extraFields[index] = field; } -void network_send_object(struct SyncObject* so) { - struct Object* o = so->o; +void network_send_object(struct Object* o) { + struct SyncObject* so = &syncObjects[o->oSyncID]; + if (so == NULL) { return; } + bool reliable = (o->activeFlags == ACTIVE_FLAG_DEACTIVATED); struct Packet p; - packet_init(&p, PACKET_OBJECT); + packet_init(&p, PACKET_OBJECT, reliable); packet_write(&p, &o->oSyncID, 4); packet_write(&p, &o->activeFlags, 2); packet_write(&p, &o->oPosX, 28); @@ -46,12 +53,10 @@ void network_send_object(struct SyncObject* so) { packet_write(&p, so->extraFields[i], 4); } - if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) { - so->syncDeactive = true; - p.reliable = true; - } - so->ticksSinceUpdate = 0; + + if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) { forget_sync_object(so); } + network_send(&p); } @@ -80,7 +85,7 @@ void network_receive_object(struct Packet* p) { packet_read(p, &activeFlags, 2); if (activeFlags == ACTIVE_FLAG_DEACTIVATED) { so->o->oSyncDeath = 1; - so->syncDeactive = true; + forget_sync_object(so); } return; } @@ -101,6 +106,11 @@ void network_receive_object(struct Packet* p) { packet_read(p, so->extraFields[i], 4); } + // deactivated + if (o->activeFlags == ACTIVE_FLAG_DEACTIVATED) { + forget_sync_object(so); + } + } float player_distance(struct MarioState* marioState, struct Object* o) { @@ -115,6 +125,7 @@ float player_distance(struct MarioState* marioState, struct Object* o) { } bool should_own_object(struct SyncObject* so) { + 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 (so->o->oHeldState == HELD_HELD && so->o->heldByPlayerIndex != 0) { return false; } return true; @@ -124,7 +135,6 @@ void forget_sync_object(struct SyncObject* so) { so->o = NULL; so->owned = false; so->ticksSinceUpdate = -1; - so->syncDeactive = false; } void network_update_objects(void) { @@ -133,7 +143,8 @@ void network_update_objects(void) { if (so->o == NULL) { continue; } // check for stale sync object - if (so->o->oSyncID != i || so->syncDeactive) { + if (so->o->oSyncID != i) { + printf("ERROR! Sync ID mismatch!\n"); forget_sync_object(so); continue; } @@ -145,7 +156,7 @@ void network_update_objects(void) { // check update rate if (so->maxSyncDistance == SYNC_DISTANCE_ONLY_DEATH) { if (so->o->activeFlags != ACTIVE_FLAG_DEACTIVATED) { continue; } - network_send_object(&syncObjects[i]); + network_send_object(syncObjects[i].o); continue; } @@ -155,7 +166,7 @@ void network_update_objects(void) { if (gMarioStates[0].heldObj == so->o) { updateRate = 0; } if (so->ticksSinceUpdate < updateRate) { continue; } - network_send_object(&syncObjects[i]); + network_send_object(syncObjects[i].o); } } \ No newline at end of file diff --git a/src/pc/network/packets/packet_player.c b/src/pc/network/packets/packet_player.c index 3876a4da8..319ba265a 100644 --- a/src/pc/network/packets/packet_player.c +++ b/src/pc/network/packets/packet_player.c @@ -10,7 +10,7 @@ void network_send_player(void) { : NULL; struct Packet p; - packet_init(&p, PACKET_PLAYER); + packet_init(&p, PACKET_PLAYER, false); packet_write(&p, &gMarioStates[0], 96); packet_write(&p, gMarioStates[0].controller, 20); packet_write(&p, gMarioStates[0].marioObj->rawData.asU32, 320); diff --git a/src/pc/network/packets/packet_read_write.c b/src/pc/network/packets/packet_read_write.c index c42e767e1..878412be8 100644 --- a/src/pc/network/packets/packet_read_write.c +++ b/src/pc/network/packets/packet_read_write.c @@ -1,10 +1,19 @@ #include "../network.h" -void packet_init(struct Packet* packet, enum PacketType packetType) { +static u16 nextSeqNum = 1; +void packet_init(struct Packet* packet, enum PacketType packetType, bool reliable) { memset(packet->buffer, 0, PACKET_LENGTH); packet->buffer[0] = (char)packetType; - packet->cursor = 1; + if (reliable) { + memcpy(&packet->buffer[1], &nextSeqNum, 2); + packet->seqId = nextSeqNum; + nextSeqNum++; + if (nextSeqNum == 0) { nextSeqNum++; } + } + packet->cursor = 3; packet->error = false; + packet->reliable = reliable; + packet->sent = false; } void packet_write(struct Packet* packet, void* data, int length) { diff --git a/src/pc/network/packets/packet_reliable.c b/src/pc/network/packets/packet_reliable.c new file mode 100644 index 000000000..893bc4bdc --- /dev/null +++ b/src/pc/network/packets/packet_reliable.c @@ -0,0 +1,97 @@ +#include +#include "../network.h" + +#define RELIABLE_RESEND_RATE 0.10f + +struct PacketLinkedList { + struct Packet p; + clock_t lastSend; + struct PacketLinkedList* prev; + struct PacketLinkedList* next; +}; + +struct PacketLinkedList* head = NULL; +struct PacketLinkedList* tail = NULL; + +static void remove_node_from_list(struct PacketLinkedList* node) { + if (node == head) { + head = node->next; + if (head != NULL) { head->prev = NULL; } + } + if (node == tail) { + tail = node->prev; + if (tail != NULL) { tail->next = NULL; } + } + + if (node->prev != NULL) { node->prev->next = node->next; } + if (node->next != NULL) { node->next->prev = node->prev; } + free(node); +} + +void network_send_ack(struct Packet* p) { + // grab seq num + u16 seqId = 0; + memcpy(&seqId, &p->buffer[1], 2); + if (seqId == 0) { return; } + + // send back the ACK + struct Packet ack = { 0 }; + packet_init(&ack, PACKET_ACK, false); + packet_write(&ack, &seqId, 2); + network_send(&ack); +} + +void network_receive_ack(struct Packet* p) { + // grab seq num + u16 seqId = 0; + packet_read(p, &seqId, 2); + + // find in list and remove + struct PacketLinkedList* node = head; + while (node != NULL) { + if (node->p.seqId == seqId) { + remove_node_from_list(node); + break; + } + node = node->next; + } +} + +void network_remember_reliable(struct Packet* p) { + if (!p->reliable) { return; } + if (p->sent) { return; } + + struct PacketLinkedList* node = malloc(sizeof(struct PacketLinkedList)); + node->p = *p; + node->p.sent = true; + node->lastSend = clock(); + node->prev = NULL; + node->next = NULL; + + if (tail == NULL) { + // start of the list + assert(head == NULL); + head = node; + tail = node; + return; + } + + // add to end of list + assert(tail->next == NULL); + tail->next = node; + node->prev = tail; + tail = node; +} + +void network_update_reliable(void) { + struct PacketLinkedList* node = head; + while (node != NULL) { + float elapsed = (clock() - node->lastSend) / CLOCKS_PER_SEC; + if (elapsed > RELIABLE_RESEND_RATE) { + // resend + network_send(&node->p); + node->lastSend = clock(); + } + node = node->next; + } +} \ No newline at end of file