From 55f534451066b111933d66a97a00491b612cfc91 Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 26 Dec 2006 21:26:10 +0000 Subject: [PATCH] Rewritted entity parsing, so should work fine with .join now. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@2451 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- fteqtv/control.c | 74 +++----------- fteqtv/parse.c | 249 ++++++++++++++++++++++++++++++++++++++++++--- fteqtv/qtv.h | 16 +-- fteqtv/qtvprox.dsp | 24 +++++ fteqtv/qw.c | 124 ++++++++++++++++++---- fteqtv/rcon.c | 45 +++++++- fteqtv/source.c | 22 +++- 7 files changed, 449 insertions(+), 105 deletions(-) diff --git a/fteqtv/control.c b/fteqtv/control.c index 722af6a2b..134ebe7de 100644 --- a/fteqtv/control.c +++ b/fteqtv/control.c @@ -203,8 +203,16 @@ void Cluster_Run(cluster_t *cluster, qboolean dowait) m = STDIN+1; #endif - timeout.tv_sec = 100/1000; - timeout.tv_usec = (100%1000)*1000; + if (cluster->viewserver) + { + timeout.tv_sec = 0; + timeout.tv_usec = 1000; + } + else + { + timeout.tv_sec = 100/1000; + timeout.tv_usec = (100%1000)*1000; + } m = select(m, &socketset, NULL, NULL, &timeout); @@ -363,11 +371,9 @@ int main(int argc, char **argv) { cluster_t cluster; -#ifndef _WIN32 #ifdef SIGPIPE signal(SIGPIPE, SIG_IGN); #endif -#endif #ifdef _WIN32 { @@ -387,61 +393,6 @@ int main(int argc, char **argv) Sys_Printf(&cluster, "QTV Build %i.\n", cluster.buildnumber); - if (argc >= 2 && (!strcmp(argv[1], "-view") || !strcmp(argv[1], "-play"))) - { -#ifdef VIEWER - sv_t *sv; - sv_t *svtest; - char sourcename[256]; - char *s; - printf("Please enter a QTV source\n"); - printf("eg: file:test.mvd\n"); - printf("eg: udp:localhost:27500\n"); - printf("eg: tcp:localhost:27599\n"); - fgets(sourcename, sizeof(sourcename), stdin); - for (s = sourcename + strlen(sourcename)-1; s>=sourcename; s--) - { - if (*s == '\r' || *s == '\n') - *s = '\0'; - else - break; - } - - sv = QTV_NewServerConnection(&cluster, sourcename, "", false, false, true); - if (!sv) - { - printf("Unable to connect\n"); - return 0; - } - if (!strcmp(argv[1], "-play")) - sv->proxyplayer = true; - DemoViewer_Init(); - while (!cluster.wanttoexit) - { - Cluster_Run(&cluster, false); - - for (svtest = cluster.servers; svtest; svtest = svtest->next) - { //not the cleanest way to do this, of course - if (svtest == sv) - break; - } - if (svtest) - DemoViewer_Update(svtest); - else - cluster.wanttoexit = true; - } - DemoViewer_Shutdown(); - while(cluster.viewers) - QW_FreeViewer(&cluster, cluster.viewers); - while(cluster.servers) - QTV_Shutdown(cluster.servers); -#else - Sys_Printf(&cluster, "Demo viewer is not enabled in this build. Sorry.\n"); -#endif - return 0; - } - - DoCommandLine(&cluster, argc, argv); if (!cluster.numservers) @@ -472,7 +423,12 @@ int main(int argc, char **argv) } while (!cluster.wanttoexit) + { Cluster_Run(&cluster, true); +#ifdef VIEWER + DemoViewer_Update(cluster.viewserver); +#endif + } return 0; } diff --git a/fteqtv/parse.c b/fteqtv/parse.c index dc047c60f..a32d5ab0f 100644 --- a/fteqtv/parse.c +++ b/fteqtv/parse.c @@ -292,7 +292,7 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma v->thinksitsconnected = false; } - tv->maxents = 0; //clear these +// tv->maxents = 0; //clear these tv->spawnstatic_count = 0; memset(tv->modellist, 0, sizeof(tv->modellist)); memset(tv->soundlist, 0, sizeof(tv->soundlist)); @@ -737,18 +737,122 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers) tv->players[num].current.origin[2]/8.0f, 32); } -static void FlushPacketEntities(sv_t *tv) -{ - int i; - for (i = 0; i < MAX_ENTITIES; i++) - tv->entity[i].current.modelindex = 0; -} - -static void ParsePacketEntities(sv_t *tv, netmsg_t *m) +static int readentitynum(netmsg_t *m, unsigned int *retflags) { int entnum; - int flags; - qboolean forcerelink; + unsigned int flags; + unsigned short moreflags = 0; + flags = ReadShort(m); + if (!flags) + { + *retflags = 0; + return 0; + } + + entnum = flags&511; + flags &= ~511; + + if (flags & U_MOREBITS) + { + flags |= ReadByte(m); + +/* if (flags & U_EVENMORE) + flags |= ReadByte(m)<<16; + if (flags & U_YETMORE) + flags |= ReadByte(m)<<24; +*/ } + +/* if (flags & U_ENTITYDBL) + entnum += 512; + if (flags & U_ENTITYDBL2) + entnum += 1024; +*/ + *retflags = flags; + + return entnum; +} + +static void ParseEntityDelta(sv_t *tv, netmsg_t *m, entity_state_t *old, entity_state_t *new, unsigned int flags, entity_t *ent, qboolean forcerelink) +{ + memcpy(new, old, sizeof(entity_state_t)); + + if (flags & U_MODEL) + new->modelindex = ReadByte(m); + if (flags & U_FRAME) + new->frame = ReadByte(m); + if (flags & U_COLORMAP) + new->colormap = ReadByte(m); + if (flags & U_SKIN) + new->skinnum = ReadByte(m); + if (flags & U_EFFECTS) + new->effects = ReadByte(m); + + if (flags & U_ORIGIN1) + new->origin[0] = ReadShort(m); + if (flags & U_ANGLE1) + new->angles[0] = ReadByte(m); + if (flags & U_ORIGIN2) + new->origin[1] = ReadShort(m); + if (flags & U_ANGLE2) + new->angles[1] = ReadByte(m); + if (flags & U_ORIGIN3) + new->origin[2] = ReadShort(m); + if (flags & U_ANGLE3) + new->angles[2] = ReadByte(m); + + + if (forcerelink || (flags & (U_ORIGIN1|U_ORIGIN2|U_ORIGIN3|U_MODEL))) + { + ent->leafcount = + BSP_SphereLeafNums(tv->bsp, MAX_ENTITY_LEAFS, ent->leafs, + new->origin[0]/8.0f, + new->origin[1]/8.0f, + new->origin[2]/8.0f, 32); + } +} + +static int ExpandFrame(unsigned int newmax, frame_t *frame) +{ + entity_state_t *newents; + unsigned short *newnums; + + if (newmax < frame->maxents) + return true; + + newmax += 16; + + newents = malloc(sizeof(*newents) * newmax); + if (!newents) + return false; + newnums = malloc(sizeof(*newnums) * newmax); + if (!newnums) + { + free(newents); + return false; + } + + memcpy(newents, frame->ents, sizeof(*newents) * frame->maxents); + memcpy(newnums, frame->entnums, sizeof(*newnums) * frame->maxents); + + if (frame->ents) + free(frame->ents); + if (frame->entnums) + free(frame->entnums); + + frame->ents = newents; + frame->entnums = newnums; + frame->maxents = newmax; + return true; +} + +static void ParsePacketEntities(sv_t *tv, netmsg_t *m, int deltaframe) +{ + frame_t *newframe; + frame_t *oldframe; + int oldcount; + int newnum, oldnum; + int newindex, oldindex; + unsigned int flags; viewer_t *v; @@ -763,6 +867,120 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m) v->chokeme = false; } + + if (deltaframe != -1) + deltaframe &= (ENTITY_FRAMES-1); + + if (tv->usequkeworldprotocols) + { + newframe = &tv->frame[tv->netchan.incoming_sequence & (ENTITY_FRAMES-1)]; + + if (newframe->oldframe != deltaframe) + Sys_Printf(tv->cluster, "Mismatching delta frames\n"); + } + else + { + deltaframe = tv->netchan.incoming_sequence & (ENTITY_FRAMES-1); + tv->netchan.incoming_sequence++; + newframe = &tv->frame[tv->netchan.incoming_sequence & (ENTITY_FRAMES-1)]; + } + if (deltaframe != -1) + { + oldframe = &tv->frame[deltaframe]; + oldcount = oldframe->numents; + } + else + { + oldframe = NULL; + oldcount = 0; + } + + oldindex = 0; + newindex = 0; + +//printf("frame\n"); + + for(;;) + { + newnum = readentitynum(m, &flags); + if (!newnum) + { + //end of packet + //any remaining old ents need to be copied to the new frame + while (oldindex < oldcount) + { +//printf("Propogate (spare)\n"); + if (!ExpandFrame(newindex, newframe)) + break; + + memcpy(&newframe->ents[newindex], &oldframe->ents[oldindex], sizeof(entity_state_t)); + newframe->entnums[newindex] = oldframe->entnums[oldindex]; + newindex++; + oldindex++; + } + break; + } + + if (oldindex >= oldcount) + oldnum = 0xffff; + else + oldnum = oldframe->entnums[oldindex]; + while(newnum > oldnum) + { +//printf("Propogate (unchanged)\n"); + if (!ExpandFrame(newindex, newframe)) + break; + + memcpy(&newframe->ents[newindex], &oldframe->ents[oldindex], sizeof(entity_state_t)); + newframe->entnums[newindex] = oldframe->entnums[oldindex]; + newindex++; + oldindex++; + + if (oldindex >= oldcount) + oldnum = 0xffff; + else + oldnum = oldframe->entnums[oldindex]; + } + + if (newnum < oldnum) + { //this ent wasn't in the last packet +//printf("add\n"); + if (flags & U_REMOVE) + { //remove this ent... just don't copy it across. + //printf("add\n"); + continue; + } + + if (!ExpandFrame(newindex, newframe)) + break; + ParseEntityDelta(tv, m, &tv->entity[newnum].baseline, &newframe->ents[newindex], flags, &tv->entity[newnum], true); + newframe->entnums[newindex] = newnum; + newindex++; + } + else if (newnum == oldnum) + { + if (flags & U_REMOVE) + { //remove this ent... just don't copy it across. + //printf("add\n"); + oldindex++; + continue; + } +//printf("Propogate (changed)\n"); + if (!ExpandFrame(newindex, newframe)) + break; + ParseEntityDelta(tv, m, &oldframe->ents[oldindex], &newframe->ents[newindex], flags, &tv->entity[newnum], false); + newframe->entnums[newindex] = newnum; + newindex++; + oldindex++; + } + + } + + newframe->numents = newindex; +return; + +/* + //luckilly, only updated entities are here, so that keeps cpu time down a bit. for (;;) { @@ -825,6 +1043,7 @@ static void ParsePacketEntities(sv_t *tv, netmsg_t *m) tv->entity[entnum].current.origin[1]/8.0f, tv->entity[entnum].current.origin[2]/8.0f, 32); } +*/ } static void ParseUpdatePing(sv_t *tv, netmsg_t *m, int to, unsigned int mask) @@ -1524,12 +1743,11 @@ void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask) break; case svc_packetentities: - FlushPacketEntities(tv); - ParsePacketEntities(tv, &buf); +// FlushPacketEntities(tv); + ParsePacketEntities(tv, &buf, -1); break; case svc_deltapacketentities: - ReadByte(&buf); - ParsePacketEntities(tv, &buf); + ParsePacketEntities(tv, &buf, ReadByte(&buf)); break; //#define svc_maxspeed 49 // maxspeed change, for prediction @@ -1561,3 +1779,4 @@ void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask) } } } + diff --git a/fteqtv/qtv.h b/fteqtv/qtv.h index 786893a00..198d91cfb 100644 --- a/fteqtv/qtv.h +++ b/fteqtv/qtv.h @@ -474,9 +474,9 @@ typedef struct bsp_s bsp_t; typedef struct { entity_state_t baseline; - entity_state_t current; - entity_state_t old; - unsigned int updatetime; //to stop lerping when it's an old entity (bodies, stationary grenades, ...) +// entity_state_t current; +// entity_state_t old; +// unsigned int updatetime; //to stop lerping when it's an old entity (bodies, stationary grenades, ...) int leafcount; unsigned short leafs[MAX_ENTITY_LEAFS]; @@ -484,9 +484,11 @@ typedef struct { #define MAX_ENTITY_FRAMES 64 typedef struct { + int oldframe; int numents; int maxents; - entity_state_t *ents; //dynamically allocated + entity_state_t *ents; //dynamically allocated + unsigned short *entnums; //dynamically allocated } frame_t; typedef struct { @@ -515,7 +517,7 @@ struct sv_s { int cdtrack; entity_t entity[MAX_ENTITIES]; frame_t frame[MAX_ENTITY_FRAMES]; - int maxents; +// int maxents; staticsound_t staticsound[MAX_STATICSOUNDS]; int staticsound_count; entity_state_t spawnstatic[MAX_STATICENTITIES]; @@ -619,6 +621,8 @@ struct cluster_s { int nextstreamid; int nextuserid; + sv_t *viewserver; + //options int qwlistenportnum; int tcplistenportnum; @@ -908,9 +912,7 @@ unsigned char *FS_ReadFile(char *gamedir, char *filename, unsigned int *size); void ChooseFavoriteTrack(sv_t *tv); -void DemoViewer_Init(void); void DemoViewer_Update(sv_t *svtest); -void DemoViewer_Shutdown(void); #ifdef __cplusplus diff --git a/fteqtv/qtvprox.dsp b/fteqtv/qtvprox.dsp index 57360b7cd..46f64ba88 100644 --- a/fteqtv/qtvprox.dsp +++ b/fteqtv/qtvprox.dsp @@ -525,8 +525,32 @@ SOURCE=.\source.c # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File +SOURCE=.\viewer\common.h +# End Source File +# Begin Source File + +SOURCE=.\viewer\cvar.h +# End Source File +# Begin Source File + +SOURCE=.\viewer\d3drend\d3drenderer.h +# End Source File +# Begin Source File + +SOURCE=.\viewer\glrenderer.h +# End Source File +# Begin Source File + +SOURCE=.\viewer\maths.h +# End Source File +# Begin Source File + SOURCE=.\qtv.h # End Source File +# Begin Source File + +SOURCE=.\viewer\renderer.h +# End Source File # End Group # Begin Group "Resource Files" diff --git a/fteqtv/qw.c b/fteqtv/qw.c index 88ee0b9f9..a2d871f4e 100644 --- a/fteqtv/qw.c +++ b/fteqtv/qw.c @@ -1198,12 +1198,14 @@ void SV_EmitPacketEntities (const sv_t *qtv, const viewer_t *v, const packet_ent void Prox_SendInitialEnts(sv_t *qtv, oproxy_t *prox, netmsg_t *msg) { - int i; + frame_t *frame; + int i, entnum; WriteByte(msg, svc_packetentities); - for (i = 0; i < qtv->maxents; i++) + frame = &qtv->frame[qtv->netchan.incoming_sequence & (ENTITY_FRAMES-1)]; + for (i = 0; i < frame->numents; i++) { - if (qtv->entity[i].current.modelindex) - SV_WriteDelta(i, &nullentstate, &qtv->entity[i].current, msg, true); + entnum = frame->entnums[i]; + SV_WriteDelta(i, &qtv->entity[entnum].baseline, &frame->ents[i], msg, true); } WriteShort(msg, 0); } @@ -1609,7 +1611,7 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg if (bits & UNQ_ANGLE3) WriteByte(msg, pl->current.angles[2]>>8); } - for (e = 0; e < tv->maxents; e++) +/* for (e = 0; e < tv->maxents; e++) { ent = &tv->entity[e]; if (!ent->current.modelindex) @@ -1617,6 +1619,9 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg if (ent->current.modelindex >= tv->numinlines && !BSP_Visible(tv->bsp, ent->leafcount, ent->leafs)) continue; + + if (msg->cursize + 128 > msg->maxsize) + break; // send an update bits = 0; @@ -1710,6 +1715,7 @@ void SendNQPlayerStates(cluster_t *cluster, sv_t *tv, viewer_t *v, netmsg_t *msg if (bits & UNQ_ANGLE3) WriteByte(msg, ent->current.angles[2]); } +*/ } else { @@ -1734,6 +1740,11 @@ void SendPlayerStates(sv_t *tv, viewer_t *v, netmsg_t *msg) int track; int runaway = 10; + int snapdist = 128; //in quake units + + snapdist = snapdist*8; + snapdist = snapdist*snapdist; + memset(&to, 0, sizeof(to)); @@ -1837,12 +1848,23 @@ void SendPlayerStates(sv_t *tv, viewer_t *v, netmsg_t *msg) WriteByte(msg, i); WriteShort(msg, flags); - interp = (lerp)*tv->players[i].current.origin[0] + (1-lerp)*tv->players[i].old.origin[0]; - WriteShort(msg, interp); - interp = (lerp)*tv->players[i].current.origin[1] + (1-lerp)*tv->players[i].old.origin[1]; - WriteShort(msg, interp); - interp = (lerp)*tv->players[i].current.origin[2] + (1-lerp)*tv->players[i].old.origin[2]; - WriteShort(msg, interp); + if ((tv->players[i].current.origin[0] - tv->players[i].old.origin[0])*(tv->players[i].current.origin[0] - tv->players[i].old.origin[0]) > snapdist || + (tv->players[i].current.origin[1] - tv->players[i].old.origin[1])*(tv->players[i].current.origin[1] - tv->players[i].old.origin[1]) > snapdist || + (tv->players[i].current.origin[2] - tv->players[i].old.origin[2])*(tv->players[i].current.origin[2] - tv->players[i].old.origin[2]) > snapdist) + { //teleported (or respawned), so don't interpolate + WriteShort(msg, tv->players[i].current.origin[0]); + WriteShort(msg, tv->players[i].current.origin[1]); + WriteShort(msg, tv->players[i].current.origin[2]); + } + else + { //send interpolated angles + interp = (lerp)*tv->players[i].current.origin[0] + (1-lerp)*tv->players[i].old.origin[0]; + WriteShort(msg, interp); + interp = (lerp)*tv->players[i].current.origin[1] + (1-lerp)*tv->players[i].old.origin[1]; + WriteShort(msg, interp); + interp = (lerp)*tv->players[i].current.origin[2] + (1-lerp)*tv->players[i].old.origin[2]; + WriteShort(msg, interp); + } WriteByte(msg, tv->players[i].current.frame); @@ -1883,22 +1905,79 @@ void SendPlayerStates(sv_t *tv, viewer_t *v, netmsg_t *msg) e = &v->frame[v->netchan.outgoing_sequence&(ENTITY_FRAMES-1)]; e->numents = 0; if (tv) - for (i = 0; i < tv->maxents; i++) + { + int oldindex = 0, newindex = 0; + entity_state_t *newstate; + int newnum, oldnum; + frame_t *frompacket, *topacket; + topacket = &tv->frame[tv->netchan.incoming_sequence&(ENTITY_FRAMES-1)]; + if (tv->usequkeworldprotocols) { - if (!tv->entity[i].current.modelindex) + //qw protocols don't interpolate... yet + frompacket = topacket; + } + else + { + frompacket = &tv->frame[(tv->netchan.incoming_sequence-1)&(ENTITY_FRAMES-1)]; + } + + for (newindex = 0; newindex < topacket->numents; newindex++) + { + //don't pvs cull bsp models + //pvs cull everything else + newstate = &topacket->ents[newindex]; + newnum = topacket->entnums[newindex]; + if (newstate->modelindex >= tv->numinlines && !BSP_Visible(tv->bsp, tv->entity[newnum].leafcount, tv->entity[newnum].leafs)) continue; - if (tv->entity[i].current.modelindex >= tv->numinlines && !BSP_Visible(tv->bsp, tv->entity[i].leafcount, tv->entity[i].leafs)) - continue; + e->entnum[e->numents] = newnum; + memcpy(&e->ents[e->numents], newstate, sizeof(entity_state_t)); - e->entnum[e->numents] = i; - memcpy(&e->ents[e->numents], &tv->entity[i].current, sizeof(entity_state_t)); - - if (tv->entity[i].updatetime == tv->oldpackettime) + if (frompacket != topacket) //optimisation for qw protocols { - e->ents[e->numents].origin[0] = (lerp)*tv->entity[i].current.origin[0] + (1-lerp)*tv->entity[i].old.origin[0]; - e->ents[e->numents].origin[1] = (lerp)*tv->entity[i].current.origin[1] + (1-lerp)*tv->entity[i].old.origin[1]; - e->ents[e->numents].origin[2] = (lerp)*tv->entity[i].current.origin[2] + (1-lerp)*tv->entity[i].old.origin[2]; + entity_state_t *oldstate; + + if (oldindex < frompacket->numents) + { + oldnum = frompacket->entnums[oldindex]; + + while(oldnum < newnum) + { + oldindex++; + if (oldindex >= frompacket->numents) + break; //no more + oldnum = frompacket->entnums[oldindex]; + } + if (oldnum == newnum) + { + //ent exists in old packet + oldstate = &frompacket->ents[oldindex]; + } + else + { + oldstate = newstate; + } + } + else + { //reached end, definatly not in packet + oldstate = newstate; + } + + + if ((newstate->origin[0] - oldstate->origin[0])*(newstate->origin[0] - oldstate->origin[0]) > snapdist || + (newstate->origin[1] - oldstate->origin[1])*(newstate->origin[1] - oldstate->origin[1]) > snapdist || + (newstate->origin[2] - oldstate->origin[2])*(newstate->origin[2] - oldstate->origin[2]) > snapdist) + { //teleported (or respawned), so don't interpolate + e->ents[e->numents].origin[0] = newstate->origin[0]; + e->ents[e->numents].origin[1] = newstate->origin[1]; + e->ents[e->numents].origin[2] = newstate->origin[2]; + } + else + { + e->ents[e->numents].origin[0] = (lerp)*newstate->origin[0] + (1-lerp)*oldstate->origin[0]; + e->ents[e->numents].origin[1] = (lerp)*newstate->origin[1] + (1-lerp)*oldstate->origin[1]; + e->ents[e->numents].origin[2] = (lerp)*newstate->origin[2] + (1-lerp)*oldstate->origin[2]; + } } e->numents++; @@ -1906,6 +1985,7 @@ void SendPlayerStates(sv_t *tv, viewer_t *v, netmsg_t *msg) if (e->numents == ENTS_PER_FRAME) break; } + } SV_EmitPacketEntities(tv, v, e, msg); diff --git a/fteqtv/rcon.c b/fteqtv/rcon.c index 756c47b55..cc3736c7d 100644 --- a/fteqtv/rcon.c +++ b/fteqtv/rcon.c @@ -486,6 +486,27 @@ void catbuffer(char *buffer, int bufsize, char *format, ...) Q_strncatz(buffer, string, bufsize); } + +char *Cmd_Say(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand) +{ + int i; + viewer_t *v; + char message[8192]; + message[0] = '\0'; + for (i = 1; i < MAX_ARGS; i++) + catbuffer(message, sizeof(message)-1, "%s%s", i==1?"":" ", arg[i]); + + for (v = cluster->viewers; v; v = v->next) + { + if (v->server == qtv || !qtv) + QW_PrintfToViewer(v, "proxy: %s\n", message); + } + + buffer[0] = '\0'; + catbuffer(buffer, sizeofbuffer, "proxy: %s\n", message); + return buffer; +} + char *Cmd_Status(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand) { @@ -769,6 +790,24 @@ char *Cmd_MVDPort(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buff } } +#ifdef VIEWER +char *Cmd_Watch(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand) +{ + if (!localcommand) + return "watch is not permitted remotly\n"; + + if (cluster->viewserver == qtv) + { + cluster->viewserver = NULL; + return "Stopped watching\n"; + } + + cluster->viewserver = qtv; + + return "Watching\n"; +} +#endif + char *Cmd_Commands(cluster_t *cluster, sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int sizeofbuffer, qboolean localcommand) { return "fixme\n"; @@ -785,6 +824,7 @@ const rconcommands_t rconcommands[] = { {"exec", 1, 1, Cmd_Exec}, {"status", 1, 1, Cmd_Status}, + {"say", 1, 1, Cmd_Say}, {"help", 0, 1, Cmd_Help}, {"commands", 0, 1, Cmd_Commands}, @@ -816,12 +856,15 @@ const rconcommands_t rconcommands[] = - {"disconnect", 1, 0, Cmd_Disconnect}, {"record", 1, 0, Cmd_Record}, {"stop", 1, 0, Cmd_Stop}, {"tcpport", 1, 0, Cmd_MVDPort}, {"mvdport", 1, 0, Cmd_MVDPort}, + +#ifdef VIEWER + {"watch", 1, 0, Cmd_Watch}, +#endif {NULL} }; diff --git a/fteqtv/source.c b/fteqtv/source.c index e9bbf3000..c11ee442b 100644 --- a/fteqtv/source.c +++ b/fteqtv/source.c @@ -857,6 +857,9 @@ void QTV_Shutdown(sv_t *qtv) } } + if (cluster->viewserver == qtv) + cluster->viewserver = NULL; + for (v = cluster->viewers; v; v = v->next) { if (v->server == qtv) @@ -1200,6 +1203,8 @@ void QTV_CollectCommentry(sv_t *qtv) void QTV_Run(sv_t *qtv) { + int from; + int to; int lengthofs; unsigned int length; unsigned char *buffer; @@ -1331,7 +1336,7 @@ void QTV_Run(sv_t *qtv) SetMoveCRC(qtv, &msg); } - else if (qtv->proxyplayer) + else if (qtv->proxyplayer || qtv->trackplayer < 0) { usercmd_t *cmd[3]; cmd[0] = &qtv->proxyplayerucmds[(qtv->proxyplayerucmdnum-2)%3]; @@ -1364,6 +1369,21 @@ void QTV_Run(sv_t *qtv) SetMoveCRC(qtv, &msg); } + to = qtv->netchan.outgoing_sequence & (ENTITY_FRAMES-1); + from = qtv->netchan.incoming_sequence & (ENTITY_FRAMES-1); + if (qtv->frame[from].numents) + { + //remember which one we came from + qtv->frame[to].oldframe = from; + + WriteByte(&msg, clc_delta); + WriteByte(&msg, qtv->frame[to].oldframe); //let the server know + } + else + qtv->frame[to].oldframe = -1; + + qtv->frame[to].numents = 0; + Netchan_Transmit(qtv->cluster, &qtv->netchan, msg.cursize, msg.data); } }