shithub: musw

Download patch

ref: d2c0ab7a62b7a2c99c4c491ce55466859429571b
parent: f959555dc653ecf54d75b180fcd018075e652e93
author: rodri <[email protected]>
date: Fri May 5 18:35:14 EDT 2023

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.

--- a/dat.h
+++ b/dat.h
@@ -32,11 +32,13 @@
 	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,
--- a/musw.c
+++ b/musw.c
@@ -232,6 +232,26 @@
 }
 
 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)
 {
 	Frame *frame;
@@ -273,8 +293,12 @@
 		}
 		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')
@@ -415,6 +439,15 @@
 				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;
 				netconn.state = NCSDisconnected;
@@ -607,6 +640,8 @@
 
 State *playing_δ(State *s, void*)
 {
+	if(!weplaying)
+		return &gamestates[GSMatching];
 	return s;
 }
 
--- a/muswd.c
+++ b/muswd.c
@@ -47,6 +47,8 @@
 {
 	int i;
 	Party *p;
+	Player *adv;
+	Frame *f;
 
 	/*
 	 * kick the player and put their adversary back in the
@@ -55,16 +57,25 @@
 	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
--- a/party.c
+++ b/party.c
@@ -117,7 +117,7 @@
 		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;
--- a/vmodeled/vmodeled.man
+++ b/vmodeled/vmodeled.man
@@ -6,9 +6,7 @@
 .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