From d2c0ab7a62b7a2c99c4c491ce55466859429571b Mon Sep 17 00:00:00 2001 From: rodri Date: Fri, 5 May 2023 22:35:14 +0000 Subject: handle player quits gracefully. also fixed a bug whereby a player would never be freed if no party was happening, and another one where deleting a player from the player queue would cause a nil pointer deref. --- dat.h | 4 +++- musw.c | 35 +++++++++++++++++++++++++++++++++++ muswd.c | 19 +++++++++++++++---- party.c | 2 +- vmodeled/vmodeled.man | 4 +--- 5 files changed, 55 insertions(+), 9 deletions(-) diff --git a/dat.h b/dat.h index 3e8e703..88f7a64 100644 --- a/dat.h +++ b/dat.h @@ -32,11 +32,13 @@ enum { NShi, /* S accepts. sends P and G for DHX */ NCdhx = 12, /* C shares pubkey */ NSdhx, /* S shares pubkey */ - NCnudge = 16, + NCnudge = 16, /* nudge ACK */ NSnudge, /* check the pulse of the line */ NCinput = 20, /* C sends player input state */ NSsimstate, /* S sends current simulation state */ + NCawol = 22, /* AWOL ACK */ + NSawol, /* notify the adversary flew away */ NCbuhbye = 30, NSbuhbye, diff --git a/musw.c b/musw.c index 0703393..edd3826 100644 --- a/musw.c +++ b/musw.c @@ -231,6 +231,26 @@ initconn(void) netconn.state = NCSConnecting; } +void +buhbye(void) +{ + Frame *frame; + int i, naptime; + + if(netconn.state != NCSConnected) + return; + + i = 10; + naptime = 2000/i; + while(i--){ + frame = newframe(nil, NCbuhbye, netconn.lastseq+1, 0, 0, nil); + signframe(frame, netconn.dh.priv); + sendp(egress, frame); + + sleep(naptime); + } +} + void sendkeys(ulong kdown) { @@ -273,8 +293,12 @@ kbdproc(void *) } if(buf[0] == 'c'){ if(utfrune(buf, Kdel)){ +defenestrate: close(fd); threadexitsall(nil); + }else if(utfrune(buf, 'q')){ + buhbye(); + goto defenestrate; } } if(buf[0] != 'k' && buf[0] != 'K') @@ -414,6 +438,15 @@ threadnetppu(void *) sendp(egress, newf); + break; + case NSawol: + weplaying = 0; + + newf = newframe(nil, NCawol, frame->seq+1, frame->seq, 0, nil); + signframe(newf, netconn.dh.priv); + + sendp(egress, newf); + break; case NSbuhbye: weplaying = 0; @@ -607,6 +640,8 @@ State *matching_δ(State *s, void*) State *playing_δ(State *s, void*) { + if(!weplaying) + return &gamestates[GSMatching]; return s; } diff --git a/muswd.c b/muswd.c index cb0be8b..472ce39 100644 --- a/muswd.c +++ b/muswd.c @@ -47,6 +47,8 @@ dissolveparty(Player *player) { int i; Party *p; + Player *adv; + Frame *f; /* * kick the player and put their adversary back in the @@ -55,16 +57,25 @@ dissolveparty(Player *player) for(p = theparty.next; p != &theparty; p = p->next) for(i = 0; i < nelem(p->players); i++) if(p->players[i] == player){ - delplayer(p->players[i]); - players.put(&players, p->players[i^1]); + adv = p->players[i^1]; + + players.put(&players, adv); delparty(p); + + /* notify the adversary */ + f = newframe(&adv->conn->udp, NSawol, 0, 0, 0, nil); + signframe(f, adv->conn->dh.priv); + sendp(egress, f); + + return; } /* - * also clean the player queue - * TODO: has nothing to do with the party + * make sure to free the player even if there's no + * party going on. */ players.del(&players, player); + delplayer(player); } int diff --git a/party.c b/party.c index 1360875..be0f4ed 100644 --- a/party.c +++ b/party.c @@ -117,7 +117,7 @@ playerq_del(Playerq *pq, Player *p) return; } - for(np = pq->head; np->next != nil; np = np->next) + for(np = pq->head; np != nil && np->next != nil; np = np->next) if(np->next == p){ np->next = np->next->next; p->next = nil; diff --git a/vmodeled/vmodeled.man b/vmodeled/vmodeled.man index c877d32..13ad0ed 100644 --- a/vmodeled/vmodeled.man +++ b/vmodeled/vmodeled.man @@ -6,9 +6,7 @@ vmodeled \- musw vector model editor .I file .SH DESCRIPTION .I Vmodeled -is a vector model— -.B VModel -—editor created with the purpose of customizing +is a vector model (VModel) editor created with the purpose of customizing .IR musw (1) ships defined in the .B vmdl -- cgit v1.2.3