aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bts.c108
-rw-r--r--btsd.c207
-rw-r--r--dat.h39
3 files changed, 314 insertions, 40 deletions
diff --git a/bts.c b/bts.c
index b777819..4f636a6 100644
--- a/bts.c
+++ b/bts.c
@@ -13,12 +13,17 @@ int debug;
char deffont[] = "/lib/font/bit/pelm/unicode.9.font";
char winspec[32];
Channel *drawchan;
+Channel *ingress, *egress;
RFrame worldrf;
Image *screenb;
Image *tiletab[NTILES];
Board alienboard;
Board localboard;
+struct {
+ int state;
+} game;
+
Point
fromworld(Point2 p)
@@ -177,28 +182,54 @@ initboards(void)
alienboard.p = Pt2(Boardmargin,Boardmargin,1);
memset(localboard.map, Twater, MAPW*MAPH);
localboard.p = addpt2(alienboard.p, Vec2(0,MAPH*TH+TH));
- alienboard.bx = localboard.bx = Vec2(TW,0);
- alienboard.by = localboard.by = Vec2(0,TH);
+ alienboard.bx = Vec2(TW,0);
+ localboard.bx = Vec2(TW,0);
+ alienboard.by = Vec2(0,TH);
+ localboard.by = Vec2(0,TH);
alienboard.bbox = Rpt(fromworld(alienboard.p), fromworld(addpt2(alienboard.p, Pt2(TW*MAPW,TH*MAPH,1))));
localboard.bbox = Rpt(fromworld(localboard.p), fromworld(addpt2(localboard.p, Pt2(TW*MAPW,TH*MAPH,1))));
}
void
+lmb(Mousectl *mc)
+{
+ Board *b;
+ Point2 cell;
+
+ b = nil;
+ if(ptinrect(mc->xy, alienboard.bbox))
+ b = &alienboard;
+ else if(ptinrect(mc->xy, localboard.bbox))
+ b = &localboard;
+
+ if(b != nil){
+ cell = toboard(b, mc->xy);
+ switch(game.state){
+ case Outlaying:
+ settile(b, cell, Tship);
+ case Playing:
+ settile(b, cell, Tmiss);
+ chanprint(egress, "shoot %d-%d", (int)cell.x, (int)cell.y);
+ break;
+ }
+ }
+ send(drawchan, nil);
+}
+
+void
mouse(Mousectl *mc)
{
mc->xy = subpt(mc->xy, screen->r.min);
switch(mc->buttons){
case 1:
- if(ptinrect(mc->xy, alienboard.bbox))
- settile(&alienboard, toboard(&alienboard, mc->xy), Tmiss);
- if(ptinrect(mc->xy, localboard.bbox))
- settile(&localboard, toboard(&localboard, mc->xy), Tmiss);
- send(drawchan, nil);
+ lmb(mc);
break;
case 2:
+ //mmb(mc);
break;
- case 3:
+ case 4:
+ //rmb(mc);
break;
}
}
@@ -233,13 +264,15 @@ inputthread(void *arg)
in = arg;
- a[0].op = CHANRCV; a[0].c = in->mc->c; a[0].v = &in->mc->Mouse;
- a[1].op = CHANRCV; a[1].c = in->mc->resizec; a[1].v = nil;
- a[2].op = CHANRCV; a[2].c = in->kc->c; a[2].v = &r;
+ a[0].c = in->mc->c; a[0].v = &in->mc->Mouse; a[0].op = CHANRCV;
+ a[1].c = in->mc->resizec; a[1].v = nil; a[1].op = CHANRCV;
+ a[2].c = in->kc->c; a[2].v = &r; a[2].op = CHANRCV;
a[3].op = CHANEND;
for(;;)
switch(alt(a)){
+ case -1:
+ sysfatal("input thread interrupted");
case 0:
mouse(in->mc);
break;
@@ -253,6 +286,51 @@ inputthread(void *arg)
}
void
+netrecvthread(void *arg)
+{
+ Ioproc *io;
+ char buf[256];
+ int n, fd;
+
+ threadsetname("netrecvthread");
+
+ fd = *(int*)arg;
+ io = ioproc();
+
+ while((n = ioread(io, fd, buf, sizeof(buf)-1)) > 0){
+ buf[n] = 0;
+ if(debug)
+ fprint(2, "rcvd '%s'\n", buf);
+ if(strcmp(buf, "wait") == 0)
+ game.state = Waiting1;
+ else if(strcmp(buf, "play") == 0)
+ game.state = Playing;
+// chanprint(ingress, "%s", buf);
+ }
+ closeioproc(io);
+ threadexitsall("connection lost");
+}
+
+void
+netsendthread(void *arg)
+{
+ char *s;
+ int fd;
+
+ threadsetname("netsendthread");
+
+ fd = *(int*)arg;
+
+ while(recv(egress, &s) > 0){
+ if(write(fd, s, strlen(s)) != strlen(s))
+ break;
+ if(debug)
+ fprint(2, "sent '%s'\n", s);
+ }
+ threadexitsall("connection lost");
+}
+
+void
usage(void)
{
fprint(2, "usage: %s [-d] addr\n", argv0);
@@ -286,6 +364,9 @@ threadmain(int argc, char *argv[])
else if(debug)
fprint(2, "line established\n");
+ if(write(fd, "join", 4) != 4)
+ sysfatal("whoops: %r");
+
snprint(winspec, sizeof winspec, "-dx %d -dy %d", SCRW, SCRH);
if(newwindow(winspec) < 0)
sysfatal("newwindow: %r");
@@ -306,10 +387,15 @@ threadmain(int argc, char *argv[])
inittiles();
initboards();
+ game.state = Waiting0;
drawchan = chancreate(sizeof(void*), 0);
+ ingress = chancreate(sizeof(char*), 0);
+ egress = chancreate(sizeof(char*), 0);
proccreate(showproc, nil, mainstacksize);
threadcreate(inputthread, &in, mainstacksize);
+ threadcreate(netrecvthread, &fd, mainstacksize);
+ threadcreate(netsendthread, &fd, mainstacksize);
send(drawchan, nil);
yield();
}
diff --git a/btsd.c b/btsd.c
index 5d5161a..7cbd283 100644
--- a/btsd.c
+++ b/btsd.c
@@ -1,6 +1,5 @@
#include <u.h>
#include <libc.h>
-#include <bio.h>
#include <thread.h>
#include <draw.h>
#include <mouse.h>
@@ -10,44 +9,182 @@
#include "fns.h"
int debug;
+int mainstacksize = 16*KB;
+Playerq playerq;
+
+
+void
+pushplayer(Player *p)
+{
+ qlock(&playerq);
+ if(++playerq.nplayers > playerq.cap){
+ playerq.cap = playerq.nplayers;
+ playerq.players = erealloc(playerq.players, playerq.cap * sizeof p);
+ }
+ playerq.players[playerq.nplayers-1] = p;
+ qunlock(&playerq);
+}
+
+Player *
+popplayer(void)
+{
+ Player *p;
+
+ p = nil;
+ if(playerq.nplayers > 0){
+ qlock(&playerq);
+ p = playerq.players[--playerq.nplayers];
+ qunlock(&playerq);
+ }
+ return p;
+}
+
+void
+netrecvthread(void *arg)
+{
+ Chanpipe *cp;
+ Ioproc *io;
+ char buf[256];
+ int n;
+
+ cp = arg;
+ io = ioproc();
+
+ while((n = ioread(io, cp->fd, buf, sizeof(buf)-1)) > 0){
+ buf[n] = 0;
+ chanprint(cp->c, "%s", buf);
+ }
+ chanclose(cp->c);
+ if(debug)
+ fprint(2, "[%d] %d lost connection\n", threadpid(threadid()), threadid());
+}
void
serveproc(void *arg)
{
- Biobuf *bin, *bout;
- NetConnInfo *nci;
- char *line;
- int fd, linelen;
-
- fd = *(int*)arg;
- nci = getnetconninfo(nil, fd);
- if(nci == nil)
+ NetConnInfo *nci[2];
+ Player **m;
+ Chanpipe *cp;
+ Alt a[3];
+ int i, n0;
+ char *s;
+
+ threadsetname("serveproc ");
+
+ m = arg;
+ s = nil;
+
+ nci[0] = getnetconninfo(nil, m[0]->fd);
+ nci[1] = getnetconninfo(nil, m[1]->fd);
+ if(nci[0] == nil || nci[1] == nil)
sysfatal("getnetconninfo: %r");
- threadsetname("serveproc %s", nci->raddr);
- freenetconninfo(nci);
-
- bin = Bfdopen(fd, OREAD);
- bout = Bfdopen(fd, OWRITE);
- if(bin == nil || bout == nil)
- sysfatal("Bfdopen: %r");
-
- while((line = Brdline(bin, '\n')) != nil){
- linelen = Blinelen(bin);
- Bwrite(bout, line, linelen);
- Bflush(bout);
- print("%.*s", linelen, line);
+ threadsetname("serveproc %s ↔ %s", nci[0]->raddr, nci[1]->raddr);
+ freenetconninfo(nci[0]);
+ freenetconninfo(nci[1]);
+
+ cp = emalloc(2*sizeof(Chanpipe));
+ cp[0].c = chancreate(sizeof(char*), 1);
+ cp[0].fd = m[0]->fd;
+ cp[1].c = chancreate(sizeof(char*), 1);
+ cp[1].fd = m[1]->fd;
+
+ a[0].c = cp[0].c; a[0].v = &s; a[0].op = CHANRCV;
+ a[1].c = cp[1].c; a[1].v = &s; a[1].op = CHANRCV;
+ a[2].op = CHANEND;
+
+ threadcreate(netrecvthread, &cp[0], mainstacksize);
+ threadcreate(netrecvthread, &cp[1], mainstacksize);
+
+ n0 = truerand();
+ write(m[n0%2]->fd, "wait", 4);
+ write(m[(n0+1)%2]->fd, "play", 4);
+
+ while((i = alt(a)) >= 0){
+ if(debug)
+ fprint(2, "[%d] %d said '%s'\n", threadpid(threadid()), threadid(), s);
+ if(a[i].err != nil){
+ write(m[i^1]->fd, "won", 3);
+ /* TODO free the player */
+ pushplayer(m[i^1]);
+ goto out;
+ }
+ if(write(m[i^1]->fd, s, strlen(s)) != strlen(s)){
+ write(m[i]->fd, "won", 3);
+ /* TODO free the player */
+ pushplayer(m[i]);
+ goto out;
+ }
+ free(s);
+ }
+out:
+ if(debug)
+ fprint(2, "[%d] serveproc ending\n", threadpid(threadid()));
+ chanclose(cp[0].c);
+ chanclose(cp[1].c);
+ /* TODO make sure this is the last thread to exit */
+// recv(cp[0].done)
+// recv(cp[1].done)
+ free(m);
+}
+
+void
+reaper(void *)
+{
+ Ioproc *io;
+ char buf[8];
+ ulong i;
+ int n;
+
+ threadsetname("reaper");
+
+ io = ioproc();
+
+ for(;;){
+ for(i = 0; i < playerq.nplayers; i++){
+ n = read(playerq.players[i]->sfd, buf, sizeof buf);
+ if(n < 0 || strncmp(buf, "Closed", 6) == 0){
+ qlock(&playerq);
+ close(playerq.players[i]->fd);
+ close(playerq.players[i]->sfd);
+ free(playerq.players[i]);
+ memmove(&playerq.players[i], &playerq.players[i+1], (--playerq.nplayers-i)*sizeof(Player*));
+ qunlock(&playerq);
+ }
+ }
+ iosleep(io, HZ2MS(3));
}
+}
+
+void
+matchmaker(void *)
+{
+ Player **match;
+
+ threadsetname("matchmaker");
- Bterm(bin);
- Bterm(bout);
+ for(;;){
+ if(playerq.nplayers < 2){
+ sleep(100);
+ continue;
+ }
+
+ match = emalloc(2*sizeof(Player*));
+ match[0] = popplayer();
+ match[1] = popplayer();
+ match[1]->o = match[0];
+ match[0]->o = match[1];
+
+ proccreate(serveproc, match, mainstacksize);
+ }
}
void
listenthread(void *arg)
{
- char *addr, adir[40], ldir[40];
- int acfd, lcfd, dfd;
+ char *addr, adir[40], ldir[40], aux[128], *s;
+ int acfd, lcfd, dfd, sfd;
+ Player *p;
addr = arg;
@@ -57,11 +194,21 @@ listenthread(void *arg)
if(debug)
fprint(2, "listening on %s\n", addr);
-
+
while((lcfd = listen(adir, ldir)) >= 0){
if((dfd = accept(lcfd, ldir)) >= 0){
- proccreate(serveproc, &dfd, mainstacksize);
- close(dfd);
+ fd2path(dfd, aux, sizeof aux);
+ s = strrchr(aux, '/');
+ *s = 0;
+ snprint(aux, sizeof aux, "%s/status", aux);
+ sfd = open(aux, OREAD);
+ if(sfd < 0)
+ sysfatal("open: %r");
+
+ p = emalloc(sizeof *p);
+ p->fd = dfd;
+ p->sfd = sfd;
+ pushplayer(p);
}
close(lcfd);
}
@@ -94,5 +241,7 @@ threadmain(int argc, char *argv[])
usage();
threadcreate(listenthread, addr, mainstacksize);
+ proccreate(matchmaker, nil, mainstacksize);
+ proccreate(reaper, nil, mainstacksize);
yield();
}
diff --git a/dat.h b/dat.h
index b0350e1..2a2c6b5 100644
--- a/dat.h
+++ b/dat.h
@@ -5,6 +5,11 @@ enum {
Tmiss,
NTILES,
+ Waiting0 = 0,
+ Outlaying,
+ Waiting1,
+ Playing,
+
Boardmargin = 50,
TW = 16,
TH = TW,
@@ -12,10 +17,16 @@ enum {
MAPH = MAPW,
SCRW = Boardmargin+MAPW*TW+Boardmargin,
SCRH = Boardmargin+MAPH*TH+TH+MAPH*TH+Boardmargin,
+
+ KB = 1024,
};
typedef struct Input Input;
typedef struct Board Board;
+typedef struct Ship Ship;
+typedef struct Player Player;
+typedef struct Playerq Playerq;
+typedef struct Chanpipe Chanpipe;
struct Input
{
@@ -29,3 +40,31 @@ struct Board
char map[17][17];
Rectangle bbox;
};
+
+struct Ship
+{
+ RFrame;
+ int ncells;
+ int sunk;
+};
+
+struct Player
+{
+ int fd;
+ int sfd;
+ Player *o; /* opponent */
+};
+
+struct Playerq
+{
+ QLock;
+ Player **players;
+ ulong cap;
+ ulong nplayers;
+};
+
+struct Chanpipe
+{
+ Channel *c;
+ int fd;
+};