Refactored entity death sync + reliable packets

Embedded an immediate packet send whenever a synced entity is unloaded
from the game.

Added reliable packet sending.
This commit is contained in:
MysterD 2020-08-05 01:01:50 -07:00
parent 6d3a90031c
commit e61b137160
9 changed files with 159 additions and 24 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,97 @@
#include <stdio.h>
#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;
}
}