Gets past map checks... but times out too easily in linux :(

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@1981 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2006-02-21 19:55:12 +00:00
parent 5e2c8dac61
commit 2d86a6140b
9 changed files with 901 additions and 159 deletions

View file

@ -4,7 +4,7 @@ STRIP=strip
STRIPFLAGS=--strip-unneeded --remove-section=.comment STRIPFLAGS=--strip-unneeded --remove-section=.comment
OBJS = netchan.o parse.o qw.o source.o bsp.o rcon.o OBJS = netchan.o parse.o qw.o source.o bsp.o rcon.o mdfour.o
qtv: $(OBJS) qtv.h qtv: $(OBJS) qtv.h
$(CC) $(CFLAGS) $(OBJS) -o $@.db -lm $(LDFLAGS) $(CC) $(CFLAGS) $(OBJS) -o $@.db -lm $(LDFLAGS)

View file

@ -28,6 +28,8 @@ typedef struct {
int child[2]; int child[2];
} node_t; } node_t;
struct bsp_s { struct bsp_s {
unsigned int fullchecksum;
unsigned int visedchecksum;
node_t *nodes; node_t *nodes;
unsigned char *pvslump; unsigned char *pvslump;
unsigned char **pvsofs; unsigned char **pvsofs;
@ -69,6 +71,7 @@ typedef struct
{ {
int fileofs, filelen; int fileofs, filelen;
} lump_t; } lump_t;
#define LUMP_ENTITIES 0
#define LUMP_PLANES 1 #define LUMP_PLANES 1
#define LUMP_VISIBILITY 4 #define LUMP_VISIBILITY 4
#define LUMP_NODES 5 #define LUMP_NODES 5
@ -186,7 +189,8 @@ unsigned char *ReadFile_WINDOWSSUCKS(char *gamedir, char *filename, int *size)
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
} }
data = malloc(*size); data = malloc(*size);
fread(data, 1, *size, f); if (data)
fread(data, 1, *size, f);
fclose(f); fclose(f);
return data; return data;
@ -204,6 +208,7 @@ bsp_t *BSP_LoadModel(cluster_t *cluster, char *gamedir, char *bspname)
int numnodes, i; int numnodes, i;
int numleafs; int numleafs;
unsigned int chksum;
bsp_t *bsp; bsp_t *bsp;
@ -237,29 +242,45 @@ bsp_t *BSP_LoadModel(cluster_t *cluster, char *gamedir, char *bspname)
numleafs = header->lumps[LUMP_LEAFS].filelen/sizeof(dleaf_t); numleafs = header->lumps[LUMP_LEAFS].filelen/sizeof(dleaf_t);
bsp = malloc(sizeof(bsp_t) + sizeof(node_t)*numnodes + header->lumps[LUMP_VISIBILITY].filelen + sizeof(unsigned char *)*numleafs); bsp = malloc(sizeof(bsp_t) + sizeof(node_t)*numnodes + header->lumps[LUMP_VISIBILITY].filelen + sizeof(unsigned char *)*numleafs);
bsp->nodes = (node_t*)(bsp+1); if (bsp)
bsp->pvsofs = (unsigned char**)(bsp->nodes+numnodes);
bsp->pvslump = (unsigned char*)(bsp->pvsofs+numleafs);
bsp->pvsbytecount = (numleafs+7)/8;
for (i = 0; i < numnodes; i++)
{ {
bsp->nodes[i].child[0] = nodes[i].children[0]; bsp->fullchecksum = 0;
bsp->nodes[i].child[1] = nodes[i].children[1]; bsp->visedchecksum = 0;
bsp->nodes[i].planedist = planes[nodes[i].planenum].dist; for (i = 0; i < HEADER_LUMPS; i++)
bsp->nodes[i].planen[0] = planes[nodes[i].planenum].normal[0]; {
bsp->nodes[i].planen[1] = planes[nodes[i].planenum].normal[1]; if (i == LUMP_ENTITIES)
bsp->nodes[i].planen[2] = planes[nodes[i].planenum].normal[2]; continue; //entities never appear in any checksums
}
memcpy(bsp->pvslump, data+header->lumps[LUMP_VISIBILITY].fileofs, header->lumps[LUMP_VISIBILITY].filelen);
for (i = 0; i < numleafs; i++) chksum = Com_BlockChecksum(data + header->lumps[i].fileofs, header->lumps[i].filelen);
{ bsp->fullchecksum ^= chksum;
if (leaf[i].visofs < 0) if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES)
bsp->pvsofs[i] = NULL; continue;
else bsp->visedchecksum ^= chksum;
bsp->pvsofs[i] = bsp->pvslump+leaf[i].visofs; }
bsp->nodes = (node_t*)(bsp+1);
bsp->pvsofs = (unsigned char**)(bsp->nodes+numnodes);
bsp->pvslump = (unsigned char*)(bsp->pvsofs+numleafs);
bsp->pvsbytecount = (numleafs+7)/8;
for (i = 0; i < numnodes; i++)
{
bsp->nodes[i].child[0] = nodes[i].children[0];
bsp->nodes[i].child[1] = nodes[i].children[1];
bsp->nodes[i].planedist = planes[nodes[i].planenum].dist;
bsp->nodes[i].planen[0] = planes[nodes[i].planenum].normal[0];
bsp->nodes[i].planen[1] = planes[nodes[i].planenum].normal[1];
bsp->nodes[i].planen[2] = planes[nodes[i].planenum].normal[2];
}
memcpy(bsp->pvslump, data+header->lumps[LUMP_VISIBILITY].fileofs, header->lumps[LUMP_VISIBILITY].filelen);
for (i = 0; i < numleafs; i++)
{
if (leaf[i].visofs < 0)
bsp->pvsofs[i] = NULL;
else
bsp->pvsofs[i] = bsp->pvslump+leaf[i].visofs;
}
} }
free(data); free(data);
@ -314,6 +335,13 @@ int BSP_SphereLeafNums_r(bsp_t *bsp, int first, int maxleafs, unsigned short *li
return numleafs; return numleafs;
} }
unsigned int BSP_Checksum(bsp_t *bsp)
{
if (!bsp)
return 0;
return bsp->visedchecksum;
}
int BSP_SphereLeafNums(bsp_t *bsp, int maxleafs, unsigned short *list, float x, float y, float z, float radius) int BSP_SphereLeafNums(bsp_t *bsp, int maxleafs, unsigned short *list, float x, float y, float z, float radius)
{ {
float pos[3]; float pos[3];

254
fteqtv/mdfour.c Normal file
View file

@ -0,0 +1,254 @@
/*
mdfour.c
An implementation of MD4 designed for use in the samba SMB
authentication protocol
Copyright (C) 1997-1998 Andrew Tridgell
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#include <string.h> /* XoXus: needed for memset call */
#ifndef _MDFOUR_H
#define _MDFOUR_H
#ifndef int32
#define int32 int
#endif
#if SIZEOF_INT > 4
#define LARGE_INT32
#endif
#ifndef uint32
#define uint32 unsigned int32
#endif
struct mdfour {
uint32 A, B, C, D;
uint32 totalN;
};
void mdfour_begin(struct mdfour *md); // old: MD4Init
void mdfour_update(struct mdfour *md, unsigned char *in, int n); //old: MD4Update
void mdfour_result(struct mdfour *md, unsigned char *out); // old: MD4Final
void mdfour(unsigned char *out, unsigned char *in, int n);
#endif // _MDFOUR_H
/* NOTE: This code makes no attempt to be fast!
It assumes that a int is at least 32 bits long
*/
static struct mdfour *m;
#define F(X,Y,Z) (((X)&(Y)) | ((~(X))&(Z)))
#define G(X,Y,Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)))
#define H(X,Y,Z) ((X)^(Y)^(Z))
#ifdef LARGE_INT32
#define lshift(x,s) ((((x)<<(s))&0xFFFFFFFF) | (((x)>>(32-(s)))&0xFFFFFFFF))
#else
#define lshift(x,s) (((x)<<(s)) | ((x)>>(32-(s))))
#endif
#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s)
#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + 0x5A827999,s)
#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1,s)
/* this applies md4 to 64 byte chunks */
static void mdfour64(uint32 *M)
{
int j;
uint32 AA, BB, CC, DD;
uint32 X[16];
uint32 A,B,C,D;
for (j=0;j<16;j++)
X[j] = M[j];
A = m->A; B = m->B; C = m->C; D = m->D;
AA = A; BB = B; CC = C; DD = D;
ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
A += AA; B += BB; C += CC; D += DD;
#ifdef LARGE_INT32
A &= 0xFFFFFFFF; B &= 0xFFFFFFFF;
C &= 0xFFFFFFFF; D &= 0xFFFFFFFF;
#endif
for (j=0;j<16;j++)
X[j] = 0;
m->A = A; m->B = B; m->C = C; m->D = D;
}
static void copy64(uint32 *M, unsigned char *in)
{
int i;
for (i=0;i<16;i++)
M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
(in[i*4+1]<<8) | (in[i*4+0]<<0);
}
static void copy4(unsigned char *out,uint32 x)
{
out[0] = x&0xFF;
out[1] = (x>>8)&0xFF;
out[2] = (x>>16)&0xFF;
out[3] = (x>>24)&0xFF;
}
void mdfour_begin(struct mdfour *md)
{
md->A = 0x67452301;
md->B = 0xefcdab89;
md->C = 0x98badcfe;
md->D = 0x10325476;
md->totalN = 0;
}
static void mdfour_tail(unsigned char *in, int n)
{
unsigned char buf[128];
uint32 M[16];
uint32 b;
m->totalN += n;
b = m->totalN * 8;
memset(buf, 0, 128);
if (n) memcpy(buf, in, n);
buf[n] = 0x80;
if (n <= 55) {
copy4(buf+56, b);
copy64(M, buf);
mdfour64(M);
} else {
copy4(buf+120, b);
copy64(M, buf);
mdfour64(M);
copy64(M, buf+64);
mdfour64(M);
}
}
void mdfour_update(struct mdfour *md, unsigned char *in, int n)
{
uint32 M[16];
m = md;
// if (n == 0) mdfour_tail(in, n); //Spike: This is where the bug was.
while (n >= 64) {
copy64(M, in);
mdfour64(M);
in += 64;
n -= 64;
m->totalN += 64;
}
mdfour_tail(in, n);
}
void mdfour_result(struct mdfour *md, unsigned char *out)
{
m = md;
copy4(out, m->A);
copy4(out+4, m->B);
copy4(out+8, m->C);
copy4(out+12, m->D);
}
void mdfour(unsigned char *out, unsigned char *in, int n)
{
struct mdfour md;
mdfour_begin(&md);
mdfour_update(&md, in, n);
mdfour_result(&md, out);
}
///////////////////////////////////////////////////////////////
// MD4-based checksum utility functions
//
// Copyright (C) 2000 Jeff Teunissen <d2deek@pmail.net>
//
// Author: Jeff Teunissen <d2deek@pmail.net>
// Date: 01 Jan 2000
unsigned Com_BlockChecksum (void *buffer, int length)
{
int digest[4];
unsigned val;
mdfour ( (unsigned char *) digest, (unsigned char *) buffer, length );
val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
return val;
}
void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf)
{
mdfour ( outbuf, (unsigned char *) buffer, len );
}

View file

@ -39,8 +39,7 @@ int Netchan_IsLocal (netadr_t adr)
{ {
struct sockaddr_in *sadr = (struct sockaddr_in *)adr; struct sockaddr_in *sadr = (struct sockaddr_in *)adr;
unsigned char *bytes; unsigned char *bytes;
bytes = (char *)&sadr->sin_addr; bytes = (unsigned char *)&sadr->sin_addr;
if (bytes[0] == 127 && if (bytes[0] == 127 &&
bytes[1] == 0 && bytes[1] == 0 &&
bytes[2] == 0 && bytes[2] == 0 &&
@ -175,13 +174,14 @@ Netchan_Setup
called to open a channel to a remote system called to open a channel to a remote system
============== ==============
*/ */
void Netchan_Setup (SOCKET sock, netchan_t *chan, netadr_t adr, int qport) void Netchan_Setup (SOCKET sock, netchan_t *chan, netadr_t adr, int qport, qboolean isclient)
{ {
memset (chan, 0, sizeof(*chan)); memset (chan, 0, sizeof(*chan));
chan->sock = sock; chan->sock = sock;
memcpy(&chan->remote_address, adr, sizeof(netadr_t)); memcpy(&chan->remote_address, adr, sizeof(netadr_t));
chan->qport = qport; chan->qport = qport;
chan->isclient = isclient;
chan->last_received = curtime; chan->last_received = curtime;
@ -284,8 +284,8 @@ void Netchan_Transmit (cluster_t *cluster, netchan_t *chan, int length, const un
WriteLong (&send, w2); WriteLong (&send, w2);
// send the qport if we are a client // send the qport if we are a client
// if (chan->sock == NS_CLIENT) if (chan->isclient)
// MSG_WriteShort (&send, chan->qport); WriteShort (&send, chan->qport);
// copy the reliable message to the packet first // copy the reliable message to the packet first
if (send_reliable) if (send_reliable)
@ -343,7 +343,7 @@ qboolean Netchan_Process (netchan_t *chan, netmsg_t *msg)
sequence_ack = ReadLong (msg); sequence_ack = ReadLong (msg);
// read the qport if we are a server // read the qport if we are a server
// if (chan->sock == NS_SERVER) if (!chan->isclient)
ReadShort (msg); ReadShort (msg);
reliable_message = sequence >> 31; reliable_message = sequence >> 31;

View file

@ -216,11 +216,17 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma
tv->parsingconnectiondata = true; tv->parsingconnectiondata = true;
ReadLong(m); //we don't care about server's servercount, it's all reliable data anyway. tv->clservercount = ReadLong(m); //we don't care about server's servercount, it's all reliable data anyway.
ReadString(m, tv->gamedir, sizeof(tv->gamedir)); ReadString(m, tv->gamedir, sizeof(tv->gamedir));
/*tv->servertime =*/ ReadFloat(m); if (tv->usequkeworldprotocols)
tv->thisplayer = ReadByte(m)&~128;
else
{
tv->thisplayer = MAX_CLIENTS-1;
/*tv->servertime =*/ ReadFloat(m);
}
ReadString(m, tv->mapname, sizeof(tv->mapname)); ReadString(m, tv->mapname, sizeof(tv->mapname));
Sys_Printf(tv->cluster, "Gamedir: %s\n", tv->gamedir); Sys_Printf(tv->cluster, "Gamedir: %s\n", tv->gamedir);
@ -254,6 +260,13 @@ static void ParseServerData(sv_t *tv, netmsg_t *m, int to, unsigned int playerma
memset(tv->staticsound, 0, sizeof(tv->staticsound)); memset(tv->staticsound, 0, sizeof(tv->staticsound));
memset(tv->players, 0, sizeof(tv->players)); memset(tv->players, 0, sizeof(tv->players));
if (tv->usequkeworldprotocols)
{
SendClientCommand(tv, "soundlist %i 0\n", tv->clservercount);
}
} }
static void ParseCDTrack(sv_t *tv, netmsg_t *m, int to, unsigned int mask) static void ParseCDTrack(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
@ -271,6 +284,7 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
qboolean fromproxy; qboolean fromproxy;
ReadString(m, text, sizeof(text)); ReadString(m, text, sizeof(text));
Sys_Printf(tv->cluster, "stuffcmd: %s", text);
if (!strcmp(text, "skins\n")) if (!strcmp(text, "skins\n"))
{ {
@ -285,6 +299,9 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
SendBufferToViewer(v, newcmd, sizeof(newcmd), true); SendBufferToViewer(v, newcmd, sizeof(newcmd), true);
} }
} }
if (tv->usequkeworldprotocols)
SendClientCommand(tv, "begin %i\n", tv->clservercount);
return; return;
} }
else if (!strncmp(text, "fullserverinfo ", 15)) else if (!strncmp(text, "fullserverinfo ", 15))
@ -325,7 +342,11 @@ static void ParseStufftext(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
return; return;
} }
else if (!strncmp(text, "cmd ", 4)) else if (!strncmp(text, "cmd ", 4))
{
if (tv->usequkeworldprotocols)
SendClientCommand(tv, "%s", text+4);
return; //commands the game server asked for are pointless. return; //commands the game server asked for are pointless.
}
Multicast(tv, m->data+m->startpos, m->readpos - m->startpos, to, mask); Multicast(tv, m->data+m->startpos, m->readpos - m->startpos, to, mask);
} }
@ -500,8 +521,10 @@ void ParseSpawnStatic(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
Multicast(tv, m->data+m->startpos, m->readpos - m->startpos, to, mask); Multicast(tv, m->data+m->startpos, m->readpos - m->startpos, to, mask);
} }
extern const usercmd_t nullcmd;
static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers) static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
{ {
usercmd_t nonnullcmd;
int flags; int flags;
int num; int num;
int i; int i;
@ -515,50 +538,100 @@ static void ParsePlayerInfo(sv_t *tv, netmsg_t *m, qboolean clearoldplayers)
} }
} }
num = ReadByte(m); num = ReadByte(m);
if (num >= MAX_CLIENTS) if (num >= MAX_CLIENTS)
{ {
num = 0; // don't be fatal. num = 0; // don't be fatal.
Sys_Printf(tv->cluster, "Too many svc_playerinfos, wrapping\n"); Sys_Printf(tv->cluster, "Too many svc_playerinfos, wrapping\n");
} }
tv->players[num].old = tv->players[num].current; tv->players[num].old = tv->players[num].current;
flags = ReadShort(m); if (tv->usequkeworldprotocols)
tv->players[num].gibbed = !!(flags & DF_GIB);
tv->players[num].dead = !!(flags & DF_DEAD);
tv->players[num].current.frame = ReadByte(m);
for (i = 0; i < 3; i++)
{ {
if (flags & (DF_ORIGIN << i)) tv->players[num].old = tv->players[num].current;
tv->players[num].current.origin[i] = ReadShort (m); flags = (unsigned short)ReadShort (m);
}
for (i = 0; i < 3; i++) tv->players[num].current.origin[0] = ReadShort (m);
{ tv->players[num].current.origin[1] = ReadShort (m);
if (flags & (DF_ANGLES << i)) tv->players[num].current.origin[2] = ReadShort (m);
tv->players[num].current.frame = ReadByte(m);
if (flags & PF_MSEC)
ReadByte (m);
if (flags & PF_COMMAND)
{ {
tv->players[num].current.angles[i] = ReadShort(m); ReadDeltaUsercmd(m, &nullcmd, &nonnullcmd);
tv->players[num].current.angles[0] = nonnullcmd.angles[0];
tv->players[num].current.angles[1] = nonnullcmd.angles[1];
tv->players[num].current.angles[2] = nonnullcmd.angles[2];
} }
for (i=0 ; i<3 ; i++)
{
if (flags & (PF_VELOCITY1<<i) )
ReadShort(m);
}
if (flags & PF_MODEL)
tv->players[num].current.modelindex = ReadByte (m);
else
tv->players[num].current.modelindex = tv->modelindex_player;
if (flags & PF_SKINNUM)
tv->players[num].current.skinnum = ReadByte (m);
else
tv->players[num].current.skinnum = 0;
if (flags & PF_EFFECTS)
tv->players[num].current.effects = ReadByte (m);
else
tv->players[num].current.effects = 0;
if (flags & PF_WEAPONFRAME)
tv->players[num].current.weaponframe = ReadByte (m);
else
tv->players[num].current.weaponframe = 0;
tv->players[num].active = (num != tv->thisplayer);
} }
else
{
flags = ReadShort(m);
tv->players[num].gibbed = !!(flags & DF_GIB);
tv->players[num].dead = !!(flags & DF_DEAD);
tv->players[num].current.frame = ReadByte(m);
if (flags & DF_MODEL) for (i = 0; i < 3; i++)
tv->players[num].current.modelindex = ReadByte (m); {
if (flags & (DF_ORIGIN << i))
tv->players[num].current.origin[i] = ReadShort (m);
}
if (flags & DF_SKINNUM) for (i = 0; i < 3; i++)
tv->players[num].current.skinnum = ReadByte (m); {
if (flags & (DF_ANGLES << i))
{
tv->players[num].current.angles[i] = ReadShort(m);
}
}
if (flags & DF_EFFECTS) if (flags & DF_MODEL)
tv->players[num].current.effects = ReadByte (m); tv->players[num].current.modelindex = ReadByte (m);
if (flags & DF_WEAPONFRAME) if (flags & DF_SKINNUM)
tv->players[num].current.weaponframe = ReadByte (m); tv->players[num].current.skinnum = ReadByte (m);
tv->players[num].active = true; if (flags & DF_EFFECTS)
tv->players[num].current.effects = ReadByte (m);
if (flags & DF_WEAPONFRAME)
tv->players[num].current.weaponframe = ReadByte (m);
tv->players[num].active = true;
}
tv->players[num].leafcount = BSP_SphereLeafNums(tv->bsp, MAX_ENTITY_LEAFS, tv->players[num].leafs, tv->players[num].leafcount = BSP_SphereLeafNums(tv->bsp, MAX_ENTITY_LEAFS, tv->players[num].leafs,
tv->players[num].current.origin[0]/8.0f, tv->players[num].current.origin[0]/8.0f,
@ -671,8 +744,10 @@ static void ParseUpdatePing(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
static void ParseUpdateFrags(sv_t *tv, netmsg_t *m, int to, unsigned int mask) static void ParseUpdateFrags(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
{ {
int best;
int pnum; int pnum;
int frags; int frags;
char buffer[64];
pnum = ReadByte(m); pnum = ReadByte(m);
frags = ReadShort(m); frags = ReadShort(m);
@ -682,6 +757,26 @@ static void ParseUpdateFrags(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
Sys_Printf(tv->cluster, "svc_updatefrags: invalid player number\n"); Sys_Printf(tv->cluster, "svc_updatefrags: invalid player number\n");
Multicast(tv, m->data+m->startpos, m->readpos - m->startpos, to, mask); Multicast(tv, m->data+m->startpos, m->readpos - m->startpos, to, mask);
if (!tv->usequkeworldprotocols)
return;
frags = -10000;
best = -1;
for (pnum = 0; pnum < MAX_CLIENTS; pnum++)
{
if (*tv->players[pnum].userinfo && !atoi(Info_ValueForKey(tv->players[pnum].userinfo, "*spectator", buffer, sizeof(buffer))))
if (frags < tv->players[pnum].frags)
{
best = pnum;
frags = tv->players[pnum].frags;
}
}
if (best != tv->trackplayer)
{
SendClientCommand (tv, "ptrack %i\n", best);
tv->trackplayer = best;
}
} }
static void ParseUpdateStat(sv_t *tv, netmsg_t *m, int to, unsigned int mask) static void ParseUpdateStat(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
@ -729,7 +824,7 @@ static void ParseUpdateStatLong(sv_t *tv, netmsg_t *m, int to, unsigned int mask
Multicast(tv, m->data+m->startpos, m->readpos - m->startpos, to, mask); Multicast(tv, m->data+m->startpos, m->readpos - m->startpos, to, mask);
} }
static void ParseUpdateUserinfo(sv_t *tv, netmsg_t *m) static void ParseUpdateUserinfo(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
{ {
int pnum; int pnum;
pnum = ReadByte(m); pnum = ReadByte(m);
@ -743,6 +838,8 @@ static void ParseUpdateUserinfo(sv_t *tv, netmsg_t *m)
{ {
} }
} }
Multicast(tv, m->data+m->startpos, m->readpos - m->startpos, to, mask);
} }
static void ParsePacketloss(sv_t *tv, netmsg_t *m, int to, unsigned int mask) static void ParsePacketloss(sv_t *tv, netmsg_t *m, int to, unsigned int mask)
@ -957,6 +1054,7 @@ void ParseNails2(sv_t *tv, netmsg_t *m)
void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask) void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask)
{ {
int i;
netmsg_t buf; netmsg_t buf;
qboolean clearoldplayers = true; qboolean clearoldplayers = true;
buf.cursize = length; buf.cursize = length;
@ -1100,7 +1198,7 @@ void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask)
break; break;
case svc_updateuserinfo: case svc_updateuserinfo:
ParseUpdateUserinfo(tv, &buf); ParseUpdateUserinfo(tv, &buf, to, mask);
break; break;
//#define svc_download 41 // [short] size [size bytes] //#define svc_download 41 // [short] size [size bytes]
@ -1113,9 +1211,10 @@ void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask)
ReadByte(&buf); ReadByte(&buf);
break; break;
case svc_modellist: case svc_modellist:
if (!ParseList(tv, &buf, tv->modellist, to, mask)) i = ParseList(tv, &buf, tv->modellist, to, mask);
if (!i)
{ {
int i; int j;
if (tv->bsp) if (tv->bsp)
BSP_Free(tv->bsp); BSP_Free(tv->bsp);
@ -1125,16 +1224,30 @@ void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask)
tv->bsp = BSP_LoadModel(tv->cluster, tv->gamedir, tv->modellist[1].name); tv->bsp = BSP_LoadModel(tv->cluster, tv->gamedir, tv->modellist[1].name);
tv->numinlines = 0; tv->numinlines = 0;
for (i = 2; i < 256; i++) for (j = 2; j < 256; j++)
{ {
if (*tv->modellist[i].name != '*') if (*tv->modellist[j].name != '*')
break; break;
tv->numinlines = i; tv->numinlines = j;
} }
} }
if (tv->usequkeworldprotocols)
{
if (i)
SendClientCommand(tv, "modellist %i %i\n", tv->clservercount, i);
else
SendClientCommand(tv, "prespawn %i 0 %i\n", tv->clservercount, BSP_Checksum(tv->bsp));
}
break; break;
case svc_soundlist: case svc_soundlist:
ParseList(tv, &buf, tv->soundlist, to, mask); i = ParseList(tv, &buf, tv->soundlist, to, mask);
if (tv->usequkeworldprotocols)
{
if (i)
SendClientCommand(tv, "soundlist %i %i\n", tv->clservercount, i);
else
SendClientCommand(tv, "modellist %i 0\n", tv->clservercount);
}
break; break;
case svc_packetentities: case svc_packetentities:
FlushPacketEntities(tv); FlushPacketEntities(tv);
@ -1145,7 +1258,9 @@ void ParseMessage(sv_t *tv, char *buffer, int length, int to, int mask)
ParsePacketEntities(tv, &buf); ParsePacketEntities(tv, &buf);
break; break;
//#define svc_maxspeed 49 // maxspeed change, for prediction //#define svc_maxspeed 49 // maxspeed change, for prediction
//#define svc_entgravity 50 // gravity change, for prediction case svc_entgravity: // gravity change, for prediction
ReadFloat(&buf);
break;
case svc_setinfo: case svc_setinfo:
ParseSetInfo(tv, &buf); ParseSetInfo(tv, &buf);
break; break;

View file

@ -164,6 +164,7 @@ typedef struct {
int reliable_length; int reliable_length;
qboolean drop; qboolean drop;
qboolean isclient;
netmsg_t message; netmsg_t message;
char message_buf[MAX_MSGLEN]; //reliable message being built char message_buf[MAX_MSGLEN]; //reliable message being built
@ -301,8 +302,17 @@ typedef struct {
unsigned short leafs[MAX_ENTITY_LEAFS]; unsigned short leafs[MAX_ENTITY_LEAFS];
} entity_t; } entity_t;
typedef struct {
unsigned char msec;
unsigned short angles[3];
short forwardmove, sidemove, upmove;
unsigned char buttons;
unsigned char impulse;
} usercmd_t;
struct sv_s { struct sv_s {
netadr_t serveraddress; netadr_t serveraddress;
netchan_t netchan;
unsigned char buffer[MAX_PROXY_BUFFER]; //this doesn't cycle. unsigned char buffer[MAX_PROXY_BUFFER]; //this doesn't cycle.
int buffersize; //it memmoves down int buffersize; //it memmoves down
@ -339,12 +349,24 @@ struct sv_s {
filename_t modellist[MAX_MODELS]; filename_t modellist[MAX_MODELS];
filename_t soundlist[MAX_SOUNDS]; filename_t soundlist[MAX_SOUNDS];
int modelindex_spike; // qw is wierd. int modelindex_spike; // qw is wierd.
int modelindex_player; // qw is wierd.
qboolean usequkeworldprotocols;
int challenge;
unsigned short qport;
int isconnected;
int clservercount;
unsigned int nextsendpings;
unsigned int trackplayer;
int thisplayer;
unsigned timeout;
FILE *file; FILE *file;
unsigned int filelength; unsigned int filelength;
SOCKET sourcesock; SOCKET sourcesock;
SOCKET listenmvd; //tcp + mvd protocol SOCKET listenmvd; //tcp + mvd protocol
int tcplistenportnum;
oproxy_t *proxies; oproxy_t *proxies;
int numproxies; int numproxies;
@ -355,9 +377,13 @@ struct sv_s {
unsigned int curtime; unsigned int curtime;
unsigned int oldpackettime; unsigned int oldpackettime;
unsigned int nextpackettime; unsigned int nextpackettime;
unsigned int nextconnectattemp; unsigned int nextconnectattempt;
qboolean disconnectwhennooneiswatching;
unsigned int numviewers;
int tcplistenportnum;
cluster_t *cluster; cluster_t *cluster;
@ -499,7 +525,7 @@ void ReadString(netmsg_t *b, char *string, int maxlen);
#define svc_packetentities 47 // [...] #define svc_packetentities 47 // [...]
#define svc_deltapacketentities 48 // [...] #define svc_deltapacketentities 48 // [...]
//#define svc_maxspeed 49 // maxspeed change, for prediction //#define svc_maxspeed 49 // maxspeed change, for prediction
//#define svc_entgravity 50 // gravity change, for prediction #define svc_entgravity 50 // gravity change, for prediction
#define svc_setinfo 51 // setinfo on a client #define svc_setinfo 51 // setinfo on a client
#define svc_serverinfo 52 // serverinfo #define svc_serverinfo 52 // serverinfo
#define svc_updatepl 53 // [qbyte] [qbyte] #define svc_updatepl 53 // [qbyte] [qbyte]
@ -596,7 +622,7 @@ void SendBufferToViewer(viewer_t *v, const char *buffer, int length, qboolean re
void QW_PrintfToViewer(viewer_t *v, char *format, ...); void QW_PrintfToViewer(viewer_t *v, char *format, ...);
void QW_StuffcmdToViewer(viewer_t *v, char *format, ...); void QW_StuffcmdToViewer(viewer_t *v, char *format, ...);
void Netchan_Setup (SOCKET sock, netchan_t *chan, netadr_t adr, int qport); void Netchan_Setup (SOCKET sock, netchan_t *chan, netadr_t adr, int qport, qboolean isclient);
void Netchan_OutOfBandPrint (cluster_t *cluster, SOCKET sock, netadr_t adr, char *format, ...); void Netchan_OutOfBandPrint (cluster_t *cluster, SOCKET sock, netadr_t adr, char *format, ...);
int Netchan_IsLocal (netadr_t adr); int Netchan_IsLocal (netadr_t adr);
void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, char *data, netadr_t adr); void NET_SendPacket(cluster_t *cluster, SOCKET sock, int length, char *data, netadr_t adr);
@ -621,6 +647,6 @@ void Info_SetValueForStarKey (char *s, const char *key, const char *value, int m
void Sys_Printf(cluster_t *cluster, char *fmt, ...); void Sys_Printf(cluster_t *cluster, char *fmt, ...);
qboolean Net_FileProxy(sv_t *qtv, char *filename); qboolean Net_FileProxy(sv_t *qtv, char *filename);
sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, qboolean force); sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, qboolean force, qboolean autoclose);
SOCKET Net_MVDListen(int port); SOCKET Net_MVDListen(int port);
qboolean Net_StopFileProxy(sv_t *qtv); qboolean Net_StopFileProxy(sv_t *qtv);

View file

@ -20,14 +20,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "qtv.h" #include "qtv.h"
#ifdef _WIN32
int snprintf(char *buffer, int buffersize, char *format, ...)
{
va_list argptr;
int ret;
va_start (argptr, format);
ret = _vsnprintf (buf, buffersize, format, argptr);
buf[buffersize - 1] = '\0';
va_end (argptr);
return ret;
}
#endif
typedef struct {
unsigned char msec;
unsigned short angles[3];
short forwardmove, sidemove, upmove;
unsigned char buttons;
unsigned char impulse;
} usercmd_t;
const usercmd_t nullcmd; const usercmd_t nullcmd;
#define CM_ANGLE1 (1<<0) #define CM_ANGLE1 (1<<0)
@ -417,6 +423,20 @@ int SendList(sv_t *qtv, int first, const filename_t *list, int svc, netmsg_t *ms
return i; return i;
} }
void QW_SetViewersServer(viewer_t *viewer, sv_t *sv)
{
if (viewer->server)
viewer->server->numviewers--;
viewer->server = sv;
if (viewer->server)
viewer->server->numviewers++;
QW_StuffcmdToViewer(viewer, "cmd new\n");
viewer->servercount++;
viewer->origin[0] = 0;
viewer->origin[1] = 0;
viewer->origin[2] = 0;
}
//fixme: will these want to have state?.. //fixme: will these want to have state?..
int NewChallenge(netadr_t *addr) int NewChallenge(netadr_t *addr)
{ {
@ -431,6 +451,7 @@ qboolean ChallengePasses(netadr_t *addr, int challenge)
void NewQWClient(cluster_t *cluster, netadr_t *addr, char *connectmessage) void NewQWClient(cluster_t *cluster, netadr_t *addr, char *connectmessage)
{ {
sv_t *initialserver;
viewer_t *viewer; viewer_t *viewer;
char qport[32]; char qport[32];
@ -451,23 +472,33 @@ void NewQWClient(cluster_t *cluster, netadr_t *addr, char *connectmessage)
viewer = malloc(sizeof(viewer_t)); viewer = malloc(sizeof(viewer_t));
if (!viewer)
{
Netchan_OutOfBandPrint(cluster, cluster->qwdsocket, *addr, "n" "Out of memory");
return;
}
memset(viewer, 0, sizeof(viewer_t)); memset(viewer, 0, sizeof(viewer_t));
viewer->trackplayer = -1; viewer->trackplayer = -1;
Netchan_Setup (cluster->qwdsocket, &viewer->netchan, *addr, atoi(qport)); Netchan_Setup (cluster->qwdsocket, &viewer->netchan, *addr, atoi(qport), false);
viewer->next = cluster->viewers; viewer->next = cluster->viewers;
cluster->viewers = viewer; cluster->viewers = viewer;
viewer->delta_frame = -1; viewer->delta_frame = -1;
initialserver = NULL;
if (cluster->numservers == 1) if (cluster->numservers == 1)
{ {
viewer->server = cluster->servers; initialserver = cluster->servers;
if (!viewer->server->modellist[1].name[0]) if (!initialserver->modellist[1].name[0])
viewer->server = NULL; //damn, that server isn't ready initialserver = NULL; //damn, that server isn't ready
} }
if (!viewer->server) viewer->server = initialserver;
if (viewer->server)
viewer->server->numviewers++;
if (!initialserver)
viewer->menunum = 1; viewer->menunum = 1;
cluster->numviewers++; cluster->numviewers++;
@ -1078,17 +1109,11 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message)
} }
else if (!strcmp(v->expectcommand, "addserver")) else if (!strcmp(v->expectcommand, "addserver"))
{ {
#ifdef _WIN32
_snprintf(buf, sizeof(buf), "tcp:%s", message);
buf[suzeof(buf)-1] = '\0';
#else
snprintf(buf, sizeof(buf), "tcp:%s", message); snprintf(buf, sizeof(buf), "tcp:%s", message);
#endif qtv = QTV_NewServerConnection(cluster, buf, false, false);
qtv = QTV_NewServerConnection(cluster, buf, false);
if (qtv) if (qtv)
{ {
v->server = qtv; QW_SetViewersServer(v, qtv);
QW_StuffcmdToViewer(v, "cmd new\n");
QW_PrintfToViewer(v, "Connected\n", message); QW_PrintfToViewer(v, "Connected\n", message);
} }
else else
@ -1110,22 +1135,46 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message)
} }
else if (!strcmp(v->expectcommand, "adddemo")) else if (!strcmp(v->expectcommand, "adddemo"))
{ {
#ifdef _WIN32
_snprintf(buf, sizeof(buf), "file:%s", message);
buf[sizeof(buf)-1] = '\0';
#else
snprintf(buf, sizeof(buf), "file:%s", message); snprintf(buf, sizeof(buf), "file:%s", message);
#endif qtv = QTV_NewServerConnection(cluster, buf, false, false);
qtv = QTV_NewServerConnection(cluster, buf, false);
if (!qtv) if (!qtv)
QW_PrintfToViewer(v, "Failed to play demo \"%s\"\n", message); QW_PrintfToViewer(v, "Failed to play demo \"%s\"\n", message);
else else
{ {
v->server = qtv; QW_SetViewersServer(v, qtv);
QW_StuffcmdToViewer(v, "cmd new\n");
QW_PrintfToViewer(v, "Opened demo file.\n", message); QW_PrintfToViewer(v, "Opened demo file.\n", message);
} }
} }
else if (!strcmp(v->expectcommand, "setmvdport"))
{
int newp;
int news;
if (qtv)
{
newp = atoi(message);
if (newp)
{
news = Net_MVDListen(newp);
if (news != INVALID_SOCKET)
{
if (qtv->listenmvd != INVALID_SOCKET)
closesocket(qtv->listenmvd);
qtv->listenmvd = news;
qtv->tcplistenportnum = newp;
qtv->disconnectwhennooneiswatching = false;
}
}
else if (qtv->listenmvd != INVALID_SOCKET)
{
closesocket(qtv->listenmvd);
qtv->listenmvd = INVALID_SOCKET;
}
}
else
QW_PrintfToViewer(v, "You were disconnected from that stream\n");
}
else else
{ {
QW_PrintfToViewer(v, "Command %s was not recognised\n", v->expectcommand); QW_PrintfToViewer(v, "Command %s was not recognised\n", v->expectcommand);
@ -1134,18 +1183,68 @@ void QTV_Say(cluster_t *cluster, sv_t *qtv, viewer_t *v, char *message)
*v->expectcommand = '\0'; *v->expectcommand = '\0';
return; return;
} }
*v->expectcommand = '\0'; if (!strncmp(message, ".qw ", 4))
{
message += 4;
snprintf(buf, sizeof(buf), "udp:%s", message);
qtv = QTV_NewServerConnection(cluster, buf, false, false);
if (qtv)
{
// QW_SetViewersServer(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, ".connect ", 9))
{
message += 9;
snprintf(buf, sizeof(buf), "tcp:%s", message);
qtv = QTV_NewServerConnection(cluster, buf, false, true);
if (qtv)
{
QW_SetViewersServer(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, ".demo ", 6))
{
message += 6;
snprintf(buf, sizeof(buf), "file:%s", message);
qtv = QTV_NewServerConnection(cluster, buf, false, true);
if (qtv)
{
QW_SetViewersServer(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_SetViewersServer(v, NULL);
QW_PrintfToViewer(v, "Connected\n", message);
}
else
{
if (cluster->notalking)
return;
InitNetMsg(&msg, buf, sizeof(buf)); *v->expectcommand = '\0';
WriteByte(&msg, svc_print); InitNetMsg(&msg, buf, sizeof(buf));
WriteByte(&msg, 3); //PRINT_CHAT
WriteString2(&msg, v->name);
WriteString2(&msg, "\x8d ");
WriteString2(&msg, message);
WriteString(&msg, "\n");
Broadcast(cluster, msg.data, msg.cursize); WriteByte(&msg, svc_print);
WriteByte(&msg, 3); //PRINT_CHAT
WriteString2(&msg, v->name);
WriteString2(&msg, "\x8d ");
WriteString2(&msg, message);
WriteString(&msg, "\n");
Broadcast(cluster, msg.data, msg.cursize);
}
} }
viewer_t *QW_IsOn(cluster_t *cluster, char *name) viewer_t *QW_IsOn(cluster_t *cluster, char *name)
@ -1230,7 +1329,12 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
// printf("stringcmd: %s\n", buf); // printf("stringcmd: %s\n", buf);
if (!strcmp(buf, "new")) if (!strcmp(buf, "new"))
SendServerData(qtv, v); {
if (qtv->parsingconnectiondata)
QW_StuffcmdToViewer(v, "cmd new\n");
else
SendServerData(qtv, v);
}
else if (!strncmp(buf, "modellist ", 10)) else if (!strncmp(buf, "modellist ", 10))
{ {
char *cmd = buf+10; char *cmd = buf+10;
@ -1357,9 +1461,9 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
else if (!strncmp(buf, "pings", 5)) else if (!strncmp(buf, "pings", 5))
{ {
} }
else if (!strncmp(buf, "say \"", 5) && !cluster->notalking) else if (!strncmp(buf, "say \"", 5))
QTV_Say(cluster, qtv, v, buf+5); QTV_Say(cluster, qtv, v, buf+5);
else if (!strncmp(buf, "say ", 4) && !cluster->notalking) else if (!strncmp(buf, "say ", 4))
QTV_Say(cluster, qtv, v, buf+4); QTV_Say(cluster, qtv, v, buf+4);
else if (!strncmp(buf, "servers", 7)) else if (!strncmp(buf, "servers", 7))
@ -1368,8 +1472,7 @@ void ParseQWC(cluster_t *cluster, sv_t *qtv, viewer_t *v, netmsg_t *m)
} }
else if (!strncmp(buf, "reset", 5)) else if (!strncmp(buf, "reset", 5))
{ {
QW_StuffcmdToViewer(v, "cmd new\n"); QW_SetViewersServer(v, NULL);
v->server = NULL;
v->menunum = 1; v->menunum = 1;
} }
else if (!strncmp(buf, "admin", 5)) else if (!strncmp(buf, "admin", 5))
@ -1514,10 +1617,12 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum)
if (viewer->server) if (viewer->server)
{ {
i = 0; i = 0;
sv = viewer->server;
if (i++ == viewer->menuop) if (i++ == viewer->menuop)
{ //mvd port { //mvd port
QW_StuffcmdToViewer(viewer, "echo You will need to reconnect\n"); WriteString(&m, "echo Please enter a new tcp port number\nmessagemode\n");
cluster->qwlistenportnum += buttonnum?-1:1; SendBufferToViewer(viewer, m.data, m.cursize, true);
strcpy(viewer->expectcommand, "setmvdport");
} }
if (i++ == viewer->menuop) if (i++ == viewer->menuop)
{ //disconnect { //disconnect
@ -1534,8 +1639,9 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum)
case 1: case 1:
if (!cluster->servers) if (!cluster->servers)
{ {
WriteString(&m, "messagemode\n"); WriteString(&m, "echo Please enter a server ip\nmessagemode\n");
SendBufferToViewer(viewer, m.data, m.cursize, true); SendBufferToViewer(viewer, m.data, m.cursize, true);
strcpy(viewer->expectcommand, "insecadddemo");
} }
else else
{ {
@ -1560,9 +1666,7 @@ void Menu_Enter(cluster_t *cluster, viewer_t *viewer, int buttonnum)
} }
else else
{ {
WriteString(&m, "cmd new\n"); QW_SetViewersServer(viewer, sv);
viewer->servercount++;
viewer->server = sv;
SendBufferToViewer(viewer, m.data, m.cursize, true); SendBufferToViewer(viewer, m.data, m.cursize, true);
viewer->menunum = 0; viewer->menunum = 0;
viewer->thinksitsconnected = false; viewer->thinksitsconnected = false;
@ -1675,7 +1779,10 @@ void Menu_Draw(cluster_t *cluster, viewer_t *viewer)
i = 0; i = 0;
WriteString2(&m, " port"); WriteString2(&m, " port");
WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : "); WriteString2(&m, (viewer->menuop==(i++))?" \r ":" : ");
sprintf(str, "%-20i", sv->tcplistenportnum); if (sv->listenmvd == INVALID_SOCKET)
sprintf(str, "!%-19i", sv->tcplistenportnum);
else
sprintf(str, "%-20i", sv->tcplistenportnum);
WriteString2(&m, str); WriteString2(&m, str);
WriteString2(&m, "\n"); WriteString2(&m, "\n");
@ -1845,6 +1952,9 @@ void QW_FreeViewer(cluster_t *cluster, viewer_t *viewer)
free(viewer->backbuf[i].data); free(viewer->backbuf[i].data);
} }
if (viewer->server)
viewer->server->numviewers--;
free(viewer); free(viewer);
cluster->numviewers--; cluster->numviewers--;

View file

@ -347,7 +347,19 @@ char *Cluster_Rcon_Dispatch(cluster_t *cluster, char *arg[MAX_ARGS], char *buffe
memmove(arg[1]+4, arg[1], ARG_LEN-5); memmove(arg[1]+4, arg[1], ARG_LEN-5);
strncpy(arg[1], "tcp:", 4); strncpy(arg[1], "tcp:", 4);
if (!QTV_NewServerConnection(cluster, arg[1], false)) if (!QTV_NewServerConnection(cluster, arg[1], false, !strcmp(arg[0], "connect")))
return "Failed to connect to server, connection aborted\n";
return "Connection registered\n";
}
else if (!strcmp(arg[0], "qw"))
{
if (!*arg[1])
return "connect requires an ip:port parameter\n";
memmove(arg[1]+4, arg[1], ARG_LEN-5);
strncpy(arg[1], "udp:", 4);
if (!QTV_NewServerConnection(cluster, arg[1], false, false))
return "Failed to connect to server, connection aborted\n"; return "Failed to connect to server, connection aborted\n";
return "Connection registered\n"; return "Connection registered\n";
} }
@ -363,7 +375,7 @@ char *Cluster_Rcon_Dispatch(cluster_t *cluster, char *arg[MAX_ARGS], char *buffe
memmove(arg[1]+5, arg[1], ARG_LEN-6); memmove(arg[1]+5, arg[1], ARG_LEN-6);
strncpy(arg[1], "file:", 5); strncpy(arg[1], "file:", 5);
if (!QTV_NewServerConnection(cluster, arg[1], false)) if (!QTV_NewServerConnection(cluster, arg[1], false, false))
return "Failed to connect to server, connection aborted\n"; return "Failed to connect to server, connection aborted\n";
return "Connection registered\n"; return "Connection registered\n";
} }
@ -558,7 +570,7 @@ char *Server_Rcon_Dispatch(sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int siz
else if (!strcmp(arg[0], "disconnect")) else if (!strcmp(arg[0], "disconnect"))
{ {
QTV_Shutdown(qtv); QTV_Shutdown(qtv);
return NULL; return "Disconnected\n";
} }
else if (!strcmp(arg[0], "file") || !strcmp(arg[0], "play") || !strcmp(arg[0], "playdemo")) else if (!strcmp(arg[0], "file") || !strcmp(arg[0], "play") || !strcmp(arg[0], "playdemo"))
@ -630,8 +642,10 @@ char *Server_Rcon_Dispatch(sv_t *qtv, char *arg[MAX_ARGS], char *buffer, int siz
if (news != INVALID_SOCKET) if (news != INVALID_SOCKET)
{ {
closesocket(qtv->listenmvd); if (qtv->listenmvd != INVALID_SOCKET)
closesocket(qtv->listenmvd);
qtv->listenmvd = news; qtv->listenmvd = news;
qtv->disconnectwhennooneiswatching = false;
qtv->tcplistenportnum = newp; qtv->tcplistenportnum = newp;
return "Opened tcp port\n"; return "Opened tcp port\n";
} }

View file

@ -21,6 +21,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "qtv.h" #include "qtv.h"
#define RECONNECT_TIME (1000*30) #define RECONNECT_TIME (1000*30)
#define UDPRECONNECT_TIME (1000)
#define PINGSINTERVAL_TIME (1000*5)
#define UDPTIMEOUT_LENGTH (1000*20)
qboolean NET_StringToAddr (char *s, netadr_t *sadr) qboolean NET_StringToAddr (char *s, netadr_t *sadr)
@ -202,34 +205,11 @@ SOCKET Net_MVDListen(int port)
return sock; return sock;
} }
qboolean Net_ConnectToServer(sv_t *qtv, char *ip) qboolean Net_ConnectToTCPServer(sv_t *qtv, char *ip)
{ {
netadr_t from; netadr_t from;
unsigned long nonblocking = true; unsigned long nonblocking = true;
if (!strncmp(ip, "file:", 5))
{
qtv->sourcesock = INVALID_SOCKET;
qtv->file = fopen(ip+5, "rb");
if (qtv->file)
{
fseek(qtv->file, 0, SEEK_END);
qtv->filelength = ftell(qtv->file);
fseek(qtv->file, 0, SEEK_SET);
return true;
}
Sys_Printf(qtv->cluster, "Unable to open file %s\n", ip+5);
return false;
}
qtv->nextconnectattemp = qtv->curtime + RECONNECT_TIME; //wait half a minuite before trying to reconnect
if (strncmp(ip, "tcp:", 4))
{
Sys_Printf(qtv->cluster, "Unknown source type %s\n", ip);
return false;
}
if (!NET_StringToAddr(ip+4, &qtv->serveraddress)) if (!NET_StringToAddr(ip+4, &qtv->serveraddress))
{ {
Sys_Printf(qtv->cluster, "Unable to resolve %s\n", ip); Sys_Printf(qtv->cluster, "Unable to resolve %s\n", ip);
@ -264,10 +244,78 @@ qboolean Net_ConnectToServer(sv_t *qtv, char *ip)
return false; return false;
} }
} }
return true;
}
qboolean Net_ConnectToUDPServer(sv_t *qtv, char *ip)
{
netadr_t from;
unsigned long nonblocking = true;
if (!NET_StringToAddr(ip+4, &qtv->serveraddress))
{
Sys_Printf(qtv->cluster, "Unable to resolve %s\n", ip);
return false;
}
qtv->sourcesock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (qtv->sourcesock == INVALID_SOCKET)
return false;
memset(&from, 0, sizeof(from));
((struct sockaddr*)&from)->sa_family = ((struct sockaddr*)&qtv->serveraddress)->sa_family;
if (bind(qtv->sourcesock, (struct sockaddr *)&from, sizeof(from)) == -1)
{
closesocket(qtv->sourcesock);
qtv->sourcesock = INVALID_SOCKET;
return false;
}
if (ioctlsocket (qtv->sourcesock, FIONBIO, &nonblocking) == -1)
{
closesocket(qtv->sourcesock);
qtv->sourcesock = INVALID_SOCKET;
return false;
}
qtv->qport = Sys_Milliseconds()*1000+Sys_Milliseconds();
return true; return true;
} }
qboolean Net_ConnectToServer(sv_t *qtv, char *ip)
{
qtv->usequkeworldprotocols = false;
if (!strncmp(ip, "file:", 5))
{
qtv->sourcesock = INVALID_SOCKET;
qtv->file = fopen(ip+5, "rb");
if (qtv->file)
{
fseek(qtv->file, 0, SEEK_END);
qtv->filelength = ftell(qtv->file);
fseek(qtv->file, 0, SEEK_SET);
return true;
}
Sys_Printf(qtv->cluster, "Unable to open file %s\n", ip+5);
return false;
}
qtv->nextconnectattempt = qtv->curtime + RECONNECT_TIME; //wait half a minuite before trying to reconnect
if (!strncmp(ip, "udp:", 4))
{
qtv->usequkeworldprotocols = true;
return Net_ConnectToUDPServer(qtv, ip);
}
else if (!strncmp(ip, "tcp:", 4))
return Net_ConnectToTCPServer(qtv, ip);
else
{
Sys_Printf(qtv->cluster, "Unknown source type %s\n", ip);
return false;
}
}
void Net_FindProxies(sv_t *qtv) void Net_FindProxies(sv_t *qtv)
{ {
oproxy_t *prox; oproxy_t *prox;
@ -286,6 +334,11 @@ void Net_FindProxies(sv_t *qtv)
} }
prox = malloc(sizeof(*prox)); prox = malloc(sizeof(*prox));
if (!prox)
{//out of mem?
closesocket(sock);
return;
}
memset(prox, 0, sizeof(*prox)); memset(prox, 0, sizeof(*prox));
prox->flushing = true; //allow the buffer overflow resumption code to send the connection info. prox->flushing = true; //allow the buffer overflow resumption code to send the connection info.
prox->sock = sock; prox->sock = sock;
@ -309,6 +362,8 @@ qboolean Net_FileProxy(sv_t *qtv, char *filename)
//no full proxy check, this is going to be used by proxy admins, who won't want to have to raise the limit to start recording. //no full proxy check, this is going to be used by proxy admins, who won't want to have to raise the limit to start recording.
prox = malloc(sizeof(*prox)); prox = malloc(sizeof(*prox));
if (!prox)
return false;
memset(prox, 0, sizeof(*prox)); memset(prox, 0, sizeof(*prox));
prox->flushing = true; //allow the buffer overflow resumption code to send the connection info. prox->flushing = true; //allow the buffer overflow resumption code to send the connection info.
prox->sock = INVALID_SOCKET; prox->sock = INVALID_SOCKET;
@ -865,8 +920,8 @@ qboolean QTV_Connect(sv_t *qtv, char *serverurl)
void QTV_Shutdown(sv_t *qtv) void QTV_Shutdown(sv_t *qtv)
{ {
return; oproxy_t *prox;
/* oproxy_t *old;
viewer_t *v; viewer_t *v;
sv_t *peer; sv_t *peer;
cluster_t *cluster; cluster_t *cluster;
@ -888,6 +943,8 @@ void QTV_Shutdown(sv_t *qtv)
fclose(qtv->file); fclose(qtv->file);
qtv->file = NULL; qtv->file = NULL;
} }
if (qtv->listenmvd != INVALID_SOCKET)
closesocket(qtv->listenmvd);
BSP_Free(qtv->bsp); BSP_Free(qtv->bsp);
qtv->bsp = NULL; qtv->bsp = NULL;
@ -910,13 +967,25 @@ void QTV_Shutdown(sv_t *qtv)
{ {
if (v->server == qtv) if (v->server == qtv)
{ {
v->server = NULL; QW_SetViewersServer(v, NULL);
v->menunum = 1; v->menunum = 1;
} }
} }
for (prox = qtv->proxies; prox; )
{
if (prox->file)
fclose(prox->file);
if (prox->sock != INVALID_SOCKET)
closesocket(prox->sock);
old = prox;
prox = prox->next;
free(old);
}
free(qtv); free(qtv);
*/ cluster->numservers--;
} }
/* /*
@ -1199,9 +1268,81 @@ int main(int argc, char **argv)
void SendClientCommand(sv_t *qtv, char *fmt, ...)
{
va_list argptr;
char buf[1024];
va_start (argptr, fmt);
#ifdef _WIN32
_vsnprintf (buf, sizeof(buf) - 1, fmt, argptr);
buf[sizeof(buf) - 1] = '\0';
#else
vsnprintf (buf, sizeof(buf), fmt, argptr);
#endif // _WIN32
va_end (argptr);
WriteByte(&qtv->netchan.message, clc_stringcmd);
WriteString(&qtv->netchan.message, buf);
}
void QTV_ParseQWStream(sv_t *qtv)
{
char buffer[1500];
netadr_t from;
int fromlen;
int readlen;
netmsg_t msg;
fromlen = sizeof(from); //bug: this won't work on (free)bsd
for (;;)
{
readlen = recvfrom(qtv->sourcesock, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&from, &fromlen);
if (readlen < 0)
{
//FIXME: Check for error
break;
}
buffer[readlen] = 0;
if (*(int*)buffer == -1)
{
if (buffer[4] == 'c')
{ //got a challenge
qtv->challenge = atoi(buffer+5);
sprintf(buffer, "connect %i %i %i \"%s\"", 28, qtv->qport, qtv->challenge, "\\*ver\\fteqtv\\name\\fteqtv\\spectator\\1");
Netchan_OutOfBand(qtv->cluster, qtv->sourcesock, qtv->serveraddress, strlen(buffer), buffer);
continue;
}
if (buffer[4] == 'n')
{
Sys_Printf(qtv->cluster, "%s: %s", qtv->server, buffer+5);
continue;
}
if (buffer[4] == 'j')
{
Netchan_Setup(qtv->sourcesock, &qtv->netchan, qtv->serveraddress, qtv->qport, true);
qtv->trackplayer = -1;
qtv->isconnected = true;
qtv->timeout = qtv->curtime + UDPTIMEOUT_LENGTH;
SendClientCommand(qtv, "new\n");
Sys_Printf(qtv->cluster, "Connected!\n");
continue;
}
Sys_Printf(qtv->cluster, "%s: unrecognised connectionless packet:\n%s\n", qtv->server, buffer+4);
continue;
}
memset(&msg, 0, sizeof(msg));
msg.cursize = readlen;
msg.data = buffer;
msg.maxsize = readlen;
qtv->timeout = qtv->curtime + UDPTIMEOUT_LENGTH;
if (!Netchan_Process(&qtv->netchan, &msg))
continue;
ParseMessage(qtv, msg.data + msg.readpos, msg.cursize - msg.readpos, dem_all, -1);
}
}
void QTV_Run(sv_t *qtv) void QTV_Run(sv_t *qtv)
@ -1212,6 +1353,12 @@ void QTV_Run(sv_t *qtv)
int oldcurtime; int oldcurtime;
int packettime; int packettime;
if (qtv->disconnectwhennooneiswatching && qtv->numviewers == 0)
{
QTV_Shutdown(qtv);
return;
}
//we will read out as many packets as we can until we're up to date //we will read out as many packets as we can until we're up to date
//note: this can cause real issues when we're overloaded for any length of time //note: this can cause real issues when we're overloaded for any length of time
@ -1235,9 +1382,51 @@ void QTV_Run(sv_t *qtv)
} }
if (qtv->usequkeworldprotocols)
{
if (!qtv->isconnected && (qtv->curtime >= qtv->nextconnectattempt || qtv->curtime < qtv->nextconnectattempt - UDPRECONNECT_TIME*2))
{
Netchan_OutOfBand(qtv->cluster, qtv->sourcesock, qtv->serveraddress, 12, "getchallenge");
qtv->nextconnectattempt = qtv->curtime + UDPRECONNECT_TIME;
}
QTV_ParseQWStream(qtv);
if (qtv->isconnected)
{
char buffer[64];
netmsg_t msg;
memset(&msg, 0, sizeof(msg));
msg.data = buffer;
msg.maxsize = sizeof(buffer);
if (qtv->curtime >= qtv->timeout || qtv->curtime < qtv->timeout - UDPTIMEOUT_LENGTH*2)
{
Sys_Printf(qtv->cluster, "Timeout\n");
qtv->isconnected = false;
return;
}
if (qtv->curtime >= qtv->nextsendpings || qtv->curtime < qtv->nextsendpings - PINGSINTERVAL_TIME*2)
{
qtv->nextsendpings = qtv->curtime + PINGSINTERVAL_TIME;
SendClientCommand(qtv, "pings\n");
}
WriteByte(&msg, clc_tmove);
WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[0]);
WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[1]);
WriteShort(&msg, qtv->players[qtv->trackplayer].current.origin[2]);
Netchan_Transmit(qtv->cluster, &qtv->netchan, msg.cursize, msg.data);
}
return;
}
if (qtv->sourcesock == INVALID_SOCKET && !qtv->file) if (qtv->sourcesock == INVALID_SOCKET && !qtv->file)
{ {
if (qtv->curtime >= qtv->nextconnectattemp || qtv->curtime < qtv->nextconnectattemp - RECONNECT_TIME*2) if (qtv->curtime >= qtv->nextconnectattempt || qtv->curtime < qtv->nextconnectattempt - RECONNECT_TIME*2)
if (!QTV_Connect(qtv, qtv->server)) if (!QTV_Connect(qtv, qtv->server))
{ {
return; return;
@ -1380,7 +1569,7 @@ void QTV_Run(sv_t *qtv)
void Cluster_Run(cluster_t *cluster) void Cluster_Run(cluster_t *cluster)
{ {
sv_t *sv; sv_t *sv, *old;
int m; int m;
struct timeval timeout; struct timeval timeout;
@ -1394,17 +1583,17 @@ void Cluster_Run(cluster_t *cluster)
if (cluster->qwdsocket >= m) if (cluster->qwdsocket >= m)
m = cluster->qwdsocket+1; m = cluster->qwdsocket+1;
} }
/*
for (sv = cluster->servers; sv; sv = sv->next) for (sv = cluster->servers; sv; sv = sv->next)
{ {
if (sv->sourcesock != INVALID_SOCKET) if (sv->usequkeworldprotocols && sv->sourcesock != INVALID_SOCKET)
{ {
FD_SET(sv->sourcesock, &socketset); FD_SET(sv->sourcesock, &socketset);
if (sv->sourcesock >= m) if (sv->sourcesock >= m)
m = sv->sourcesock+1; m = sv->sourcesock+1;
} }
} }
*/
#ifndef _WIN32 #ifndef _WIN32
#ifndef STDIN #ifndef STDIN
#define STDIN 0 #define STDIN 0
@ -1491,17 +1680,21 @@ void Cluster_Run(cluster_t *cluster)
for (sv = cluster->servers; sv; sv = sv->next) for (sv = cluster->servers; sv; )
{ {
QTV_Run(sv); old = sv;
sv = sv->next;
QTV_Run(old);
} }
QW_UpdateUDPStuff(cluster); QW_UpdateUDPStuff(cluster);
} }
sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, qboolean force) sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, qboolean force, qboolean autoclose)
{ {
sv_t *qtv = malloc(sizeof(sv_t)); sv_t *qtv = malloc(sizeof(sv_t));
if (!qtv)
return NULL;
memset(qtv, 0, sizeof(*qtv)); memset(qtv, 0, sizeof(*qtv));
//set up a default config //set up a default config
@ -1510,6 +1703,8 @@ sv_t *QTV_NewServerConnection(cluster_t *cluster, char *server, qboolean force)
qtv->listenmvd = INVALID_SOCKET; qtv->listenmvd = INVALID_SOCKET;
qtv->sourcesock = INVALID_SOCKET; qtv->sourcesock = INVALID_SOCKET;
qtv->disconnectwhennooneiswatching = autoclose;
qtv->parsingconnectiondata = true;
qtv->cluster = cluster; qtv->cluster = cluster;
qtv->next = cluster->servers; qtv->next = cluster->servers;