From 5845dc7e350419dd36c6b1b4b938d23dd29e2e77 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sun, 18 Mar 2007 05:07:10 +0000 Subject: [PATCH] routing is more obvious / usable now (beware some 'cmd cmd new's are required). reworked the menus (could be a little better). added qqshka's invisible player fix. de-spammified the centerprint menus. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2483 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- fteqtv/forward.c | 55 +- fteqtv/parse.c | 71 ++- fteqtv/qtv.h | 43 +- fteqtv/qw.c | 1458 +++++++++++++++++++++++++++------------------- fteqtv/source.c | 8 +- 5 files changed, 1003 insertions(+), 632 deletions(-) diff --git a/fteqtv/forward.c b/fteqtv/forward.c index 95189521e..d6f671408 100644 --- a/fteqtv/forward.c +++ b/fteqtv/forward.c @@ -260,6 +260,56 @@ void Prox_SendPlayerStats(sv_t *qtv, oproxy_t *prox) } } +void Prox_SendInitialPlayers(sv_t *qtv, oproxy_t *prox, netmsg_t *msg) +{ + int i, j, flags; + char buffer[64]; + + for (i = 0; i < MAX_CLIENTS; i++) + { + if (!qtv->players[i].active) // interesting, is this set to false if player disconnect from server? + continue; + + flags = (DF_ORIGIN << 0) | (DF_ORIGIN << 1) | (DF_ORIGIN << 2) + | (DF_ANGLES << 0) | (DF_ANGLES << 1) | (DF_ANGLES << 2) // angles is something what changed frequently, so may be not send it? + | DF_EFFECTS + | DF_SKINNUM // though it rare thingie, so better send it? + | (qtv->players[i].dead ? DF_DEAD : 0) + | (qtv->players[i].gibbed ? DF_GIB : 0) + | DF_WEAPONFRAME // do we so really need it? + | DF_MODEL; // generally, that why we wrote this function, so YES send this + + if (*qtv->players[i].userinfo && atoi(Info_ValueForKey(qtv->players[i].userinfo, "*spectator", buffer, sizeof(buffer)))) + flags = DF_MODEL; // oh, that spec, just sent his model, may be even better ignore him? + + WriteByte (msg, svc_playerinfo); + WriteByte (msg, i); + WriteShort (msg, flags); + + WriteByte (msg, qtv->players[i].current.frame); // always sent + + for (j = 0 ; j < 3 ; j++) + if (flags & (DF_ORIGIN << j)) + WriteShort (msg, qtv->players[i].current.origin[j]); + + for (j = 0 ; j < 3 ; j++) + if (flags & (DF_ANGLES << j)) + WriteShort (msg, qtv->players[i].current.angles[j]); + + if (flags & DF_MODEL) // generally, that why we wrote this function, so YES send this + WriteByte (msg, qtv->players[i].current.modelindex); + + if (flags & DF_SKINNUM) + WriteByte (msg, qtv->players[i].current.skinnum); + + if (flags & DF_EFFECTS) + WriteByte (msg, qtv->players[i].current.effects); + + if (flags & DF_WEAPONFRAME) + WriteByte (msg, qtv->players[i].current.weaponframe); + } +} + void Net_SendConnectionMVD(sv_t *qtv, oproxy_t *prox) { char buffer[MAX_MSGLEN*8]; @@ -301,7 +351,10 @@ void Net_SendConnectionMVD(sv_t *qtv, oproxy_t *prox) msg.cursize = 0; } - //playerstates arn't actually delta-compressed, so the first send (simply forwarded from server) entirly replaces the old. + //playerstates are delta-compressed, unfortunatly this isn't qwd (thanks to qqshka for showing my folly) + Prox_SendInitialPlayers(qtv, prox, &msg); + Prox_SendMessage(qtv->cluster, prox, msg.data, msg.cursize, dem_read, (unsigned)-1); + msg.cursize = 0; //we do need to send entity states. Prox_SendInitialEnts(qtv, prox, &msg); diff --git a/fteqtv/parse.c b/fteqtv/parse.c index 772ce9b86..dca8415ee 100644 --- a/fteqtv/parse.c +++ b/fteqtv/parse.c @@ -163,15 +163,6 @@ void WriteData(netmsg_t *b, const char *data, int length) b->cursize+=length; } -#define DF_ORIGIN 1 -#define DF_ANGLES (1<<3) -#define DF_EFFECTS (1<<6) -#define DF_SKINNUM (1<<7) -#define DF_DEAD (1<<8) -#define DF_GIB (1<<9) -#define DF_WEAPONFRAME (1<<10) -#define DF_MODEL (1<<11) - void SendBufferToViewer(viewer_t *v, const char *buffer, int length, qboolean reliable) { if (reliable) @@ -182,7 +173,13 @@ void SendBufferToViewer(viewer_t *v, const char *buffer, int length, qboolean re else if (v->backbuffered>0 && v->backbuf[v->backbuffered-1].cursize+length < v->backbuf[v->backbuffered-1].maxsize) //try and put it in the current backbuffer WriteData(&v->backbuf[v->backbuffered-1], buffer, length); else if (v->backbuffered == MAX_BACK_BUFFERS) + { + v->netchan.message.cursize = 0; + WriteByte(&v->netchan.message, svc_print); + WriteString(&v->netchan.message, "backbuffer overflow\n"); + Sys_Printf(NULL, "%s backbuffers overflowed\n", v->name); //FIXME v->drop = true; //we would need too many backbuffers. + } else { //create a new backbuffer @@ -225,7 +222,7 @@ void Multicast(sv_t *tv, char *buffer, int length, int to, unsigned int playerma if (v->thinksitsconnected||suitablefor&CONNECTING) if (v->server == tv) if (suitablefor&(v->netchan.isnqprotocol?NQ:QW)) - SendBufferToViewer(v, buffer, length, true); //FIXME: change the reliable depending on message type + SendBufferToViewer(v, buffer, length, true); //FIXME: change the reliable depending on message type } break; } @@ -341,8 +338,20 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask) ReadString(m, text, sizeof(text)); // Sys_Printf(tv->cluster, "stuffcmd: %s", text); - if (strstr(text, "screenshot")) - return; + if (!strcmp(text, "say proxy:menu\n")) + { //qizmo's 'previous proxy' message + tv->proxyisselected = true; + if (tv->controller) + QW_SetMenu(tv->controller, MENU_MAIN); + tv->serverisproxy = true; //FIXME: Detect this properly on qizmo + } + else if (!strncmp(text, "//set prox_inmenu ", 18)) + { + if (tv->controller) + QW_SetMenu(tv->controller, atoi(text+18)?MENU_FORWARDING:MENU_NONE); + } + else if (strstr(text, "screenshot")) + return; //this was generating far too many screenshots when watching demos else if (!strcmp(text, "skins\n")) { const char newcmd[10] = {svc_stufftext, 'c', 'm', 'd', ' ', 'n','e','w','\n','\0'}; @@ -371,12 +380,14 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask) //copy over the server's serverinfo strncpy(tv->serverinfo, text+16, sizeof(tv->serverinfo)-1); - Info_ValueForKey(tv->serverinfo, "*qtv", value, sizeof(value)); + Info_ValueForKey(tv->serverinfo, "*QTV", value, sizeof(value)); if (*value) fromproxy = true; else fromproxy = false; + tv->serverisproxy = fromproxy; + //add on our extra infos Info_SetValueForStarKey(tv->serverinfo, "*qtv", VERSION, sizeof(tv->serverinfo)); Info_SetValueForStarKey(tv->serverinfo, "*z_ext", Z_EXT_STRING, sizeof(tv->serverinfo)); @@ -512,10 +523,42 @@ static void ParsePrint(sv_t *tv, netmsg_t *m, int to, unsigned int mask) } static void ParseCenterprint(sv_t *tv, netmsg_t *m, int to, unsigned int mask) { + viewer_t *v; char text[1024]; ReadString(m, text, sizeof(text)); - Multicast(tv, m->data+m->startpos, m->readpos - m->startpos, to, mask, Q1); + + + + switch(to) + { + case dem_multiple: + case dem_single: + case dem_stats: + //check and send to them only if they're tracking this player(s). + for (v = tv->cluster->viewers; v; v = v->next) + { + if (!v->menunum || v->menunum == MENU_FORWARDING) + if (v->thinksitsconnected) + if (v->server == tv) + if (v->trackplayer>=0) + if ((1<trackplayer)&mask) + { + SendBufferToViewer(v, m->data+m->startpos, m->readpos - m->startpos, true); //FIXME: change the reliable depending on message type + } + } + break; + default: + //send to all + for (v = tv->cluster->viewers; v; v = v->next) + { + if (!v->menunum || v->menunum == MENU_FORWARDING) + if (v->thinksitsconnected) + if (v->server == tv) + SendBufferToViewer(v, m->data+m->startpos, m->readpos - m->startpos, true); //FIXME: change the reliable depending on message type + } + break; + } } static int ParseList(sv_t *tv, netmsg_t *m, filename_t *list, int to, unsigned int mask) { diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index 69787859c..8843abbb9 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -406,6 +406,7 @@ typedef struct viewer_s { qboolean chokeme; qboolean thinksitsconnected; qboolean conmenussupported; + qboolean isproxy; int delta_frame; int servercount; @@ -440,6 +441,7 @@ typedef struct viewer_s { sv_t *server; + int menuspamtime; int menunum; int menuop; int fwdval; //for scrolling up/down the menu using +forward/+back :) @@ -512,6 +514,11 @@ struct sv_s { //details about a server connection (also known as stream) netchan_t netchan; qboolean serverquery; + //proxy chaining + qboolean serverisproxy; + qboolean proxyisselected; + // + unsigned char buffer[MAX_PROXY_BUFFER]; //this doesn't cycle. int buffersize; //it memmoves down int forwardpoint; //the point in the stream that we're forwarded up to. @@ -673,13 +680,30 @@ struct cluster_s { }; #define MENU_NONE 0 -#define MENU_SERVERS 1 -#define MENU_ADMIN 2 -#define MENU_ADMINSERVER 3 -#define MENU_DEMOS 4 -#define MENU_MAIN MENU_SERVERS +#define MENU_MAIN 1//MENU_SERVERS +#define MENU_SERVERS 2 +#define MENU_CLIENTS 3 +#define MENU_ADMIN 4 +#define MENU_ADMINSERVER 5 +#define MENU_DEMOS 6 +#define MENU_FORWARDING 7 + +#define MENU_DEFAULT MENU_MAIN +enum { + MENU_MAIN_STREAMS, + MENU_MAIN_NEWSTREAM, + MENU_MAIN_FIXME, + MENU_MAIN_PREVPROX, + + MENU_MAIN_CLIENTLIST, + MENU_MAIN_DEMOS, + MENU_MAIN_ADMIN, + MENU_MAIN_NEXTPROX, + + MENU_MAIN_ITEMCOUNT +}; @@ -840,6 +864,15 @@ unsigned int BigLong(unsigned int val); #define PF_DEAD (1<<9) // don't block movement any more #define PF_GIB (1<<10) // offset the view height differently +//flags on players in mvds +#define DF_ORIGIN 1 +#define DF_ANGLES (1<<3) +#define DF_EFFECTS (1<<6) +#define DF_SKINNUM (1<<7) +#define DF_DEAD (1<<8) +#define DF_GIB (1<<9) +#define DF_WEAPONFRAME (1<<10) +#define DF_MODEL (1<<11) //flags for where a message can be sent, for easy broadcasting diff --git a/fteqtv/qw.c b/fteqtv/qw.c index 1d60be205..bcc5f53db 100644 --- a/fteqtv/qw.c +++ b/fteqtv/qw.c @@ -20,6 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "qtv.h" +#define CENTERTIME 1.5 + static const filename_t ConnectionlessModelList[] = {{""}, {"maps/start.bsp"}, {"progs/player.mdl"}, {""}}; static const filename_t ConnectionlessSoundList[] = {{""}, {""}}; @@ -754,6 +756,16 @@ void ParseUserInfo(cluster_t *cluster, viewer_t *viewer) char buf[1024]; float rate; char temp[64]; + + viewer->isproxy = false; + + Info_ValueForKey(viewer->userinfo, "*qtv", temp, sizeof(temp)); + if (*temp) + viewer->isproxy = true; + Info_ValueForKey(viewer->userinfo, "Qizmo", temp, sizeof(temp)); + if (*temp) + viewer->isproxy = true; + Info_ValueForKey(viewer->userinfo, "name", temp, sizeof(temp)); if (!*temp) @@ -939,42 +951,66 @@ void QW_SetMenu(viewer_t *v, int menunum) { if ((v->menunum==MENU_NONE) != (menunum==MENU_NONE)) { - if (menunum != MENU_NONE) + if (v->isproxy) { - QW_StuffcmdToViewer(v, "//set prox_inmenu 1\n"); - - QW_StuffcmdToViewer(v, "alias \"+proxfwd\" \"proxy:up\"\n"); - QW_StuffcmdToViewer(v, "alias \"+proxback\" \"proxy:down\"\n"); - QW_StuffcmdToViewer(v, "alias \"+proxleft\" \"proxy:left\"\n"); - QW_StuffcmdToViewer(v, "alias \"+proxright\" \"proxy:right\"\n"); - - QW_StuffcmdToViewer(v, "alias \"-proxfwd\" \" \"\n"); - QW_StuffcmdToViewer(v, "alias \"-proxback\" \" \"\n"); - QW_StuffcmdToViewer(v, "alias \"-proxleft\" \" \"\n"); - QW_StuffcmdToViewer(v, "alias \"-proxright\" \" \"\n"); + if (menunum != MENU_NONE) + QW_StuffcmdToViewer(v, "//set prox_inmenu 1\n"); + else + QW_StuffcmdToViewer(v, "//set prox_inmenu 0\n"); } else { - QW_StuffcmdToViewer(v, "//set prox_inmenu 0\n"); + if (menunum != MENU_NONE) + { + QW_StuffcmdToViewer(v, "//set prox_inmenu 1\n"); - QW_StuffcmdToViewer(v, "alias \"+proxfwd\" \"+forward\"\n"); - QW_StuffcmdToViewer(v, "alias \"+proxback\" \"+back\"\n"); - QW_StuffcmdToViewer(v, "alias \"+proxleft\" \"+moveleft\"\n"); - QW_StuffcmdToViewer(v, "alias \"+proxright\" \"+moveright\"\n"); + QW_StuffcmdToViewer(v, "alias \"+proxjump\" \"say proxy:menu enter\"\n"); + QW_StuffcmdToViewer(v, "alias \"+proxfwd\" \"say proxy:menu up\"\n"); + QW_StuffcmdToViewer(v, "alias \"+proxback\" \"say proxy:menu down\"\n"); + QW_StuffcmdToViewer(v, "alias \"+proxleft\" \"say proxy:menu left\"\n"); + QW_StuffcmdToViewer(v, "alias \"+proxright\" \"say proxy:menu right\"\n"); - QW_StuffcmdToViewer(v, "alias \"-proxfwd\" \"-forward\"\n"); - QW_StuffcmdToViewer(v, "alias \"-proxback\" \"-back\"\n"); - QW_StuffcmdToViewer(v, "alias \"-proxleft\" \"-moveleft\"\n"); - QW_StuffcmdToViewer(v, "alias \"-proxright\" \"-moveright\"\n"); + QW_StuffcmdToViewer(v, "alias \"-proxjump\" \" \"\n"); + QW_StuffcmdToViewer(v, "alias \"-proxfwd\" \" \"\n"); + QW_StuffcmdToViewer(v, "alias \"-proxback\" \" \"\n"); + QW_StuffcmdToViewer(v, "alias \"-proxleft\" \" \"\n"); + QW_StuffcmdToViewer(v, "alias \"-proxright\" \" \"\n"); + } + else + { + QW_StuffcmdToViewer(v, "//set prox_inmenu 0\n"); + + QW_StuffcmdToViewer(v, "alias \"+proxjump\" \"+jump\"\n"); + QW_StuffcmdToViewer(v, "alias \"+proxfwd\" \"+forward\"\n"); + QW_StuffcmdToViewer(v, "alias \"+proxback\" \"+back\"\n"); + QW_StuffcmdToViewer(v, "alias \"+proxleft\" \"+moveleft\"\n"); + QW_StuffcmdToViewer(v, "alias \"+proxright\" \"+moveright\"\n"); + + QW_StuffcmdToViewer(v, "alias \"-proxjump\" \"-jump\"\n"); + QW_StuffcmdToViewer(v, "alias \"-proxfwd\" \"-forward\"\n"); + QW_StuffcmdToViewer(v, "alias \"-proxback\" \"-back\"\n"); + QW_StuffcmdToViewer(v, "alias \"-proxleft\" \"-moveleft\"\n"); + QW_StuffcmdToViewer(v, "alias \"-proxright\" \"-moveright\"\n"); + } + QW_StuffcmdToViewer(v, "-forward\n"); + QW_StuffcmdToViewer(v, "-back\n"); + QW_StuffcmdToViewer(v, "-moveleft\n"); + QW_StuffcmdToViewer(v, "-moveright\n"); } - QW_StuffcmdToViewer(v, "-forward\n"); - QW_StuffcmdToViewer(v, "-back\n"); - QW_StuffcmdToViewer(v, "-moveleft\n"); - QW_StuffcmdToViewer(v, "-moveright\n"); + } + + if (v->server && v->server->controller == v) + { + if (menunum==MENU_NONE || menunum==MENU_FORWARDING) + v->server->proxyisselected = false; + else + v->server->proxyisselected = true; } v->menunum = menunum; v->menuop = 0; + + v->menuspamtime = 0; } void QTV_Rcon(cluster_t *cluster, char *message, netadr_t *from) @@ -2273,6 +2309,587 @@ void QW_SetCommentator(cluster_t *cluster, viewer_t *v, viewer_t *commentator) v->commentator = commentator; } +void QTV_SayCommand(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *fullcommand) +{ + char command[256]; + char *args; + args = COM_ParseToken(fullcommand, command, sizeof(command), NULL); + if (!args) + args = ""; + while(*args && *args <= ' ') + args++; + + if (!strcmp(command, "help")) + { + QW_PrintfToViewer(v, "Website: http://www.fteqw.com/\n" + "Commands:\n" + ".observe qwserver:port\n" + ".qtv tcpserver:port\n" + ".demo gamedir/demoname.mvd\n" + ".disconnect\n" + ".admin\n" + ".bind\n" + ); + } + else if (!strcmp(command, "qtvinfo")) + { + char buf[256]; + netadr_t addr; + unsigned char *ip; + gethostname(buf, sizeof(buf)); //ask the operating system for the local dns name + NET_StringToAddr(buf, &addr, 0); //look that up + ip = (char*)&((struct sockaddr_in *)&addr)->sin_addr; + QW_PrintfToViewer(v, "[QuakeTV] %s | %i.%i.%i.%i\n", cluster->hostname, ip[0], ip[1], ip[2], ip[3]); + } + else if (!strcmp(command, "menu")) + { + v->menuspamtime = cluster->curtime-1; + + COM_ParseToken(args, command, sizeof(command), NULL); + if (!strcmp(command, "up")) + { + v->menuop -= 1; + } + else if (!strcmp(command, "down")) + { + v->menuop += 1; + } + else if (!strcmp(command, "enter")) + { + Menu_Enter(cluster, v, 0); + } + else if (!strcmp(command, "use")) + { + Menu_Enter(cluster, v, 0); + } + else if (!strcmp(command, "right")) + { + Menu_Enter(cluster, v, 1); + } + else if (!strcmp(command, "left")) + { + Menu_Enter(cluster, v, -1); + } + else if (!strcmp(command, "select")) + { + Menu_Enter(cluster, v, 0); + } + else if (!strcmp(command, "home")) + { + v->menuop -= 100000; + } + else if (!strcmp(command, "end")) + { + v->menuop += 100000; + } + else if (!strcmp(command, "back")) + { + QW_SetMenu(v, MENU_DEFAULT); + } + else if (!strcmp(command, "enter")) + { + if (v->menunum) + Menu_Enter(cluster, v, 0); + else + QW_SetMenu(v, MENU_SERVERS); + } + else if (!strcmp(command, "bind") || !strcmp(command, "bindstd")) + { + QW_StuffcmdToViewer(v, "bind uparrow \"say proxy:menu up\"\n"); + QW_StuffcmdToViewer(v, "bind downarrow \"say proxy:menu down\"\n"); + QW_StuffcmdToViewer(v, "bind rightarrow \"say proxy:menu right\"\n"); + QW_StuffcmdToViewer(v, "bind leftarrow \"say proxy:menu left\"\n"); + + QW_StuffcmdToViewer(v, "bind enter \"say proxy:menu select\"\n"); + + QW_StuffcmdToViewer(v, "bind home \"say proxy:menu home\"\n"); + QW_StuffcmdToViewer(v, "bind end \"say proxy:menu end\"\n"); + QW_StuffcmdToViewer(v, "bind pause \"say proxy:menu\"\n"); + QW_StuffcmdToViewer(v, "bind backspace \"say proxy:menu back\"\n"); + + QW_PrintfToViewer(v, "All keys bound not recognised\n"); + } + else if (!*command) + { + if (v->menunum) + QW_SetMenu(v, MENU_NONE); + else if (v->conmenussupported) + goto guimenu; + else + goto tuimenu; + } + else + QW_PrintfToViewer(v, "\"menu %s\" not recognised\n", command); + } + + else if (!strcmp(command, "tuimenu")) + { +tuimenu: + if (v->menunum) + QW_SetMenu(v, MENU_NONE); + else + QW_SetMenu(v, MENU_MAIN); + } + else if (!strcmp(command, "guimenu")) + { + sv_t *sv; + int y; + qboolean shownheader; + +guimenu: + + QW_SetMenu(v, MENU_NONE); + + shownheader = false; + + QW_StuffcmdToViewer(v, + + "alias menucallback\n" + "{\n" + "menuclear\n" + "if (option == \"OBSERVE\")\n" + "{\necho Spectating server $_server\nsay .observe $_server\n}\n" + "if (option == \"QTV\")\n" + "{\necho Streaming from qtv at $_server\nsay .qtv $_server\n}\n" + "if (option == \"JOIN\")\n" + "{\necho Joining game at $_server\nsay .join $_server\n}\n" + "if (option == \"ADMIN\")\n" + "{\nsay .guiadmin\n}\n" + "if (option == \"DEMOS\")\n" + "{\nsay .demos\n}\n" + "if (\"stream \" isin option)\n" + "{\necho Changing stream\nsay .$option\n}\n" + "}\n" + + "conmenu menucallback\n" + "menupic 0 4 gfx/qplaque.lmp\n" + "menupic 96 4 gfx/p_option.lmp\n" + + "menuedit 48 36 \"Óåòöåòº\" \"_server\"\n" + + "menutext 48 52 \"Demos\" DEMOS\n" + + "menutext 104 52 \"Join\" JOIN\n" + + "menutext 152 52 \"Observe\" OBSERVE\n" + + "menutext 224 52 \"QTV\" QTV\n" + + + + "menutext 48 84 \"Admin\" ADMIN\n" + + "menutext 48 92 \"Close Menu\" cancel\n" + + + + "menutext 48 116 \"Type in a server address and\"\n" + "menutext 48 124 \"click join to play in the game,\"\n" + "menutext 48 132 \"observe(udp) to watch, or qtv(tcp)\"\n" + "menutext 48 140 \"to connect to a stream or proxy.\"\n" + ); + + y = 140+16; + for (sv = cluster->servers; sv; sv = sv->next) + { + if (!shownheader) + { + shownheader = true; + QW_StuffcmdToViewer(v, "menutext 72 %i \"Áãôéöå Çáíåóº\"\n", y); + y+=8; + } + QW_StuffcmdToViewer(v, "menutext 32 %i \"%30s\" \"stream %i\"\n", y, *sv->hostname?sv->hostname:sv->server, sv->streamid); + y+=8; + } + if (!shownheader) + QW_StuffcmdToViewer(v, "menutext 72 %i \"There are no active games\"\n", y); + + } + + else if (!strcmp(command, "demos")) + { + if (v->conmenussupported) + goto guidemos; + else + goto tuidemos; + } + else if (!strcmp(command, "guidemos")) + { + int maxshowndemos; + char sizestr[7]; + int start; + int i; + +guidemos: + maxshowndemos = 12; + + if (!*args) + Cluster_BuildAvailableDemoList(cluster); + + start = atoi(args); //FIXME + QW_SetMenu(v, MENU_NONE); + + QW_StuffcmdToViewer(v, + + "alias menucallback\n" + "{\n" + "menuclear\n" + "if (option == \"PREV\")\n" + "{\nsay .demos %i\n}\n" + "if (option == \"NEXT\")\n" + "{\nsay .demos %i\n}\n" + "if (\"demo \" isin option)\n" + "{\necho Changing stream\nsay .$option\n}\n" + "}\n" + + "conmenu menucallback\n" + "menupic 0 4 gfx/qplaque.lmp\n" + "menupic 96 4 gfx/p_option.lmp\n", + start - maxshowndemos, start + maxshowndemos + ); + + if (start < 0) + start = 0; + + if (start-maxshowndemos >= 0) + QW_StuffcmdToViewer(v, "menutext 48 52 \"Prev\" \"PREV\"\n"); + if (start+maxshowndemos <= cluster->availdemoscount) + QW_StuffcmdToViewer(v, "menutext 152 52 \"Next\" \"NEXT\"\n"); + + for (i = start; i < start+maxshowndemos; i++) + { + if (i >= cluster->availdemoscount) + break; + if (cluster->availdemos[i].size < 1024) + sprintf(sizestr, "%4ib", cluster->availdemos[i].size); + else if (cluster->availdemos[i].size < 1024*1024) + sprintf(sizestr, "%4ikb", cluster->availdemos[i].size/1024); + else if (cluster->availdemos[i].size < 1024*1024*1024) + sprintf(sizestr, "%4imb", cluster->availdemos[i].size/(1024*1024)); + else// if (cluster->availdemos[i].size < 1024*1024*1024*1024) + sprintf(sizestr, "%4igb", cluster->availdemos[i].size/(1024*1024*1024)); +// else +// *sizestr = 0; + QW_StuffcmdToViewer(v, "menutext 32 %i \"%6s %-30s\" \"demo %s\"\n", (i-start)*8 + 52+16, sizestr, cluster->availdemos[i].name, cluster->availdemos[i].name); + } + } + else if (!strncmp(command, ".tuidemos", 9)) + { +tuidemos: + if (!*args) + Cluster_BuildAvailableDemoList(cluster); + + if (v->menunum == MENU_DEMOS) + QW_SetMenu(v, MENU_NONE); + else + QW_SetMenu(v, MENU_DEMOS); + } + + else if (!strcmp(command, "admin")) + { + if (v->conmenussupported) + goto guiadmin; + else + goto tuiadmin; + } + + else if (!strcmp(command, "guiadmin")) + { +guiadmin: + if (!*cluster->adminpassword) + { + QW_StuffcmdToViewer(v, + + "alias menucallback\n" + "{\n" + "menuclear\n" + "}\n" + + "conmenu menucallback\n" + "menupic 16 4 gfx/qplaque.lmp\n" + "menupic - 4 gfx/p_option.lmp\n" + + "menutext 72 48 \"No admin password is set\"\n" + "menutext 72 56 \"Admin access is prohibited\"\n" + ); + } + else if (v->isadmin) + //already an admin, so don't show admin login screen + QW_SetMenu(v, MENU_ADMIN); + else + { + QW_StuffcmdToViewer(v, + + "alias menucallback\n" + "{\n" + "menuclear\n" + "if (option == \"log\")\n" + "{\nsay $_password\n}\n" + "set _password \"\"\n" + "}\n" + + "conmenu menucallback\n" + "menupic 16 4 gfx/qplaque.lmp\n" + "menupic - 4 gfx/p_option.lmp\n" + + "menuedit 16 32 \" Password\" \"_password\"\n" + + "menutext 72 48 \"Log in QW\" log\n" + "menutext 192 48 \"Cancel\" cancel\n" + ); + + strcpy(v->expectcommand, "admin"); + } + } + + else if (!strcmp(command, "tuiadmin")) + { +tuiadmin: + if (!*cluster->adminpassword) + { + if (Netchan_IsLocal(v->netchan.remote_address)) + { + Sys_Printf(cluster, "Local player %s logs in as admin\n", v->name); + QW_SetMenu(v, MENU_ADMIN); + v->isadmin = true; + } + else + QW_PrintfToViewer(v, "There is no admin password set\nYou may not log in.\n"); + } + else if (v->isadmin) + QW_SetMenu(v, MENU_ADMIN); + else + { + strcpy(v->expectcommand, "admin"); + QW_StuffcmdToViewer(v, "echo Please enter the rcon password\nmessagemode\n"); + } + } + + else if (!strcmp(command, "reset")) + { + QW_SetCommentator(cluster, v, NULL); + QW_SetViewersServer(cluster, v, NULL); + QW_SetMenu(v, MENU_SERVERS); + } + else if (!strcmp(command, "connect") || !strcmp(command, "qw") || !strcmp(command, "observe") || !strcmp(command, "join")) + { + char buf[256]; + int isjoin = false; + + if (!strcmp(command, "join") || !strcmp(command, "connect")) + isjoin = true; + + snprintf(buf, sizeof(buf), "udp:%s", args); + qtv = QTV_NewServerConnection(cluster, buf, "", false, true, !isjoin, false); + if (qtv) + { + QW_SetMenu(v, MENU_NONE); + QW_SetViewersServer(cluster, v, qtv); + if (isjoin) + qtv->controller = v; + QW_PrintfToViewer(v, "Connected to %s\n", qtv->server); + } + else + QW_PrintfToViewer(v, "Failed to connect to server \"%s\", connection aborted\n", buf); + } + else if (!strcmp(command, "qtv")) + { + char buf[256]; + + snprintf(buf, sizeof(buf), "tcp:%s", args); + qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true, false); + if (qtv) + { + QW_SetMenu(v, MENU_NONE); + QW_SetViewersServer(cluster, v, qtv); + QW_PrintfToViewer(v, "Connected to %s\n", qtv->server); + } + else + QW_PrintfToViewer(v, "Failed to connect to server \"%s\", connection aborted\n", buf); + } + else if (!strcmp(command, "stream")) + { + int id; + id = atoi(args); + for (qtv = cluster->servers; qtv; qtv = qtv->next) + { + if (qtv->streamid == id) + { + break; + } + } + if (qtv) + { + QW_SetMenu(v, MENU_NONE); + QW_SetViewersServer(cluster, v, qtv); + QW_PrintfToViewer(v, "Watching to %s\n", qtv->server); + } + else + { + QW_PrintfToViewer(v, "Stream not recognised. Stream id is invalid or terminated.\n", args); + } + } + else if (!strcmp(command, "demo")) + { + char buf[256]; + snprintf(buf, sizeof(buf), "file:%s", args); + qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true, false); + if (qtv) + { + QW_SetMenu(v, MENU_NONE); + QW_SetViewersServer(cluster, v, qtv); + QW_PrintfToViewer(v, "Streaming from %s\n", qtv->server); + } + else + QW_PrintfToViewer(v, "Demo is not exist on proxy\n", buf); + } + else if (!strcmp(command, "disconnect")) + { + QW_SetMenu(v, MENU_SERVERS); + QW_SetViewersServer(cluster, v, NULL); + QW_PrintfToViewer(v, "Connected\n"); + } + else if (!strcmp(command, "clients")) + { + viewer_t *ov; + int skipfirst = 0; + int printable = 30; + int remaining = 0; + for (ov = cluster->viewers; ov; ov = ov->next) + { + if (skipfirst > 0) + { + skipfirst--; + } + else if (printable > 0) + { + printable--; + if (ov->server) + { + if (ov->server->controller == ov) + QW_PrintfToViewer(v, "%i: %s: *%s\n", ov->userid, ov->name, ov->server->server); + else + QW_PrintfToViewer(v, "%i: %s: %s\n", ov->userid, ov->name, ov->server->server); + } + else + QW_PrintfToViewer(v, "%i: %s: %s\n", ov->userid, ov->name, "None"); + } + else + remaining++; + } + if (remaining) + QW_PrintfToViewer(v, "%i clients not shown\n", remaining); + } + else if (!strcmp(command, "followid")) + { + int id = atoi(args); + viewer_t *cv; + + for (cv = cluster->viewers; cv; cv = cv->next) + { + if (cv->userid == id) + { + QW_SetCommentator(cluster, v, cv); + return; + } + } + QW_PrintfToViewer(v, "Couldn't find that player\n"); + QW_SetCommentator(cluster, v, NULL); + } + else if (!strcmp(command, "follow")) + { + int id = atoi(args); + viewer_t *cv; + + for (cv = cluster->viewers; cv; cv = cv->next) + { + if (!strcmp(cv->name, args)) + { + QW_SetCommentator(cluster, v, cv); + return; + } + } + if (id) + { + for (cv = cluster->viewers; cv; cv = cv->next) + { + if (cv->userid == id) + { + QW_SetCommentator(cluster, v, cv); + return; + } + } + } + QW_PrintfToViewer(v, "Couldn't find that player\n"); + QW_SetCommentator(cluster, v, NULL); + } + else if (!strcmp(command, "follow")) + { + QW_SetCommentator(cluster, v, NULL); + } + else if (!strcmp(command, "bind")) + { + QW_StuffcmdToViewer(v, "bind uparrow +proxfwd\n"); + QW_StuffcmdToViewer(v, "bind downarrow +proxback\n"); + QW_StuffcmdToViewer(v, "bind rightarrow +proxright\n"); + QW_StuffcmdToViewer(v, "bind leftarrow +proxleft\n"); + QW_PrintfToViewer(v, "Keys bound not recognised\n"); + } + else if (!strcmp(command, "bsay")) + { + char buf[1024]; + netmsg_t msg; + + viewer_t *ov; + if (cluster->notalking) + return; + + for (ov = cluster->viewers; ov; ov = ov->next) + { + InitNetMsg(&msg, buf, sizeof(buf)); + + WriteByte(&msg, svc_print); + + if (ov->netchan.isnqprotocol) + WriteByte(&msg, 1); + else + { + if (ov->conmenussupported) + { + WriteByte(&msg, 3); //PRINT_CHAT + WriteString2(&msg, "[^sBQTV^s]^s^5"); + } + else + { + WriteByte(&msg, 2); //PRINT_HIGH + WriteByte(&msg, 91+128); + WriteString2(&msg, "BQTV"); + WriteByte(&msg, 93+128); + WriteByte(&msg, 0); + + WriteByte(&msg, svc_print); + WriteByte(&msg, 3); //PRINT_CHAT + + } + } + + WriteString2(&msg, v->name); + WriteString2(&msg, ": "); +// WriteString2(&msg, "\x8d "); + WriteString2(&msg, args); + WriteString(&msg, "\n"); + + if (msg.maxsize == msg.cursize) + return; + SendBufferToViewer(ov, msg.data, msg.cursize, true); + } + } + else + { + QW_PrintfToViewer(v, "QTV Proxy command not recognised\n"); + } +} + void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean noupwards) { char buf[1024]; @@ -2381,532 +2998,76 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message, qboolean *v->expectcommand = '\0'; return; } - if (!strncmp(message, ".help", 5)) + + if (*message == '.') { - QW_PrintfToViewer(v, "Website: http://www.fteqw.com/\n" - "Commands:\n" - ".observe qwserver:port\n" - ".qtv tcpserver:port\n" - ".demo gamedir/demoname.mvd\n" - ".disconnect\n" - ".admin\n" - ".bind\n" - ); - } - - else if (!strncmp(message, ".qtvinfo", 8)) - { - netadr_t addr; - unsigned char *ip; - gethostname(buf, sizeof(buf)); - NET_StringToAddr(buf, &addr, 0); - ip = (char*)&((struct sockaddr_in *)&addr)->sin_addr; - QW_PrintfToViewer(v, "[QuakeTV] %s | %i.%i.%i.%i\n", cluster->hostname, ip[0], ip[1], ip[2], ip[3]); - } - - else if (!strncmp(message, ".menu", 5)) - { - message += 5; - - if (v->conmenussupported) - goto guimenu; - else - goto tuimenu; - } - - else if (!strncmp(message, ".tuimenu", 8)) - { - message += 8; - -tuimenu: - if (v->menunum) - QW_SetMenu(v, MENU_NONE); - else - QW_SetMenu(v, MENU_SERVERS); - } - else if (!strncmp(message, ".guimenu", 8)) - { - sv_t *sv; - int y; - qboolean shownheader; - - message += 8; - -guimenu: - - QW_SetMenu(v, MENU_NONE); - - shownheader = false; - - QW_StuffcmdToViewer(v, - - "alias menucallback\n" - "{\n" - "menuclear\n" - "if (option == \"OBSERVE\")\n" - "{\necho Spectating server $_server\nsay .observe $_server\n}\n" - "if (option == \"QTV\")\n" - "{\necho Streaming from qtv at $_server\nsay .qtv $_server\n}\n" - "if (option == \"JOIN\")\n" - "{\necho Joining game at $_server\nsay .join $_server\n}\n" - "if (option == \"ADMIN\")\n" - "{\nsay .guiadmin\n}\n" - "if (option == \"DEMOS\")\n" - "{\nsay .demos\n}\n" - "if (\"stream \" isin option)\n" - "{\necho Changing stream\nsay .$option\n}\n" - "}\n" -/* - "conmenu menucallback\n" - "menupic 16 4 gfx/qplaque.lmp\n" - "menupic - 4 gfx/p_option.lmp\n" - - "menuedit 16 32 \" Server\" \"_server\"\n" - - "menutext 72 48 \"Observe\" OBSERVE\n" - "menutext 136 48 \"QTV\" QTV\n" - "menutext 168 48 \"Cancel\" cancel\n" - "menutext 224 48 \"Join\" JOIN\n" - "menutext 264 48 \"Admin\" ADMIN\n" -*/ - "conmenu menucallback\n" - "menupic 0 4 gfx/qplaque.lmp\n" - "menupic 96 4 gfx/p_option.lmp\n" - - "menuedit 48 36 \"Óåòöåòº\" \"_server\"\n" - - "menutext 48 52 \"Demos\" DEMOS\n" - - "menutext 104 52 \"Join\" JOIN\n" - - "menutext 152 52 \"Observe\" OBSERVE\n" - - "menutext 224 52 \"QTV\" QTV\n" - - - - "menutext 48 84 \"Admin\" ADMIN\n" - - "menutext 48 92 \"Close Menu\" cancel\n" - - - - "menutext 48 116 \"Type in a server address and\"\n" - "menutext 48 124 \"click join to play in the game,\"\n" - "menutext 48 132 \"observe(udp) to watch, or qtv(tcp)\"\n" - "menutext 48 140 \"to connect to a stream or proxy.\"\n" - ); - - y = 140+16; - for (sv = cluster->servers; sv; sv = sv->next) - { - if (!shownheader) - { - shownheader = true; - QW_StuffcmdToViewer(v, "menutext 72 %i \"Áãôéöå Çáíåóº\"\n", y); - y+=8; - } - QW_StuffcmdToViewer(v, "menutext 32 %i \"%30s\" \"stream %i\"\n", y, *sv->hostname?sv->hostname:sv->server, sv->streamid); - y+=8; - } - if (!shownheader) - QW_StuffcmdToViewer(v, "menutext 72 %i \"There are no active games\"\n", y); - - } - else if (!strncmp(message, ".demos", 6)) - { - message += 6; - - if (v->conmenussupported) - goto guidemos; - else - goto tuidemos; - } - else if (!strncmp(message, ".guidemos", 9)) - { - int maxshowndemos; - char sizestr[7]; - int start; - int i; - message += 9; - -guidemos: - maxshowndemos = 12; - - if (!*message) - Cluster_BuildAvailableDemoList(cluster); - - while(*message == ' ') + if (message[1] == '.') //double it up to say it message++; - start = atoi(message); //FIXME - QW_SetMenu(v, MENU_NONE); - - QW_StuffcmdToViewer(v, - - "alias menucallback\n" - "{\n" - "menuclear\n" - "if (option == \"PREV\")\n" - "{\nsay .demos %i\n}\n" - "if (option == \"NEXT\")\n" - "{\nsay .demos %i\n}\n" - "if (\"demo \" isin option)\n" - "{\necho Changing stream\nsay .$option\n}\n" - "}\n" - - "conmenu menucallback\n" - "menupic 0 4 gfx/qplaque.lmp\n" - "menupic 96 4 gfx/p_option.lmp\n", - start - maxshowndemos, start + maxshowndemos - ); - - if (start < 0) - start = 0; - - if (start-maxshowndemos >= 0) - QW_StuffcmdToViewer(v, "menutext 48 52 \"Prev\" \"PREV\"\n"); - if (start+maxshowndemos <= cluster->availdemoscount) - QW_StuffcmdToViewer(v, "menutext 152 52 \"Next\" \"NEXT\"\n"); - - for (i = start; i < start+maxshowndemos; i++) - { - if (i >= cluster->availdemoscount) - break; - if (cluster->availdemos[i].size < 1024) - sprintf(sizestr, "%4ib", cluster->availdemos[i].size); - else if (cluster->availdemos[i].size < 1024*1024) - sprintf(sizestr, "%4ikb", cluster->availdemos[i].size/1024); - else if (cluster->availdemos[i].size < 1024*1024*1024) - sprintf(sizestr, "%4imb", cluster->availdemos[i].size/(1024*1024)); - else// if (cluster->availdemos[i].size < 1024*1024*1024*1024) - sprintf(sizestr, "%4igb", cluster->availdemos[i].size/(1024*1024*1024)); -// else -// *sizestr = 0; - QW_StuffcmdToViewer(v, "menutext 32 %i \"%6s %-30s\" \"demo %s\"\n", (i-start)*8 + 52+16, sizestr, cluster->availdemos[i].name, cluster->availdemos[i].name); - } - } - else if (!strncmp(message, ".tuidemos", 9)) - { - message += 9; -tuidemos: - if (!*message) - Cluster_BuildAvailableDemoList(cluster); - - if (v->menunum == MENU_DEMOS) - QW_SetMenu(v, MENU_NONE); - else - QW_SetMenu(v, MENU_DEMOS); - } - else if (!strncmp(message, ".guiadmin", 6)) - { - if (!*cluster->adminpassword) - { - QW_StuffcmdToViewer(v, - - "alias menucallback\n" - "{\n" - "menuclear\n" - "}\n" - - "conmenu menucallback\n" - "menupic 16 4 gfx/qplaque.lmp\n" - "menupic - 4 gfx/p_option.lmp\n" - - "menutext 72 48 \"No admin password is set\"\n" - "menutext 72 56 \"Admin access is prohibited\"\n" - ); - } - else if (v->isadmin) - //already an admin, so don't show admin login screen - QW_SetMenu(v, MENU_ADMIN); else { - QW_StuffcmdToViewer(v, - - "alias menucallback\n" - "{\n" - "menuclear\n" - "if (option == \"log\")\n" - "{\nsay $_password\n}\n" - "set _password \"\"\n" - "}\n" - - "conmenu menucallback\n" - "menupic 16 4 gfx/qplaque.lmp\n" - "menupic - 4 gfx/p_option.lmp\n" - - "menuedit 16 32 \" Password\" \"_password\"\n" - - "menutext 72 48 \"Log in QW\" log\n" - "menutext 192 48 \"Cancel\" cancel\n" - ); - - strcpy(v->expectcommand, "admin"); + //this is always execed (. is local server) + QTV_SayCommand(cluster, qtv, v, message+1); + return; } } - else if (!strncmp(message, ".reset", 6)) + else if (!strncmp(message, "proxy:", 6)) { - QW_SetCommentator(cluster, v, NULL); - QW_SetViewersServer(cluster, v, NULL); - QW_SetMenu(v, MENU_SERVERS); + //this is execed on the 'active' server + if (qtv && (qtv->controller == v && !qtv->proxyisselected)) + SendClientCommand(qtv, "say %s", message); + else + QTV_SayCommand(cluster, qtv, v, message+6); + return; } - else if (!strncmp(message, ".admin", 6)) + else if (*message == ',') { - if (!*cluster->adminpassword) + if (message[1] == ',') //double up to say it + message++; + else { - if (Netchan_IsLocal(v->netchan.remote_address)) - { - Sys_Printf(cluster, "Local player %s logs in as admin\n", v->name); - QW_SetMenu(v, MENU_ADMIN); - v->isadmin = true; - } + if (qtv && (qtv->controller == v && qtv->serverisproxy)) + SendClientCommand(qtv, "say %s", message); else - QW_PrintfToViewer(v, "There is no admin password set\nYou may not log in.\n"); - } - else if (v->isadmin) - QW_SetMenu(v, MENU_ADMIN); - else - { - strcpy(v->expectcommand, "admin"); - QW_StuffcmdToViewer(v, "echo Please enter the rcon password\nmessagemode\n"); + QTV_SayCommand(cluster, qtv, v, message+1); + return; } } - else if (!strncmp(message, ".connect ", 9) || !strncmp(message, ".qw ", 4) || !strncmp(message, ".observe ", 9)) - { - if (!strncmp(message, ".qw ", 4)) - message += 4; - else - message += 9; - snprintf(buf, sizeof(buf), "udp:%s", message); - qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true, false); - if (qtv) - { - QW_SetMenu(v, MENU_NONE); - QW_SetViewersServer(cluster, v, qtv); - QW_PrintfToViewer(v, "Connected\n", message); - } - else - QW_PrintfToViewer(v, "Failed to connect to server \"%s\", connection aborted\n", message); - } - else if (!strncmp(message, ".join ", 6)) - { - message += 6; - snprintf(buf, sizeof(buf), "udp:%s", message); - qtv = QTV_NewServerConnection(cluster, buf, "", false, true, false, false); - if (qtv) - { - QW_SetMenu(v, MENU_NONE); - QW_SetViewersServer(cluster, v, qtv); - qtv->controller = v; - QW_PrintfToViewer(v, "Connected\n", message); - } - else - QW_PrintfToViewer(v, "Failed to connect to server \"%s\", connection aborted\n", message); - } - else if (!strncmp(message, ".qtv ", 5)) - { - message += 5; - snprintf(buf, sizeof(buf), "tcp:%s", message); - qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true, false); - if (qtv) - { - QW_SetMenu(v, MENU_NONE); - QW_SetViewersServer(cluster, v, qtv); - QW_PrintfToViewer(v, "Connected\n", message); - } - else - QW_PrintfToViewer(v, "Failed to connect to server \"%s\", connection aborted\n", message); - } - else if (!strncmp(message, ".stream ", 7)) - { - int id; - message += 7; - id = atoi(message); - for (qtv = cluster->servers; qtv; qtv = qtv->next) - { - if (qtv->streamid == id) - { - break; - } - } - if (qtv) - { - QW_SetMenu(v, MENU_NONE); - QW_SetViewersServer(cluster, v, qtv); - QW_PrintfToViewer(v, "Connected\n", message); - } - else - { - QW_PrintfToViewer(v, "Stream not recognised. Stream id is invalid or terminated.\n", message); - } - } - else if (!strncmp(message, ".demo ", 6)) - { - message += 6; - snprintf(buf, sizeof(buf), "file:%s", message); - qtv = QTV_NewServerConnection(cluster, buf, "", false, true, true, false); - if (qtv) - { - QW_SetMenu(v, MENU_NONE); - QW_SetViewersServer(cluster, v, qtv); - QW_PrintfToViewer(v, "Connected\n", message); - } - else - QW_PrintfToViewer(v, "Failed to connect to server \"%s\", connection aborted\n", message); - } - else if (!strncmp(message, ".disconnect", 11)) - { - QW_SetMenu(v, MENU_SERVERS); - QW_SetViewersServer(cluster, v, NULL); - QW_PrintfToViewer(v, "Connected\n", message); - } - else if (!strncmp(message, "admin", 11)) - { - QW_StuffcmdToViewer(v, "cmd say \".admin\"\n"); - } - else if (!strncmp(message, ".clients", 8)) - { - viewer_t *ov; - int skipfirst = 0; - int printable = 30; - int remaining = 0; - for (ov = cluster->viewers; ov; ov = ov->next) - { - if (skipfirst > 0) - { - skipfirst--; - } - else if (printable > 0) - { - printable--; - if (ov->server) - { - if (ov->server->controller == ov) - QW_PrintfToViewer(v, "%i: %s: *%s\n", ov->userid, ov->name, ov->server->server); - else - QW_PrintfToViewer(v, "%i: %s: %s\n", ov->userid, ov->name, ov->server->server); - } - else - QW_PrintfToViewer(v, "%i: %s: %s\n", ov->userid, ov->name, "None"); - } - else - remaining++; - } - if (remaining) - QW_PrintfToViewer(v, "%i clients not shown\n", remaining); - } - else if (!strncmp(message, ".followid ", 10)) - { - int id = atoi(message+10); - viewer_t *cv; - for (cv = cluster->viewers; cv; cv = cv->next) + + + if (!strncmp(message, ".", 1)) + message++; + *v->expectcommand = '\0'; + + if (qtv && qtv->usequkeworldprotocols && !noupwards) + { + if (qtv->controller == v || !*v->name) { - if (cv->userid == id) - { - QW_SetCommentator(cluster, v, cv); + SendClientCommand(qtv, "say %s", message); + + if (cluster->notalking) return; - } } - QW_PrintfToViewer(v, "Couldn't find that player\n"); - QW_SetCommentator(cluster, v, NULL); - } - else if (!strncmp(message, ".follow ", 8)) - { - char *id = message+8; - viewer_t *cv; - - for (cv = cluster->viewers; cv; cv = cv->next) - { - if (!strcmp(cv->name, id)) - { - QW_SetCommentator(cluster, v, cv); - return; - } - } - QW_PrintfToViewer(v, "Couldn't find that player\n"); - QW_SetCommentator(cluster, v, NULL); - } - else if (!strncmp(message, ".follow", 7)) - { - QW_SetCommentator(cluster, v, NULL); - } - else if (!strncmp(message, "proxy:menu up", 13)) - { - v->menuop -= 1; - } - else if (!strncmp(message, "proxy:menu down", 15)) - { - v->menuop += 1; - } - else if (!strncmp(message, "proxy:menu enter", 16)) - { - Menu_Enter(cluster, v, 1); - } - else if (!strncmp(message, "proxy:menu right", 16)) - { - Menu_Enter(cluster, v, 1); - } - else if (!strncmp(message, "proxy:menu left", 15)) - { - Menu_Enter(cluster, v, -1); - } - else if (!strncmp(message, "proxy:menu select", 17)) - { - Menu_Enter(cluster, v, 0); - } - else if (!strncmp(message, "proxy:menu home", 15)) - { - v->menuop -= 100000; - } - else if (!strncmp(message, "proxy:menu end", 14)) - { - v->menuop += 100000; - } - else if (!strncmp(message, "proxy:menu back", 15)) - { - } - else if (!strncmp(message, "proxy:menu", 10)) - { - if (v->menunum) - Menu_Enter(cluster, v, 0); else - QW_SetMenu(v, MENU_SERVERS); - } - else if (!strncmp(message, ".bind", 5)) - { - QW_StuffcmdToViewer(v, "bind uparrow +proxfwd\n"); - QW_StuffcmdToViewer(v, "bind downarrow +proxback\n"); - QW_StuffcmdToViewer(v, "bind rightarrow +proxright\n"); - QW_StuffcmdToViewer(v, "bind leftarrow +proxleft\n"); - QW_PrintfToViewer(v, "Keys bound not recognised\n"); - } - else if (!strncmp(message, ".menu bind", 10) || !strncmp(message, "proxy:menu bindstd", 18)) - { - QW_StuffcmdToViewer(v, "bind uparrow \"proxy:menu up\"\n"); - QW_StuffcmdToViewer(v, "bind downarrow \"proxy:menu down\"\n"); - QW_StuffcmdToViewer(v, "bind rightarrow \"proxy:menu right\"\n"); - QW_StuffcmdToViewer(v, "bind leftarrow \"proxy:menu left\"\n"); + { + if (cluster->notalking) + return; + SendClientCommand(qtv, "say [%s]: %s", v->name, message); + } - QW_StuffcmdToViewer(v, "bind enter \"proxy:menu select\"\n"); - - QW_StuffcmdToViewer(v, "bind home \"proxy:menu home\"\n"); - QW_StuffcmdToViewer(v, "bind end \"proxy:menu end\"\n"); - QW_StuffcmdToViewer(v, "bind pause \"proxy:menu\"\n"); - QW_StuffcmdToViewer(v, "bind backspace \"proxy:menu back\"\n"); - - QW_PrintfToViewer(v, "All keys bound not recognised\n"); + //FIXME: we ought to broadcast this to everyone not watching that qtv. } - else if (!strncmp(message, ".bsay ", 6)) + else { viewer_t *ov; if (cluster->notalking) return; - message += 6; - for (ov = cluster->viewers; ov; ov = ov->next) { + if (ov->server != v->server) + continue; + InitNetMsg(&msg, buf, sizeof(buf)); WriteByte(&msg, svc_print); @@ -2918,13 +3079,13 @@ tuidemos: if (ov->conmenussupported) { WriteByte(&msg, 3); //PRINT_CHAT - WriteString2(&msg, "[^sBQTV^s]^s^5"); + WriteString2(&msg, "[^sQTV^s]^s^5"); } else { WriteByte(&msg, 2); //PRINT_HIGH WriteByte(&msg, 91+128); - WriteString2(&msg, "BQTV"); + WriteString2(&msg, "QTV"); WriteByte(&msg, 93+128); WriteByte(&msg, 0); @@ -2936,89 +3097,13 @@ tuidemos: WriteString2(&msg, v->name); WriteString2(&msg, ": "); -// WriteString2(&msg, "\x8d "); +// WriteString2(&msg, "\x8d "); WriteString2(&msg, message); WriteString(&msg, "\n"); SendBufferToViewer(ov, msg.data, msg.cursize, true); } } - else if (!strncmp(message, ".", 1) && strncmp(message, "..", 2)) - { - QW_PrintfToViewer(v, "Proxy command not recognised\n"); - } - else - { - if (!strncmp(message, ".", 1)) - message++; - *v->expectcommand = '\0'; - - if (qtv && qtv->usequkeworldprotocols && !noupwards) - { - if (qtv->controller == v || !*v->name) - { - SendClientCommand(qtv, "say %s\n", message); - - if (cluster->notalking) - return; - } - else - { - if (cluster->notalking) - return; - SendClientCommand(qtv, "say [%s]: %s\n", v->name, message); - } - - //FIXME: we ought to broadcast this to everyone not watching that qtv. - } - else - { - viewer_t *ov; - if (cluster->notalking) - return; - - for (ov = cluster->viewers; ov; ov = ov->next) - { - if (ov->server != v->server) - continue; - - InitNetMsg(&msg, buf, sizeof(buf)); - - WriteByte(&msg, svc_print); - - if (ov->netchan.isnqprotocol) - WriteByte(&msg, 1); - else - { - if (ov->conmenussupported) - { - WriteByte(&msg, 3); //PRINT_CHAT - WriteString2(&msg, "[^sQTV^s]^s^5"); - } - else - { - WriteByte(&msg, 2); //PRINT_HIGH - WriteByte(&msg, 91+128); - WriteString2(&msg, "QTV"); - WriteByte(&msg, 93+128); - WriteByte(&msg, 0); - - WriteByte(&msg, svc_print); - WriteByte(&msg, 3); //PRINT_CHAT - - } - } - - WriteString2(&msg, v->name); - WriteString2(&msg, ": "); -// WriteString2(&msg, "\x8d "); - WriteString2(&msg, message); - WriteString(&msg, "\n"); - - SendBufferToViewer(ov, msg.data, msg.cursize, true); - } - } - } } viewer_t *QW_IsOn(cluster_t *cluster, char *name) @@ -3284,7 +3369,7 @@ void ParseNQC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) if ((v->ucmds[1].buttons&2) != (v->ucmds[2].buttons&2) && (v->ucmds[2].buttons&2)) { if (!v->server && !v->menunum) - QW_SetMenu(v, MENU_MAIN); + QW_SetMenu(v, MENU_DEFAULT); if(v->server) { @@ -3361,7 +3446,12 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) ReadString (m, buf, sizeof(buf)); // printf("stringcmd: %s\n", buf); - if (!strcmp(buf, "new")) + if (!strncmp(buf, "cmd ", 4)) + { + if (v->server && v->server->controller == v) + SendClientCommand(v->server, "%s", buf+4); + } + else if (!strcmp(buf, "new")) { if (qtv && qtv->parsingconnectiondata) QW_StuffcmdToViewer(v, "cmd new\n"); @@ -3613,7 +3703,7 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) else if (!qtv) { //all the other things need an active server. - QW_PrintfToViewer(v, "Choose a server first\n"); + QW_PrintfToViewer(v, "Choose a server first DEBUG:(%s)\n", buf); } else if (!strncmp(buf, "serverinfo", 5)) { @@ -3677,7 +3767,7 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m) if (v->ucmds[0].buttons & 2) { if (!v->server && !v->menunum) - QW_SetMenu(v, MENU_MAIN); + QW_SetMenu(v, MENU_DEFAULT); } break; case clc_tmove: @@ -3711,6 +3801,65 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum) default: break; + case MENU_MAIN: + if (buttonnum < 0) + viewer->menuop -= MENU_MAIN_ITEMCOUNT/2; + else if (buttonnum > 0) + viewer->menuop += MENU_MAIN_ITEMCOUNT/2; + else if (buttonnum == 0) + { + switch(viewer->menuop) + { + case MENU_MAIN_STREAMS: //Streams + QW_SetMenu(viewer, MENU_SERVERS); + break; + case MENU_MAIN_CLIENTLIST://Client List + QW_SetMenu(viewer, MENU_CLIENTS); + break; + + case MENU_MAIN_NEWSTREAM://New Stream + QW_PrintfToViewer(viewer, "Not implemented yet\n"); + break; + case MENU_MAIN_DEMOS://Demos + Cluster_BuildAvailableDemoList(cluster); + QW_SetMenu(viewer, MENU_DEMOS); + break; + + case MENU_MAIN_FIXME://FIXME + QW_PrintfToViewer(viewer, "Not implemented yet\n"); + break; + case MENU_MAIN_ADMIN://Admin + QW_SetMenu(viewer, MENU_ADMIN); + break; + + case MENU_MAIN_PREVPROX://Previous Proxy + if (viewer->isproxy) + { + QW_SetMenu(viewer, MENU_NONE); + QW_StuffcmdToViewer(viewer, "say proxy:menu\n"); + } + else + QW_PrintfToViewer(viewer, "No client proxy detected\n"); + break; + case MENU_MAIN_NEXTPROX://Next Proxy + if (viewer->server && viewer->server->serverisproxy && viewer->server->controller == viewer) + { + viewer->server->proxyisselected = false; + QW_SetMenu(viewer, MENU_NONE); + SendClientCommand(viewer->server, "say .menu"); + } + else + QW_PrintfToViewer(viewer, "No server proxy detected\n"); + break; + } + } + break; + + case MENU_CLIENTS: + { + } + break; + case MENU_DEMOS: if (buttonnum >= 0) QW_StuffcmdToViewer(viewer, "say .demo %s\n", cluster->availdemos[viewer->menuop].name); @@ -3842,11 +3991,26 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum) QW_SetMenu(viewer, MENU_NONE); } - break; } } +void WriteStringSelection(netmsg_t *b, qboolean selected, const char *str) +{ + if (selected) + { + WriteByte(b, 13); + while(*str) + WriteByte(b, 128|*str++); + } + else + { + WriteByte(b, ' '); + while(*str) + WriteByte(b, *str++); + } +} + void Menu_Draw(cluster_t *cluster, viewer_t *viewer) { char buffer[2048]; @@ -3860,6 +4024,13 @@ void Menu_Draw(cluster_t *cluster, viewer_t *viewer) if (viewer->backbuffered) return; + if (viewer->menunum == MENU_FORWARDING) + return; + + if (viewer->menuspamtime > cluster->curtime && viewer->menuspamtime < cluster->curtime + CENTERTIME*2000) + return; + viewer->menuspamtime = cluster->curtime + CENTERTIME*1000; + InitNetMsg(&m, buffer, sizeof(buffer)); WriteByte(&m, svc_centerprint); @@ -3875,6 +4046,76 @@ void Menu_Draw(cluster_t *cluster, viewer_t *viewer) WriteString2(&m, "bad menu"); break; + case MENU_MAIN: + { + int o = 8; + WriteString2(&m, "\n\x1d\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1f\n"); + while (viewer->menuop < 0) + viewer->menuop += MENU_MAIN_ITEMCOUNT; + while (viewer->menuop >= MENU_MAIN_ITEMCOUNT) + viewer->menuop -= MENU_MAIN_ITEMCOUNT; + i = viewer->menuop; + + WriteStringSelection(&m, i==MENU_MAIN_STREAMS, "Streams "); + WriteStringSelection(&m, i==MENU_MAIN_CLIENTLIST, "Client List "); + WriteByte(&m, '\n'); + WriteStringSelection(&m, i==MENU_MAIN_NEWSTREAM, "New Stream "); + WriteStringSelection(&m, i==MENU_MAIN_DEMOS, "Demos "); + WriteByte(&m, '\n'); + WriteStringSelection(&m, i==MENU_MAIN_FIXME, "FIXME "); + WriteStringSelection(&m, i==MENU_MAIN_ADMIN, "Admin "); + WriteByte(&m, '\n'); + WriteStringSelection(&m, i==MENU_MAIN_PREVPROX, "Previous Proxy "); + WriteStringSelection(&m, i==MENU_MAIN_NEXTPROX, "Next Proxy "); + + WriteString2(&m, "\n\x1d\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x1f\n"); + } + break; + + case MENU_CLIENTS: + { + int start; + viewer_t *v; + char *srv; + int c; + v = cluster->viewers; + + WriteString2(&m, "\nActive Clients\n\n"); + + start = viewer->menuop & ~7; + for (i = 0; i < start; i++) + v = v->next; + for (i = start; i < start+8 && v; i++, v = v->next) + { + for (c = strlen(v->name); c < 14; c++) + WriteByte(&m, ' '); + WriteStringSelection(&m, viewer->menuop == i, v->name); + WriteString2(&m, ": "); + if (v->server) + { + if (!v->server->sourcefile && !v->server->parsingconnectiondata) + srv = v->server->hostname; + else + srv = v->server->server; + } + else + srv = "None"; + for (c = 0; c < 20; c++) + { + if (*srv) + WriteByte(&m, *srv++); + else + WriteByte(&m, ' '); + } + + WriteByte(&m, '\n'); + } + for (; i < start+8; i++) + WriteByte(&m, '\n'); + } + break; + + case MENU_DEMOS: { int start; @@ -4263,6 +4504,7 @@ void QW_UpdateUDPStuff(cluster_t *cluster) } m.cursize = read; + m.readpos = 0; if (*(int*)buffer == -1) { //connectionless message diff --git a/fteqtv/source.c b/fteqtv/source.c index f5f395c3f..d6aac955b 100644 --- a/fteqtv/source.c +++ b/fteqtv/source.c @@ -1170,7 +1170,7 @@ void QTV_ParseQWStream(sv_t *qtv) strcpy(qtv->status, "Attemping connection\n"); qtv->challenge = atoi(buffer+5); if (qtv->controller) - sprintf(buffer, "connect %i %i %i \"%s\\*qtv\\1\"", 28, qtv->qport, qtv->challenge, qtv->controller->userinfo); + sprintf(buffer, "connect %i %i %i \"%s\\*qtv\\1\\Qizmo\\2.9 notimer\"", 28, qtv->qport, qtv->challenge, qtv->controller->userinfo); else if (qtv->proxyplayer) sprintf(buffer, "connect %i %i %i \"%s\\name\\%s\"", 28, qtv->qport, qtv->challenge, "\\*ver\\fteqtv\\spectator\\0\\rate\\10000", qtv->cluster->hostname); else @@ -1194,7 +1194,7 @@ void QTV_ParseQWStream(sv_t *qtv) qtv->isconnected = true; qtv->timeout = qtv->curtime + UDPTIMEOUT_LENGTH; - SendClientCommand(qtv, "new\n"); + SendClientCommand(qtv, "new"); Sys_Printf(qtv->cluster, "Connected!\n"); continue; } @@ -1220,8 +1220,8 @@ void QTV_ParseQWStream(sv_t *qtv) if (qtv->controller) { qtv->controller->maysend = true; -if (qtv->controller->netchan.outgoing_sequence != qtv->controller->netchan.incoming_sequence) -printf("bug is here\n"); +//if (qtv->controller->netchan.outgoing_sequence != qtv->controller->netchan.incoming_sequence) +//printf("bug is here\n"); qtv->controller->netchan.outgoing_sequence = qtv->controller->netchan.incoming_sequence; // qtv->controller->netchan.incoming_sequence = qtv->netchan.incoming_acknowledged; }