mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-10-18 19:22:41 +00:00
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:
parent
6d3a90031c
commit
e61b137160
9 changed files with 159 additions and 24 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
97
src/pc/network/packets/packet_reliable.c
Normal file
97
src/pc/network/packets/packet_reliable.c
Normal 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;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue