forked from fte/fteqw
1
0
Fork 0

mvd playback works properly now.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@587 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2004-12-08 04:14:52 +00:00
parent 2bc22c8e79
commit 0322bdd338
35 changed files with 803 additions and 200 deletions

View File

@ -49,7 +49,6 @@ cvar_t cl_chasecam = {"cl_chasecam", "0"};
//cvar_t cl_camera_maxpitch = {"cl_camera_maxpitch", "10" };
//cvar_t cl_camera_maxyaw = {"cl_camera_maxyaw", "30" };
qboolean cam_forceview[MAX_SPLITS];
vec3_t cam_viewangles[MAX_SPLITS];
double cam_lastviewtime[MAX_SPLITS];
@ -129,12 +128,19 @@ void Cam_Lock(int pnum, int playernum)
{
char st[40];
cam_lastviewtime[pnum] = -1000;
sprintf(st, "ptrack %i", playernum);
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
MSG_WriteString (&cls.netchan.message, st);
spec_track[pnum] = playernum;
cam_forceview[pnum] = true;
locked[pnum] = false;
if (cls.demoplayback == DPB_MVD)
{
memcpy(&cl.stats[pnum], cl.players[playernum].stats, sizeof(cl.stats[pnum]));
}
Sbar_Changed();
}
@ -351,7 +357,7 @@ void Cam_Track(int pnum, usercmd_t *cmd)
vec3_t vec;
float len;
if (!cl.spectator)
if (!cl.spectator || !cl.worldmodel) //can happen when the server changes level
return;
if (cl_hightrack.value && !locked[pnum])
@ -370,11 +376,11 @@ void Cam_Track(int pnum, usercmd_t *cmd)
return;
}
frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
frame = &cl.frames[cl.validsequence & UPDATE_MASK];
player = frame->playerstate + spec_track[pnum];
self = frame->playerstate + cl.playernum[pnum];
if (/*locked[pnum] ||*/ !Cam_IsVisible(player, desired_position[pnum]))
if (!locked[pnum] || !Cam_IsVisible(player, desired_position[pnum]))
{
if (!locked[pnum] || realtime - cam_lastviewtime[pnum] > 0.1)
{

View File

@ -154,7 +154,7 @@ qboolean CL_GetDemoMessage (void)
int r, i, j, tracknum;
float f;
float demotime;
qbyte c, msecsadded;
qbyte c, msecsadded=0;
usercmd_t *pcmd;
q1usercmd_t q1cmd;
@ -173,6 +173,7 @@ qboolean CL_GetDemoMessage (void)
{
cl.gametime = 0;
cl.gametimemark = realtime;
prevtime = 0;
return 0;
}
if (realtime<= cl.gametime && cl.gametime)// > dem_lasttime+realtime)
@ -182,6 +183,24 @@ qboolean CL_GetDemoMessage (void)
realtime = cl.gametime;
cls.netchan.last_received = realtime;
}
{
float f = (cl.gametime-realtime)/(cl.gametime-prevtime);
float a1;
float a2;
for (i=0 ; i<3 ; i++)
{
a1 = cl.viewangles[2][i];
a2 = cl.viewangles[1][i];
if (a1 - a2 > 180)
a1 -= 360;
if (a1 - a2 < -180)
a1 += 360;
cl.simangles[0][i] = a2 + f * (a1 - a2);
}
VectorCopy(cl.simangles[0], cl.viewangles[0]);
}
return 0;
}
}
@ -189,12 +208,16 @@ qboolean CL_GetDemoMessage (void)
// VectorCopy (cl.mviewangles[0], cl.mviewangles[1]);
if (cls.demoplayback == DPB_NETQUAKE)
{
VectorCopy (cl.viewangles[1], cl.viewangles[2]);
for (i=0 ; i<3 ; i++)
{
r = fread (&f, 4, 1, cls.demofile);
cl.simangles[0][i] = cl.viewangles[0][i] = LittleFloat (f);
cl.simangles[0][i] = cl.viewangles[1][i] = LittleFloat (f);
}
VectorCopy (cl.viewangles[1], cl.viewangles[0]);
}
prevtime = realtime;
net_message.cursize = LittleLong (net_message.cursize);
if (net_message.cursize > MAX_NQMSGLEN)
@ -230,14 +253,6 @@ readnext:
fread(&msecsadded, sizeof(msecsadded), 1, cls.demofile);
demotime = prevtime + msecsadded*(1.0f/1000);
if (msecsadded)
{
cls.netchan.incoming_sequence++;
cls.netchan.incoming_acknowledged++;
cls.netchan.frame_latency = 0;
cls.netchan.last_received = demotime; // just to happy timeout check
}
}
else
{
@ -299,6 +314,17 @@ readnext:
else
realtime = demotime; // we're warping
if (cls.demoplayback == DPB_MVD)
{
if (msecsadded)
{
cls.netchan.incoming_sequence++;
cls.netchan.incoming_acknowledged++;
cls.netchan.frame_latency = 0;
cls.netchan.last_received = demotime; // just to happy timeout check
}
}
prevtime = demotime;
if (cls.state < ca_demostart)
@ -1080,7 +1106,7 @@ void CL_PlayDemo_f (void)
//
// disconnect from server
//
CL_Disconnect ();
CL_Disconnect_f ();
//
// open the demo file

View File

@ -406,7 +406,7 @@ void CL_ParsePacketEntities (qboolean delta)
int oldindex, newindex;
int word, newnum, oldnum;
qboolean full;
qbyte from;
int from;
newpacket = cls.netchan.incoming_sequence&UPDATE_MASK;
newp = &cl.frames[newpacket].packet_entities;
@ -417,37 +417,45 @@ void CL_ParsePacketEntities (qboolean delta)
from = MSG_ReadByte ();
oldpacket = cl.frames[newpacket].delta_sequence;
if (cls.demoplayback == DPB_MVD)
from = oldpacket = cls.netchan.incoming_sequence - 1;
if ( (from&UPDATE_MASK) != (oldpacket&UPDATE_MASK) )
Con_DPrintf ("WARNING: from mismatch\n");
}
else
oldpacket = -1;
full = false;
if (oldpacket != -1)
{
if (cls.netchan.outgoing_sequence - oldpacket >= UPDATE_BACKUP-1)
{ // we can't use this, it is too old
if (cls.netchan.outgoing_sequence - cls.netchan.incoming_sequence >= UPDATE_BACKUP - 1) {
// there are no valid frames left, so drop it
FlushEntityPacket ();
cl.validsequence = 0;
return;
}
cl.oldvalidsequence = cl.validsequence;
cl.validsequence = cls.netchan.incoming_sequence;
oldp = &cl.frames[oldpacket&UPDATE_MASK].packet_entities;
if ((from & UPDATE_MASK) != (oldpacket & UPDATE_MASK)) {
Con_DPrintf ("WARNING: from mismatch\n");
FlushEntityPacket ();
cl.validsequence = 0;
return;
}
if (cls.netchan.outgoing_sequence - oldpacket >= UPDATE_BACKUP - 1) {
// we can't use this, it is too old
FlushEntityPacket ();
// don't clear cl.validsequence, so that frames can still be rendered;
// it is possible that a fresh packet will be received before
// (outgoing_sequence - incoming_sequence) exceeds UPDATE_BACKUP - 1
return;
}
oldp = &cl.frames[oldpacket & UPDATE_MASK].packet_entities;
full = false;
}
else
{ // this is a full update that we can start delta compressing from now
oldp = &dummy;
dummy.num_entities = 0;
cl.oldvalidsequence = cl.validsequence;
cl.validsequence = cls.netchan.incoming_sequence;
full = true;
}
cl.oldvalidsequence = cl.validsequence;
cl.validsequence = cls.netchan.incoming_sequence;
oldindex = 0;
newindex = 0;
newp->num_entities = 0;
@ -805,9 +813,7 @@ void CLNQ_ParseDarkPlaces5Entities(void) //the things I do.. :o(
int oldi;
qboolean remove;
cls.netchan.incoming_sequence++;
cl.validsequence=1;
cl.validsequence = cls.netchan.incoming_sequence++;
cl_latestframenum = MSG_ReadLong();
@ -926,7 +932,6 @@ void CLNQ_ParseEntity(unsigned int bits)
static float lasttime;
packet_entities_t *pack;
cl.validsequence=1;
#define NQU_MOREBITS (1<<0)
#define NQU_ORIGIN1 (1<<1)
#define NQU_ORIGIN2 (1<<2)
@ -1232,7 +1237,7 @@ void CL_LinkPacketEntities (void)
dlight_t *dl;
vec3_t angles;
pack = &cl.frames[cls.netchan.incoming_sequence&UPDATE_MASK].packet_entities;
pack = &cl.frames[cl.validsequence&UPDATE_MASK].packet_entities;
autorotate = anglemod(100*cl.time);
@ -1253,7 +1258,7 @@ void CL_LinkPacketEntities (void)
CL_NewDlight (s1->number, s1->origin[0], s1->origin[1], s1->origin[2], 200 + (rand()&31), 0, 0);
// if set to invisible, skip
if (s1->modelindex<0)
if (s1->modelindex<1)
continue;
#if 0
for (spnum = 0; spnum < cl.splitclients; spnum++)
@ -1557,7 +1562,7 @@ CL_ParseProjectiles
Nails are passed as efficient temporary entities
=====================
*/
void CL_ParseProjectiles (int modelindex)
void CL_ParseProjectiles (int modelindex, qboolean nails2)
{
int i, c, j;
qbyte bits[6];
@ -1566,6 +1571,8 @@ void CL_ParseProjectiles (int modelindex)
c = MSG_ReadByte ();
for (i=0 ; i<c ; i++)
{
if (nails2)
MSG_ReadByte();
for (j=0 ; j<6 ; j++)
bits[j] = MSG_ReadByte ();
@ -2080,7 +2087,7 @@ void CL_LinkPlayers (void)
CL_NewDlight (j+1, state->origin[0], state->origin[1], state->origin[2], 200 + (rand()&31), 0.1, 0)->noppl = (j != cl.playernum[0]);
}
if (!state->modelindex)
if (state->modelindex < 1)
continue;
/*
if (!Cam_DrawPlayer(j))
@ -2442,10 +2449,22 @@ void CL_EmitEntities (void)
void CL_ParseClientdata (void);
void MVD_Interpolate(void)
{
player_state_t *self, *oldself;
CL_ParseClientdata();
self = &cl.frames[cl.parsecount & UPDATE_MASK].playerstate[cl.playernum[0]];
oldself = &cl.frames[(cls.netchan.outgoing_sequence-1) & UPDATE_MASK].playerstate[cl.playernum[0]];
self->messagenum = cl.parsecount;
VectorCopy(oldself->origin, self->origin);
VectorCopy(oldself->velocity, self->velocity);
VectorCopy(oldself->viewangles, self->viewangles);
cls.netchan.outgoing_sequence = cl.parsecount+1;
}

View File

@ -847,6 +847,8 @@ void CL_SendCmd (void)
if (cls.demoplayback == DPB_MVD)
{
i = cls.netchan.outgoing_sequence & UPDATE_MASK;
cl.frames[i].senttime = realtime; // we haven't gotten a reply yet
cl.frames[i].receivedtime = -1; // we haven't gotten a reply yet
cmd = &cl.frames[i].cmd[0];
memset(cmd, 0, sizeof(*cmd));
@ -867,7 +869,6 @@ void CL_SendCmd (void)
Cam_FinishMove(0, cmd);
cls.netchan.outgoing_sequence++;
}

View File

@ -1296,8 +1296,8 @@ void CL_Packet_f (void)
return;
}
if (Cmd_FromServer())
{
if (Cmd_FromServer()) //some mvd servers stuffcmd a packet command which lets them know which ip the client is from.
{ //unfortunatly, 50% of servers are badly configured.
if (adr.type == NA_IP)
if (adr.ip[0] == 127)
if (adr.ip[1] == 0)
@ -1307,6 +1307,8 @@ void CL_Packet_f (void)
Con_Printf ("^b^1Server is broken. Ignoring 'realip' packet request\n");
return;
}
Con_Printf ("Sending realip packet\n");
}
in = Cmd_Argv(2);

View File

@ -1258,7 +1258,8 @@ void CL_ParseServerData (void)
if (cls.demoplayback == DPB_MVD)
{
int i;
cls.netchan.last_received = MSG_ReadFloat();
extern float nextdemotime;
cls.netchan.last_received = nextdemotime = /*olddemotime =*/ MSG_ReadFloat();
cl.playernum[0] = MAX_CLIENTS - 1;
cl.spectator = true;
for (i = 0; i < UPDATE_BACKUP; i++)
@ -1732,7 +1733,7 @@ void CLNQ_ParseClientdata (int bits)
CL_SetStat(0, STAT_ROCKETS, MSG_ReadByte());
CL_SetStat(0, STAT_CELLS, MSG_ReadByte());
CL_SetStat(0, STAT_ACTIVEWEAPON, (unsigned short)MSG_ReadShort());
CL_SetStat(0, STAT_ACTIVEWEAPON, MSG_ReadByte());
}
if (bits & DPSU_VIEWZOOM)
@ -2521,6 +2522,14 @@ void CL_SetStat (int pnum, int stat, int value)
return;
// Host_EndGame ("CL_SetStat: %i is invalid", stat);
if (cls.demoplayback == DPB_MVD)
{
extern int cls_lastto;
cl.players[cls_lastto].stats[stat]=value;
if ( spec_track[pnum] != cls_lastto )
return;
}
if (cl.stats[pnum][stat] != value)
Sbar_Changed ();
@ -3698,7 +3707,10 @@ void CL_ParseServerMessage (void)
break;
case svc_nails:
CL_ParseProjectiles (cl_spikeindex);
CL_ParseProjectiles (cl_spikeindex, false);
break;
case svc_nails2:
CL_ParseProjectiles (cl_spikeindex, true);
break;
case svc_chokecount: // some preceding packets were choked
@ -4142,7 +4154,7 @@ void CLNQ_ParseServerMessage (void)
cl.gametimemark = realtime;
if (nq_dp_protocol<5)
{
cls.netchan.incoming_sequence++;
cl.validsequence = cls.netchan.incoming_sequence++;
// cl.frames[(cls.netchan.incoming_sequence-1)&UPDATE_MASK].packet_entities = cl.frames[cls.netchan.incoming_sequence&UPDATE_MASK].packet_entities;
cl.frames[cls.netchan.incoming_sequence&UPDATE_MASK].packet_entities.num_entities=0;
}

View File

@ -579,7 +579,7 @@ void CL_PredictMovePNum (int pnum)
return;
}
if (cls.netchan.outgoing_sequence - cls.netchan.incoming_sequence >= UPDATE_BACKUP-1)
if (cls.netchan.outgoing_sequence - cl.validsequence >= UPDATE_BACKUP-1)
{
return;
}
@ -597,7 +597,7 @@ void CL_PredictMovePNum (int pnum)
}
// this is the last frame received from the server
from = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
from = &cl.frames[cl.validsequence & UPDATE_MASK];
if (!cl.intermission)
{
@ -637,13 +637,13 @@ void CL_PredictMovePNum (int pnum)
}
}
#endif
if ((cl_nopred.value|| cl.fixangle))
if (((cl_nopred.value && cls.demoplayback!=DPB_MVD)|| cl.fixangle))
{
fixedorg:
VectorCopy (vel, cl.simvel[pnum]);
VectorCopy (org, cl.simorg[pnum]);
to = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
to = &cl.frames[cl.validsequence & UPDATE_MASK];
@ -655,12 +655,12 @@ fixedorg:
oldphysent = pmove.numphysent;
CL_SetSolidPlayers (cl.playernum[pnum]);
to = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK];
to = &cl.frames[cl.validsequence & UPDATE_MASK];
for (i=1 ; i<UPDATE_BACKUP-1 && cls.netchan.incoming_sequence+i <
for (i=1 ; i<UPDATE_BACKUP-1 && cl.validsequence+i <
cls.netchan.outgoing_sequence; i++)
{
to = &cl.frames[(cls.netchan.incoming_sequence+i) & UPDATE_MASK];
to = &cl.frames[(cl.validsequence+i) & UPDATE_MASK];
if (cl.intermission)
to->playerstate->pm_type = PM_FLY;
CL_PredictUsercmd (pnum, &from->playerstate[cl.playernum[pnum]]

View File

@ -156,6 +156,8 @@ typedef struct player_info_s
unsigned short vweapindex;
int prevcount;
int stats[MAX_CL_STATS];
} player_info_t;
@ -703,7 +705,7 @@ void CL_SetSolidPlayers (int playernum);
void CL_SetUpPlayerPrediction(qboolean dopred);
void CL_EmitEntities (void);
void CL_ClearProjectiles (void);
void CL_ParseProjectiles (int modelindex);
void CL_ParseProjectiles (int modelindex, qboolean nails2);
void CL_ParsePacketEntities (qboolean delta);
void CL_SetSolidEntities (void);
void CL_ParsePlayerinfo (void);

View File

@ -322,7 +322,7 @@ static void Stats_LoadFragFile(char *name)
if (!*file)
break;
Cmd_TokenizeString(file);
Cmd_TokenizeString(file, true, false);
file = end+1;
if (!Cmd_Argc())
continue;

View File

@ -869,7 +869,7 @@ void Key_Bind_f (void)
if (c > 3)
{
Cmd_ShiftArgs(1);
Cmd_ShiftArgs(1, Cmd_ExecLevel==RESTRICT_LOCAL);
Key_SetBinding (b, modifier, Cmd_Args(), Cmd_ExecLevel);
return;
}

View File

@ -142,6 +142,33 @@ void PF_loadfromdata (progfuncs_t *prinst, struct globalvars_s *pr_globals)
G_FLOAT(OFS_RETURN) = 0;
}
void PF_parseentitydata(progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
void *ed = G_EDICT(prinst, OFS_PARM0);
char *file = PR_GetStringOfs(prinst, OFS_PARM1);
int size;
if (!*file)
{
G_FLOAT(OFS_RETURN) = -1;
return;
}
if (!prinst->restoreent(prinst, file, &size, ed))
Con_Printf("parseentitydata: missing opening data\n");
else
{
file += size;
while(*file < ' ' && *file)
file++;
if (*file)
Con_Printf("parseentitydata: too much data\n");
}
G_FLOAT(OFS_RETURN) = 0;
}
void PF_mod (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_FLOAT(OFS_RETURN) = (float)(((int)G_FLOAT(OFS_PARM0))%((int)G_FLOAT(OFS_PARM1)));
@ -885,6 +912,18 @@ void PF_etof(progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
G_FLOAT(OFS_RETURN) = G_EDICTNUM(prinst, OFS_PARM0);
}
void PF_ftoe(progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int entnum = G_FLOAT(OFS_PARM0);
RETURN_EDICT(prinst, EDICT_NUM(prinst, entnum));
}
void PF_IsNull(progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int str = G_INT(OFS_PARM0);
G_FLOAT(OFS_RETURN) = !str;
}
builtin_t menu_builtins[] = {
//0
@ -977,7 +1016,16 @@ builtin_t menu_builtins[] = {
PF_chr2str,//8
PF_etof,//9 //float etof(entity ent) = #79;
//80
skip10
PF_ftoe,//10
PF_IsNull,
skip1
skip1
skip1
skip1
skip1
skip1
skip1
skip1
//90
skip10
//100
@ -1033,7 +1081,7 @@ builtin_t menu_builtins[] = {
PF_CL_findkeysforcommand,
PF_gethostcachevalue,
PF_gethostcachestring,
PF_Fixme //void parseentitydata(entity ent, string data) = #613;
PF_parseentitydata //void parseentitydata(entity ent, string data) = #613;
};
int menu_numbuiltins = sizeof(menu_builtins)/sizeof(menu_builtins[0]);
@ -1084,6 +1132,8 @@ void MP_Shutdown (void)
mouseusedforgui = false;
M_Init_Internal();
if (inmenuprogs) //something in the menu caused the problem, so...
{
inmenuprogs = 0;
@ -1108,6 +1158,14 @@ void VARGS Menu_Abort (char *format, ...)
Con_Printf("Menu_Abort: %s\nShutting down menu.dat\n", string);
{
static char buffer[1024*1024*8];
int size = sizeof buffer;
menuprogs->save_ents(menuprogs, buffer, &size, 3);
COM_WriteFile("menucore.txt", buffer, size);
}
MP_Shutdown();
}

View File

@ -368,7 +368,7 @@ void R_ParticleEffect_f(void)
return;
}
Cmd_TokenizeString(buf);
Cmd_TokenizeString(buf, true, true);
var = Cmd_Argv(0);
value = Cmd_Argv(1);

View File

@ -2,6 +2,7 @@
char *particle_set_spikeset =
#if 0
"r_part rockettail\n"
"{\n"
" texture \"particles/rtrail\"\n"
@ -37,7 +38,47 @@ char *particle_set_spikeset =
" blend add\n"
" assoc rockettail\n"
"}\n"
"\n"
#else
"r_part t_rocket\n"
"{\n"
" texture \"\"\n"
" gravity -200\n"
" step 40\n"
" scale 10\n"
" scaledelta 50\n"
" alpha 0.5\n"
" die 0.5\n"
" red 254\n"
" green 128\n"
" blue 64\n"
" blend add\n"
" isbeam\n"
" spawnmode spiral\n"
" offsetspread 5\n"
"}\n"
#endif
//TeamFortress railgun (by model - this is also the effect used with the TE_LIGHTNING1 extension)
"r_part t_railtrail\n"
"{\n"
" texture \"particles/b_rocket3\"\n"
" step 15\n"
" scale 10\n"
" alpha 1\n"
" die 1\n"
" red 255\n"
" green 255\n"
" blue 255\n"
" blend add\n"
" isbeam\n"
" spawnmode spiral\n"
" offsetspread 100\n"
" cliptype t_railtrail\n"
" friction 0.7\n"
"}\n"
"r_trail progs/e_spike1.mdl t_railtrail\n"
"r_part t_grenade\n"
"{\n"
" texture \"particles/rtrail\"\n"
@ -245,6 +286,8 @@ char *particle_set_spikeset =
" emitintervalrand 0\n"
"}\n"
"\n"
//fixme: 16?!?!
"r_part te_explosion\n"
"{\n"
" texture \"particles/explosion\"\n"
@ -269,29 +312,7 @@ char *particle_set_spikeset =
" scalefactor 1\n"
"}\n"
"\n"
"r_part cte_greenexplosion\n"
"{\n"
" texture \"particles/explosion\"\n"
" count 16\n"
" scale 100\n"
" alpha 0.7\n"
" die 4\n"
" randomvel 32\n"
" veladd 0\n"
" red 128\n"
" green 255\n"
" blue 76\n"
" reddelta 0\n"
" greendelta 0\n"
" reddelta 0\n"
" gravity 0\n"
"friction 1\n"
" stains 0\n"
" blend add\n"
" assoc shrapnal\n"
" scalefactor 1\n"
"}\n"
"\n"
"r_part empcentral\n"
"{\n"
" texture \"particles/emp\"\n"
@ -429,7 +450,7 @@ char *particle_set_spikeset =
"r_part te_teleportsplash\n"
"{\n"
" texture \"particles/teleport\"\n"
" count 4192\n"
" count 4192\n" //EGAD!!!! 4192?!??! What was I thinking?!?!? (it's a very pwetty effect though...)
" scale 2\n"
" scalefactor 1\n"
" alpha 1\n"

View File

@ -1099,7 +1099,7 @@ static void TP_LoadLocFile (char *filename, qbool quiet)
}
line[i] = 0;
Cmd_TokenizeString (line);
Cmd_TokenizeString (line, true, false);
argc = Cmd_Argc();
if (!argc)

View File

@ -965,7 +965,7 @@ Cmd_ShiftArgs
Shifts Cmd_Argv results down one (killing first param)
============
*/
void Cmd_ShiftArgs (int ammount)
void Cmd_ShiftArgs (int ammount, qboolean expandstring)
{
int arg;
while (ammount>0 && cmd_argc)
@ -984,7 +984,7 @@ void Cmd_ShiftArgs (int ammount)
if (cmd_args)
{
cmd_args = COM_StringParse(cmd_args);
cmd_args = COM_StringParse(cmd_args, expandstring, false);
if (cmd_args)
while(*cmd_args == ' ')
cmd_args++;
@ -1114,7 +1114,7 @@ Cmd_TokenizeString
Parses the given string into command line tokens.
============
*/
void Cmd_TokenizeString (char *text)
void Cmd_TokenizeString (char *text, qboolean expandmacros, qboolean qctokenize)
{
int i;
@ -1144,8 +1144,8 @@ void Cmd_TokenizeString (char *text)
if (cmd_argc == 1)
cmd_args = text;
text = COM_StringParse (text);
text = COM_StringParse (text, expandmacros, qctokenize);
if (!text)
return;
@ -1581,7 +1581,7 @@ void Cmd_ExecuteString (char *text, int level)
Cmd_ExecLevel = level;
text = Cmd_ExpandString(text, dest, sizeof(dest), level);
Cmd_TokenizeString (text);
Cmd_TokenizeString (text, level == RESTRICT_LOCAL, false);
// execute the command line
if (!Cmd_Argc())

View File

@ -101,7 +101,7 @@ int Cmd_CheckParm (char *parm);
char *Cmd_AliasExist(char *name, int restrictionlevel);
void Alias_WipeStuffedAliaes(void);
void Cmd_TokenizeString (char *text);
void Cmd_TokenizeString (char *text, qboolean expandmacros, qboolean qctokenize);
// Takes a null terminated string. Does not need to be /n terminated.
// breaks the string up into arg tokens.
@ -131,7 +131,7 @@ void Cmd_MessageTrigger (char *message, int type);
void Cmd_StuffCmds_f (void);
void Cmd_ShiftArgs (int ammount);
void Cmd_ShiftArgs (int ammount, qboolean expandstring);
char *Cmd_ExpandString (char *data, char *dest, int destlen, int maxaccesslevel);

View File

@ -1428,7 +1428,7 @@ skipwhite:
}
//same as COM_Parse, but parses two quotes next to each other as a single quote as part of the string
char *COM_StringParse (char *data)
char *COM_StringParse (char *data, qboolean expandmacros, qboolean qctokenize)
{
int c;
int len;
@ -1442,7 +1442,7 @@ char *COM_StringParse (char *data)
// skip whitespace
skipwhite:
while ( (c = *data) <= ' ')
while ( (c = *data), c <= ' ' && c != '\n')
{
if (c == 0)
return NULL; // end of file;
@ -1501,6 +1501,54 @@ skipwhite:
}
}
// handle quoted strings specially
if (c == '\'' && qctokenize)
{
data++;
while (1)
{
if (len >= TOKENSIZE-1)
{
com_token[len] = '\0';
return data;
}
c = *data++;
if (c=='\'')
{
c = *(data);
if (c!='\'')
{
com_token[len] = 0;
return data;
}
while (c=='\'')
{
com_token[len] = c;
len++;
data++;
c = *(data+1);
}
}
if (!c)
{
com_token[len] = 0;
return data;
}
com_token[len] = c;
len++;
}
}
if (qctokenize && (c == '\n' || c == '{' || c == '}' || c == ')' || c == '(' || c == ']' || c == '[' || c == '\'' || c == ':' || c == ',' || c == ';'))
{
// single character
com_token[len++] = c;
com_token[len] = 0;
return data+1;
}
// parse a regular word
do
{
@ -1514,16 +1562,13 @@ skipwhite:
data++;
len++;
c = *data;
} while (c>32);
} while (c>32 && !(qctokenize && (c == '\n' || c == '{' || c == '}' || c == ')' || c == '(' || c == ']' || c == '[' || c == '\'' || c == ':' || c == ',' || c == ';')));
com_token[len] = 0;
#ifndef CLIENTONLY
{
extern redirect_t sv_redirected;
if (sv_redirected) //servers shouldn't give the values of cvars to all clients... Like password...
if (!expandmacros)
return data;
}
#endif
//now we check for macros.
for (s = com_token, c= 0; c < len; c++, s++) //this isn't a quoted token by the way.
{

View File

@ -202,7 +202,7 @@ extern qboolean com_eof;
char *COM_Parse (char *data);
char *COM_ParseCString (char *data);
char *COM_StringParse (char *data);
char *COM_StringParse (char *data, qboolean expandmacros, qboolean qctokenize);
char *COM_ParseToken (char *data);
char *COM_TrimString(char *str);

View File

@ -556,6 +556,11 @@ iwboolean FTP_ServerThinkForConnection(FTPclient_t *cl)
strcpy(buffer, cl->path+1);
else
strcpy(buffer, cl->path);
if (*buffer) //last characture should be a /
if (buffer[strlen(buffer)-1] != '/')
strcat(buffer, "/");
strcat(buffer, "*");
QueueMessage (cl, "125 Opening FAKE ASCII mode data connection for file.\r\n");

View File

@ -121,7 +121,13 @@ struct edict_s *ED_Alloc (progfuncs_t *progfuncs)
}
if (i >= maxedicts-1)
{
int size;
char *buf;
buf = progfuncs->save_ents(progfuncs, NULL, &size, 0);
progfuncs->parms->WriteFile("edalloc.dump", buf, size);
Sys_Error ("ED_Alloc: no free edicts");
}
}
sv_num_edicts++;
@ -1348,6 +1354,99 @@ char *ED_WriteEdict(progfuncs_t *progfuncs, edictrun_t *ed, char *buffer, pbool
#undef AddS
}
char *SaveCallStack (progfuncs_t *progfuncs, char *s)
{
#define AddS(str) strcpy(s, str);s+=strlen(str);
char buffer[8192];
dfunction_t *f;
int i;
int progs;
int arg;
int *globalbase;
progs = -1;
if (pr_depth == 0)
{
AddS ("<NO STACK>\n");
return s;
}
globalbase = (int *)pr_globals + pr_xfunction->parm_start + pr_xfunction->locals;
pr_stack[pr_depth].f = pr_xfunction;
for (i=pr_depth ; i>0 ; i--)
{
f = pr_stack[i].f;
if (!f)
{
AddS ("<NO FUNCTION>\n");
}
else
{
if (pr_stack[i].progsnum != progs)
{
progs = pr_stack[i].progsnum;
sprintf(buffer, "//%i %s\n", progs, pr_progstate[progs].filename);
AddS (buffer);
}
if (!*f->s_file)
sprintf(buffer, "\t\"%i:%s\"\n", progs, f->s_name);
else
sprintf(buffer, "\t\"%i:%s\" //%s\n", progs, f->s_name, f->s_file);
AddS (buffer);
AddS ("\t{\n");
for (arg = 0; arg < f->locals; arg++)
{
ddef16_t *local;
local = ED_GlobalAtOfs16(progfuncs, f->parm_start+arg);
if (!local)
sprintf(buffer, "\t\tofs%i %i // %f\n", f->parm_start+arg, *(int *)(globalbase - f->locals+arg), *(float *)(globalbase - f->locals+arg) );
else
{
__try
{
if (local->type == ev_entity)
{ //go safly.
int n;
sprintf(buffer, "\t\t\"%s\"\t\"entity INVALID POINTER\"\n", local->s_name, n);
for (n = 0; n < sv_num_edicts; n++)
{
if (prinst->edicttable[n] == (struct edict_s *)PROG_TO_EDICT(((eval_t*)(globalbase - f->locals+arg))->edict))
{
sprintf(buffer, "\t\t\"%s\" \"entity %i\"\n", local->s_name, n);
break;
}
}
}
else
sprintf(buffer, "\t\t\"%s\"\t\"%s\"\n", local->s_name, PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase - f->locals+arg)));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
sprintf(buffer, "\t\t\"%s\" \"ILLEGAL POINTER\"\n", local->s_name);
}
if (local->type == ev_vector)
arg+=2;
}
AddS (buffer);
}
AddS ("\t}\n");
if (i == pr_depth)
globalbase = localstack + localstack_used - f->locals;
else
globalbase -= f->locals;
}
}
return s;
#undef AddS
}
//there are two ways of saving everything.
//0 is to save just the entities.
//1 is to save the entites, and all the progs info so that all the variables are saved off, and it can be reloaded to exactly how it was (provided no files or data has been changed outside, like the progs.dat for example)
@ -1413,7 +1512,6 @@ char *SaveEnts(progfuncs_t *progfuncs, char *mem, int *len, int alldata)
if (alldata)
{
AddS("general {\n");
AddS(qcva("\"maxprogs\" \"%i\"\n", maxprogs));
// AddS(qcva("\"maxentities\" \"%i\"\n", maxedicts));
@ -1438,6 +1536,14 @@ char *SaveEnts(progfuncs_t *progfuncs, char *mem, int *len, int alldata)
}
}
if (alldata == 3)
{
//include callstack
AddS("stacktrace {\n");
s = SaveCallStack(progfuncs, s);
AddS("}\n");
}
for (a = 0; a < maxprogs; a++) //I would mix, but external functions rely on other progs being loaded
{
if (!pr_progstate[a].progs)
@ -2003,8 +2109,6 @@ struct edict_s *RestoreEnt (progfuncs_t *progfuncs, char *buf, int *size, struct
ent = (edictrun_t *)ed;
ent->isfree = false;
ED_ClearEdict(progfuncs, ent);
buf = ED_ParseEdict(progfuncs, buf, ent);
*size = buf - start;

View File

@ -241,9 +241,14 @@ int PR_EnterFunction (progfuncs_t *progfuncs, dfunction_t *f, int progsnum)
pr_depth++;
if (pr_depth == MAX_STACK_DEPTH)
{
printf ("stack overflow on call to %s", f->s_name);
pr_depth--;
PR_StackTrace (progfuncs);
printf ("stack overflow on call to %s\n", f->s_name);
//comment this out if you want the progs to try to continue anyway (could cause infinate loops)
Abort("Stack Overflow\n");
PR_AbortStack(progfuncs);
return pr_xstatement;
}

View File

@ -363,7 +363,7 @@ vars(prstack_t, pr_stack, MAX_STACK_DEPTH);
var(int, pr_depth);
#define pr_depth prinst->pr_depth
#define LOCALSTACK_SIZE 16384
#define LOCALSTACK_SIZE 4096
vars(int, localstack, LOCALSTACK_SIZE);
#define localstack prinst->localstack
var(int, localstack_used);

View File

@ -2704,7 +2704,7 @@ void Draw_CharToDrawable (int num, unsigned int *drawable, int x, int y, int wid
if (s > e)
return;
if (y >= height)
if (y >= height-e)
return;
if (y < -8)
return;
@ -2819,13 +2819,13 @@ void XR_PolyText(xclient_t *cl, xReq *request)
while(1)
{
charnum = 0;
charnum |= *str++;
if (req->reqType == X_ImageText16)
charnum |= (*str++)<<8;
charnum |= *str++;
if (!charnum)
return;
Draw_CharToDrawable(charnum, (unsigned int *)drbuffer, xpos, ypos, drwidth, drheight, gc);
Draw_CharToDrawable(charnum&255, (unsigned int *)drbuffer, xpos, ypos, drwidth, drheight, gc);
xpos += 8;
}
@ -2877,6 +2877,8 @@ void XR_QueryFont(xclient_t *cl, xReq *request) //basically ignored. We only sup
{
// xResourceReq *req = (xResourceReq *)request;
char buffer[8192];
int i;
xCharInfo *ci;
xQueryFontReply *rep = (xQueryFontReply *)buffer;
rep->type = X_Reply;
@ -2910,13 +2912,23 @@ void XR_QueryFont(xclient_t *cl, xReq *request) //basically ignored. We only sup
rep->drawDirection = 0;
rep->minByte1 = 0;
rep->maxByte1 = 0;
rep->allCharsExist = 1;
rep->allCharsExist = 0;
rep->fontAscent = 4;
rep->fontDescent = 4;
rep->nCharInfos = 0; /* followed by this many xCharInfo structures */
rep->nCharInfos = 255; /* followed by this many xCharInfo structures */
rep->length = ((sizeof(xQueryFontReply) - sizeof(xGenericReply)) + rep->nFontProps*sizeof(xFontProp) + rep->nCharInfos*sizeof(xCharInfo))/4;
ci = (xCharInfo*)(rep+1);
for (i = 0; i < rep->nCharInfos; i++)
{
ci[i].leftSideBearing = 0;
ci[i].rightSideBearing = 0;
ci[i].characterWidth = 8;
ci[i].ascent = 4;
ci[i].descent = 4;
}
X_SendData(cl, rep, sizeof(xGenericReply)+rep->length*4);
}

View File

@ -1294,18 +1294,18 @@ void NPP_MVDFlush(void)
if (1)
{
int entnum, i;
entity_state_t *ent;
mvdentity_state_t *ent;
if (!sv.demostate)
sv.demostate = BZ_Malloc(sizeof(entity_state_t)*MAX_EDICTS);
sv.demostatevalid = true;
if (!sv.demobaselines)
{
sv.demobaselines = (mvdentity_state_t*)BZ_Malloc(sizeof(mvdentity_state_t)*MAX_EDICTS);
sv.demostatevalid = true;
}
entnum = buffer[1] + (buffer[2]<<8);
// if (entnum < MAX_CLIENTS)
// break;
ent = &sv.demostate[entnum];
ent = &sv.demobaselines[entnum];
ent->number = entnum;
ent->modelindex = buffer[3];
ent->frame = buffer[4];
ent->colormap = buffer[5];
@ -1314,7 +1314,7 @@ void NPP_MVDFlush(void)
for (i=0 ; i<3 ; i++)
{
ent->origin[i] = (short)(buffer[7+i*3] + (buffer[8+i*3]<<8))/8.0f;
ent->angles[i] = buffer[9+i*3]*360.0/256;
ent->angles[i] = buffer[9+i*3];
}
}
break;
@ -1412,11 +1412,14 @@ void NPP_MVDFlush(void)
ignoreprotocol=true; //a bug exists in that the delta MUST have been reliably recorded.
{
int i;
entity_state_t *ents;
int entnum;
mvdentity_state_t *ents;
unsigned short s;
if (!sv.demostate)
sv.demostate = BZ_Malloc(sizeof(entity_state_t)*MAX_EDICTS);
sv.demostatevalid = true;
{
sv.demostate = BZ_Malloc(sizeof(mvdentity_state_t)*MAX_EDICTS);
sv.demostatevalid = true;
}
i = majortype-svc_packetentities+1;
while (1)
{
@ -1428,14 +1431,25 @@ void NPP_MVDFlush(void)
}
else
{
ents = &sv.demostate[s&511];
ents->number = s&511;
entnum = s&511;
s &= ~511;
if (entnum > sv.demomaxents)
sv.demomaxents = entnum;
ents = &sv.demostate[entnum];
if (s & U_REMOVE)
{
{ //this entity went from the last packet
ents->modelindex = 0;
ents->effects = 0;
continue;
}
if (!ents->modelindex && !ents->effects && sv.demobaselines)
{ //new entity, reset to baseline
memcpy(ents, &sv.demobaselines[entnum], sizeof(mvdentity_state_t));
}
if (s & U_MOREBITS)
{
s |= buffer[i];
@ -1480,7 +1494,7 @@ void NPP_MVDFlush(void)
if (s & U_ANGLE1)
{
ents->angles[0] = (unsigned char)(buffer[i]) * (360.0/256);
ents->angles[0] = (unsigned char)(buffer[i]);// * (360.0/256);
i++;
}
@ -1492,7 +1506,7 @@ void NPP_MVDFlush(void)
if (s & U_ANGLE2)
{
ents->angles[1] = (unsigned char)(buffer[i]) * (360.0/256);
ents->angles[1] = (unsigned char)(buffer[i]);// * (360.0/256);
i++;
}
@ -1504,7 +1518,7 @@ void NPP_MVDFlush(void)
if (s & U_ANGLE3)
{
ents->angles[2] = (unsigned char)(buffer[i]) * (360.0/256);
ents->angles[2] = (unsigned char)(buffer[i]);// * (360.0/256);
i++;
}
}
@ -1516,7 +1530,7 @@ void NPP_MVDFlush(void)
{
int i, j;
unsigned short flags;
entity_state_t *ents;
mvdentity_state_t *ents;
int wframe, playernum;
vec3_t oldorg;
vec3_t oldang;
@ -1549,7 +1563,8 @@ void NPP_MVDFlush(void)
for (j=0 ; j<3 ; j++)
if (flags & (DF_ANGLES << j))
{
ents->angles[j] = (int)(buffer[i] + (buffer[i+1]<<8))*360.0f/(256*256);
//FIXME: angle truncation here.
ents->angles[j] = (int)(buffer[i] + (buffer[i+1]<<8))/256;
i+=2;
}
@ -1620,7 +1635,7 @@ void NPP_MVDFlush(void)
case svc_stufftext:
ignoreprotocol = true;
Cmd_TokenizeString(buffer+1);
Cmd_TokenizeString(buffer+1, false, false);
if (!stricmp(Cmd_Argv(0), "fullserverinfo"))
{
Q_strncpyz(sv.demoinfo, Cmd_Argv(1), sizeof(sv.demoinfo));

View File

@ -3474,7 +3474,14 @@ void PF_walkmove (progfuncs_t *prinst, struct globalvars_s *pr_globals)
// oldf = pr_xfunction;
oldself = pr_global_struct->self;
G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
if (!SV_TestEntityPosition(ent))
{
G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true, false, settrace);
if (SV_TestEntityPosition(ent))
Con_Printf("Entity became stuck\n");
}
else
Con_Printf("Ent is stuck - sorry\n");
// restore program state
@ -3502,7 +3509,7 @@ void PF_droptofloor (progfuncs_t *prinst, struct globalvars_s *pr_globals)
end[2] -= 512;
VectorCopy (ent->v.origin, start);
trace = SV_Move (start, ent->v.mins, ent->v.maxs, end, false, ent);
trace = SV_Move (start, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
if (trace.fraction == 1 || trace.allsolid)
G_FLOAT(OFS_RETURN) = 0;
@ -3510,7 +3517,7 @@ void PF_droptofloor (progfuncs_t *prinst, struct globalvars_s *pr_globals)
{
VectorCopy (trace.endpos, ent->v.origin);
SV_LinkEdict (ent, false);
// ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
ent->v.groundentity = EDICT_TO_PROG(prinst, trace.ent);
G_FLOAT(OFS_RETURN) = 1;
}
@ -5396,9 +5403,9 @@ void PF_fgets (progfuncs_t *prinst, struct globalvars_s *pr_globals)
pf_fopen_files[fnum].ofs = s - pf_fopen_files[fnum].data;
if (!pr_string_temp[0] && !*s)
G_INT(OFS_PARM0) = 0; //EOF
G_INT(OFS_RETURN) = 0; //EOF
else
RETURN_SSTRING(pr_string_temp);
G_INT(OFS_RETURN) = (int)pr_string_temp - prinst->stringtable;
}
void PF_fputs (progfuncs_t *prinst, struct globalvars_s *pr_globals)
@ -5776,7 +5783,7 @@ void PF_ArgC (progfuncs_t *prinst, struct globalvars_s *pr_globals) //85 /
//KRIMZON_SV_PARSECLIENTCOMMAND added these two.
void PF_Tokenize (progfuncs_t *prinst, struct globalvars_s *pr_globals) //84 //void(string str) tokanize;
{
Cmd_TokenizeString(PR_GetStringOfs(prinst, OFS_PARM0));
Cmd_TokenizeString(PR_GetStringOfs(prinst, OFS_PARM0), false, true);
G_FLOAT(OFS_RETURN) = Cmd_Argc();
}
void PF_ArgV (progfuncs_t *prinst, struct globalvars_s *pr_globals) //86 //string(float num) argv;

View File

@ -80,6 +80,23 @@ typedef struct {
#define CTE_CHANNELFADE 16
#define CTE_ISBEAM 128
typedef struct
{
vec3_t origin;
qbyte angles[3];
qbyte modelindex;
qbyte frame;
qbyte colormap;
qbyte skinnum;
qbyte effects;
qbyte scale;
qbyte trans;
qbyte fatness;
} mvdentity_state_t;
typedef struct
{
qboolean active; // false when server is going down
@ -175,7 +192,9 @@ typedef struct
qboolean mvdrecording;
//====================================================
//this lot is for playback of demos
qboolean mvdplayback;
float realtime;
FILE *demofile; //also signifies playing the thing.
@ -183,6 +202,7 @@ typedef struct
int lasttype;
int lastto;
//playback spikes (svc_nails/nails2)
int numdemospikes;
struct {
vec3_t org;
@ -191,9 +211,14 @@ typedef struct
qbyte yaw;
qbyte modelindex;
} demospikes[255];
entity_state_t *demostate;
//playback of entities (svc_nails/nails2)
mvdentity_state_t *demostate;
mvdentity_state_t *demobaselines;
int demomaxents;
qboolean demostatevalid;
char demoinfo[MAX_SERVERINFO_STRING];
//players
struct {
int stats[MAX_CL_STATS];
int pl;
@ -207,11 +232,14 @@ typedef struct
float updatetime;
} recordedplayer[MAX_CLIENTS];
//gamestate
char demoinfo[MAX_SERVERINFO_STRING];
char demmodel_precache[MAX_MODELS][MAX_QPATH]; // NULL terminated
char demsound_precache[MAX_SOUNDS][MAX_QPATH]; // NULL terminated
char demgamedir[64];
char demname[64]; // map name
qboolean democausesreconnect; //make players load the level.
qboolean democausesreconnect; //this makes current clients go through the connection process (and when the demo ends too)
sizebuf_t demosignon;
int num_demosignon_buffers;
int demosignon_buffer_size[MAX_SIGNON_BUFFERS];
@ -219,6 +247,7 @@ typedef struct
char demfullmapname[64];
char *demolightstyles[MAX_LIGHTSTYLES];
//====================================================
entity_state_t extendedstatics[MAX_STATIC_ENTITIES];
int numextrastatics;

View File

@ -751,12 +751,12 @@ void SV_StuffToClient_f(void)
char *c;
char *key;
Cmd_ShiftArgs(1);
Cmd_ShiftArgs(1, Cmd_ExecLevel==RESTRICT_LOCAL);
if (!strcmp(Cmd_Argv(1), "bind"))
{
key = Z_Malloc(strlen(Cmd_Argv(2))+1);
strcpy(key, Cmd_Argv(2));
Cmd_ShiftArgs(2);
Cmd_ShiftArgs(2, Cmd_ExecLevel==RESTRICT_LOCAL);
}
else
key = NULL;
@ -1169,7 +1169,7 @@ void SV_SaveInfo(FILE *f, char *info, char *commandname)
command = info+1;
value = strchr(command, '\\');
info = strchr(value+1, '\\');
if (!*info) //eot..
if (!info) //eot..
info = value+strlen(value);
if (*command == '*') //unsettable, so don't write it for later setting.
@ -1496,7 +1496,7 @@ void SV_SetTimer_f(void)
return;
}
Cmd_ShiftArgs(2); //strip the two vars
Cmd_ShiftArgs(2, Cmd_ExecLevel==RESTRICT_LOCAL); //strip the two vars
command = Cmd_Args();
timercommand = Cvar_Get("sv_timer", "", CVAR_NOSET, NULL);

View File

@ -225,6 +225,14 @@ void SV_LoadClientDemo_f (void)
SV_ReadMVD();
}
if (!sv.state)
Cmd_ExecuteString("map start\n", Cmd_ExecLevel); //go for the start map
if (!sv.state)
{
Con_Printf("Could not activate server\n");
return;
}
demoname = Cmd_Argv(1);
com_filesize = COM_FOpenFile(demoname, &svd.demofile);
@ -312,7 +320,7 @@ qboolean SV_RunDemo (void)
float demotime;
qbyte c;
// usercmd_t *pcmd;
usercmd_t emptycmd;
// usercmd_t emptycmd;
static float prevtime = 0.0;
qbyte newtime;
@ -376,11 +384,18 @@ readnext:
switch (c & 7) {
case dem_cmd :
Con_Printf ("dem_cmd not supported\n");
fclose(svd.demofile);
svd.demofile = NULL;
return false;
// user sent input
// i = svd.netchan.outgoing_sequence & UPDATE_MASK;
// pcmd = &cl.frames[i].cmd;
if ((r = fread (&emptycmd, sizeof(emptycmd), 1, svd.demofile)) != 1)
SV_Error ("Corrupted demo");
// if ((r = fread (&emptycmd, sizeof(emptycmd), 1, svd.demofile)) != 1)
// SV_Error ("Corrupted demo");
/*
// qbyte order stuff
for (j = 0; j < 3; j++)
@ -393,7 +408,7 @@ readnext:
cl.frames[i].receivedtime = -1; // we haven't gotten a reply yet
svd.netchan.outgoing_sequence++;
*/
fread (&emptycmd, 12, 1, svd.demofile);
// fread (&emptycmd, 12, 1, svd.demofile);
/* for (j = 0; j < 3; j++)
cl.viewangles[i] = LittleFloat (cl.viewangles[i]);
if (cl.spectator)

View File

@ -278,6 +278,10 @@ void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qb
int i;
float miss;
static entity_state_t defaultbaseline;
if (from == &((edict_t*)NULL)->baseline)
from = &defaultbaseline;
// send an update
bits = 0;
@ -1028,6 +1032,9 @@ void SV_WritePlayersToClient (client_t *client, edict_t *clent, qbyte *pvs, size
client_t *cl;
edict_t *ent, *vent;
int pflags;
vec3_t lerpedang;
int splitnum = 0;
demo_frame_t *demo_frame;
demo_client_t *dcl;
@ -1194,7 +1201,10 @@ void SV_WritePlayersToClient (client_t *client, edict_t *clent, qbyte *pvs, size
clst.zext = client->zquake_extensions;
clst.cl = NULL;
VectorMA(sv.demostate[i+1].angles, realtime - sv.recordedplayer[i].updatetime, sv.recordedplayer[i].avelocity, ang);
ang[0] = sv.demostate[i+1].angles[0]*360.0f/256+ (realtime - sv.recordedplayer[i].updatetime)*sv.recordedplayer[i].avelocity[0];
ang[1] = sv.demostate[i+1].angles[1]*360.0f/256+ (realtime - sv.recordedplayer[i].updatetime)*sv.recordedplayer[i].avelocity[1];
ang[2] = sv.demostate[i+1].angles[2]*360.0f/256+ (realtime - sv.recordedplayer[i].updatetime)*sv.recordedplayer[i].avelocity[2];
VectorMA(sv.demostate[i+1].origin, realtime - sv.recordedplayer[i].updatetime, sv.recordedplayer[i].velocity, org);
ang[0] *= -3;
@ -1221,7 +1231,19 @@ void SV_WritePlayersToClient (client_t *client, edict_t *clent, qbyte *pvs, size
SV_WritePlayerToClient(msg, &clst);
}
if (ent != clent)
splitnum = 0;
if (cl->controlled)
{ //hrm. splitscreen.
client_t *s;
for (s = cl; s; s = s->controlled, splitnum++)
{
if (s->edict == ent)
break;
}
if (!s)
continue;
}
else if (ent != clent)
continue;
}
@ -1314,7 +1336,7 @@ void SV_WritePlayersToClient (client_t *client, edict_t *clent, qbyte *pvs, size
clst.health = 100;
if (sv.demostatevalid)
clst.playernum = MAX_CLIENTS-1;
clst.playernum = MAX_CLIENTS-1-splitnum;
clst.isself = false;
if ((cl == client || cl->controller == client) && !sv.demostatevalid)
@ -1343,7 +1365,10 @@ void SV_WritePlayersToClient (client_t *client, edict_t *clent, qbyte *pvs, size
{
clst.origin = sv.demostate[client->spec_track].origin;
clst.velocity = sv.recordedplayer[client->spec_track-1].velocity;
clst.angles = sv.demostate[client->spec_track].angles;
clst.angles = lerpedang;
lerpedang[0] = sv.demostate[client->spec_track].angles[0]*360.0/256;
lerpedang[1] = sv.demostate[client->spec_track].angles[1]*360.0/256;
lerpedang[2] = sv.demostate[client->spec_track].angles[2]*360.0/256;
}
clst.spectator = 2;
}
@ -1704,7 +1729,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
vec3_t org;
edict_t *ent;
packet_entities_t *pack;
entity_state_t *dement;
mvdentity_state_t *dement;
edict_t *clent;
client_frame_t *frame;
entity_state_t *state;
@ -1779,7 +1804,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
if (sv.demostatevalid) //generate info from demo stats
{
for (e=1, dement=&sv.demostate[e] ; e<sv.num_edicts ; e++, dement++)
for (e=1, dement=&sv.demostate[e] ; e<=sv.demomaxents ; e++, dement++)
{
if (!dement->modelindex)
continue;
@ -1805,7 +1830,9 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
state->number = e;
state->flags = EF_DIMLIGHT;
VectorCopy (dement->origin, state->origin);
VectorCopy (dement->angles, state->angles);
state->angles[0] = dement->angles[0]*360.0f/256;
state->angles[1] = dement->angles[1]*360.0f/256;
state->angles[2] = dement->angles[2]*360.0f/256;
state->modelindex = dement->modelindex;
state->frame = dement->frame;
state->colormap = dement->colormap;
@ -1817,8 +1844,6 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
#endif
#ifdef PEXT_TRANS
state->trans = dement->trans;
if (!state->trans)
state->trans = 1;
#endif
#ifdef PEXT_FATNESS
state->fatness = dement->fatness;

View File

@ -649,7 +649,7 @@ void SVC_Status (void)
int slots=0;
Cmd_TokenizeString ("status");
Cmd_TokenizeString ("status", false, false);
SV_BeginRedirect (RD_PACKET);
Con_Printf ("%s\n", svs.info);
for (i=0 ; i<MAX_CLIENTS ; i++)
@ -1132,7 +1132,7 @@ void SVC_DirectConnect
{
while(!msg_badread)
{
Cmd_TokenizeString(MSG_ReadStringLine());
Cmd_TokenizeString(MSG_ReadStringLine(), false, false);
switch(Q_atoi(Cmd_Argv(0)))
{
case PROTOCOL_VERSION_FTE:
@ -1979,7 +1979,7 @@ qboolean SV_ConnectionlessPacket (void)
s = MSG_ReadStringLine ();
Cmd_TokenizeString (s);
Cmd_TokenizeString (s, false, false);
c = Cmd_Argv(0);
@ -2020,7 +2020,7 @@ qboolean SV_ConnectionlessPacket (void)
{
//these messages contain the ip address that it was origionally from (before being farmed out)
NET_StringToAdr(Cmd_Argv(1), &net_from);
Cmd_ShiftArgs(1); //get rid of the ip address...
Cmd_ShiftArgs(1, false); //get rid of the ip address...
#ifdef NQPROT
SVC_DirectConnect (sock);
#else
@ -2721,6 +2721,11 @@ void SV_Frame (float time)
SVM_Think(PORT_MASTER);
}
{
void SV_MVDStream_Poll(void);
SV_MVDStream_Poll();
}
if (sv.state < ss_active)
{
#ifndef SERVERONLY

View File

@ -220,6 +220,8 @@ cvar_t sv_demoNoVis = {"sv_demoNoVis", ""};
cvar_t sv_demoMaxSize = {"sv_demoMaxSize", ""};
cvar_t sv_demoExtraNames = {"sv_demoExtraNames", ""};
cvar_t mvd_streamport = {"mvd_streamport", "27515"};
static int demo_max_size;
static int demo_size;
cvar_t sv_demoPrefix = {"sv_demoPrefix", ""};
@ -520,16 +522,21 @@ void SV_WriteMVDMessage (sizebuf_t *msg, int type, int to, float time)
demo.size += DWRITE (&len, 4, 1, demo.dest);
demo.size += DWRITE (msg->data, msg->cursize, 1, demo.dest);
if (demo.disk)
fflush (demo.file);
else if (demo.size - demo_size > demo_max_size)
if (demo.file)
{
demo_size = demo.size;
demo.mfile -= 0x80000;
fwrite(svs.demomem, 1, 0x80000, demo.file);
fflush(demo.file);
memmove(svs.demomem, svs.demomem + 0x80000, demo.size - 0x80000);
if (demo.disk)
fflush (demo.file);
else if (demo.size - demo_size > demo_max_size)
{
demo_size = demo.size;
demo.mfile -= 0x80000;
fwrite(svs.demomem, 1, 0x80000, demo.file);
fflush(demo.file);
memmove(svs.demomem, svs.demomem + 0x80000, demo.size - 0x80000);
}
}
else
demo_size = demo.size;
}
@ -736,6 +743,17 @@ size_t memwrite ( const void *buffer, size_t size, size_t count, qbyte **mem)
return c;
}
size_t streamwrite ( const void *buffer, size_t size, size_t count, qbyte **mem)
{
int sent;
sent = send(demo.tcpsocket, buffer, size*count, 0);
if (sent <= 0)
return 0;
return count;
}
static char chartbl[256];
void CleanName_Init ();
@ -745,17 +763,17 @@ void MVD_Init (void)
#define MVDVARGROUP "Server MVD cvars"
Cvar_Register (&sv_demofps, MVDVARGROUP);
Cvar_Register (&sv_demofps, MVDVARGROUP);
Cvar_Register (&sv_demoPings, MVDVARGROUP);
Cvar_Register (&sv_demoNoVis, MVDVARGROUP);
Cvar_Register (&sv_demoUseCache, MVDVARGROUP);
Cvar_Register (&sv_demoCacheSize, MVDVARGROUP);
Cvar_Register (&sv_demoMaxSize, MVDVARGROUP);
Cvar_Register (&sv_demoMaxDirSize, MVDVARGROUP);
Cvar_Register (&sv_demoDir, MVDVARGROUP);
Cvar_Register (&sv_demoDir, MVDVARGROUP);
Cvar_Register (&sv_demoPrefix, MVDVARGROUP);
Cvar_Register (&sv_demoSuffix, MVDVARGROUP);
Cvar_Register (&sv_demotxt , MVDVARGROUP);
Cvar_Register (&sv_demotxt, MVDVARGROUP);
Cvar_Register (&sv_demoExtraNames, MVDVARGROUP);
@ -765,7 +783,7 @@ void MVD_Init (void)
if (p < com_argc-1)
size = Q_atoi (com_argv[p+1]) * 1024;
else
Sys_Error ("Memory_Init: you must specify a size in KB after -democache");
Sys_Error ("MVD_Init: you must specify a size in KB after -democache");
}
if (size < MIN_MVD_MEMORY)
@ -806,6 +824,25 @@ qboolean SV_InitRecord(void)
return true;
}
qboolean SV_InitStream(void)
{
if (!USACACHE)
{
dwrite = (void *)&streamwrite;
demo.dest = &demo.tcpsocket;
demo.disk = false;
} else
{
dwrite = (void *)&memwrite;
demo.mfile = svs.demomem;
demo.dest = &demo.mfile;
}
demo_size = 0;
return true;
}
/*
====================
SV_Stop
@ -1031,6 +1068,8 @@ static qboolean SV_MVD_Record (char *name, int tcpsocket)
char *gamedir;
int seq = 1;
//okay, this is lame. We're going to allow a new mvd to 'reconnect' if we start recording the other...
memset(&demo, 0, sizeof(demo));
demo.recorder.frames = demo_frames;
for (i = 0; i < UPDATE_BACKUP; i++)
@ -1093,9 +1132,11 @@ static qboolean SV_MVD_Record (char *name, int tcpsocket)
}
else
{
SV_InitStream();
if (demo.tcpsocket)
return false;
SV_BroadcastPrintf (PRINT_CHAT, "Server starts recording to network client\n");
SV_BroadcastPrintf (PRINT_CHAT, "Server starts recording to QWTV\n");
demo.tcpsocket = tcpsocket;
}
@ -1308,15 +1349,15 @@ static qboolean SV_MVD_Record (char *name, int tcpsocket)
MSG_WriteByte (&buf, svc_updatefrags);
MSG_WriteByte (&buf, i);
MSG_WriteShort (&buf, player->old_frags);
MSG_WriteByte (&buf, svc_updateping);
MSG_WriteByte (&buf, i);
MSG_WriteShort (&buf, SV_CalcPing(player));
MSG_WriteByte (&buf, svc_updatepl);
MSG_WriteByte (&buf, i);
MSG_WriteByte (&buf, player->lossage);
MSG_WriteByte (&buf, svc_updateentertime);
MSG_WriteByte (&buf, i);
MSG_WriteFloat (&buf, realtime - player->connection_started);
@ -1750,6 +1791,139 @@ void SV_MVDEasyRecord_f (void)
SV_MVD_Record (name2, 0);
}
#ifdef _WIN32
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EMSGSIZE WSAEMSGSIZE
#define ECONNRESET WSAECONNRESET
#define ECONNABORTED WSAECONNABORTED
#define ECONNREFUSED WSAECONNREFUSED
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
#define qerrno WSAGetLastError()
#else
#define qerrno errno
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#ifdef sun
#include <sys/filio.h>
#endif
#ifdef NeXT
#include <libc.h>
#endif
#define closesocket close
#define ioctlsocket ioctl
#endif
int MVD_StreamStartListening(int port)
{
char name[256];
int sock;
struct hostent *hent;
struct sockaddr_in address;
// int fromlen;
unsigned int nonblocking = true;
address.sin_family = AF_INET;
if (gethostname(name, sizeof(name)) == -1)
return INVALID_SOCKET;
hent = gethostbyname(name);
if (!hent)
return INVALID_SOCKET;
address.sin_addr.s_addr = *(int *)(hent->h_addr_list[0]);
address.sin_port = htons((u_short)port);
if ((sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
{
Sys_Error ("MVD_StreamStartListening: socket:", strerror(qerrno));
}
if (ioctlsocket (sock, FIONBIO, &nonblocking) == -1)
{
Sys_Error ("FTP_TCP_OpenSocket: ioctl FIONBIO:", strerror(qerrno));
}
if( bind (sock, (void *)&address, sizeof(address)) == -1)
{
closesocket(sock);
return INVALID_SOCKET;
}
listen(sock, 2);
return sock;
}
void SV_MVDStream_Poll(void)
{
static int listensocket=INVALID_SOCKET;
static int listenport;
int client;
netadr_t na;
struct sockaddr_qstorage addr;
int addrlen;
qboolean wanted;
if (!sv.state)
wanted = false;
else if (listenport && (int)mvd_streamport.value != listenport) //easy way to switch... disable for a frame. :)
{
listenport = mvd_streamport.value;
wanted = false;
}
else
{
listenport = mvd_streamport.value;
wanted = true;
}
if (wanted && listensocket==INVALID_SOCKET)
listensocket = MVD_StreamStartListening(listenport);
else if (!wanted && listensocket!=INVALID_SOCKET)
{
closesocket(listensocket);
listensocket = INVALID_SOCKET;
return;
}
if (listensocket==INVALID_SOCKET)
return;
addrlen = sizeof(addr);
client = accept(listensocket, (struct sockaddr *)&addr, &addrlen);
if (client == INVALID_SOCKET)
return;
if (sv.mvdrecording)
{ //sorry
closesocket(client);
return;
}
SockadrToNetadr(&addr, &na);
Con_Printf("MVD streaming client connected from %s\n", NET_AdrToString(na));
SV_MVD_Record (NULL, client);
}
void SV_MVDList_f (void)
{
dir_t dir;
@ -2122,6 +2296,8 @@ void SV_MVDInit(void)
Cmd_AddCommand ("demolist", SV_MVDList_f);
Cmd_AddCommand ("rmdemo", SV_MVDRemove_f);
Cmd_AddCommand ("rmdemonum", SV_MVDRemoveNum_f);
Cvar_Register(&mvd_streamport, "MVD Streaming");
}
#endif

View File

@ -270,7 +270,7 @@ int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
if (trace.allsolid)
if (trace.startsolid)
{ // entity is trapped in another solid
VectorCopy (vec3_origin, ent->v.velocity);
return 3;

View File

@ -109,6 +109,7 @@ void SV_New_f (void)
{
char *gamedir;
int playernum;
int splitnum;
client_t *split;
if (host_client->state == cs_spawned)
@ -166,6 +167,7 @@ void SV_New_f (void)
MSG_WriteByte (&host_client->netchan.message, 0);
MSG_WriteString (&host_client->netchan.message, gamedir);
splitnum = 0;
for (split = host_client; split; split = split->controlled)
{
#ifdef Q2SERVER
@ -175,7 +177,9 @@ void SV_New_f (void)
#endif
playernum = NUM_FOR_EDICT(svprogfuncs, split->edict)-1;
if (sv.demostate)
playernum = (MAX_CLIENTS-1)|128;
{
playernum = (MAX_CLIENTS-1-splitnum)|128;
}
else if (split->spectator)
playernum |= 128;
@ -192,6 +196,7 @@ void SV_New_f (void)
#ifdef SVRANKING
split->stats_started = realtime;
#endif
splitnum++;
}
if (host_client->fteprotocolextensions & PEXT_SPLITSCREEN)
MSG_WriteByte (&host_client->netchan.message, 128);
@ -620,7 +625,7 @@ void SV_Soundlist_f (void)
{
int i;
//char **s;
int n;
unsigned n;
if (host_client->state != cs_connected)
{
@ -646,9 +651,10 @@ void SV_Soundlist_f (void)
SZ_Clear(&host_client->netchan.message);
}
if (n < 0)
if (n >= MAX_SOUNDS)
{
Con_Printf ("SV_Soundlist_f: %s tried to crash us\n", host_client->name);
SV_EndRedirect();
Con_Printf ("SV_Soundlist_f: %s send an invalid index\n", host_client->name);
SV_DropClient(host_client);
return;
}
@ -690,7 +696,7 @@ SV_Modellist_f
void SV_Modellist_f (void)
{
int i;
int n;
unsigned n;
if (host_client->state != cs_connected)
{
@ -716,9 +722,10 @@ void SV_Modellist_f (void)
SZ_Clear(&host_client->netchan.message);
}
if (n < 0)
if (n >= MAX_MODELS)
{
Con_Printf ("SV_Modellist_f: %s tried to crash us\n", host_client->name);
SV_EndRedirect();
Con_Printf ("SV_Modellist_f: %s send an invalid index\n", host_client->name);
SV_DropClient(host_client);
return;
}
@ -795,9 +802,12 @@ void SV_PreSpawn_f (void)
buf = atoi(Cmd_Argv(2));
if (buf >= bufs+statics+sv.num_edicts+255)
buf = 0;
if (buf < 0)
buf = 0;
{
SV_EndRedirect();
Con_Printf ("SV_Modellist_f: %s send an invalid index\n", host_client->name);
SV_DropClient(host_client);
return;
}
if (!buf)
{
@ -2748,7 +2758,7 @@ void SV_ExecuteUserCommand (char *s, qboolean fromQC)
Con_DPrintf("Client command: %s\n", s);
Cmd_TokenizeString (s);
Cmd_TokenizeString (s, false, false);
sv_player = host_client->edict;
Cmd_ExecLevel=1;
@ -2766,7 +2776,7 @@ void SV_ExecuteUserCommand (char *s, qboolean fromQC)
}
}
sv_player = host_client->edict;
Cmd_ShiftArgs(1);
Cmd_ShiftArgs(1, false);
}
#ifdef Q2SERVER
@ -3103,7 +3113,7 @@ void SVNQ_PreSpawn_f (void)
}
void SVNQ_NQInfo_f (void)
{
Cmd_TokenizeString(va("setinfo \"%s\" \"%s\"\n", Cmd_Argv(0), Cmd_Argv(1)));
Cmd_TokenizeString(va("setinfo \"%s\" \"%s\"\n", Cmd_Argv(0), Cmd_Argv(1)), false, false);
SV_SetInfo_f();
}
@ -3209,7 +3219,7 @@ void SVNQ_ExecuteUserCommand (char *s)
client_t *oldhost = host_client;
ucmd_t *u;
Cmd_TokenizeString (s);
Cmd_TokenizeString (s, false, false);
sv_player = host_client->edict;
Cmd_ExecLevel=1;

View File

@ -1197,8 +1197,8 @@ void Mod_LoadPlanes (lump_t *l)
}
void Q1BSP_FatPVS (vec3_t org, qboolean add);
qboolean Q1BSP_EdictInFatPVS(edict_t *ent);
void Q1BSP_FindTouchedLeafs(edict_t *ent);
qboolean Q1BSP_EdictInFatPVS(struct edict_s *ent);
void Q1BSP_FindTouchedLeafs(struct edict_s *ent);
/*
=================

View File

@ -1847,6 +1847,9 @@ trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, e
#endif
SV_ClipToLinks ( sv_areanodes, &clip );
if (clip.trace.startsolid)
clip.trace.fraction = 0;
return clip.trace;
}
#ifdef Q2SERVER