cvar_t cl_netinputpacketspersecond = {CVAR_SAVE, "cl_netinputpacketspersecond","50", "how many input packets to send to server each second"};
+cvar_t cl_nodelta = {0, "cl_nodelta", "0", "disables delta compression of non-player entities in QW network protocol"};
+
/*
================
//CL_SparkShower(cl.cmd.cursor_impact, cl.cmd.cursor_normal, 5, 0);
}
+void CL_ClientMovement_InputQW(qw_usercmd_t *cmd)
+{
+ int i;
+ int n;
+ // remove stale queue items
+ n = cl.movement_numqueue;
+ cl.movement_numqueue = 0;
+ for (i = 0;i < n;i++)
+ if (cl.movement_queue[i].sequence > cls.netcon->qw.incoming_sequence)
+ cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
+ // add to input queue if there is room
+ if (cl.movement_numqueue < (int)(sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0])) && cl.mtime[0] > cl.mtime[1])
+ {
+ // add to input queue
+ cl.movement_queue[cl.movement_numqueue].sequence = cls.netcon->qw.outgoing_sequence;
+ cl.movement_queue[cl.movement_numqueue].time = cl.mtime[0] + cl_movement_latency.value / 1000.0;
+ cl.movement_queue[cl.movement_numqueue].frametime = cmd->msec * 0.001;
+ VectorCopy(cmd->angles, cl.movement_queue[cl.movement_numqueue].viewangles);
+ cl.movement_queue[cl.movement_numqueue].move[0] = cmd->forwardmove;
+ cl.movement_queue[cl.movement_numqueue].move[1] = cmd->sidemove;
+ cl.movement_queue[cl.movement_numqueue].move[2] = cmd->upmove;
+ cl.movement_queue[cl.movement_numqueue].jump = (cmd->buttons & 2) != 0;
+ cl.movement_queue[cl.movement_numqueue].crouch = false;
+ cl.movement_numqueue++;
+ }
+ cl.movement_replay = true;
+}
+
void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch)
{
int i;
//VectorSet(cl_entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0);
}
+void QW_MSG_WriteDeltaUsercmd(sizebuf_t *buf, qw_usercmd_t *from, qw_usercmd_t *to)
+{
+ int bits;
+
+ bits = 0;
+ if (to->angles[0] != from->angles[0])
+ bits |= QW_CM_ANGLE1;
+ if (to->angles[1] != from->angles[1])
+ bits |= QW_CM_ANGLE2;
+ if (to->angles[2] != from->angles[2])
+ bits |= QW_CM_ANGLE3;
+ if (to->forwardmove != from->forwardmove)
+ bits |= QW_CM_FORWARD;
+ if (to->sidemove != from->sidemove)
+ bits |= QW_CM_SIDE;
+ if (to->upmove != from->upmove)
+ bits |= QW_CM_UP;
+ if (to->buttons != from->buttons)
+ bits |= QW_CM_BUTTONS;
+ if (to->impulse != from->impulse)
+ bits |= QW_CM_IMPULSE;
+
+ MSG_WriteByte(buf, bits);
+ if (bits & QW_CM_ANGLE1)
+ MSG_WriteAngle16i(buf, to->angles[0]);
+ if (bits & QW_CM_ANGLE2)
+ MSG_WriteAngle16i(buf, to->angles[1]);
+ if (bits & QW_CM_ANGLE3)
+ MSG_WriteAngle16i(buf, to->angles[2]);
+ if (bits & QW_CM_FORWARD)
+ MSG_WriteShort(buf, to->forwardmove);
+ if (bits & QW_CM_SIDE)
+ MSG_WriteShort(buf, to->sidemove);
+ if (bits & QW_CM_UP)
+ MSG_WriteShort(buf, to->upmove);
+ if (bits & QW_CM_BUTTONS)
+ MSG_WriteShort(buf, to->buttons);
+ if (bits & QW_CM_IMPULSE)
+ MSG_WriteShort(buf, to->impulse);
+ MSG_WriteByte(buf, to->msec);
+}
+
/*
==============
CL_SendMove
// PROTOCOL_DARKPLACES5 clc_move = 19 bytes total
// PROTOCOL_DARKPLACES6 clc_move = 52 bytes total
// PROTOCOL_DARKPLACES7 clc_move = 56 bytes total
- if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE)
+ if (cls.protocol == PROTOCOL_QUAKEWORLD)
+ {
+ int checksumindex;
+ double msectime;
+ static double oldmsectime;
+ qw_usercmd_t *cmd, *oldcmd;
+ qw_usercmd_t nullcmd;
+
+ //Con_Printf("code qw_clc_move\n");
+
+ i = cls.netcon->qw.outgoing_sequence & QW_UPDATE_MASK;
+ cmd = &cl.qw_moves[i];
+ memset(&nullcmd, 0, sizeof(nullcmd));
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->buttons = bits;
+ cmd->impulse = impulse;
+ cmd->forwardmove = (short)bound(-32768, forwardmove, 32767);
+ cmd->sidemove = (short)bound(-32768, sidemove, 32767);
+ cmd->upmove = (short)bound(-32768, upmove, 32767);
+ VectorCopy(cl.viewangles, cmd->angles);
+ msectime = realtime * 1000;
+ cmd->msec = (unsigned char)bound(0, msectime - oldmsectime, 255);
+ // ridiculous value rejection (matches qw)
+ if (cmd->msec > 250)
+ cmd->msec = 100;
+ oldmsectime = msectime;
+
+ CL_ClientMovement_InputQW(cmd);
+
+ MSG_WriteByte(&buf, qw_clc_move);
+ // save the position for a checksum byte
+ checksumindex = buf.cursize;
+ MSG_WriteByte(&buf, 0);
+ // packet loss percentage
+ // FIXME: netgraph stuff
+ MSG_WriteByte(&buf, 0);
+ // write most recent 3 moves
+ i = (cls.netcon->qw.outgoing_sequence-2) & QW_UPDATE_MASK;
+ cmd = &cl.qw_moves[i];
+ QW_MSG_WriteDeltaUsercmd(&buf, &nullcmd, cmd);
+ oldcmd = cmd;
+ i = (cls.netcon->qw.outgoing_sequence-1) & QW_UPDATE_MASK;
+ cmd = &cl.qw_moves[i];
+ QW_MSG_WriteDeltaUsercmd(&buf, oldcmd, cmd);
+ oldcmd = cmd;
+ i = cls.netcon->qw.outgoing_sequence & QW_UPDATE_MASK;
+ cmd = &cl.qw_moves[i];
+ QW_MSG_WriteDeltaUsercmd(&buf, oldcmd, cmd);
+ // calculate the checksum
+ buf.data[checksumindex] = COM_BlockSequenceCRCByteQW(buf.data + checksumindex + 1, buf.cursize - checksumindex - 1, cls.netcon->qw.outgoing_sequence);
+ // if delta compression history overflows, request no delta
+ if (cls.netcon->qw.outgoing_sequence - cl.qw_validsequence >= QW_UPDATE_BACKUP-1)
+ cl.qw_validsequence = 0;
+ // request delta compression if appropriate
+ if (cl.qw_validsequence && !cl_nodelta.integer && cls.state == ca_connected && !cls.demorecording)
+ {
+ MSG_WriteByte(&buf, qw_clc_delta);
+ MSG_WriteByte(&buf, cl.qw_validsequence & 255);
+ }
+ }
+ else if (cls.protocol == PROTOCOL_QUAKE || cls.protocol == PROTOCOL_QUAKEDP || cls.protocol == PROTOCOL_NEHAHRAMOVIE)
{
// 5 bytes
MSG_WriteByte (&buf, clc_move);
// 2 bytes
MSG_WriteByte (&buf, bits);
MSG_WriteByte (&buf, impulse);
+
+ CL_ClientMovement_Input((bits & 2) != 0, false);
}
else if (cls.protocol == PROTOCOL_DARKPLACES2 || cls.protocol == PROTOCOL_DARKPLACES3)
{
// 2 bytes
MSG_WriteByte (&buf, bits);
MSG_WriteByte (&buf, impulse);
+
+ CL_ClientMovement_Input((bits & 2) != 0, false);
}
else if (cls.protocol == PROTOCOL_DARKPLACES1 || cls.protocol == PROTOCOL_DARKPLACES4 || cls.protocol == PROTOCOL_DARKPLACES5)
{
// 2 bytes
MSG_WriteByte (&buf, bits);
MSG_WriteByte (&buf, impulse);
+
+ CL_ClientMovement_Input((bits & 2) != 0, false);
}
else
{
MSG_WriteFloat (&buf, cl.cmd.cursor_impact[1]);
MSG_WriteFloat (&buf, cl.cmd.cursor_impact[2]);
MSG_WriteShort (&buf, cl.cmd.cursor_entitynumber);
- }
- // FIXME: bits & 16 is +button5, Nexuiz specific
- CL_ClientMovement_Input((bits & 2) != 0, (bits & 16) != 0);
+ // FIXME: bits & 16 is +button5, Nexuiz specific
+ CL_ClientMovement_Input((bits & 2) != 0, (bits & 16) != 0);
+ }
}
- // ack the last few frame numbers
- // (redundent to improve handling of client->server packet loss)
- // for LATESTFRAMENUMS == 3 case this is 15 bytes
- for (i = 0;i < LATESTFRAMENUMS;i++)
+ if (cls.protocol != PROTOCOL_QUAKEWORLD)
{
- if (cl.latestframenums[i] > 0)
+ // ack the last few frame numbers
+ // (redundent to improve handling of client->server packet loss)
+ // for LATESTFRAMENUMS == 3 case this is 15 bytes
+ for (i = 0;i < LATESTFRAMENUMS;i++)
{
- if (developer_networkentities.integer >= 1)
- Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]);
- MSG_WriteByte(&buf, clc_ackframe);
- MSG_WriteLong(&buf, cl.latestframenums[i]);
+ if (cl.latestframenums[i] > 0)
+ {
+ if (developer_networkentities.integer >= 1)
+ Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]);
+ MSG_WriteByte(&buf, clc_ackframe);
+ MSG_WriteLong(&buf, cl.latestframenums[i]);
+ }
}
}
Cvar_RegisterVariable(&m_filter);
Cvar_RegisterVariable(&cl_netinputpacketspersecond);
+
+ Cvar_RegisterVariable(&cl_nodelta);
}
// done checking sounds and models, send a prespawn command now
MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
// FIXME: calculate the checksum2 this wants
- //MSG_WriteString(&cls.netcon->message, va(qw_prespawn_name, cl.qw_servercount, cl.worldmodel->checksum2));
- MSG_WriteString(&cls.netcon->message, va(qw_prespawn_name, cl.qw_servercount, 0));
+ //MSG_WriteString(&cls.netcon->message, va("prespawn %i 0 %i", cl.qw_servercount, cl.worldmodel->checksum2));
+ MSG_WriteString(&cls.netcon->message, va("prespawn %i 0 %i", cl.qw_servercount, 0));
if (cls.qw_downloadmemory)
{
if (cl.sound_name[cls.qw_downloadnumber][0] == '*')
continue;
// check if we need to download the file, and return if so
- if (!QW_CL_CheckOrDownloadFile(cl.sound_name[cls.qw_downloadnumber]))
+ if (!QW_CL_CheckOrDownloadFile(va("sound/%s", cl.sound_name[cls.qw_downloadnumber])))
return;
}
// done with sound downloads, next we check models
MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
- MSG_WriteString(&cls.netcon->message, va(qw_modellist_name, cl.qw_servercount, 0));
+ MSG_WriteString(&cls.netcon->message, va("modellist %i %i", cl.qw_servercount, 0));
break;
case dl_none:
default:
}
n = MSG_ReadByte();
+ if (n)
{
MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
- MSG_WriteString(&cls.netcon->message, va(qw_modellist_name, cl.qw_servercount, n));
+ MSG_WriteString(&cls.netcon->message, va("modellist %i %i", cl.qw_servercount, n));
return;
}
if (n)
{
MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
- MSG_WriteString(&cls.netcon->message, va(qw_soundlist_name, cl.qw_servercount, n));
+ MSG_WriteString(&cls.netcon->message, va("soundlist %i %i", cl.qw_servercount, n));
return;
}
}
#endif
- // parse maxclients
- cl.maxclients = MSG_ReadByte ();
- if (cl.maxclients & 128)
- {
- cl.qw_spectator = true;
- cl.maxclients &= ~128;
- }
- if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
- {
- Host_Error("Bad maxclients (%u) from server", cl.maxclients);
- return;
- }
- cl.scores = (scoreboard_t *)Mem_Alloc(cl_mempool, cl.maxclients*sizeof(*cl.scores));
-
cl.gametype = GAME_DEATHMATCH;
+ cl.maxclients = 32;
+
+ // parse player number
+ i = MSG_ReadByte();
+ cl.qw_spectator = (i & 128) != 0;
+ cl.playerentity = cl.viewentity = (i & 127) + 1;
+ cl.scores = (scoreboard_t *)Mem_Alloc(cl_mempool, cl.maxclients*sizeof(*cl.scores));
// get the full level name
str = MSG_ReadString ();
memset(cl.sound_precache, 0, sizeof(cl.sound_precache));
MSG_WriteByte(&cls.netcon->message, qw_clc_stringcmd);
- MSG_WriteString(&cls.netcon->message, va(qw_soundlist_name, cl.qw_servercount, 0));
+ MSG_WriteString(&cls.netcon->message, va("soundlist %i %i", cl.qw_servercount, 0));
cls.state = ca_connected;
cls.signon = 1;
break;
case qw_svc_cdtrack:
- cl.cdtrack = MSG_ReadByte ();
- cl.looptrack = MSG_ReadByte ();
+ cl.cdtrack = cl.looptrack = MSG_ReadByte ();
if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
CDAudio_Play ((unsigned char)cls.forcetrack, true);
else
qboolean drawcrosshair;
}csqc_vidvars_t;
+typedef struct qw_usercmd_s
+{
+ vec3_t angles;
+ short forwardmove, sidemove, upmove;
+ unsigned char padding1[2];
+ unsigned char msec;
+ unsigned char buttons;
+ unsigned char impulse;
+ unsigned char padding2;
+}
+qw_usercmd_t;
+
//
// the client_state_t structure is wiped completely at every
// server signon
// 255 is the most nails the QW protocol could send
int qw_num_nails;
vec_t qw_nails[255][6];
+
+ int qw_validsequence;
+
+ qw_usercmd_t qw_moves[QW_UPDATE_BACKUP];
}
client_state_t;
extern int cl_num_temp_entities;
extern int cl_num_brushmodel_entities;
-extern char qw_emodel_name[], qw_pmodel_name[], qw_prespawn_name[], qw_modellist_name[], qw_soundlist_name[];
-
extern client_state_t cl;
extern void CL_AllocDlight (entity_render_t *ent, matrix4x4_t *matrix, float radius, float red, float green, float blue, float decay, float lifetime, int cubemapnum, int style, int shadowenable, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags);
return crc ^ CRC_XOR_VALUE;
}
+// QuakeWorld
+static unsigned char chktbl[1024 + 4] =
+{
+ 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01,
+ 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a,
+ 0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58,
+ 0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3,
+ 0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b,
+ 0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36,
+ 0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8,
+ 0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27,
+ 0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd,
+ 0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63,
+ 0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2,
+ 0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d,
+ 0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65,
+ 0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f,
+ 0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f,
+ 0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42,
+ 0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59,
+ 0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9,
+ 0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69,
+ 0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba,
+ 0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85,
+ 0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4,
+ 0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8,
+ 0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa,
+ 0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05,
+ 0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7,
+ 0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a,
+ 0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb,
+ 0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b,
+ 0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d,
+ 0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce,
+ 0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3,
+
+ // map checksum goes here
+ 0x00,0x00,0x00,0x00
+};
+
+// QuakeWorld
+unsigned char COM_BlockSequenceCRCByteQW(unsigned char *base, int length, int sequence)
+{
+ unsigned char *p;
+ unsigned char chkb[60 + 4];
+
+ p = chktbl + (sequence % (sizeof(chktbl) - 8));
+
+ if (length > 60)
+ length = 60;
+ memcpy(chkb, base, length);
+
+ chkb[length] = (sequence & 0xff) ^ p[0];
+ chkb[length+1] = p[1];
+ chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2];
+ chkb[length+3] = p[3];
+
+ return CRC_Block(chkb, length + 4) & 0xff;
+}
/*
==============================================================================
unsigned short CRC_Block(const unsigned char *data, size_t size);
+unsigned char COM_BlockSequenceCRCByteQW(unsigned char *base, int length, int sequence);
+
//============================================================================
// Endianess handling
// QuakeWorld commands
-char qw_emodel_name[] =
- { 'e' ^ 0xff, 'm' ^ 0xff, 'o' ^ 0xff, 'd' ^ 0xff, 'e' ^ 0xff, 'l' ^ 0xff, 0 };
-char qw_pmodel_name[] =
- { 'p' ^ 0xff, 'm' ^ 0xff, 'o' ^ 0xff, 'd' ^ 0xff, 'e' ^ 0xff, 'l' ^ 0xff, 0 };
-char qw_prespawn_name[] =
- { 'p'^0xff, 'r'^0xff, 'e'^0xff, 's'^0xff, 'p'^0xff, 'a'^0xff, 'w'^0xff, 'n'^0xff,
- ' '^0xff, '%'^0xff, 'i'^0xff, ' '^0xff, '0'^0xff, ' '^0xff, '%'^0xff, 'i'^0xff, 0 };
-char qw_modellist_name[] =
- { 'm'^0xff, 'o'^0xff, 'd'^0xff, 'e'^0xff, 'l'^0xff, 'l'^0xff, 'i'^0xff, 's'^0xff, 't'^0xff,
- ' '^0xff, '%'^0xff, 'i'^0xff, ' '^0xff, '%'^0xff, 'i'^0xff, 0 };
-char qw_soundlist_name[] =
- { 's'^0xff, 'o'^0xff, 'u'^0xff, 'n'^0xff, 'd'^0xff, 'l'^0xff, 'i'^0xff, 's'^0xff, 't'^0xff,
- ' '^0xff, '%'^0xff, 'i'^0xff, ' '^0xff, '%'^0xff, 'i'^0xff, 0 };
-
/*
=====================
Host_Rcon_f
if (*s)
s++;
- if (!strcasecmp(key, qw_pmodel_name) || !strcasecmp(key, qw_emodel_name))
+ if (!strcasecmp(key, "pmodel") || !strcasecmp(key, "emodel"))
continue;
if (key[0] == '*')
Con_Printf ("usage: setinfo [ <key> <value> ]\n");
return;
}
- if (!strcasecmp(Cmd_Argv(1), qw_pmodel_name) || !strcasecmp(Cmd_Argv(1), qw_emodel_name))
+ if (!strcasecmp(Cmd_Argv(1), "pmodel") || !strcasecmp(Cmd_Argv(1), "emodel"))
return;
if (Cmd_Argv(1)[0] == '*')
{
int packetLen;
qboolean sendreliable;
- if (data->cursize == 0 && conn->message.cursize == 0)
- {
- Con_Printf ("Datagram_SendUnreliableMessage: zero length message\n");
- return -1;
- }
+ // note that it is ok to send empty messages to the qw server,
+ // otherwise it won't respond to us at all
sendreliable = false;
// if the remote side dropped the last reliable message, resend it
}
packetsReceived++;
- reliable_message = sequence >> 31;
- reliable_ack = sequence_ack >> 31;
+ reliable_message = (sequence >> 31) & 1;
+ reliable_ack = (sequence_ack >> 31) & 1;
sequence &= ~(1<<31);
sequence_ack &= ~(1<<31);
if (sequence <= conn->qw.incoming_sequence)
NetConn_WriteString(mysocket, va("\377\377\377\377connect\\protocol\\darkplaces 3\\protocols\\%s\\challenge\\%s", protocolnames, string + 10), peeraddress);
return true;
}
- if (length > 1 && string[0] == 'c' && string[1] >= '0' && string[1] <= '9')
+ if (length > 1 && string[0] == 'c' && (string[1] == '-' || (string[1] >= '0' && string[1] <= '9')))
{
// quakeworld
LHNETADDRESS_ToString(peeraddress, addressstring2, sizeof(addressstring2), true);
void EntityFrameQW_CL_ReadFrame(qboolean delta)
{
qboolean invalid = false;
- int i, number, oldsnapindex, newsnapindex, oldindex, newindex, oldnum, newnum;
+ int number, oldsnapindex, newsnapindex, oldindex, newindex, oldnum, newnum;
entity_t *ent;
entityframeqw_database_t *d = cl.entitydatabaseqw;
entityframeqw_snapshot_t *oldsnap, *newsnap;
}
// read the number of this frame to echo back in next input packet
- for (i = 0;i < LATESTFRAMENUMS-1;i++)
- cl.latestframenums[i] = cl.latestframenums[i+1];
- cl.latestframenums[LATESTFRAMENUMS-1] = cls.netcon->qw.incoming_sequence;
+ cl.qw_validsequence = cls.netcon->qw.incoming_sequence;
if (invalid)
- cl.latestframenums[LATESTFRAMENUMS-1] = 0;
+ cl.qw_validsequence = 0;
// read entity numbers until we find a 0x0000
// (which would be an empty update on world entity, but is actually a terminator)
{
if (newnum != oldnum && !delta && !invalid)
{
- cl.latestframenums[LATESTFRAMENUMS-1] = 0;
+ cl.qw_validsequence = 0;
Con_Printf("WARNING: U_REMOVE %i on full update\n", newnum);
}
}