ref: bab80c934d2714937198f25041f8047146158f9c
parent: caa94b6b82aecb7a20e4e6de2cc2f2f9332436f9
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Thu Oct 12 19:48:32 EDT 2023
add basic RMQ net protocol support (for bigger mods)
--- a/cl_input.c
+++ b/cl_input.c
@@ -330,7 +330,7 @@
MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times
for (i=0 ; i<3 ; i++)
- sv.protocol->MSG_WriteAngle (&buf, cl.viewangles[i]);
+ cl.protocol->MSG_WriteAngle (&buf, cl.viewangles[i]);
MSG_WriteShort (&buf, cmd->forwardmove);
MSG_WriteShort (&buf, cmd->sidemove);
--- a/cl_main.c
+++ b/cl_main.c
@@ -228,14 +228,13 @@
for (i=0,ent=cl_entities ; i<cl.num_entities ; i++,ent++)
{
- Con_Printf ("%3d:",i);
if (!ent->model)
- {
- Con_Printf ("EMPTY\n");
continue;
- }
- Con_Printf ("%s:%2d (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n"
- ,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]);
+ Con_Printf ("%3d:%s:%2d (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n",
+ i,ent->model->name,ent->frame,
+ ent->origin[0], ent->origin[1], ent->origin[2],
+ ent->angles[0], ent->angles[1], ent->angles[2]
+ );
}
}
--- a/cl_parse.c
+++ b/cl_parse.c
@@ -47,7 +47,11 @@
"svc_finale", // [string] music [string] text
"svc_cdtrack", // [byte] track [byte] looptrack
"svc_sellscreen",
- "svc_cutscene"
+ "svc_cutscene",
+
+ "svc_spawnbaseline2",
+ "svc_spawnstatic2",
+ "svc_spawnstaticsound2",
};
//=============================================================================
@@ -91,28 +95,22 @@
float attenuation;
field_mask = MSG_ReadByte();
+ volume = (field_mask & SND_VOLUME) ? MSG_ReadByte() : Spktvol;
+ attenuation = (field_mask & SND_ATTENUATION) ? MSG_ReadByte()/64.0 : Spktatt;
+ if(field_mask & (sv.protocol->fl_large_entity | sv.protocol->fl_large_channel)){
+ ent = MSG_ReadShort();
+ channel = MSG_ReadByte();
+ }else{
+ channel = MSG_ReadShort ();
+ ent = channel >> 3;
+ channel &= 7;
+ }
+ sound_num = (field_mask & sv.protocol->fl_large_sound) ? MSG_ReadShort() : MSG_ReadByte();
- if (field_mask & SND_VOLUME)
- volume = MSG_ReadByte ();
- else
- volume = Spktvol;
-
- if (field_mask & SND_ATTENUATION)
- attenuation = MSG_ReadByte () / 64.0;
- else
- attenuation = Spktatt;
-
- channel = MSG_ReadShort ();
- sound_num = MSG_ReadByte ();
+ if(ent > MAX_EDICTS)
+ Host_Error("CL_ParseStartSoundPacket: ent = %d", ent);
- ent = channel >> 3;
- channel &= 7;
-
- if (ent > MAX_EDICTS)
- Host_Error ("CL_ParseStartSoundPacket: ent = %d", ent);
-
- MSG_ReadVec(pos);
-
+ MSG_ReadVec(cl.protocol, pos);
startsfx (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
}
@@ -185,10 +183,11 @@
void CL_ParseServerInfo (void)
{
char *str;
- int i;
+ void *p;
+ int i, n;
int nummodels, numsounds;
- char model_precache[MAX_MODELS][Npath];
- char sound_precache[MAX_SOUNDS][Npath];
+ static char model_precache[MAX_MODELS][Npath];
+ static char sound_precache[MAX_SOUNDS][Npath];
dprint("CL_ParseServerInfo: parsing serverinfo pkt...\n");
//
@@ -198,11 +197,21 @@
// parse protocol version number
i = MSG_ReadLong ();
- if (i != PROTOCOL_VERSION)
- {
- Con_Printf ("Server returned version %d, not %d", i, PROTOCOL_VERSION);
+ free(cl.protocol);
+ p = nil;
+ for(n = 0; n < nelem(protos); n++){
+ if(protos[n].version == i){
+ p = &protos[n];
+ break;
+ }
+ }
+ if(p == nil){
+ Con_Printf ("Server returned unknown protocol version %d", i);
return;
}
+ cl.protocol = malloc(sizeof(*cl.protocol));
+ memmove(cl.protocol, p, sizeof(*cl.protocol));
+ cl.protocol->MSG_ReadProtocolInfo(cl.protocol);
// parse maxclients
cl.maxclients = MSG_ReadByte ();
@@ -302,7 +311,7 @@
relinked. Other attributes can change without relinking.
==================
*/
-int bitcounts[16];
+static int bitcounts[16];
void CL_ParseUpdate (int bits)
{
@@ -311,7 +320,7 @@
int modnum;
qboolean forcelink;
entity_t *ent;
- int num;
+ int num, skin, colormap;
if (cls.signon == SIGNONS - 1)
{ // first update is the final signon stage
@@ -319,39 +328,66 @@
CL_SignonReply ();
}
- if (bits & U_MOREBITS)
- {
- i = MSG_ReadByte ();
- bits |= (i<<8);
+ if (bits & U_MOREBITS){
+ bits |= MSG_ReadByte()<<8;
+ if(bits & U_MOREBITS2){
+ bits |= MSG_ReadByte()<<16;
+ if(bits & U_MOREBITS3)
+ bits |= MSG_ReadByte()<<24;
+ }
+ if(bits == -1)
+ Host_Error("CL_ParseUpdate: unexpected EOF while reading extended bits");
}
- if (bits & U_LONGENTITY)
- num = MSG_ReadShort ();
- else
- num = MSG_ReadByte ();
-
+ num = (bits & U_LONGENTITY) ? MSG_ReadShort() : MSG_ReadByte ();
ent = CL_EntityNum (num);
-for (i=0 ; i<16 ; i++)
-if (bits&(1<<i))
- bitcounts[i]++;
+ for (i=0 ; i<16 ; i++)
+ if (bits&(1<<i))
+ bitcounts[i]++;
- if (ent->msgtime != cl.mtime[1])
- forcelink = true; // no previous frame to lerp from
+ forcelink = ent->msgtime != cl.mtime[1]; // no previous frame to lerp from
+ ent->msgtime = cl.mtime[0];
+
+// shift the known values for interpolation
+ VectorCopy (ent->msg_origins[0], ent->msg_origins[1]);
+ VectorCopy (ent->msg_angles[0], ent->msg_angles[1]);
+
+ modnum = (bits & U_MODEL) ? MSG_ReadByte() : ent->baseline.modelindex;
+ ent->frame = (bits & U_FRAME) ? MSG_ReadByte() : ent->baseline.frame;
+ colormap = (bits & U_COLORMAP) ? MSG_ReadByte() : ent->baseline.colormap;
+ skin = (bits & U_SKIN) ? MSG_ReadByte() : ent->baseline.skin;
+ ent->effects = (bits & U_EFFECTS) ? MSG_ReadByte() : ent->baseline.effects;
+
+ if(colormap == 0)
+ ent->colormap = vid.colormap;
+ else if(colormap > cl.maxclients)
+ fatal("colormap > cl.maxclients");
else
- forcelink = false;
+ ent->colormap = cl.scores[colormap-1].translations;
- ent->msgtime = cl.mtime[0];
-
- if (bits & U_MODEL)
- {
- modnum = MSG_ReadByte ();
- if (modnum >= MAX_MODELS)
- Host_Error ("CL_ParseModel: bad modnum");
+ if(skin != ent->skinnum && num >= 0 && num <= cl.maxclients){
+ // FIXME(sigrid): update the skin
+ ent->skinnum = skin;
}
- else
- modnum = ent->baseline.modelindex;
-
+
+ ent->msg_origins[0][0] = (bits & U_ORIGIN1) ? cl.protocol->MSG_ReadCoord() : ent->baseline.origin[0];
+ ent->msg_angles[0][0] = (bits & U_ANGLE1) ? cl.protocol->MSG_ReadAngle() : ent->baseline.angles[0];
+ ent->msg_origins[0][1] = (bits & U_ORIGIN2) ? cl.protocol->MSG_ReadCoord() : ent->baseline.origin[1];
+ ent->msg_angles[0][1] = (bits & U_ANGLE2) ? cl.protocol->MSG_ReadAngle() : ent->baseline.angles[1];
+ ent->msg_origins[0][2] = (bits & U_ORIGIN3) ? cl.protocol->MSG_ReadCoord() : ent->baseline.origin[2];
+ ent->msg_angles[0][2] = (bits & U_ANGLE3) ? cl.protocol->MSG_ReadAngle() : ent->baseline.angles[2];
+
+ if(bits & U_NOLERP)
+ ent->forcelink = true;
+
+ if(bits & cl.protocol->fl_large_frame)
+ ent->frame |= MSG_ReadByte()<<8;
+ if(bits & cl.protocol->fl_large_model)
+ modnum |= MSG_ReadByte()<<8;
+
+ if(modnum < 0 || modnum >= MAX_MODELS)
+ Host_Error("CL_ParseModel: bad modnum: %d (bits 0x%08ux)", modnum, bits);
model = cl.model_precache[modnum];
if (model != ent->model)
{
@@ -368,69 +404,7 @@
else
forcelink = true; // hack to make null model players work
}
-
- if (bits & U_FRAME)
- ent->frame = MSG_ReadByte ();
- else
- ent->frame = ent->baseline.frame;
- if (bits & U_COLORMAP)
- i = MSG_ReadByte();
- else
- i = ent->baseline.colormap;
- if (!i)
- ent->colormap = vid.colormap;
- else
- {
- if (i > cl.maxclients)
- fatal ("i >= cl.maxclients");
- ent->colormap = cl.scores[i-1].translations;
- }
-
- if (bits & U_SKIN)
- ent->skinnum = MSG_ReadByte();
- else
- ent->skinnum = ent->baseline.skin;
-
- if (bits & U_EFFECTS)
- ent->effects = MSG_ReadByte();
- else
- ent->effects = ent->baseline.effects;
-
-// shift the known values for interpolation
- VectorCopy (ent->msg_origins[0], ent->msg_origins[1]);
- VectorCopy (ent->msg_angles[0], ent->msg_angles[1]);
-
- if (bits & U_ORIGIN1)
- ent->msg_origins[0][0] = sv.protocol->MSG_ReadCoord ();
- else
- ent->msg_origins[0][0] = ent->baseline.origin[0];
- if (bits & U_ANGLE1)
- ent->msg_angles[0][0] = sv.protocol->MSG_ReadAngle();
- else
- ent->msg_angles[0][0] = ent->baseline.angles[0];
-
- if (bits & U_ORIGIN2)
- ent->msg_origins[0][1] = sv.protocol->MSG_ReadCoord ();
- else
- ent->msg_origins[0][1] = ent->baseline.origin[1];
- if (bits & U_ANGLE2)
- ent->msg_angles[0][1] = sv.protocol->MSG_ReadAngle();
- else
- ent->msg_angles[0][1] = ent->baseline.angles[1];
-
- if (bits & U_ORIGIN3)
- ent->msg_origins[0][2] = sv.protocol->MSG_ReadCoord ();
- else
- ent->msg_origins[0][2] = ent->baseline.origin[2];
- if (bits & U_ANGLE3)
- ent->msg_angles[0][2] = sv.protocol->MSG_ReadAngle();
- else
- ent->msg_angles[0][2] = ent->baseline.angles[2];
-
- if ( bits & U_NOLERP )
- ent->forcelink = true;
-
if ( forcelink )
{ // didn't have an update last message
VectorCopy (ent->msg_origins[0], ent->msg_origins[1]);
@@ -446,18 +420,19 @@
CL_ParseBaseline
==================
*/
-void CL_ParseBaseline (entity_t *ent)
+void CL_ParseBaseline (int withbits, entity_t *ent)
{
- int i;
-
- ent->baseline.modelindex = MSG_ReadByte ();
- ent->baseline.frame = MSG_ReadByte ();
+ int i, bits;
+
+ bits = withbits ? MSG_ReadByte() : 0;
+ ent->baseline.modelindex = (bits & cl.protocol->fl_large_baseline_model) ? MSG_ReadShort() : MSG_ReadByte();
+ ent->baseline.frame = (bits & cl.protocol->fl_large_baseline_frame) ? MSG_ReadShort() : MSG_ReadByte();
ent->baseline.colormap = MSG_ReadByte();
ent->baseline.skin = MSG_ReadByte();
for (i=0 ; i<3 ; i++)
{
- ent->baseline.origin[i] = sv.protocol->MSG_ReadCoord ();
- ent->baseline.angles[i] = sv.protocol->MSG_ReadAngle ();
+ ent->baseline.origin[i] = cl.protocol->MSG_ReadCoord ();
+ ent->baseline.angles[i] = cl.protocol->MSG_ReadAngle ();
}
}
@@ -471,36 +446,26 @@
*/
void CL_ParseClientdata (unsigned int bits)
{
- int i, j;
-
- if (bits & SU_VIEWHEIGHT)
- cl.viewheight = MSG_ReadChar ();
- else
- cl.viewheight = DEFAULT_VIEWHEIGHT;
+ int i, j, weaponmodel;
- if (bits & SU_IDEALPITCH)
- cl.idealpitch = MSG_ReadChar ();
- else
- cl.idealpitch = 0;
-
- VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
+ if(bits & SU_MOREBITS){
+ bits |= MSG_ReadByte() << 16;
+ if(bits & SU_MOREBITS2)
+ bits |= MSG_ReadByte() << 24;
+ }
+
+ cl.viewheight = (bits & SU_VIEWHEIGHT) ? MSG_ReadChar() : DEFAULT_VIEWHEIGHT;
+ cl.idealpitch = (bits & SU_IDEALPITCH) ? MSG_ReadChar() : 0;
+
+ VectorCopy(cl.mvelocity[0], cl.mvelocity[1]);
for (i=0 ; i<3 ; i++)
{
- if (bits & (SU_PUNCH1<<i) )
- cl.punchangle[i] = MSG_ReadChar();
- else
- cl.punchangle[i] = 0;
- if (bits & (SU_VELOCITY1<<i) )
- cl.mvelocity[0][i] = MSG_ReadChar()*16;
- else
- cl.mvelocity[0][i] = 0;
+ cl.punchangle[i] = (bits & (SU_PUNCH1<<i)) ? MSG_ReadChar() : 0;
+ cl.mvelocity[0][i] = (bits & (SU_VELOCITY1<<i)) ? MSG_ReadChar()*16 : 0;
}
-// [always sent] if (bits & SU_ITEMS)
- i = MSG_ReadLong ();
-
- if (cl.items != i)
- { // set flash times
+ i = (bits & SU_ITEMS) ? MSG_ReadLong() : cl.items;
+ if(cl.items != i){ // set flash times
Sbar_Changed ();
for (j=0 ; j<32 ; j++)
if ( (i & (1<<j)) && !(cl.items & (1<<j)))
@@ -507,78 +472,60 @@
cl.item_gettime[j] = cl.time;
cl.items = i;
}
-
+
cl.onground = (bits & SU_ONGROUND) != 0;
cl.inwater = (bits & SU_INWATER) != 0;
+ cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
- if (bits & SU_WEAPONFRAME)
- cl.stats[STAT_WEAPONFRAME] = MSG_ReadByte ();
- else
- cl.stats[STAT_WEAPONFRAME] = 0;
-
- if (bits & SU_ARMOR)
- i = MSG_ReadByte ();
- else
- i = 0;
- if (cl.stats[STAT_ARMOR] != i)
- {
+ i = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
+ if(cl.stats[STAT_ARMOR] != i){
cl.stats[STAT_ARMOR] = i;
Sbar_Changed ();
}
- if (bits & SU_WEAPON)
- i = MSG_ReadByte ();
- else
- i = 0;
- if (cl.stats[STAT_WEAPON] != i)
- {
- cl.stats[STAT_WEAPON] = i;
- Sbar_Changed ();
- }
+ weaponmodel = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
- i = MSG_ReadShort ();
- if (cl.stats[STAT_HEALTH] != i)
- {
+ i = MSG_ReadShort();
+ if (cl.stats[STAT_HEALTH] != i){
cl.stats[STAT_HEALTH] = i;
- Sbar_Changed ();
+ Sbar_Changed();
}
- i = MSG_ReadByte ();
- if (cl.stats[STAT_AMMO] != i)
- {
+ i = MSG_ReadByte();
+ if(cl.stats[STAT_AMMO] != i){
cl.stats[STAT_AMMO] = i;
- Sbar_Changed ();
+ Sbar_Changed();
}
- for (i=0 ; i<4 ; i++)
- {
- j = MSG_ReadByte ();
- if (cl.stats[STAT_SHELLS+i] != j)
- {
+ for (i=0 ; i<4 ; i++){
+ j = MSG_ReadByte();
+ if(cl.stats[STAT_SHELLS+i] != j){
cl.stats[STAT_SHELLS+i] = j;
- Sbar_Changed ();
+ Sbar_Changed();
}
}
- i = MSG_ReadByte ();
-
- if (standard_quake)
- {
- if (cl.stats[STAT_ACTIVEWEAPON] != i)
- {
+ i = MSG_ReadByte();
+ if(standard_quake){
+ if(cl.stats[STAT_ACTIVEWEAPON] != i){
cl.stats[STAT_ACTIVEWEAPON] = i;
- Sbar_Changed ();
+ Sbar_Changed();
}
+ }else if(cl.stats[STAT_ACTIVEWEAPON] != (1<<i)){
+ cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
+ Sbar_Changed();
}
- else
- {
- if (cl.stats[STAT_ACTIVEWEAPON] != (1<<i))
- {
- cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
- Sbar_Changed ();
- }
+
+ if(bits & cl.protocol->fl_large_weaponmodel)
+ weaponmodel |= MSG_ReadByte() << 8;
+ if(cl.stats[STAT_WEAPON] != weaponmodel){
+ cl.stats[STAT_WEAPON] = weaponmodel;
+ Sbar_Changed();
}
+ if(bits & cl.protocol->fl_large_weaponframe)
+ cl.stats[STAT_WEAPONFRAME] |= MSG_ReadByte() << 8;
+
if(cl.viewent.model != cl.model_precache[cl.stats[STAT_WEAPON]]){
// FIXME(sigrid) - reset lerp
}
@@ -624,7 +571,7 @@
CL_ParseStatic
=====================
*/
-void CL_ParseStatic (void)
+void CL_ParseStatic (int withbits)
{
entity_t *ent;
int i;
@@ -634,7 +581,7 @@
Host_Error ("Too many static entities");
ent = &cl_static_entities[i];
cl.num_statics++;
- CL_ParseBaseline (ent);
+ CL_ParseBaseline(withbits, ent);
// copy it to the current state
ent->model = cl.model_precache[ent->baseline.modelindex];
@@ -653,17 +600,17 @@
CL_ParseStaticSound
===================
*/
-void CL_ParseStaticSound (void)
+void CL_ParseStaticSound (int large_sound)
{
vec3_t org;
int sound_num, vol, atten;
- MSG_ReadVec(org);
- sound_num = MSG_ReadByte ();
- vol = MSG_ReadByte ();
- atten = MSG_ReadByte ();
+ MSG_ReadVec(cl.protocol, org);
+ sound_num = large_sound ? MSG_ReadShort() : MSG_ReadByte();
+ vol = MSG_ReadByte();
+ atten = MSG_ReadByte();
- staticsfx (cl.sound_precache[sound_num], org, vol, atten);
+ staticsfx(cl.sound_precache[sound_num], org, vol, atten);
}
@@ -676,8 +623,8 @@
*/
void CL_ParseServerMessage (void)
{
- int cmd;
- int i;
+ int cmd, i, n;
+ protocol_t *p;
//
// if recording demos, copy the message out
@@ -700,7 +647,7 @@
cmd = MSG_ReadByte ();
- if (cmd == -1)
+ if (cmd < 0)
{
SHOWNET("END OF MESSAGE");
return; // end of message
@@ -707,10 +654,10 @@
}
// if the high bit of the command byte is set, it is a fast update
- if (cmd & 128)
+ if (cmd & U_SIGNAL)
{
SHOWNET("fast update");
- CL_ParseUpdate (cmd&127);
+ CL_ParseUpdate (cmd);
continue;
}
@@ -733,14 +680,21 @@
break;
case svc_clientdata:
- i = (ushort)MSG_ReadShort ();
- CL_ParseClientdata (i);
+ CL_ParseClientdata((ushort)MSG_ReadShort());
break;
case svc_version:
- i = MSG_ReadLong ();
- if (i != PROTOCOL_VERSION)
- Host_Error ("CL_ParseServerMessage: Server is protocol %d instead of %d\n", i, PROTOCOL_VERSION);
+ i = MSG_ReadLong();
+ for(p = nil, n = 0; n < nelem(protos); n++){
+ if(protos[n].version == i){
+ p = &protos[n];
+ break;
+ }
+ }
+ if(p == nil)
+ Host_Error("CL_ParseServerMessage: server uses unknown protocol %d\n", i);
+ if(p->version != cl.protocol->version)
+ Host_Error("CL_ParseServerMessage: server decided to switch protocol to %d mid-game?\n", i);
break;
case svc_disconnect:
@@ -769,7 +723,7 @@
case svc_setangle:
for (i=0 ; i<3 ; i++)
- cl.viewangles[i] = sv.protocol->MSG_ReadAngle ();
+ cl.viewangles[i] = cl.protocol->MSG_ReadAngle ();
break;
case svc_setview:
@@ -823,15 +777,17 @@
break;
case svc_spawnbaseline:
- i = MSG_ReadShort ();
+ case svc_spawnbaseline2:
+ i = MSG_ReadShort();
// must use CL_EntityNum() to force cl.num_entities up
- CL_ParseBaseline (CL_EntityNum(i));
+ CL_ParseBaseline(cmd == svc_spawnbaseline2, CL_EntityNum(i));
break;
case svc_spawnstatic:
- CL_ParseStatic ();
- break;
+ case svc_spawnstatic2:
+ CL_ParseStatic(cmd == svc_spawnstatic2);
+ break;
case svc_temp_entity:
- CL_ParseTEnt ();
+ CL_ParseTEnt();
break;
case svc_setpause:
@@ -869,7 +825,8 @@
break;
case svc_spawnstaticsound:
- CL_ParseStaticSound ();
+ case svc_spawnstaticsound2:
+ CL_ParseStaticSound(cmd == svc_spawnstaticsound2);
break;
case svc_cdtrack:
--- a/cl_tent.c
+++ b/cl_tent.c
@@ -46,8 +46,8 @@
ent = MSG_ReadShort ();
- MSG_ReadVec(start);
- MSG_ReadVec(end);
+ MSG_ReadVec(cl.protocol, start);
+ MSG_ReadVec(cl.protocol, end);
// override any beam with the same entity
for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)
@@ -94,19 +94,19 @@
switch (type)
{
case TE_WIZSPIKE: // spike hitting wall
- MSG_ReadVec(pos);
+ MSG_ReadVec(cl.protocol, pos);
R_RunParticleEffect (pos, vec3_origin, 20, 30);
startsfx (-1, 0, cl_sfx_wizhit, pos, 1, 1);
break;
case TE_KNIGHTSPIKE: // spike hitting wall
- MSG_ReadVec(pos);
+ MSG_ReadVec(cl.protocol, pos);
R_RunParticleEffect (pos, vec3_origin, 226, 20);
startsfx (-1, 0, cl_sfx_knighthit, pos, 1, 1);
break;
case TE_SPIKE: // spike hitting wall
- MSG_ReadVec(pos);
+ MSG_ReadVec(cl.protocol, pos);
R_RunParticleEffect (pos, vec3_origin, 0, 10);
if ( rand() % 5 )
startsfx (-1, 0, cl_Sfxink1, pos, 1, 1);
@@ -122,7 +122,7 @@
}
break;
case TE_SUPERSPIKE: // super spike hitting wall
- MSG_ReadVec(pos);
+ MSG_ReadVec(cl.protocol, pos);
R_RunParticleEffect (pos, vec3_origin, 0, 20);
if ( rand() % 5 )
@@ -140,12 +140,12 @@
break;
case TE_GUNSHOT: // bullet hitting wall
- MSG_ReadVec(pos);
+ MSG_ReadVec(cl.protocol, pos);
R_RunParticleEffect (pos, vec3_origin, 0, 20);
break;
case TE_EXPLOSION: // rocket explosion
- MSG_ReadVec(pos);
+ MSG_ReadVec(cl.protocol, pos);
R_ParticleExplosion (pos);
dl = CL_AllocDlight (0);
VectorCopy (pos, dl->origin);
@@ -156,7 +156,7 @@
break;
case TE_TAREXPLOSION: // tarbaby explosion
- MSG_ReadVec(pos);
+ MSG_ReadVec(cl.protocol, pos);
R_BlobExplosion (pos);
startsfx (-1, 0, cl_sfx_r_exp3, pos, 1, 1);
@@ -181,17 +181,17 @@
// PGM 01/21/97
case TE_LAVASPLASH:
- MSG_ReadVec(pos);
+ MSG_ReadVec(cl.protocol, pos);
R_LavaSplash (pos);
break;
case TE_TELEPORT:
- MSG_ReadVec(pos);
+ MSG_ReadVec(cl.protocol, pos);
R_TeleportSplash (pos);
break;
case TE_EXPLOSION2: // color mapped explosion
- MSG_ReadVec(pos);
+ MSG_ReadVec(cl.protocol, pos);
colorStart = MSG_ReadByte ();
colorLength = MSG_ReadByte ();
R_ParticleExplosion2 (pos, colorStart, colorLength);
--- a/client.h
+++ b/client.h
@@ -119,6 +119,7 @@
//
typedef struct
{
+ protocol_t *protocol;
int movemessages; // since connecting to this server
// throw out the first couple, so the player
// doesn't accidentally do something the
--- a/common.c
+++ b/common.c
@@ -175,7 +175,7 @@
void MSG_WriteAngleInt16 (sizebuf_t *sb, float f)
{
- MSG_WriteShort (sb, Qrint(f*65536.0/360.0));
+ MSG_WriteShort (sb, Qrint(f*65536.0/360.0) & 65535);
}
//
--- a/common.h
+++ b/common.h
@@ -36,6 +36,10 @@
//============================================================================
+#define max(a,b) ((a)>(b)?(a):(b))
+#define min(a,b) ((a)<(b)?(a):(b))
+#define clamp(x,a,b) (min(max((x),(a)),(b)))
+
#define Q_MAXCHAR ((char)0x7f)
#define Q_MAXSHORT ((short)0x7fff)
#define Q_MAXINT ((int)0x7fffffff)
@@ -59,8 +63,6 @@
//============================================================================
-#define Qrint(f) (int)((f) + ((f) >= 0 ? 0.5 : -0.5))
-
void MSG_WriteChar (sizebuf_t *sb, int c);
void MSG_WriteByte (sizebuf_t *sb, int c);
void MSG_WriteShort (sizebuf_t *sb, int c);
@@ -88,10 +90,16 @@
float MSG_ReadAngle (void);
float MSG_ReadAngleInt16 (void);
-#define MSG_ReadVec(d) do{ \
- (d)[0] = sv.protocol->MSG_ReadCoord(); \
- (d)[1] = sv.protocol->MSG_ReadCoord(); \
- (d)[2] = sv.protocol->MSG_ReadCoord(); \
+#define MSG_ReadVec(proto, d) do{ \
+ (d)[0] = (proto)->MSG_ReadCoord(); \
+ (d)[1] = (proto)->MSG_ReadCoord(); \
+ (d)[2] = (proto)->MSG_ReadCoord(); \
+}while(0)
+
+#define MSG_WriteVec(proto, sb, s) do{ \
+ (proto)->MSG_WriteCoord(sb, (s)[0]); \
+ (proto)->MSG_WriteCoord(sb, (s)[1]); \
+ (proto)->MSG_WriteCoord(sb, (s)[2]); \
}while(0)
//============================================================================
--- a/dat.h
+++ b/dat.h
@@ -3,7 +3,7 @@
extern char *game;
enum{
- Npath = 64,
+ Npath = 128,
Nfspath = 128,
Nsav = 12,
Nsavcm = 40,
--- a/mathlib.h
+++ b/mathlib.h
@@ -17,6 +17,8 @@
extern vec3_t vec3_origin;
extern int nanmask;
+#define Qrint(f) (int)((f) + ((f) >= 0 ? 0.5 : -0.5))
+
#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
--- a/mkfile
+++ b/mkfile
@@ -47,6 +47,7 @@
pr_cmds.$O\
pr_edict.$O\
pr_exec.$O\
+ protocol.$O\
qk1.$O\
r_aclip.$O\
r_alias.$O\
--- a/pr_cmds.c
+++ b/pr_cmds.c
@@ -229,7 +229,6 @@
for (i=0, check = sv.model_precache ; *check ; i++, check++)
if (!strcmp(*check, m))
break;
-
if (!*check)
PR_RunError ("no precache: %s\n", m);
e->v.model = PR_SetStr(m);
@@ -511,15 +510,22 @@
// add an svc_spawnambient command to the level signon packet
- MSG_WriteByte (&sv.signon,svc_spawnstaticsound);
+ if(soundnum >= sv.protocol->limit_sound)
+ return;
+
+ MSG_WriteByte(
+ &sv.signon,
+ soundnum < sv.protocol->large_sound ?
+ svc_spawnstaticsound :
+ svc_spawnstaticsound2
+ );
for (i=0 ; i<3 ; i++)
sv.protocol->MSG_WriteCoord(&sv.signon, pos[i]);
- MSG_WriteByte (&sv.signon, soundnum);
+ (soundnum < sv.protocol->large_sound ? MSG_WriteByte : MSG_WriteShort)(&sv.signon, soundnum);
+ MSG_WriteByte(&sv.signon, vol*255);
+ MSG_WriteByte(&sv.signon, attenuation*64);
- MSG_WriteByte (&sv.signon, vol*255);
- MSG_WriteByte (&sv.signon, attenuation*64);
-
}
/*
@@ -994,7 +1000,7 @@
if (sv.state != ss_loading)
PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions");
-
+
s = G_STRING(OFS_PARM0);
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
PR_CheckEmptyString (s);
--- a/pr_edict.c
+++ b/pr_edict.c
@@ -7,6 +7,7 @@
dprograms_t *progs;
dfunction_t *pr_functions;
char *pr_strings;
+static int pr_strings_size;
ddef_t *pr_fielddefs;
ddef_t *pr_globaldefs;
dstatement_t *pr_statements;
@@ -81,6 +82,10 @@
{
int i;
+ if(s == nil)
+ return 0;
+ if(s >= pr_strings && s < pr_strings+pr_strings_size-1)
+ return s - pr_strings;
for(i = 0; i < num_prstr; i++){
if(s == prstr[i])
return -1-i;
@@ -958,7 +963,7 @@
if(prtempstr == nil)
prtempstr = malloc(MAX_PRTEMPSTR*PRTEMPSTR_SIZE);
- memset(prstr, 0, MAX_PRSTR*sizeof(*prstr));
+ memset(prstr, 0, max_prstr*sizeof(*prstr));
memset(prtempstr, 0, MAX_PRTEMPSTR*PRTEMPSTR_SIZE);
num_prstr = 0;
num_prtempstr = 0;
@@ -985,6 +990,7 @@
pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions);
pr_strings = (char *)progs + progs->ofs_strings;
+ pr_strings_size = progs->numstrings;
pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs);
pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);
pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);
--- a/pr_exec.c
+++ b/pr_exec.c
@@ -373,9 +373,9 @@
s++; // next statement
st = &pr_statements[s];
- a = (eval_t *)&pr_globals[st->a];
- b = (eval_t *)&pr_globals[st->b];
- c = (eval_t *)&pr_globals[st->c];
+ a = (eval_t *)&pr_globals[(unsigned short)st->a];
+ b = (eval_t *)&pr_globals[(unsigned short)st->b];
+ c = (eval_t *)&pr_globals[(unsigned short)st->c];
if (!--runaway)
PR_RunError ("runaway loop error");
@@ -618,9 +618,9 @@
case OP_DONE:
case OP_RETURN:
- pr_globals[OFS_RETURN] = pr_globals[st->a];
- pr_globals[OFS_RETURN+1] = pr_globals[st->a+1];
- pr_globals[OFS_RETURN+2] = pr_globals[st->a+2];
+ pr_globals[OFS_RETURN] = pr_globals[(unsigned short)st->a];
+ pr_globals[OFS_RETURN+1] = pr_globals[(unsigned short)st->a+1];
+ pr_globals[OFS_RETURN+2] = pr_globals[(unsigned short)st->a+2];
s = PR_LeaveFunction ();
if (pr_depth == exitdepth)
--- a/progs.h
+++ b/progs.h
@@ -11,7 +11,7 @@
int edict;
} eval_t;
-#define MAX_ENT_LEAFS 16
+#define MAX_ENT_LEAFS 32
typedef struct edict_s
{
qboolean free;
@@ -18,7 +18,7 @@
link_t area; // linked to a division node or leaf
int num_leafs;
- short leafnums[MAX_ENT_LEAFS];
+ int leafnums[MAX_ENT_LEAFS];
entity_state_t baseline;
--- /dev/null
+++ b/protocol.c
@@ -1,0 +1,72 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "quakedef.h"
+#include "fns.h"
+
+static void
+MSG_WriteProtocolInfoNQ(sizebuf_t *sb, protocol_t *proto)
+{
+ USED(sb, proto);
+}
+
+static void
+MSG_ReadProtocolInfoNQ(protocol_t *proto)
+{
+ USED(proto);
+ proto->flags = 0;
+}
+
+static void
+MSG_WriteProtocolInfoRMQ(sizebuf_t *sb, protocol_t *proto)
+{
+ USED(proto);
+ MSG_WriteLong(sb, PF_RMQ_ANGLE_INT16|PF_RMQ_COORD_INT32);
+}
+
+static void
+MSG_ReadProtocolInfoRMQ(protocol_t *proto)
+{
+ proto->flags = MSG_ReadLong();
+ if(proto->flags != (PF_RMQ_ANGLE_INT16|PF_RMQ_COORD_INT32))
+ fatal("FIXME RMQ protocol implementation limited to angle_int16 and coord_int32");
+}
+
+protocol_t protos[PROTO_NUM] = {
+ [PROTO_NQ] = {
+ .id = PROTO_NQ,
+ .name = "Quake",
+ .version = 15,
+ .limit_entity = 8192,
+ .limit_channel = 8,
+ .limit_sound = 256,
+ .limit_frame = 256,
+ .limit_model = 256,
+ .MSG_WriteCoord = MSG_WriteCoord,
+ .MSG_WriteAngle = MSG_WriteAngle,
+ .MSG_ReadCoord = MSG_ReadCoord,
+ .MSG_ReadAngle = MSG_ReadAngle,
+ .MSG_WriteProtocolInfo = MSG_WriteProtocolInfoNQ,
+ .MSG_ReadProtocolInfo = MSG_ReadProtocolInfoNQ,
+ },
+ [PROTO_RMQ] = {
+ .id = PROTO_RMQ,
+ .name = "RMQ",
+ .version = 999,
+ .fl_large_entity = 1<<3, .large_entity = 8192, .limit_entity = 65536,
+ .fl_large_channel = 1<<3, .large_channel = 8, .limit_channel = 256,
+ .fl_large_sound = 1<<4, .large_sound = 256, .limit_sound = MAX_SOUNDS,
+ .fl_large_frame = 1<<17, .large_frame = 256, .limit_frame = 65536,
+ .fl_large_model = 1<<18, .large_model = 256, .limit_model = MAX_MODELS,
+ .fl_large_weaponframe = 1<<24,
+ .fl_large_weaponmodel = 1<<16,
+ .fl_large_baseline_model = 1<<0,
+ .fl_large_baseline_frame = 1<<1,
+ .MSG_WriteCoord = MSG_WriteCoordInt32,
+ .MSG_WriteAngle = MSG_WriteAngleInt16,
+ .MSG_ReadCoord = MSG_ReadCoordInt32,
+ .MSG_ReadAngle = MSG_ReadAngleInt16,
+ .MSG_WriteProtocolInfo = MSG_WriteProtocolInfoRMQ,
+ .MSG_ReadProtocolInfo = MSG_ReadProtocolInfoRMQ,
+ },
+};
--- a/protocol.h
+++ b/protocol.h
@@ -1,143 +1,179 @@
// protocol.h -- communications protocols
-#define PROTOCOL_VERSION 15
+enum {
+ PROTO_NQ,
+ PROTO_RMQ,
+ PROTO_NUM,
+};
-// if the high bit of the servercmd is set, the low bits are fast update flags:
-#define U_MOREBITS (1<<0)
-#define U_ORIGIN1 (1<<1)
-#define U_ORIGIN2 (1<<2)
-#define U_ORIGIN3 (1<<3)
-#define U_ANGLE2 (1<<4)
-#define U_NOLERP (1<<5) // don't interpolate movement
-#define U_FRAME (1<<6)
-#define U_SIGNAL (1<<7) // just differentiates from other updates
+// these are the only ones supported with RMQ atm
+enum {
+ PF_RMQ_ANGLE_INT16 = 1<<1,
+ PF_RMQ_COORD_INT32 = 1<<7,
+};
-// svc_update can pass all of the fast update bits, plus more
-#define U_ANGLE1 (1<<8)
-#define U_ANGLE3 (1<<9)
-#define U_MODEL (1<<10)
-#define U_COLORMAP (1<<11)
-#define U_SKIN (1<<12)
-#define U_EFFECTS (1<<13)
-#define U_LONGENTITY (1<<14)
+typedef struct protocol_t protocol_t;
+struct protocol_t {
+ int id;
+ int version;
+ int flags;
+ char *name;
-#define SU_VIEWHEIGHT (1<<0)
-#define SU_IDEALPITCH (1<<1)
-#define SU_PUNCH1 (1<<2)
-#define SU_PUNCH2 (1<<3)
-#define SU_PUNCH3 (1<<4)
-#define SU_VELOCITY1 (1<<5)
-#define SU_VELOCITY2 (1<<6)
-#define SU_VELOCITY3 (1<<7)
-//define SU_AIMENT (1<<8) AVAILABLE BIT
-#define SU_ITEMS (1<<9)
-#define SU_ONGROUND (1<<10) // no data follows, the bit is it
-#define SU_INWATER (1<<11) // no data follows, the bit is it
-#define SU_WEAPONFRAME (1<<12)
-#define SU_ARMOR (1<<13)
-#define SU_WEAPON (1<<14)
+ // flexible limits - messages change
+ u32int fl_large_entity;
+ int large_entity;
+ u32int fl_large_channel;
+ int large_channel;
+ u32int fl_large_sound;
+ int large_sound;
+ u32int fl_large_frame;
+ int large_frame;
+ u32int fl_large_model;
+ int large_model;
+ u32int fl_large_weaponframe;
+ u32int fl_large_weaponmodel;
+ u32int fl_large_baseline_model;
+ u32int fl_large_baseline_frame;
-// a sound with no channel is a local only sound
-#define SND_VOLUME (1<<0) // a byte
-#define SND_ATTENUATION (1<<1) // a byte
-#define SND_LOOPING (1<<2) // a long
+ // absolute limits for the protocol
+ int limit_entity;
+ int limit_channel;
+ int limit_model;
+ int limit_frame;
+ int limit_sound;
+ void (*MSG_WriteCoord)(sizebuf_t *sb, float f);
+ void (*MSG_WriteAngle)(sizebuf_t *sb, float f);
+ float (*MSG_ReadCoord)(void);
+ float (*MSG_ReadAngle)(void);
+ void (*MSG_WriteProtocolInfo)(sizebuf_t *sb, protocol_t *proto);
+ void (*MSG_ReadProtocolInfo)(protocol_t *proto);
+};
+
+extern protocol_t protos[PROTO_NUM];
+
// defaults for clientinfo messages
#define DEFAULT_VIEWHEIGHT 22
+// if the high bit of the servercmd is set, the low bits are fast update flags:
+enum {
+ // game types sent by serverinfo
+ // these determine which intermission screen plays
+ GAME_COOP = 0,
+ GAME_DEATHMATCH,
-// game types sent by serverinfo
-// these determine which intermission screen plays
-#define GAME_COOP 0
-#define GAME_DEATHMATCH 1
+ U_MOREBITS = 1<<0,
+ U_ORIGIN1 = 1<<1,
+ U_ORIGIN2 = 1<<2,
+ U_ORIGIN3 = 1<<3,
+ U_ANGLE2 = 1<<4,
+ U_NOLERP = 1<<5, // don't interpolate movement
+ U_FRAME = 1<<6,
+ U_SIGNAL = 1<<7, // just differentiates from other updates
+ // svc_update can pass all of the fast update bits, plus more
+ U_ANGLE1 = 1<<8,
+ U_ANGLE3 = 1<<9,
+ U_MODEL = 1<<10,
+ U_COLORMAP = 1<<11,
+ U_SKIN = 1<<12,
+ U_EFFECTS = 1<<13,
+ U_LONGENTITY = 1<<14,
+ U_MOREBITS2 = 1<<15,
+ // some of the bits here (1<<16…1<<22) are reserved by specific protocols
+ U_MOREBITS3 = 1<<23,
-//==================
-// note that there are some defs.qc that mirror to these numbers
-// also related to svc_strings[] in cl_parse
-//==================
+ SU_VIEWHEIGHT = 1<<0,
+ SU_IDEALPITCH = 1<<1,
+ SU_PUNCH1 = 1<<2,
+ SU_PUNCH2 = 1<<3,
+ SU_PUNCH3 = 1<<4,
+ SU_VELOCITY1 = 1<<5,
+ SU_VELOCITY2 = 1<<6,
+ SU_VELOCITY3 = 1<<7,
+ //SU_AIMENT = 1<<8, AVAILABLE BIT
+ SU_ITEMS = 1<<9,
+ SU_ONGROUND = 1<<10, // no data follows, the bit is it
+ SU_INWATER = 1<<11, // no data follows, the bit is it
+ SU_WEAPONFRAME = 1<<12,
+ SU_ARMOR = 1<<13,
+ SU_WEAPON = 1<<14,
+ SU_MOREBITS = 1<<15,
+ // some of the bits here (1<<16…1<<22) are reserved by specific protocols
+ SU_MOREBITS2 = 1<<23,
-//
-// server to client
-//
-#define svc_bad 0
-#define svc_nop 1
-#define svc_disconnect 2
-#define svc_updatestat 3 // [byte] [long]
-#define svc_version 4 // [long] server version
-#define svc_setview 5 // [short] entity number
-#define svc_sound 6 // <see code>
-#define svc_time 7 // [float] server time
-#define svc_print 8 // [string] null terminated string
-#define svc_stufftext 9 // [string] stuffed into client's console buffer
+ // a sound with no channel is a local only sound
+ SND_VOLUME = 1<<0, // a byte
+ SND_ATTENUATION = 1<<1, // a byte
+ SND_LOOPING = 1<<2, // a long
+
+ // server to client
+ svc_bad = 0,
+ svc_nop,
+ svc_disconnect,
+ svc_updatestat, // [byte] [long]
+ svc_version, // [long] server version
+ svc_setview, // [short] entity number
+ svc_sound, // <see code>
+ svc_time, // [float] server time
+ svc_print, // [string] null terminated string
+ svc_stufftext, // [string] stuffed into client's console buffer
// the string should be \n terminated
-#define svc_setangle 10 // [angle3] set the view angle to this absolute value
-
-#define svc_serverinfo 11 // [long] version
+ svc_setangle, // [angle3] set the view angle to this absolute value
+ svc_serverinfo, // [long] version
// [string] signon string
// [string]..[0]model cache
// [string]...[0]sounds cache
-#define svc_lightstyle 12 // [byte] [string]
-#define svc_updatename 13 // [byte] [string]
-#define svc_updatefrags 14 // [byte] [short]
-#define svc_clientdata 15 // <shortbits + data>
-#define svc_stopsound 16 // <see code>
-#define svc_updatecolors 17 // [byte] [byte]
-#define svc_particle 18 // [vec3] <variable>
-#define svc_damage 19
-
-#define svc_spawnstatic 20
-// svc_spawnbinary 21
-#define svc_spawnbaseline 22
-
-#define svc_temp_entity 23
+ svc_lightstyle, // [byte] [string]
+ svc_updatename, // [byte] [string]
+ svc_updatefrags, // [byte] [short]
+ svc_clientdata, // <shortbits + data>
+ svc_stopsound, // <see code>
+ svc_updatecolors, // [byte] [byte]
+ svc_particle, // [vec3] <variable>
+ svc_damage,
+ svc_spawnstatic,
+ svc_spawnbinary, // unused
+ svc_spawnbaseline,
+ svc_temp_entity,
+ svc_setpause, // [byte] on / off
+ svc_signonnum, // [byte] used for the signon sequence
+ svc_centerprint, // [string] to put in center of the screen
+ svc_killedmonster,
+ svc_foundsecret,
+ svc_spawnstaticsound, // [coord3] [byte] samp [byte] vol [byte] aten
+ svc_intermission, // [string] music
+ svc_finale, // [string] music [string] text
+ svc_cdtrack, // [byte] track [byte] looptrack
+ svc_sellscreen,
+ svc_cutscene,
-#define svc_setpause 24 // [byte] on / off
-#define svc_signonnum 25 // [byte] used for the signon sequence
+ // non-NQ stuff
+ svc_spawnbaseline2 = 42,
+ svc_spawnstatic2,
+ svc_spawnstaticsound2,
-#define svc_centerprint 26 // [string] to put in center of the screen
+ // client to server
+ clc_bad = 0,
+ clc_nop,
+ clc_disconnect,
+ clc_move, // [usercmd_t]
+ clc_stringcmd, // [string] message
-#define svc_killedmonster 27
-#define svc_foundsecret 28
-
-#define svc_spawnstaticsound 29 // [coord3] [byte] samp [byte] vol [byte] aten
-
-#define svc_intermission 30 // [string] music
-#define svc_finale 31 // [string] music [string] text
-
-#define svc_cdtrack 32 // [byte] track [byte] looptrack
-#define svc_sellscreen 33
-
-#define svc_cutscene 34
-
-//
-// client to server
-//
-#define clc_bad 0
-#define clc_nop 1
-#define clc_disconnect 2
-#define clc_move 3 // [usercmd_t]
-#define clc_stringcmd 4 // [string] message
-
-
-//
-// temp entity events
-//
-#define TE_SPIKE 0
-#define TE_SUPERSPIKE 1
-#define TE_GUNSHOT 2
-#define TE_EXPLOSION 3
-#define TE_TAREXPLOSION 4
-#define TE_LIGHTNING1 5
-#define TE_LIGHTNING2 6
-#define TE_WIZSPIKE 7
-#define TE_KNIGHTSPIKE 8
-#define TE_LIGHTNING3 9
-#define TE_LAVASPLASH 10
-#define TE_TELEPORT 11
-#define TE_EXPLOSION2 12
-
-// PGM 01/21/97
-#define TE_BEAM 13
-// PGM 01/21/97
+ // temp entity events
+ TE_SPIKE = 0,
+ TE_SUPERSPIKE,
+ TE_GUNSHOT,
+ TE_EXPLOSION,
+ TE_TAREXPLOSION,
+ TE_LIGHTNING1,
+ TE_LIGHTNING2,
+ TE_WIZSPIKE,
+ TE_KNIGHTSPIKE,
+ TE_LIGHTNING3,
+ TE_LAVASPLASH,
+ TE_TELEPORT,
+ TE_EXPLOSION2,
+ TE_BEAM,
+};
--- a/quakedef.h
+++ b/quakedef.h
@@ -34,8 +34,8 @@
//
#define MAX_EDICTS 65536
#define Nlights 64
-#define MAX_MODELS 4096 // these are sent over the net as bytes
-#define MAX_SOUNDS 2048 // so they cannot be blindly increased
+#define MAX_MODELS 4096 // these are sent over the net as bytes with NQ
+#define MAX_SOUNDS 2048
#define MAX_STYLESTRING 64
--- a/r_part.c
+++ b/r_part.c
@@ -120,7 +120,7 @@
vec3_t org, dir;
int i, count, msgcount, color;
- MSG_ReadVec(org);
+ MSG_ReadVec(cl.protocol, org);
for (i=0 ; i<3 ; i++)
dir[i] = MSG_ReadChar () * (1.0/16);
msgcount = MSG_ReadByte ();
--- a/server.h
+++ b/server.h
@@ -11,21 +11,6 @@
typedef enum {ss_loading, ss_active} server_state_t;
-enum {
- PROTO_NQ,
- PROTO_RMQ,
- PROTO_NUM,
-};
-
-typedef struct {
- int id;
- char *name;
- void (*MSG_WriteCoord)(sizebuf_t *sb, float f);
- void (*MSG_WriteAngle)(sizebuf_t *sb, float f);
- float (*MSG_ReadCoord)(void);
- float (*MSG_ReadAngle)(void);
-}protocol_t;
-
typedef struct
{
qboolean active; // false if only a net client
@@ -101,62 +86,62 @@
//=============================================================================
-// edict->movetype values
-#define MOVETYPE_NONE 0 // never moves
-#define MOVETYPE_ANGLENOCLIP 1
-#define MOVETYPE_ANGLECLIP 2
-#define MOVETYPE_WALK 3 // gravity
-#define MOVETYPE_STEP 4 // gravity, special edge handling
-#define MOVETYPE_FLY 5
-#define MOVETYPE_TOSS 6 // gravity
-#define MOVETYPE_PUSH 7 // no clip to world, push and crush
-#define MOVETYPE_NOCLIP 8
-#define MOVETYPE_FLYMISSILE 9 // extra size to monsters
-#define MOVETYPE_BOUNCE 10
+enum {
+ // edict->movetype values
+ MOVETYPE_NONE, // never moves
+ MOVETYPE_ANGLENOCLIP,
+ MOVETYPE_ANGLECLIP,
+ MOVETYPE_WALK, // gravity
+ MOVETYPE_STEP, // gravity, special edge handling
+ MOVETYPE_FLY,
+ MOVETYPE_TOSS, // gravity
+ MOVETYPE_PUSH, // no clip to world, push and crush
+ MOVETYPE_NOCLIP,
+ MOVETYPE_FLYMISSILE, // extra size to monsters
+ MOVETYPE_BOUNCE,
-// edict->solid values
-#define SOLID_NOT 0 // no interaction with other objects
-#define SOLID_TRIGGER 1 // touch on edge, but not blocking
-#define SOLID_BBOX 2 // touch on edge, block
-#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground
-#define SOLID_BSP 4 // bsp clip, touch on edge, block
+ // edict->solid values
+ SOLID_NOT = 0, // no interaction with other objects
+ SOLID_TRIGGER, // touch on edge, but not blocking
+ SOLID_BBOX, // touch on edge, block
+ SOLID_SLIDEBOX, // touch on edge, but not an onground
+ SOLID_BSP, // bsp clip, touch on edge, block
-// edict->deadflag values
-#define DEAD_NO 0
-#define DEAD_DYING 1
-#define DEAD_DEAD 2
+ // edict->deadflag values
+ DEAD_NO = 0,
+ DEAD_DYING,
+ DEAD_DEAD,
-#define DAMAGE_NO 0
-#define DAMAGE_YES 1
-#define DAMAGE_AIM 2
+ DAMAGE_NO = 0,
+ DAMAGE_YES,
+ DAMAGE_AIM,
-// edict->flags
-#define FL_FLY 1
-#define FL_SWIM 2
-//#define FL_GLIMPSE 4
-#define FL_CONVEYOR 4
-#define FL_CLIENT 8
-#define FL_INWATER 16
-#define FL_MONSTER 32
-#define FL_GODMODE 64
-#define FL_NOTARGET 128
-#define FL_ITEM 256
-#define FL_ONGROUND 512
-#define FL_PARTIALGROUND 1024 // not all corners are valid
-#define FL_WATERJUMP 2048 // player jumping out of water
-#define FL_JUMPRELEASED 4096 // for jump debouncing
+ // edict->flags
+ FL_FLY = 1<<0,
+ FL_SWIM = 1<<1,
+ FL_CONVEYOR = 1<<2,
+ FL_CLIENT = 1<<3,
+ FL_INWATER = 1<<4,
+ FL_MONSTER = 1<<5,
+ FL_GODMODE = 1<<6,
+ FL_NOTARGET = 1<<7,
+ FL_ITEM = 1<<8,
+ FL_ONGROUND = 1<<9,
+ FL_PARTIALGROUND = 1<<10, // not all corners are valid
+ FL_WATERJUMP = 1<<11, // player jumping out of water
+ FL_JUMPRELEASED = 1<<12, // for jump debouncing
-// entity effects
+ // entity effects
+ EF_BRIGHTFIELD = 1<<0,
+ EF_MUZZLEFLASH = 1<<1,
+ EF_BRIGHTLIGHT = 1<<2,
+ EF_DIMLIGHT = 1<<3,
-#define EF_BRIGHTFIELD 1
-#define EF_MUZZLEFLASH 2
-#define EF_BRIGHTLIGHT 4
-#define EF_DIMLIGHT 8
-
-#define SPAWNFLAG_NOT_EASY 256
-#define SPAWNFLAG_NOT_MEDIUM 512
-#define SPAWNFLAG_NOT_HARD 1024
-#define SPAWNFLAG_NOT_DEATHMATCH 2048
+ SPAWNFLAG_NOT_EASY = 1<<8,
+ SPAWNFLAG_NOT_MEDIUM = 1<<9,
+ SPAWNFLAG_NOT_HARD = 1<<10,
+ SPAWNFLAG_NOT_DEATHMATCH = 1<<11,
+};
//============================================================================
--- a/sv_main.c
+++ b/sv_main.c
@@ -7,25 +7,6 @@
server_t sv;
server_static_t svs;
-static protocol_t protos[PROTO_NUM] = {
- [PROTO_NQ] = {
- .id = PROTO_NQ,
- .name = "Quake",
- .MSG_WriteCoord = MSG_WriteCoord,
- .MSG_WriteAngle = MSG_WriteAngle,
- .MSG_ReadCoord = MSG_ReadCoord,
- .MSG_ReadAngle = MSG_ReadAngle,
- },
- [PROTO_RMQ] = {
- .id = PROTO_RMQ,
- .name = "RMQ",
- .MSG_WriteCoord = MSG_WriteCoordInt32,
- .MSG_WriteAngle = MSG_WriteAngleInt16,
- .MSG_ReadCoord = MSG_ReadCoordInt32,
- .MSG_ReadAngle = MSG_ReadAngleInt16,
- },
-};
-
// we can't just change protocol mid-game, so it's saved here first
static protocol_t *sv_protocol = &protos[PROTO_RMQ];
@@ -111,9 +92,7 @@
if (sv.datagram.cursize > MAX_DATAGRAM-16)
return;
MSG_WriteByte (&sv.datagram, svc_particle);
- sv.protocol->MSG_WriteCoord (&sv.datagram, org[0]);
- sv.protocol->MSG_WriteCoord (&sv.datagram, org[1]);
- sv.protocol->MSG_WriteCoord (&sv.datagram, org[2]);
+ MSG_WriteVec(sv.protocol, &sv.datagram, org);
for (i=0 ; i<3 ; i++)
{
v = dir[i]*16;
@@ -149,17 +128,8 @@
int field_mask;
int i;
int ent;
-
- if (volume < 0 || volume > 255)
- fatal ("SV_StartSound: volume = %d", volume);
- if (attenuation < 0 || attenuation > 4)
- fatal ("SV_StartSound: attenuation = %f", attenuation);
-
- if (channel < 0 || channel > 7)
- fatal ("SV_StartSound: channel = %d", channel);
-
- if (sv.datagram.cursize > MAX_DATAGRAM-16)
+ if (sv.datagram.cursize > MAX_DATAGRAM-21)
return;
// find precache number for sound
@@ -173,29 +143,41 @@
Con_Printf ("SV_StartSound: %s not precacheed\n", sample);
return;
}
-
+
+ volume = clamp(volume, 0, 255);
+ attenuation = clamp(attenuation, 0, 4);
+ channel = max(channel, 0);
ent = NUM_FOR_EDICT(entity);
- if(ent > 8191 || channel > 7 || sound_num > 255){ // FIXME(sigrid) - better protocol
+ if(ent >= sv.protocol->limit_entity || channel >= sv.protocol->limit_channel || sound_num >= sv.protocol->limit_sound)
return;
- }
- channel = (ent<<3) | channel;
-
field_mask = 0;
- if (volume != Spktvol)
+ if(ent >= sv.protocol->large_entity || channel >= sv.protocol->large_channel)
+ field_mask |= sv.protocol->fl_large_entity | sv.protocol->fl_large_channel;
+ if(sound_num >= sv.protocol->large_sound)
+ field_mask |= sv.protocol->fl_large_sound;
+ if(volume != Spktvol)
field_mask |= SND_VOLUME;
- if (attenuation != Spktatt)
+ if(attenuation != Spktatt)
field_mask |= SND_ATTENUATION;
// directed messages go only to the entity the are targeted on
- MSG_WriteByte (&sv.datagram, svc_sound);
- MSG_WriteByte (&sv.datagram, field_mask);
- if (field_mask & SND_VOLUME)
- MSG_WriteByte (&sv.datagram, volume);
- if (field_mask & SND_ATTENUATION)
- MSG_WriteByte (&sv.datagram, attenuation*64);
- MSG_WriteShort (&sv.datagram, channel);
- MSG_WriteByte (&sv.datagram, sound_num);
+ MSG_WriteByte(&sv.datagram, svc_sound);
+ MSG_WriteByte(&sv.datagram, field_mask);
+ if(field_mask & SND_VOLUME)
+ MSG_WriteByte(&sv.datagram, volume);
+ if(field_mask & SND_ATTENUATION)
+ MSG_WriteByte(&sv.datagram, attenuation*64);
+ if(field_mask & (sv.protocol->fl_large_entity | sv.protocol->fl_large_channel)){
+ MSG_WriteShort(&sv.datagram, ent);
+ MSG_WriteByte(&sv.datagram, channel);
+ }else{
+ MSG_WriteShort(&sv.datagram, ent<<3 | channel);
+ }
+ if(field_mask & sv.protocol->fl_large_sound)
+ MSG_WriteShort(&sv.datagram, sound_num);
+ else
+ MSG_WriteByte(&sv.datagram, sound_num);
for (i=0 ; i<3 ; i++)
sv.protocol->MSG_WriteCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]));
}
@@ -218,34 +200,31 @@
*/
void SV_SendServerinfo (client_t *client)
{
- char **s;
- char message[2048];
+ char **s;
+ int n;
+ char tmp[64];
MSG_WriteByte (&client->message, svc_print);
- sprint(message, "%c\nVERSION %4.2f SERVER (%ud CRC)\n", 2, VERSION, crcn);
- MSG_WriteString (&client->message,message);
+ snprint(tmp, sizeof(tmp), "%c\nNeinQuake %4.2f SERVER (%ud CRC)\n", 2, VERSION, crcn);
+ MSG_WriteString (&client->message, tmp);
MSG_WriteByte (&client->message, svc_serverinfo);
- MSG_WriteLong (&client->message, PROTOCOL_VERSION);
+ MSG_WriteLong (&client->message, sv.protocol->version);
+ sv.protocol->MSG_WriteProtocolInfo(&client->message, sv.protocol);
MSG_WriteByte (&client->message, svs.maxclients);
- if (!coop.value && deathmatch.value)
- MSG_WriteByte (&client->message, GAME_DEATHMATCH);
- else
- MSG_WriteByte (&client->message, GAME_COOP);
+ MSG_WriteByte (&client->message, (!coop.value && deathmatch.value) ? GAME_DEATHMATCH : GAME_COOP);
- sprint (message, PR_Str(sv.edicts->v.message));
+ MSG_WriteString (&client->message, PR_Str(sv.edicts->v.message));
- MSG_WriteString (&client->message,message);
+ for (n = 1, s = sv.model_precache+1 ; *s && n < sv.protocol->limit_model ; s++)
+ MSG_WriteString(&client->message, *s);
+ MSG_WriteByte(&client->message, 0);
- for (s = sv.model_precache+1 ; *s ; s++)
- MSG_WriteString (&client->message, *s);
- MSG_WriteByte (&client->message, 0);
+ for (n = 1, s = sv.sound_precache+1 ; *s && n < sv.protocol->limit_sound ; s++)
+ MSG_WriteString(&client->message, *s);
+ MSG_WriteByte(&client->message, 0);
- for (s = sv.sound_precache+1 ; *s ; s++)
- MSG_WriteString (&client->message, *s);
- MSG_WriteByte (&client->message, 0);
-
// send music
MSG_WriteByte (&client->message, svc_cdtrack);
MSG_WriteByte (&client->message, sv.edicts->v.sounds);
@@ -453,8 +432,8 @@
*/
void SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg)
{
+ u32int bits;
int e, i;
- int bits;
byte *pvs;
vec3_t org;
float miss;
@@ -468,8 +447,6 @@
ent = NEXT_EDICT(sv.edicts);
for (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent))
{
- if (e > 65535) // FIXME(sigrid) - better protocol
- continue;
// ignore if not touching a PV leaf
if (ent != clent) // clent is ALLWAYS sent
{
@@ -476,7 +453,7 @@
// ignore ents without visible models
if (!ent->v.modelindex || !*PR_Str(ent->v.model))
continue;
- if(ent->v.modelindex > 0xff) // FIXME(sigrid) - better protocol
+ if(ent->v.modelindex >= sv.protocol->limit_model)
continue;
for (i=0 ; i < ent->num_leafs ; i++)
@@ -483,7 +460,7 @@
if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
break;
- if (i == ent->num_leafs)
+ if (i == ent->num_leafs && ent->num_leafs < MAX_ENT_LEAFS)
continue; // not visible
}
@@ -502,47 +479,57 @@
if ( miss < -0.1 || miss > 0.1 )
bits |= U_ORIGIN1<<i;
}
-
if ( ent->v.angles[0] != ent->baseline.angles[0] )
bits |= U_ANGLE1;
-
if ( ent->v.angles[1] != ent->baseline.angles[1] )
bits |= U_ANGLE2;
-
if ( ent->v.angles[2] != ent->baseline.angles[2] )
bits |= U_ANGLE3;
-
if (ent->v.movetype == MOVETYPE_STEP)
bits |= U_NOLERP; // don't mess up the step animation
-
if (ent->baseline.colormap != ent->v.colormap)
bits |= U_COLORMAP;
-
if (ent->baseline.skin != ent->v.skin)
bits |= U_SKIN;
-
if (ent->baseline.frame != ent->v.frame)
bits |= U_FRAME;
-
if (ent->baseline.effects != ent->v.effects)
bits |= U_EFFECTS;
-
if (ent->baseline.modelindex != ent->v.modelindex)
bits |= U_MODEL;
-
if (e >= 256)
bits |= U_LONGENTITY;
-
- if (bits >= 256)
+ if((bits & U_FRAME) != 0){
+ if(ent->v.frame >= sv.protocol->limit_frame)
+ bits ^= U_FRAME;
+ else if(ent->v.frame >= sv.protocol->large_frame)
+ bits |= sv.protocol->fl_large_frame;
+ }
+ if((bits & U_MODEL) != 0){
+ if(ent->v.model >= sv.protocol->limit_model)
+ bits ^= U_MODEL;
+ else if(ent->v.model >= sv.protocol->large_model)
+ bits |= sv.protocol->fl_large_model;
+ }
+ if(bits >= (1<<8)){
bits |= U_MOREBITS;
-
+ if(bits >= (1<<16)){
+ bits |= U_MOREBITS2;
+ if(bits >= (1<<24))
+ bits |= U_MOREBITS3;
+ }
+ }
//
// write the message
//
- MSG_WriteByte (msg,bits | U_SIGNAL);
-
+ MSG_WriteByte (msg, bits | U_SIGNAL);
+
if (bits & U_MOREBITS)
MSG_WriteByte (msg, bits>>8);
+ if (bits & U_MOREBITS2)
+ MSG_WriteByte (msg, bits>>16);
+ if (bits & U_MOREBITS3)
+ MSG_WriteByte (msg, bits>>24);
if (bits & U_LONGENTITY)
MSG_WriteShort (msg,e);
else
@@ -570,6 +557,10 @@
sv.protocol->MSG_WriteCoord (msg, ent->v.origin[2]);
if (bits & U_ANGLE3)
sv.protocol->MSG_WriteAngle(msg, ent->v.angles[2]);
+ if (bits & sv.protocol->fl_large_frame)
+ MSG_WriteByte(msg, (int)ent->v.frame>>8);
+ if (bits & sv.protocol->fl_large_model)
+ MSG_WriteByte(msg, (int)ent->v.modelindex>>8);
}
}
@@ -600,10 +591,10 @@
*/
void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)
{
- int bits;
+ u32int bits;
int i;
edict_t *other;
- int items;
+ int items, weaponmodel;
eval_t *val;
//
@@ -632,15 +623,13 @@
{
MSG_WriteByte (msg, svc_setangle);
for (i=0 ; i < 3 ; i++)
- sv.protocol->MSG_WriteAngle (msg, ent->v.angles[i] );
+ sv.protocol->MSG_WriteAngle (msg, ent->v.angles[i]);
ent->v.fixangle = 0;
}
- bits = 0;
-
+ bits = SU_ITEMS | SU_WEAPON;
if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT)
bits |= SU_VIEWHEIGHT;
-
if (ent->v.idealpitch)
bits |= SU_IDEALPITCH;
@@ -647,45 +636,56 @@
// stuff the sigil bits into the high bits of items for sbar, or else
// mix in items2
val = GetEdictFieldValue(ent, "items2");
+ items = (int)ent->v.items | (val ? ((int)val->_float << 23) : ((int)pr_global_struct->serverflags << 28));
+ weaponmodel = SV_ModelIndex(PR_Str(ent->v.weaponmodel));
- if (val)
- items = (int)ent->v.items | ((int)val->_float << 23);
- else
- items = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28);
-
- bits |= SU_ITEMS;
-
- if ( (int)ent->v.flags & FL_ONGROUND)
+ if ((int)ent->v.flags & FL_ONGROUND)
bits |= SU_ONGROUND;
-
- if ( ent->v.waterlevel >= 2)
+ if (ent->v.waterlevel >= 2)
bits |= SU_INWATER;
-
+
for (i=0 ; i<3 ; i++)
{
if (ent->v.punchangle[i])
- bits |= (SU_PUNCH1<<i);
+ bits |= SU_PUNCH1<<i;
if (ent->v.velocity[i])
- bits |= (SU_VELOCITY1<<i);
+ bits |= SU_VELOCITY1<<i;
}
-
- if (ent->v.weaponframe)
- bits |= SU_WEAPONFRAME;
+ if (bits & SU_WEAPON){
+ if(weaponmodel >= sv.protocol->limit_model)
+ bits ^= SU_WEAPON; // yikes.
+ else if(weaponmodel >= sv.protocol->large_model)
+ bits |= sv.protocol->fl_large_weaponmodel;
+ }
+ if (ent->v.weaponframe){
+ bits |= SU_WEAPONFRAME;
+ if((int)ent->v.weaponframe >= sv.protocol->limit_frame)
+ bits ^= SU_WEAPONFRAME;
+ else if((int)ent->v.weaponframe >= sv.protocol->large_frame)
+ bits |= sv.protocol->fl_large_weaponframe;
+ }
if (ent->v.armorvalue)
bits |= SU_ARMOR;
-// if (ent->v.weapon)
- bits |= SU_WEAPON;
+ if(bits >= (1<<16)){
+ bits |= SU_MOREBITS;
+ if(bits >= (1<<24))
+ bits |= SU_MOREBITS2;
+ }
// send the data
MSG_WriteByte (msg, svc_clientdata);
MSG_WriteShort (msg, bits);
+ if(bits & SU_MOREBITS){
+ MSG_WriteByte(msg, bits>>16);
+ if(bits & SU_MOREBITS2)
+ MSG_WriteByte(msg, bits>>24);
+ }
if (bits & SU_VIEWHEIGHT)
MSG_WriteChar (msg, ent->v.view_ofs[2]);
-
if (bits & SU_IDEALPITCH)
MSG_WriteChar (msg, ent->v.idealpitch);
@@ -705,7 +705,7 @@
if (bits & SU_ARMOR)
MSG_WriteByte (msg, ent->v.armorvalue);
if (bits & SU_WEAPON)
- MSG_WriteByte (msg, SV_ModelIndex(PR_Str(ent->v.weaponmodel)));
+ MSG_WriteByte (msg, weaponmodel);
MSG_WriteShort (msg, ent->v.health);
MSG_WriteByte (msg, ent->v.currentammo);
@@ -729,6 +729,11 @@
}
}
}
+
+ if(bits & sv.protocol->fl_large_weaponmodel)
+ MSG_WriteByte(msg, weaponmodel>>8);
+ if(bits & sv.protocol->fl_large_weaponframe)
+ MSG_WriteByte(msg, (int)ent->v.weaponframe>>8);
}
/*
@@ -944,6 +949,7 @@
*/
void SV_CreateBaseline (void)
{
+ u32int bits;
int i;
edict_t *svent;
int entnum;
@@ -975,15 +981,29 @@
svent->baseline.modelindex =
SV_ModelIndex(PR_Str(svent->v.model));
}
-
+
+ bits = 0;
+ if(svent->baseline.modelindex >= sv.protocol->limit_model)
+ svent->baseline.modelindex = 0; // yikes.
+ else if(svent->baseline.modelindex >= sv.protocol->large_model)
+ bits |= sv.protocol->fl_large_baseline_model;
+ if(svent->baseline.frame >= sv.protocol->limit_frame)
+ svent->baseline.frame = 0; // yikes.
+ else if(svent->baseline.frame >= sv.protocol->large_frame)
+ bits |= sv.protocol->fl_large_baseline_frame;
+
//
// add to the message
//
- MSG_WriteByte (&sv.signon,svc_spawnbaseline);
- MSG_WriteShort (&sv.signon,entnum);
+ MSG_WriteByte (&sv.signon, bits ? svc_spawnbaseline2 : svc_spawnbaseline);
+ MSG_WriteShort (&sv.signon, entnum);
+ if(bits != 0)
+ MSG_WriteByte(&sv.signon, bits);
- MSG_WriteByte (&sv.signon, svent->baseline.modelindex);
- MSG_WriteByte (&sv.signon, svent->baseline.frame);
+ ((bits & sv.protocol->fl_large_baseline_model) ? MSG_WriteShort : MSG_WriteByte)
+ (&sv.signon, svent->baseline.modelindex);
+ ((bits & sv.protocol->fl_large_baseline_frame) ? MSG_WriteShort : MSG_WriteByte)
+ (&sv.signon, svent->baseline.frame);
MSG_WriteByte (&sv.signon, svent->baseline.colormap);
MSG_WriteByte (&sv.signon, svent->baseline.skin);
for (i=0 ; i<3 ; i++)
--- a/view.c
+++ b/view.c
@@ -299,7 +299,7 @@
armor = MSG_ReadByte ();
blood = MSG_ReadByte ();
- MSG_ReadVec(from);
+ MSG_ReadVec(cl.protocol, from);
count = blood*0.5 + armor*0.5;
if (count < 10)