short CGVM_MSG_ReadShort(void)
{
- int num;
+ short num;
num = CGVM_MSG_ReadByte() | (CGVM_MSG_ReadByte() << 8);
return num;
}
Called to play the next demo in the demo loop
=====================
*/
-extern void Call_MR_ToggleMenu_f (void);
void CL_NextDemo (void)
{
char str[1024];
{
Con_Print("No demos listed with startdemos\n");
cls.demonum = -1;
- // put up menu instead of staring at console
- if (key_dest != key_menu)
- Call_MR_ToggleMenu_f();
return;
}
}
MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times
- if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
+ if (cl.protocol == PROTOCOL_QUAKE)
{
for (i = 0;i < 3;i++)
- MSG_WriteFloat (&buf, cl.viewangles[i]);
+ MSG_WriteAngle8i (&buf, cl.viewangles[i]);
}
- else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
+ else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
{
- for (i=0 ; i<3 ; i++)
- MSG_WritePreciseAngle (&buf, cl.viewangles[i]);
+ for (i = 0;i < 3;i++)
+ MSG_WriteAngle32f (&buf, cl.viewangles[i]);
}
- else
+ else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
{
- for (i=0 ; i<3 ; i++)
- MSG_WriteAngle (&buf, cl.viewangles[i]);
+ for (i = 0;i < 3;i++)
+ MSG_WriteAngle16i (&buf, cl.viewangles[i]);
}
- MSG_WriteShort (&buf, forwardmove);
- MSG_WriteShort (&buf, sidemove);
- MSG_WriteShort (&buf, upmove);
+ MSG_WriteCoord16i (&buf, forwardmove);
+ MSG_WriteCoord16i (&buf, sidemove);
+ MSG_WriteCoord16i (&buf, upmove);
forwardmove = sidemove = upmove = 0;
// send button bits
bits = 0;
- if ( in_attack.state & 3 )
- bits |= 1;
- in_attack.state &= ~2;
-
- if (in_jump.state & 3)
- bits |= 2;
- in_jump.state &= ~2;
// LordHavoc: added 6 new buttons
+ if (in_attack.state & 3) bits |= 1;in_attack.state &= ~2;
+ if (in_jump.state & 3) bits |= 2;in_jump.state &= ~2;
if (in_button3.state & 3) bits |= 4;in_button3.state &= ~2;
if (in_button4.state & 3) bits |= 8;in_button4.state &= ~2;
if (in_button5.state & 3) bits |= 16;in_button5.state &= ~2;
if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
{
// LordHavoc: should we ack this on receipt instead? would waste net bandwidth though
- i = EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase);
- if (i > 0)
+ if (cl.entitydatabase)
{
- MSG_WriteByte(&buf, clc_ackentities);
- MSG_WriteLong(&buf, i);
+ i = EntityFrame_MostRecentlyRecievedFrameNum(cl.entitydatabase);
+ if (i > 0)
+ {
+ MSG_WriteByte(&buf, clc_ackentities);
+ MSG_WriteLong(&buf, i);
+ }
}
}
- else
+ else if (cl.protocol == PROTOCOL_DARKPLACES4)
{
if (cl.entitydatabase4)
{
MSG_WriteLong(&buf, i);
}
}
+ else if (cl.protocol == PROTOCOL_DARKPLACES5)
+ {
+ i = cl.latestframenum;
+ if (cl_nodelta.integer)
+ i = -1;
+ if (developer_networkentities.integer >= 1)
+ Con_Printf("send clc_ackentities %i\n", i);
+ MSG_WriteByte(&buf, clc_ackentities);
+ MSG_WriteLong(&buf, i);
+ }
// deliver the message
if (cls.demoplayback)
// LordHavoc: have to set up the baseline info for alpha and other stuff
for (i = 0;i < cl_max_entities;i++)
{
- ClearStateToDefault(&cl_entities[i].state_baseline);
- ClearStateToDefault(&cl_entities[i].state_previous);
- ClearStateToDefault(&cl_entities[i].state_current);
+ cl_entities[i].state_baseline = defaultstate;
+ cl_entities[i].state_previous = defaultstate;
+ cl_entities[i].state_current = defaultstate;
}
CL_CGVM_Clear();
ent = &cl.viewent;
ent->state_previous = ent->state_current;
- ClearStateToDefault(&ent->state_current);
+ ent->state_current = defaultstate;
ent->state_current.time = cl.time;
ent->state_current.number = -1;
ent->state_current.active = true;
if (ent >= MAX_EDICTS)
Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
}
CL_ParseServerInfo
==================
*/
-qbyte entlife[MAX_EDICTS];
// FIXME: this is a lot of memory to be keeping around, this needs to be dynamically allocated and freed
static char parse_model_precache[MAX_MODELS][MAX_QPATH];
static char parse_sound_precache[MAX_SOUNDS][MAX_QPATH];
Matrix4x4_CreateFromQuakeEntity(&ent->render.matrix, 0, 0, 0, 0, 0, 0, 1);
Matrix4x4_Invert_Simple(&ent->render.inversematrix, &ent->render.matrix);
CL_BoundingBoxForEntity(&ent->render);
- // clear entlife array
- memset(entlife, 0, MAX_EDICTS);
cl_num_entities = 1;
void CL_MoveLerpEntityStates(entity_t *ent)
{
float odelta[3], adelta[3];
+ CL_ValidateState(&ent->state_current);
VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer)
}
}
-/*
-==================
-CL_ParseUpdate
-
-Parse an entity update message from the server
-If an entities model or origin changes from frame to frame, it must be
-relinked. Other attributes can change without relinking.
-==================
-*/
-void CL_ParseUpdate (int bits)
-{
- int num;
- entity_t *ent;
- entity_state_t new;
-
- if (bits & U_MOREBITS)
- bits |= (MSG_ReadByte()<<8);
- if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE)
- {
- bits |= MSG_ReadByte() << 16;
- if (bits & U_EXTEND2)
- bits |= MSG_ReadByte() << 24;
- }
-
- if (bits & U_LONGENTITY)
- num = (unsigned) MSG_ReadShort ();
- else
- num = (unsigned) MSG_ReadByte ();
-
- if (num >= MAX_EDICTS)
- Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
- if (num < 1)
- Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
-
- ent = cl_entities + num;
-
- // note: this inherits the 'active' state of the baseline chosen
- // (state_baseline is always active, state_current may not be active if
- // the entity was missing in the last frame)
- if (bits & U_DELTA)
- new = ent->state_current;
- else
- {
- new = ent->state_baseline;
- new.active = true;
- }
-
- new.number = num;
- new.time = cl.mtime[0];
- new.flags = 0;
- if (bits & U_MODEL) new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
- if (bits & U_FRAME) new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
- if (bits & U_COLORMAP) new.colormap = MSG_ReadByte();
- if (bits & U_SKIN) new.skin = MSG_ReadByte();
- if (bits & U_EFFECTS) new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
- if (bits & U_ORIGIN1) new.origin[0] = MSG_ReadCoord();
- if (bits & U_ANGLE1) new.angles[0] = MSG_ReadAngle();
- if (bits & U_ORIGIN2) new.origin[1] = MSG_ReadCoord();
- if (bits & U_ANGLE2) new.angles[1] = MSG_ReadAngle();
- if (bits & U_ORIGIN3) new.origin[2] = MSG_ReadCoord();
- if (bits & U_ANGLE3) new.angles[2] = MSG_ReadAngle();
- if (bits & U_STEP) new.flags |= RENDER_STEP;
- if (bits & U_ALPHA) new.alpha = MSG_ReadByte();
- if (bits & U_SCALE) new.scale = MSG_ReadByte();
- if (bits & U_EFFECTS2) new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
- if (bits & U_GLOWSIZE) new.glowsize = MSG_ReadByte();
- if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
- // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
- if (bits & U_COLORMOD) MSG_ReadByte();
- if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
- if (bits & U_FRAME2) new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
- if (bits & U_MODEL2) new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
- if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
- if (bits & U_EXTERIORMODEL) new.flags |= RENDER_EXTERIORMODEL;
-
- // LordHavoc: to allow playback of the Nehahra movie
- if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
- {
- // LordHavoc: evil format
- int i = MSG_ReadFloat();
- int j = MSG_ReadFloat() * 255.0f;
- if (i == 2)
- {
- i = MSG_ReadFloat();
- if (i)
- new.effects |= EF_FULLBRIGHT;
- }
- if (j < 0)
- new.alpha = 0;
- else if (j == 0 || j >= 255)
- new.alpha = 255;
- else
- new.alpha = j;
- }
-
- if (new.active)
- CL_ValidateState(&new);
-
- ent->state_previous = ent->state_current;
- ent->state_current = new;
- if (ent->state_current.active)
- {
- CL_MoveLerpEntityStates(ent);
- cl_entities_active[ent->state_current.number] = true;
- // mark as visible (no kill this frame)
- entlife[ent->state_current.number] = 2;
- }
-}
-
-static entity_frame_t entityframe;
-extern mempool_t *cl_entities_mempool;
void CL_ReadEntityFrame(void)
{
if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
- {
- int i;
- entity_t *ent;
- EntityFrame_Read(&cl.entitydatabase);
- EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
- for (i = 0;i < entityframe.numentities;i++)
- {
- // copy the states
- ent = &cl_entities[entityframe.entitydata[i].number];
- ent->state_previous = ent->state_current;
- ent->state_current = entityframe.entitydata[i];
- CL_MoveLerpEntityStates(ent);
- // the entity lives again...
- entlife[ent->state_current.number] = 2;
- cl_entities_active[ent->state_current.number] = true;
- }
- }
- else
- {
- if (!cl.entitydatabase4)
- cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool);
- EntityFrame4_CL_ReadFrame(cl.entitydatabase4);
- }
-}
-
-void CL_EntityUpdateSetup(void)
-{
-}
-
-void CL_EntityUpdateEnd(void)
-{
- if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
- {
- int i;
- // disable entities that disappeared this frame
- for (i = 1;i < MAX_EDICTS;i++)
- {
- // clear only the entities that were active last frame but not this
- // frame, don't waste time clearing all entities (which would cause
- // cache misses)
- if (entlife[i])
- {
- entlife[i]--;
- if (!entlife[i])
- cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
- }
- }
- }
+ EntityFrame_CL_ReadFrame();
+ else if (cl.protocol == PROTOCOL_DARKPLACES4)
+ EntityFrame4_CL_ReadFrame();
+ else if (cl.protocol == PROTOCOL_DARKPLACES5)
+ EntityFrame5_CL_ReadFrame();
}
/*
{
int i;
- ClearStateToDefault(&ent->state_baseline);
+ ent->state_baseline = defaultstate;
+ // FIXME: set ent->state_baseline.number?
ent->state_baseline.active = true;
if (large)
{
ent->state_baseline.skin = MSG_ReadByte();
for (i = 0;i < 3;i++)
{
- ent->state_baseline.origin[i] = MSG_ReadCoord ();
- ent->state_baseline.angles[i] = MSG_ReadAngle ();
+ ent->state_baseline.origin[i] = MSG_ReadCoord(cl.protocol);
+ ent->state_baseline.angles[i] = MSG_ReadAngle8i();
}
CL_ValidateState(&ent->state_baseline);
ent->state_previous = ent->state_current = ent->state_baseline;
cl.idealpitch = 0;
VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
- if (cl.protocol == PROTOCOL_DARKPLACES5)
+ for (i = 0;i < 3;i++)
{
- for (i = 0;i < 3;i++)
+ if (bits & (SU_PUNCH1<<i) )
{
- if (bits & (SU_PUNCH1<<i) )
- cl.punchangle[i] = MSG_ReadPreciseAngle();
- else
- cl.punchangle[i] = 0;
- if (bits & (SU_PUNCHVEC1<<i))
- cl.punchvector[i] = MSG_ReadFloat();
- else
- cl.punchvector[i] = 0;
- if (bits & (SU_VELOCITY1<<i) )
- cl.mvelocity[0][i] = MSG_ReadFloat();
+ if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
+ cl.punchangle[i] = MSG_ReadAngle16i();
+ else if (cl.protocol == PROTOCOL_QUAKE)
+ cl.punchangle[i] = MSG_ReadChar();
else
- cl.mvelocity[0][i] = 0;
+ Host_Error("CL_ParseClientData: unknown cl.protocol\n");
}
- }
- else
- {
- for (i = 0;i < 3;i++)
+ else
+ cl.punchangle[i] = 0;
+ if (bits & (SU_PUNCHVEC1<<i))
{
- if (bits & (SU_PUNCH1<<i) )
- {
- if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
- cl.punchangle[i] = MSG_ReadPreciseAngle();
- else
- cl.punchangle[i] = MSG_ReadChar();
- }
+ if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4)
+ cl.punchvector[i] = MSG_ReadCoord16i();
+ else if (cl.protocol == PROTOCOL_DARKPLACES5)
+ cl.punchvector[i] = MSG_ReadCoord32f();
else
- cl.punchangle[i] = 0;
- if (bits & (SU_PUNCHVEC1<<i))
- cl.punchvector[i] = MSG_ReadCoord();
- else
- cl.punchvector[i] = 0;
- if (bits & (SU_VELOCITY1<<i) )
+ Host_Error("CL_ParseClientData: unknown cl.protocol\n");
+ }
+ else
+ cl.punchvector[i] = 0;
+ if (bits & (SU_VELOCITY1<<i) )
+ {
+ if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4)
cl.mvelocity[0][i] = MSG_ReadChar()*16;
+ else if (cl.protocol == PROTOCOL_DARKPLACES5)
+ cl.mvelocity[0][i] = MSG_ReadCoord32f();
else
- cl.mvelocity[0][i] = 0;
+ Host_Error("CL_ParseClientData: unknown cl.protocol\n");
}
+ else
+ cl.mvelocity[0][i] = 0;
}
i = MSG_ReadLong ();
cl.onground = (bits & SU_ONGROUND) != 0;
cl.inwater = (bits & SU_INWATER) != 0;
- cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
- cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
- cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
- cl.stats[STAT_HEALTH] = MSG_ReadShort();
- cl.stats[STAT_AMMO] = MSG_ReadByte();
-
- cl.stats[STAT_SHELLS] = MSG_ReadByte();
- cl.stats[STAT_NAILS] = MSG_ReadByte();
- cl.stats[STAT_ROCKETS] = MSG_ReadByte();
- cl.stats[STAT_CELLS] = MSG_ReadByte();
-
- i = MSG_ReadByte ();
+ if (cl.protocol == PROTOCOL_DARKPLACES5)
+ {
+ cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadShort() : 0;
+ cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadShort() : 0;
+ cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadShort() : 0;
+ cl.stats[STAT_HEALTH] = MSG_ReadShort();
+ cl.stats[STAT_AMMO] = MSG_ReadShort();
+
+ cl.stats[STAT_SHELLS] = MSG_ReadShort();
+ cl.stats[STAT_NAILS] = MSG_ReadShort();
+ cl.stats[STAT_ROCKETS] = MSG_ReadShort();
+ cl.stats[STAT_CELLS] = MSG_ReadShort();
+ //cl.stats[STAT_GENERIC1] = MSG_ReadShort();
+ //cl.stats[STAT_GENERIC2] = MSG_ReadShort();
+ //cl.stats[STAT_GENERIC3] = MSG_ReadShort();
+ //cl.stats[STAT_GENERIC4] = MSG_ReadShort();
+ //cl.stats[STAT_GENERIC5] = MSG_ReadShort();
+ //cl.stats[STAT_GENERIC6] = MSG_ReadShort();
+
+ i = (unsigned short) MSG_ReadShort ();
+ }
+ else
+ {
+ cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
+ cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
+ cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
+ cl.stats[STAT_HEALTH] = MSG_ReadShort();
+ cl.stats[STAT_AMMO] = MSG_ReadByte();
+
+ cl.stats[STAT_SHELLS] = MSG_ReadByte();
+ cl.stats[STAT_NAILS] = MSG_ReadByte();
+ cl.stats[STAT_ROCKETS] = MSG_ReadByte();
+ cl.stats[STAT_CELLS] = MSG_ReadByte();
+
+ i = MSG_ReadByte ();
+ if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
+ i = (1<<i);
+ }
- if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
- i = (1<<i);
// GAME_NEXUIZ hud needs weapon change time
// GAME_NEXUIZ uses a bit number as it's STAT_ACTIVEWEAPON, not a bitfield
// like other modes
cl.viewzoomold = cl.viewzoomnew; // for interpolation
if (bits & SU_VIEWZOOM)
{
- i = MSG_ReadByte();
+ if (cl.protocol == PROTOCOL_DARKPLACES5)
+ i = (unsigned short) MSG_ReadShort();
+ else
+ i = MSG_ReadByte();
if (i < 2)
i = 2;
cl.viewzoomnew = (float) i * (1.0f / 255.0f);
vec3_t org;
int sound_num, vol, atten;
- MSG_ReadVector(org);
+ MSG_ReadVector(org, cl.protocol);
if (large)
sound_num = (unsigned short) MSG_ReadShort ();
else
vec3_t org;
int modelindex, startframe, framecount, framerate;
- MSG_ReadVector(org);
+ MSG_ReadVector(org, cl.protocol);
modelindex = MSG_ReadByte ();
startframe = MSG_ReadByte ();
framecount = MSG_ReadByte ();
vec3_t org;
int modelindex, startframe, framecount, framerate;
- MSG_ReadVector(org);
- modelindex = MSG_ReadShort ();
- startframe = MSG_ReadShort ();
+ MSG_ReadVector(org, cl.protocol);
+ modelindex = (unsigned short) MSG_ReadShort ();
+ startframe = (unsigned short) MSG_ReadShort ();
framecount = MSG_ReadByte ();
framerate = MSG_ReadByte ();
vec3_t start, end;
beam_t *b;
- ent = MSG_ReadShort ();
- MSG_ReadVector(start);
- MSG_ReadVector(end);
+ ent = (unsigned short) MSG_ReadShort ();
+ MSG_ReadVector(start, cl.protocol);
+ MSG_ReadVector(end, cl.protocol);
if (ent >= MAX_EDICTS)
{
{
case TE_WIZSPIKE:
// spike hitting wall
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 4);
Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
CL_AllocDlight(NULL, &tempmatrix, 100, 0.12f, 0.50f, 0.12f, 500, 0.2, 0, 0, false, 1);
case TE_KNIGHTSPIKE:
// spike hitting wall
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 4);
Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
CL_AllocDlight(NULL, &tempmatrix, 100, 0.50f, 0.30f, 0.10f, 500, 0.2, 0, 0, false, 1);
case TE_SPIKE:
// spike hitting wall
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 4);
// LordHavoc: changed to spark shower
CL_SparkShower(pos, vec3_origin, 15);
break;
case TE_SPIKEQUAD:
// quad spike hitting wall
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 4);
// LordHavoc: changed to spark shower
CL_SparkShower(pos, vec3_origin, 15);
break;
case TE_SUPERSPIKE:
// super spike hitting wall
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 4);
// LordHavoc: changed to dust shower
CL_SparkShower(pos, vec3_origin, 30);
break;
case TE_SUPERSPIKEQUAD:
// quad super spike hitting wall
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 4);
// LordHavoc: changed to dust shower
CL_SparkShower(pos, vec3_origin, 30);
// LordHavoc: added for improved blood splatters
case TE_BLOOD:
// blood puff
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 4);
dir[0] = MSG_ReadChar();
dir[1] = MSG_ReadChar();
break;
case TE_SPARK:
// spark shower
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 4);
dir[0] = MSG_ReadChar();
dir[1] = MSG_ReadChar();
CL_SparkShower(pos, dir, count);
break;
case TE_PLASMABURN:
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 4);
Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
CL_AllocDlight(NULL, &tempmatrix, 200, 1, 1, 1, 1000, 0.2, 0, 0, true, 1);
// LordHavoc: added for improved gore
case TE_BLOODSHOWER:
// vaporized body
- MSG_ReadVector(pos); // mins
- MSG_ReadVector(pos2); // maxs
- velspeed = MSG_ReadCoord(); // speed
- count = MSG_ReadShort(); // number of particles
+ MSG_ReadVector(pos, cl.protocol); // mins
+ MSG_ReadVector(pos2, cl.protocol); // maxs
+ velspeed = MSG_ReadCoord(cl.protocol); // speed
+ count = (unsigned short) MSG_ReadShort(); // number of particles
CL_BloodShower(pos, pos2, velspeed, count);
break;
case TE_PARTICLECUBE:
// general purpose particle effect
- MSG_ReadVector(pos); // mins
- MSG_ReadVector(pos2); // maxs
- MSG_ReadVector(dir); // dir
- count = MSG_ReadShort(); // number of particles
+ MSG_ReadVector(pos, cl.protocol); // mins
+ MSG_ReadVector(pos2, cl.protocol); // maxs
+ MSG_ReadVector(dir, cl.protocol); // dir
+ count = (unsigned short) MSG_ReadShort(); // number of particles
colorStart = MSG_ReadByte(); // color
colorLength = MSG_ReadByte(); // gravity (1 or 0)
- velspeed = MSG_ReadCoord(); // randomvel
+ velspeed = MSG_ReadCoord(cl.protocol); // randomvel
CL_ParticleCube(pos, pos2, dir, count, colorStart, colorLength, velspeed);
break;
case TE_PARTICLERAIN:
// general purpose particle effect
- MSG_ReadVector(pos); // mins
- MSG_ReadVector(pos2); // maxs
- MSG_ReadVector(dir); // dir
- count = MSG_ReadShort(); // number of particles
+ MSG_ReadVector(pos, cl.protocol); // mins
+ MSG_ReadVector(pos2, cl.protocol); // maxs
+ MSG_ReadVector(dir, cl.protocol); // dir
+ count = (unsigned short) MSG_ReadShort(); // number of particles
colorStart = MSG_ReadByte(); // color
CL_ParticleRain(pos, pos2, dir, count, colorStart, 0);
break;
case TE_PARTICLESNOW:
// general purpose particle effect
- MSG_ReadVector(pos); // mins
- MSG_ReadVector(pos2); // maxs
- MSG_ReadVector(dir); // dir
- count = MSG_ReadShort(); // number of particles
+ MSG_ReadVector(pos, cl.protocol); // mins
+ MSG_ReadVector(pos2, cl.protocol); // maxs
+ MSG_ReadVector(dir, cl.protocol); // dir
+ count = (unsigned short) MSG_ReadShort(); // number of particles
colorStart = MSG_ReadByte(); // color
CL_ParticleRain(pos, pos2, dir, count, colorStart, 1);
break;
case TE_GUNSHOT:
// bullet hitting wall
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 4);
// LordHavoc: changed to dust shower
CL_SparkShower(pos, vec3_origin, 15);
case TE_GUNSHOTQUAD:
// quad bullet hitting wall
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 4);
CL_SparkShower(pos, vec3_origin, 15);
Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
case TE_EXPLOSION:
// rocket explosion
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 10);
CL_ParticleExplosion(pos);
// LordHavoc: boosted color from 1.0, 0.8, 0.4 to 1.25, 1.0, 0.5
case TE_EXPLOSIONQUAD:
// quad rocket explosion
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 10);
CL_ParticleExplosion(pos);
Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
case TE_EXPLOSION3:
// Nehahra movie colored lighting explosion
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 10);
CL_ParticleExplosion(pos);
Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
- color[0] = MSG_ReadCoord() * (2.0f / 1.0f);
- color[1] = MSG_ReadCoord() * (2.0f / 1.0f);
- color[2] = MSG_ReadCoord() * (2.0f / 1.0f);
+ color[0] = MSG_ReadCoord(cl.protocol) * (2.0f / 1.0f);
+ color[1] = MSG_ReadCoord(cl.protocol) * (2.0f / 1.0f);
+ color[2] = MSG_ReadCoord(cl.protocol) * (2.0f / 1.0f);
CL_AllocDlight(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, 0, true, 1);
S_StartSound(-1, 0, cl_sfx_r_exp3, pos, 1, 1);
break;
case TE_EXPLOSIONRGB:
// colored lighting explosion
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 10);
CL_ParticleExplosion(pos);
color[0] = MSG_ReadByte() * (2.0f / 255.0f);
case TE_TAREXPLOSION:
// tarbaby explosion
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 10);
CL_BlobExplosion(pos);
break;
case TE_SMALLFLASH:
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 10);
Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
CL_AllocDlight(NULL, &tempmatrix, 200, 2, 2, 2, 1000, 0.2, 0, 0, true, 1);
break;
case TE_CUSTOMFLASH:
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 4);
radius = MSG_ReadByte() * 8;
velspeed = (MSG_ReadByte() + 1) * (1.0 / 256.0);
break;
case TE_FLAMEJET:
- MSG_ReadVector(pos);
- MSG_ReadVector(dir);
+ MSG_ReadVector(pos, cl.protocol);
+ MSG_ReadVector(dir, cl.protocol);
count = MSG_ReadByte();
CL_Flames(pos, dir, count);
break;
break;
case TE_LAVASPLASH:
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_LavaSplash(pos);
break;
case TE_TELEPORT:
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
CL_AllocDlight(NULL, &tempmatrix, 500, 1.0f, 1.0f, 1.0f, 1500, 99.0f, 0, 0, true, 1);
// CL_TeleportSplash(pos);
case TE_EXPLOSION2:
// color mapped explosion
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 10);
colorStart = MSG_ReadByte();
colorLength = MSG_ReadByte();
break;
case TE_TEI_G3:
- MSG_ReadVector(pos);
- MSG_ReadVector(pos2);
- MSG_ReadVector(dir);
+ MSG_ReadVector(pos, cl.protocol);
+ MSG_ReadVector(pos2, cl.protocol);
+ MSG_ReadVector(dir, cl.protocol);
CL_BeamParticle(pos, pos2, 12, 1, 0.3, 0.1, 1, 1);
CL_BeamParticle(pos, pos2, 5, 1, 0.9, 0.3, 1, 1);
break;
case TE_TEI_SMOKE:
- MSG_ReadVector(pos);
- MSG_ReadVector(dir);
+ MSG_ReadVector(pos, cl.protocol);
+ MSG_ReadVector(dir, cl.protocol);
count = MSG_ReadByte();
CL_FindNonSolidLocation(pos, pos, 4);
CL_Tei_Smoke(pos, dir, count);
break;
case TE_TEI_BIGEXPLOSION:
- MSG_ReadVector(pos);
+ MSG_ReadVector(pos, cl.protocol);
CL_FindNonSolidLocation(pos, pos, 10);
CL_ParticleExplosion(pos);
Matrix4x4_CreateTranslate(&tempmatrix, pos[0], pos[1], pos[2]);
break;
case TE_TEI_PLASMAHIT:
- MSG_ReadVector(pos);
- MSG_ReadVector(dir);
+ MSG_ReadVector(pos, cl.protocol);
+ MSG_ReadVector(dir, cl.protocol);
count = MSG_ReadByte();
CL_FindNonSolidLocation(pos, pos, 5);
CL_Tei_PlasmaHit(pos, dir, count);
// if the high bit of the command byte is set, it is a fast update
if (cmd & 128)
{
+ entitiesupdated = true;
// LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer)
temp = "entity";
cmdlogname[cmdindex] = temp;
cls.signon = SIGNONS;
CL_SignonReply ();
}
- CL_ParseUpdate (cmd&127);
+ EntityFrameQuake_ReadEntity (cmd&127);
continue;
}
break;
case svc_time:
- if (!entitiesupdated)
- {
- // this is a new frame, we'll be seeing entities,
- // so prepare for entity updates
- CL_EntityUpdateSetup();
- entitiesupdated = true;
- }
cl.mtime[1] = cl.mtime[0];
cl.mtime[0] = MSG_ReadFloat ();
break;
case svc_clientdata:
- i = MSG_ReadShort ();
+ i = (unsigned short) MSG_ReadShort ();
CL_ParseClientdata (i);
break;
case svc_setangle:
for (i=0 ; i<3 ; i++)
- cl.viewangles[i] = MSG_ReadAngle ();
+ {
+ if (cl.protocol == PROTOCOL_DARKPLACES5)
+ cl.viewangles[i] = MSG_ReadAngle16i ();
+ else
+ cl.viewangles[i] = MSG_ReadAngle8i ();
+ }
break;
case svc_setview:
break;
case svc_stopsound:
- i = MSG_ReadShort();
+ i = (unsigned short) MSG_ReadShort();
S_StopSound(i>>3, i&7);
break;
i = MSG_ReadByte ();
if (i >= cl.maxclients)
Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
- cl.scores[i].frags = MSG_ReadShort ();
+ cl.scores[i].frags = (unsigned short) MSG_ReadShort ();
break;
case svc_updatecolors:
break;
case svc_spawnbaseline:
- i = MSG_ReadShort ();
+ i = (unsigned short) MSG_ReadShort ();
if (i < 0 || i >= MAX_EDICTS)
Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
CL_ParseBaseline (cl_entities + i, false);
break;
case svc_spawnbaseline2:
- i = MSG_ReadShort ();
+ i = (unsigned short) MSG_ReadShort ();
if (i < 0 || i >= MAX_EDICTS)
Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
CL_ParseBaseline (cl_entities + i, true);
if (gamemode == GAME_TENEBRAE)
{
// repeating particle effect
- MSG_ReadCoord();
- MSG_ReadCoord();
- MSG_ReadCoord();
- MSG_ReadCoord();
- MSG_ReadCoord();
- MSG_ReadCoord();
+ MSG_ReadCoord(cl.protocol);
+ MSG_ReadCoord(cl.protocol);
+ MSG_ReadCoord(cl.protocol);
+ MSG_ReadCoord(cl.protocol);
+ MSG_ReadCoord(cl.protocol);
+ MSG_ReadCoord(cl.protocol);
MSG_ReadByte();
MSG_ReadLong();
MSG_ReadLong();
if (gamemode == GAME_TENEBRAE)
{
// particle effect
- MSG_ReadCoord();
- MSG_ReadCoord();
- MSG_ReadCoord();
+ MSG_ReadCoord(cl.protocol);
+ MSG_ReadCoord(cl.protocol);
+ MSG_ReadCoord(cl.protocol);
MSG_ReadByte();
MSG_ReadString();
}
}
if (entitiesupdated)
- CL_EntityUpdateEnd();
+ EntityFrameQuake_ISeeDeadEntities();
parsingerror = false;
}
vec3_t org, dir;
int i, count, msgcount, color;
- MSG_ReadVector(org);
+ MSG_ReadVector(org, cl.protocol);
for (i=0 ; i<3 ; i++)
dir[i] = MSG_ReadChar () * (1.0/16);
msgcount = MSG_ReadByte ();
int protocol;
// entity database stuff
- entity_database_t entitydatabase;
- entity_database4_t *entitydatabase4;
+ // latest received entity frame number
+ int latestframenum;
+ entityframe_database_t *entitydatabase;
+ entityframe4_database_t *entitydatabase4;
}
client_state_t;
extern int cl_num_temp_entities;
extern int cl_num_brushmodel_entities;
+extern mempool_t *cl_entities_mempool;
extern entity_t *cl_entities;
extern qbyte *cl_entities_active;
extern entity_t *cl_static_entities;
void CL_SendCmd (usercmd_t *cmd);
void CL_SendMove (usercmd_t *cmd);
+void CL_ValidateState(entity_state_t *s);
+void CL_MoveLerpEntityStates(entity_t *ent);
void CL_LerpUpdate(entity_t *e);
void CL_ParseTEnt (void);
void CL_RelinkBeams (void);
SZ_Write (sb, s, strlen(s)+1);
}
-// used by server (always latest PROTOCOL_DARKPLACES)
-void MSG_WriteDPCoord (sizebuf_t *sb, float f)
+void MSG_WriteCoord13i (sizebuf_t *sb, float f)
+{
+ if (f >= 0)
+ MSG_WriteShort (sb, (int)(f * 8.0f + 0.5f));
+ else
+ MSG_WriteShort (sb, (int)(f * 8.0f - 0.5f));
+}
+
+void MSG_WriteCoord16i (sizebuf_t *sb, float f)
{
if (f >= 0)
MSG_WriteShort (sb, (int)(f + 0.5f));
MSG_WriteShort (sb, (int)(f - 0.5f));
}
-void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
+void MSG_WriteCoord32f (sizebuf_t *sb, float f)
{
- if (f >= 0)
- MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
+ MSG_WriteFloat (sb, f);
+}
+
+void MSG_WriteCoord (sizebuf_t *sb, float f, int protocol)
+{
+ if (protocol == PROTOCOL_QUAKE)
+ MSG_WriteCoord13i (sb, f);
+ else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5)
+ MSG_WriteCoord32f (sb, f);
+ else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
+ MSG_WriteCoord16i (sb, f);
else
- MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
+ Host_Error("MSG_WriteCoord: unknown protocol\n");
+}
+
+void MSG_WriteVector (sizebuf_t *sb, float *v, int protocol)
+{
+ MSG_WriteCoord (sb, v[0], protocol);
+ MSG_WriteCoord (sb, v[1], protocol);
+ MSG_WriteCoord (sb, v[2], protocol);
}
// LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
-void MSG_WriteAngle (sizebuf_t *sb, float f)
+void MSG_WriteAngle8i (sizebuf_t *sb, float f)
{
if (f >= 0)
MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) - 0.5f) & 255);
}
+void MSG_WriteAngle16i (sizebuf_t *sb, float f)
+{
+ if (f >= 0)
+ MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
+ else
+ MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
+}
+
+void MSG_WriteAngle32f (sizebuf_t *sb, float f)
+{
+ MSG_WriteFloat (sb, f);
+}
+
+
//
// reading functions
//
return l;
}
-// used by client
-float MSG_ReadCoord (void)
+float MSG_ReadCoord13i (void)
{
- if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
- return (signed short) MSG_ReadLittleShort();
- else if (cl.protocol == PROTOCOL_DARKPLACES1)
- return MSG_ReadLittleFloat();
- else
- return MSG_ReadLittleShort() * (1.0f/8.0f);
+ return MSG_ReadLittleShort() * (1.0f/8.0f);
+}
+
+float MSG_ReadCoord16i (void)
+{
+ return (signed short) MSG_ReadLittleShort();
+}
+
+float MSG_ReadCoord32f (void)
+{
+ return MSG_ReadLittleFloat();
+}
+
+float MSG_ReadCoord (int protocol)
+{
+ if (protocol == PROTOCOL_QUAKE)
+ return MSG_ReadCoord13i();
+ else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5)
+ return MSG_ReadCoord32f();
+ else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
+ return MSG_ReadCoord16i();
+ Host_Error("MSG_ReadCoord: unknown protocol\n");
+ return 0;
+}
+
+void MSG_ReadVector (float *v, int protocol)
+{
+ v[0] = MSG_ReadCoord(protocol);
+ v[1] = MSG_ReadCoord(protocol);
+ v[2] = MSG_ReadCoord(protocol);
+}
+
+// LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
+float MSG_ReadAngle8i (void)
+{
+ return MSG_ReadByte () * (360.0f/256.0f);
+}
+
+float MSG_ReadAngle16i (void)
+{
+ return MSG_ReadShort () * (360.0f/65536.0f);
+}
+
+float MSG_ReadAngle32f (void)
+{
+ return MSG_ReadFloat ();
}
void MSG_WriteLong (sizebuf_t *sb, int c);
void MSG_WriteFloat (sizebuf_t *sb, float f);
void MSG_WriteString (sizebuf_t *sb, const char *s);
-void MSG_WriteCoord (sizebuf_t *sb, float f);
-void MSG_WriteAngle (sizebuf_t *sb, float f);
-void MSG_WritePreciseAngle (sizebuf_t *sb, float f);
-void MSG_WriteDPCoord (sizebuf_t *sb, float f);
+void MSG_WriteAngle8i (sizebuf_t *sb, float f);
+void MSG_WriteAngle16i (sizebuf_t *sb, float f);
+void MSG_WriteAngle32f (sizebuf_t *sb, float f);
+void MSG_WriteCoord13i (sizebuf_t *sb, float f);
+void MSG_WriteCoord16i (sizebuf_t *sb, float f);
+void MSG_WriteCoord32f (sizebuf_t *sb, float f);
+void MSG_WriteCoord (sizebuf_t *sb, float f, int protocol);
+void MSG_WriteVector (sizebuf_t *sb, float *v, int protocol);
extern int msg_readcount;
extern qboolean msg_badread; // set if a read goes beyond end of message
#define MSG_ReadLong MSG_ReadLittleLong
#define MSG_ReadFloat MSG_ReadLittleFloat
-float MSG_ReadCoord (void);
-
-#define MSG_ReadAngle() (MSG_ReadByte() * (360.0f / 256.0f))
-#define MSG_ReadPreciseAngle() (MSG_ReadShort() * (360.0f / 65536.0f))
-
-#define MSG_ReadVector(v) ((v)[0] = MSG_ReadCoord(), (v)[1] = MSG_ReadCoord(), (v)[2] = MSG_ReadCoord())
+float MSG_ReadAngle8i (void);
+float MSG_ReadAngle16i (void);
+float MSG_ReadAngle32f (void);
+float MSG_ReadCoord13i (void);
+float MSG_ReadCoord16i (void);
+float MSG_ReadCoord32f (void);
+float MSG_ReadCoord (int protocol);
+void MSG_ReadVector (float *v, int protocol);
//============================================================================
NetConn_Heartbeat(1);
// free the client now
+ if (host_client->entitydatabase)
+ EntityFrame_FreeDatabase(host_client->entitydatabase);
if (host_client->entitydatabase4)
EntityFrame4_FreeDatabase(host_client->entitydatabase4);
+ if (host_client->entitydatabase5)
+ EntityFrame5_FreeDatabase(host_client->entitydatabase5);
// clear the client struct (this sets active to false)
memset(host_client, 0, sizeof(*host_client));
}
*/
void Host_Status_f (void)
{
+ const char *protocolname;
client_t *client;
int seconds, minutes, hours = 0, j, players;
void (*print) (const char *fmt, ...);
players++;
print ("host: %s\n", Cvar_VariableString ("hostname"));
print ("version: %s build %s\n", gamename, buildstring);
+ switch(sv.protocol)
+ {
+ case PROTOCOL_QUAKE: protocolname = sv.netquakecompatible ? "QUAKE" : "QUAKEDP";break;
+ case PROTOCOL_DARKPLACES1: protocolname = "PROTOCOL_DARKPLACES1";break;
+ case PROTOCOL_DARKPLACES2: protocolname = "PROTOCOL_DARKPLACES2";break;
+ case PROTOCOL_DARKPLACES3: protocolname = "PROTOCOL_DARKPLACES3";break;
+ case PROTOCOL_DARKPLACES4: protocolname = "PROTOCOL_DARKPLACES4";break;
+ case PROTOCOL_DARKPLACES5: protocolname = "PROTOCOL_DARKPLACES5";break;
+ default: protocolname = "PROTOCOL_UNKNOWN";break;
+ }
+ print ("protocol: %i (%s)\n", sv.protocol, protocolname);
print ("map: %s\n", sv.name);
print ("players: %i active (%i max)\n\n", players, svs.maxclients);
for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
}
cvar_t cl_rate = {CVAR_SAVE, "_cl_rate", "10000"};
-cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000"};
void Host_Rate_f(void)
{
- int rate, maxrate;
+ int rate;
if (Cmd_Argc() != 2)
{
return;
}
- maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
- if (sv_maxrate.integer != maxrate)
- Cvar_SetValueQuick(&sv_maxrate, maxrate);
-
- if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) != LHNETADDRESSTYPE_LOOP)
- host_client->netconnection->rate = bound(NET_MINRATE, rate, maxrate);
+ host_client->netconnection->rate = rate;
}
/*
// and it won't happen if the game was just loaded, so you wind up
// with a permanent head tilt
MSG_WriteByte (&host_client->message, svc_setangle);
- for (i=0 ; i < 2 ; i++)
- MSG_WriteAngle (&host_client->message, sv_player->v->angles[i] );
- MSG_WriteAngle (&host_client->message, 0 );
+ if (sv.protocol == PROTOCOL_DARKPLACES5)
+ {
+ MSG_WriteAngle16i (&host_client->message, sv_player->v->angles[0]);
+ MSG_WriteAngle16i (&host_client->message, sv_player->v->angles[1]);
+ MSG_WriteAngle16i (&host_client->message, 0);
+ }
+ else
+ {
+ MSG_WriteAngle8i (&host_client->message, sv_player->v->angles[0]);
+ MSG_WriteAngle8i (&host_client->message, sv_player->v->angles[1]);
+ MSG_WriteAngle8i (&host_client->message, 0);
+ }
SV_WriteClientdataToMessage (sv_player, &host_client->message);
Cmd_AddCommand ("color", Host_Color_f);
Cvar_RegisterVariable (&cl_rate);
Cmd_AddCommand ("rate", Host_Rate_f);
- Cvar_RegisterVariable (&sv_maxrate);
if (gamemode == GAME_NEHAHRA)
{
Cvar_RegisterVariable (&cl_pmodel);
qboolean m_serverInfoMessage = false;
double m_serverInfoMessageTime;
-extern cvar_t sv_public;
-extern cvar_t sv_maxrate;
-
void M_Menu_GameOptions_f (void)
{
key_dest = key_menu;
#define CHECKPVSBIT(pvs,b) ((b) >= 0 ? ((pvs)[(b) >> 3] & (1 << ((b) & 7))) : false)
#define SETPVSBIT(pvs,b) ((b) >= 0 ? ((pvs)[(b) >> 3] |= (1 << ((b) & 7))) : false)
+#define CLEARPVSBIT(pvs,b) ((b) >= 0 ? ((pvs)[(b) >> 3] &= ~(1 << ((b) & 7))) : false)
#endif
if (clientnum < svs.maxclients)
{
// prepare the client struct
- if ((client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool)))
+ if ((conn = NetConn_Open(mysocket, peeraddress)))
{
- if ((conn = NetConn_Open(mysocket, peeraddress)))
- {
- // allocated connection
- LHNETADDRESS_ToString(peeraddress, conn->address, sizeof(conn->address), true);
- if (developer.integer)
- Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", conn->address);
- NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress);
- // now set up the client
- SV_ConnectClient(clientnum, conn);
- NetConn_Heartbeat(1);
- }
- else
- EntityFrame4_FreeDatabase(client->entitydatabase4);
+ // allocated connection
+ LHNETADDRESS_ToString(peeraddress, conn->address, sizeof(conn->address), true);
+ if (developer.integer)
+ Con_Printf("Datagram_ParseConnectionless: sending \"accept\" to %s.\n", conn->address);
+ NetConn_WriteString(mysocket, "\377\377\377\377accept", peeraddress);
+ // now set up the client
+ SV_ConnectClient(clientnum, conn);
+ NetConn_Heartbeat(1);
}
}
else
char *samp;
float *pos;
float vol, attenuation;
- int i, soundnum, large;
+ int soundnum, large;
pos = G_VECTOR (OFS_PARM0);
samp = G_STRING(OFS_PARM1);
else
MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
- for (i=0 ; i<3 ; i++)
- MSG_WriteDPCoord(&sv.signon, pos[i]);
+ MSG_WriteVector(&sv.signon, pos, sv.protocol);
if (large)
MSG_WriteShort (&sv.signon, soundnum);
{
char *s;
int i;
+ int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_SOUNDS);
if (sv.state != ss_loading)
PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
PR_CheckEmptyString (s);
- for (i=0 ; i<MAX_SOUNDS ; i++)
+ for (i=0 ; i<limit ; i++)
{
if (!sv.sound_precache[i])
{
{
char *s;
int i;
+ int limit = (sv.protocol == PROTOCOL_QUAKE ? 256 : MAX_MODELS);
if (sv.state != ss_loading)
PF_ERROR("PF_Precache_*: Precache can only be done in spawn functions");
G_INT(OFS_RETURN) = G_INT(OFS_PARM0);
PR_CheckEmptyString (s);
- for (i=0 ; i<MAX_MODELS ; i++)
+ for (i = 0;i < limit;i++)
{
if (!sv.model_precache[i])
{
void PF_WriteAngle (void)
{
- MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1));
+ if (sv.protocol == PROTOCOL_DARKPLACES5)
+ MSG_WriteAngle16i (WriteDest(), G_FLOAT(OFS_PARM1));
+ else
+ MSG_WriteAngle8i (WriteDest(), G_FLOAT(OFS_PARM1));
}
void PF_WriteCoord (void)
{
- MSG_WriteDPCoord (WriteDest(), G_FLOAT(OFS_PARM1));
+ MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1), sv.protocol);
}
void PF_WriteString (void)
MSG_WriteByte (&sv.signon, ent->v->skin);
for (i=0 ; i<3 ; i++)
{
- MSG_WriteDPCoord(&sv.signon, ent->v->origin[i]);
- MSG_WriteAngle(&sv.signon, ent->v->angles[i]);
+ MSG_WriteCoord(&sv.signon, ent->v->origin[i], sv.protocol);
+ MSG_WriteAngle8i(&sv.signon, ent->v->angles[i]);
}
// throw the entity away now
*/
void PF_effect (void)
{
+ int i;
char *s;
s = G_STRING(OFS_PARM1);
if (!s || !s[0])
PF_WARNING("effect: no model specified\n");
- SV_StartEffect(G_VECTOR(OFS_PARM0), SV_ModelIndex(s), G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
+ i = SV_ModelIndex(s);
+ if (i < 0)
+ PF_WARNING("effect: model not precached\n");
+ SV_StartEffect(G_VECTOR(OFS_PARM0), i, G_FLOAT(OFS_PARM2), G_FLOAT(OFS_PARM3), G_FLOAT(OFS_PARM4));
}
void PF_te_blood (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_BLOOD);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
// velocity
MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
// min
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
// max
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
// speed
- MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM2));
+ MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM2), sv.protocol);
// count
MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
}
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
// color
MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[0] * 255), 255));
MSG_WriteByte(&sv.datagram, bound(0, (int) (G_VECTOR(OFS_PARM1)[1] * 255), 255));
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
// min
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
// max
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
// velocity
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
// count
MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
// color
// gravity true/false
MSG_WriteByte(&sv.datagram, ((int) G_FLOAT(OFS_PARM5)) != 0);
// randomvel
- MSG_WriteDPCoord(&sv.datagram, G_FLOAT(OFS_PARM6));
+ MSG_WriteCoord(&sv.datagram, G_FLOAT(OFS_PARM6), sv.protocol);
}
void PF_te_particlerain (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
// min
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
// max
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
// velocity
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
// count
MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
// color
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
// min
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
// max
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
// velocity
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
// count
MSG_WriteShort(&sv.datagram, bound(0, G_FLOAT(OFS_PARM3), 65535));
// color
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_SPARK);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
// velocity
MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[0], 127));
MSG_WriteByte(&sv.datagram, bound(-128, (int) G_VECTOR(OFS_PARM1)[1], 127));
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_spikequad (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_superspikequad (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_explosionquad (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_smallflash (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_customflash (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
// radius
MSG_WriteByte(&sv.datagram, bound(0, G_FLOAT(OFS_PARM1) / 8 - 1, 255));
// lifetime
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_spike (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_SPIKE);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_superspike (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_explosion (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_tarexplosion (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_wizspike (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_knightspike (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_lavasplash (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_teleport (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_TELEPORT);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
void PF_te_explosion2 (void)
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
// origin
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
// color
MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM1));
MSG_WriteByte(&sv.datagram, G_FLOAT(OFS_PARM2));
// owner entity
MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
// start
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
// end
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
}
void PF_te_lightning2 (void)
// owner entity
MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
// start
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
// end
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
}
void PF_te_lightning3 (void)
// owner entity
MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
// start
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
// end
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
}
void PF_te_beam (void)
// owner entity
MSG_WriteShort(&sv.datagram, G_EDICTNUM(OFS_PARM0));
// start
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM1)[2], sv.protocol);
// end
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM2)[2], sv.protocol);
}
void PF_te_plasmaburn (void)
{
MSG_WriteByte(&sv.datagram, svc_temp_entity);
MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1]);
- MSG_WriteDPCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2]);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[0], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[1], sv.protocol);
+ MSG_WriteCoord(&sv.datagram, G_VECTOR(OFS_PARM0)[2], sv.protocol);
}
static void clippointtosurface(msurface_t *surf, vec3_t p, vec3_t out)
// we should avoid extensive checking on entities already encountered
int areagridmarknumber;
- // old entity protocol, not used
-#ifdef QUAKEENTITIES
+ // PROTOCOL_QUAKE
// baseline values
entity_state_t baseline;
- // LordHavoc: previous frame
- entity_state_t deltabaseline;
-#endif
// LordHavoc: gross hack to make floating items still work
int suspendedinairflag;
// this is 80 bytes
entity_state_t defaultstate =
{
- // ! means this is sent to client
- 0,//double time; // time this state was built (used on client for interpolation)
- {0,0,0},//float origin[3]; // !
- {0,0,0},//float angles[3]; // !
- 0,//int number; // ! entity number this state is for
- 0,//int effects; // !
- 0,//unsigned short modelindex; // !
- 0,//unsigned short frame; // !
- 0,//unsigned short tagentity; // !
- 0,//unsigned short specialvisibilityradius; // larger if it has effects/light
- 0,//unsigned short viewmodelforclient;
- 0,//unsigned short exteriormodelforclient; // not shown if first person viewing from this entity, shown in all other cases
- 0,//unsigned short nodrawtoclient;
- 0,//unsigned short drawonlytoclient;
- {0,0,0,0},//unsigned short light[4]; // ! color*256 (0.00 to 255.996), and radius*1
- 0,//unsigned char active; // ! true if a valid state
- 0,//unsigned char lightstyle; // !
- 0,//unsigned char lightpflags; // !
- 0,//unsigned char colormap; // !
- 0,//unsigned char skin; // ! also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC
- 255,//unsigned char alpha; // !
- 16,//unsigned char scale; // !
- 0,//unsigned char glowsize; // !
- 254,//unsigned char glowcolor; // !
- 0,//unsigned char flags; // !
- 0,//unsigned char tagindex; // !
+ // ! means this is not sent to client
+ 0,//double time; // ! time this state was built (used on client for interpolation)
+ {0,0,0},//float origin[3];
+ {0,0,0},//float angles[3];
+ 0,//int number; // entity number this state is for
+ 0,//int effects;
+ 0,//unsigned short modelindex;
+ 0,//unsigned short frame;
+ 0,//unsigned short tagentity;
+ 0,//unsigned short specialvisibilityradius; // ! larger if it has effects/light
+ 0,//unsigned short viewmodelforclient; // !
+ 0,//unsigned short exteriormodelforclient; // ! not shown if first person viewing from this entity, shown in all other cases
+ 0,//unsigned short nodrawtoclient; // !
+ 0,//unsigned short drawonlytoclient; // !
+ {0,0,0,0},//unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1
+ 0,//unsigned char active; // true if a valid state
+ 0,//unsigned char lightstyle;
+ 0,//unsigned char lightpflags;
+ 0,//unsigned char colormap;
+ 0,//unsigned char skin; // also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC
+ 255,//unsigned char alpha;
+ 16,//unsigned char scale;
+ 0,//unsigned char glowsize;
+ 254,//unsigned char glowcolor;
+ 0,//unsigned char flags;
+ 0,//unsigned char tagindex;
+ 255,//unsigned char colormod;
// padding to a multiple of 8 bytes (to align the double time)
- {0,0,0,0,0}//unsigned char unused[5];
+ {0,0,0,0}//unsigned char unused[4]; // !
};
-void ClearStateToDefault(entity_state_t *s)
+double entityframequake_mtime = 0;
+
+void EntityFrameQuake_ReadEntity(int bits)
{
- *s = defaultstate;
+ int num;
+ entity_t *ent;
+ entity_state_t s;
+
+ entityframequake_mtime = cl.mtime[0];
+
+ if (bits & U_MOREBITS)
+ bits |= (MSG_ReadByte()<<8);
+ if ((bits & U_EXTEND1) && cl.protocol != PROTOCOL_NEHAHRAMOVIE)
+ {
+ bits |= MSG_ReadByte() << 16;
+ if (bits & U_EXTEND2)
+ bits |= MSG_ReadByte() << 24;
+ }
+
+ if (bits & U_LONGENTITY)
+ num = (unsigned short) MSG_ReadShort ();
+ else
+ num = MSG_ReadByte ();
+
+ if (num >= MAX_EDICTS)
+ Host_Error("EntityFrameQuake_ReadEntity: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
+ if (num < 1)
+ Host_Error("EntityFrameQuake_ReadEntity: invalid entity number (%i)\n", num);
+
+ ent = cl_entities + num;
+
+ // note: this inherits the 'active' state of the baseline chosen
+ // (state_baseline is always active, state_current may not be active if
+ // the entity was missing in the last frame)
+ if (bits & U_DELTA)
+ s = ent->state_current;
+ else
+ {
+ s = ent->state_baseline;
+ s.active = true;
+ }
+
+ s.number = num;
+ s.time = cl.mtime[0];
+ s.flags = 0;
+ if (bits & U_MODEL) s.modelindex = (s.modelindex & 0xFF00) | MSG_ReadByte();
+ if (bits & U_FRAME) s.frame = (s.frame & 0xFF00) | MSG_ReadByte();
+ if (bits & U_COLORMAP) s.colormap = MSG_ReadByte();
+ if (bits & U_SKIN) s.skin = MSG_ReadByte();
+ if (bits & U_EFFECTS) s.effects = (s.effects & 0xFF00) | MSG_ReadByte();
+ if (bits & U_ORIGIN1) s.origin[0] = MSG_ReadCoord13i();
+ if (bits & U_ANGLE1) s.angles[0] = MSG_ReadAngle8i();
+ if (bits & U_ORIGIN2) s.origin[1] = MSG_ReadCoord13i();
+ if (bits & U_ANGLE2) s.angles[1] = MSG_ReadAngle8i();
+ if (bits & U_ORIGIN3) s.origin[2] = MSG_ReadCoord13i();
+ if (bits & U_ANGLE3) s.angles[2] = MSG_ReadAngle8i();
+ if (bits & U_STEP) s.flags |= RENDER_STEP;
+ if (bits & U_ALPHA) s.alpha = MSG_ReadByte();
+ if (bits & U_SCALE) s.scale = MSG_ReadByte();
+ if (bits & U_EFFECTS2) s.effects = (s.effects & 0x00FF) | (MSG_ReadByte() << 8);
+ if (bits & U_GLOWSIZE) s.glowsize = MSG_ReadByte();
+ if (bits & U_GLOWCOLOR) s.glowcolor = MSG_ReadByte();
+ if (bits & U_COLORMOD) s.colormod = MSG_ReadByte();
+ if (bits & U_GLOWTRAIL) s.flags |= RENDER_GLOWTRAIL;
+ if (bits & U_FRAME2) s.frame = (s.frame & 0x00FF) | (MSG_ReadByte() << 8);
+ if (bits & U_MODEL2) s.modelindex = (s.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
+ if (bits & U_VIEWMODEL) s.flags |= RENDER_VIEWMODEL;
+ if (bits & U_EXTERIORMODEL) s.flags |= RENDER_EXTERIORMODEL;
+
+ // LordHavoc: to allow playback of the Nehahra movie
+ if (cl.protocol == PROTOCOL_NEHAHRAMOVIE && (bits & U_EXTEND1))
+ {
+ // LordHavoc: evil format
+ int i = MSG_ReadFloat();
+ int j = MSG_ReadFloat() * 255.0f;
+ if (i == 2)
+ {
+ i = MSG_ReadFloat();
+ if (i)
+ s.effects |= EF_FULLBRIGHT;
+ }
+ if (j < 0)
+ s.alpha = 0;
+ else if (j == 0 || j >= 255)
+ s.alpha = 255;
+ else
+ s.alpha = j;
+ }
+
+ ent->state_previous = ent->state_current;
+ ent->state_current = s;
+ if (ent->state_current.active)
+ {
+ CL_MoveLerpEntityStates(ent);
+ cl_entities_active[ent->state_current.number] = true;
+ }
+
+ if (msg_badread)
+ Host_Error("EntityFrameQuake_ReadEntity: read error\n");
+}
+
+void EntityFrameQuake_ISeeDeadEntities(void)
+{
+ int i;
+ for (i = 0;i < cl_max_entities;i++)
+ {
+ if (cl_entities_active[i] && cl_entities[i].state_current.time != cl.mtime[0])
+ {
+ cl_entities_active[i] = false;
+ cl_entities[i].state_current = defaultstate;
+ cl_entities[i].state_current.number = i;
+ }
+ }
+}
+
+void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int numstates, const entity_state_t *states)
+{
+ const entity_state_t *s;
+ entity_state_t baseline;
+ int i, bits;
+ sizebuf_t buf;
+ qbyte data[128];
+
+ // prepare the buffer
+ memset(&buf, 0, sizeof(buf));
+ buf.data = data;
+ buf.maxsize = sizeof(data);
+
+ for (i = 0, s = states;i < numstates;i++, s++)
+ {
+ // prepare the buffer
+ SZ_Clear(&buf);
+
+// send an update
+ bits = 0;
+ if (s->number >= 256)
+ bits |= U_LONGENTITY;
+ if (s->flags & RENDER_STEP)
+ bits |= U_STEP;
+ if (s->flags & RENDER_VIEWMODEL)
+ bits |= U_VIEWMODEL;
+ if (s->flags & RENDER_GLOWTRAIL)
+ bits |= U_GLOWTRAIL;
+ if (s->flags & RENDER_EXTERIORMODEL)
+ bits |= U_EXTERIORMODEL;
+
+ // LordHavoc: old stuff, but rewritten to have more exact tolerances
+ baseline = sv.edicts[s->number].e->baseline;
+ if (baseline.origin[0] != s->origin[0])
+ bits |= U_ORIGIN1;
+ if (baseline.origin[1] != s->origin[1])
+ bits |= U_ORIGIN2;
+ if (baseline.origin[2] != s->origin[2])
+ bits |= U_ORIGIN3;
+ if (baseline.angles[0] != s->angles[0])
+ bits |= U_ANGLE1;
+ if (baseline.angles[1] != s->angles[1])
+ bits |= U_ANGLE2;
+ if (baseline.angles[2] != s->angles[2])
+ bits |= U_ANGLE3;
+ if (baseline.colormap != s->colormap)
+ bits |= U_COLORMAP;
+ if (baseline.skin != s->skin)
+ bits |= U_SKIN;
+ if (baseline.frame != s->frame)
+ {
+ bits |= U_FRAME;
+ if (s->frame & 0xFF00)
+ bits |= U_FRAME2;
+ }
+ if (baseline.effects != s->effects)
+ {
+ bits |= U_EFFECTS;
+ if (s->effects & 0xFF00)
+ bits |= U_EFFECTS2;
+ }
+ if (baseline.modelindex != s->modelindex)
+ {
+ bits |= U_MODEL;
+ if (s->modelindex & 0xFF00)
+ bits |= U_MODEL2;
+ }
+ if (baseline.alpha != s->alpha)
+ bits |= U_ALPHA;
+ if (baseline.scale != s->scale)
+ bits |= U_SCALE;
+ if (baseline.glowsize != s->glowsize)
+ bits |= U_GLOWSIZE;
+ if (baseline.glowcolor != s->glowcolor)
+ bits |= U_GLOWCOLOR;
+
+ // if extensions are disabled, clear the relevant update flags
+ if (sv.netquakecompatible)
+ bits &= 0x7FFF;
+
+ // write the message
+ if (bits >= 16777216)
+ bits |= U_EXTEND2;
+ if (bits >= 65536)
+ bits |= U_EXTEND1;
+ if (bits >= 256)
+ bits |= U_MOREBITS;
+ bits |= U_SIGNAL;
+
+ MSG_WriteByte (&buf, bits);
+ if (bits & U_MOREBITS) MSG_WriteByte(&buf, bits>>8);
+ if (bits & U_EXTEND1) MSG_WriteByte(&buf, bits>>16);
+ if (bits & U_EXTEND2) MSG_WriteByte(&buf, bits>>24);
+ if (bits & U_LONGENTITY) MSG_WriteShort(&buf, s->number);
+ else MSG_WriteByte(&buf, s->number);
+
+ if (bits & U_MODEL) MSG_WriteByte(&buf, s->modelindex);
+ if (bits & U_FRAME) MSG_WriteByte(&buf, s->frame);
+ if (bits & U_COLORMAP) MSG_WriteByte(&buf, s->colormap);
+ if (bits & U_SKIN) MSG_WriteByte(&buf, s->skin);
+ if (bits & U_EFFECTS) MSG_WriteByte(&buf, s->effects);
+ if (bits & U_ORIGIN1) MSG_WriteCoord13i(&buf, s->origin[0]);
+ if (bits & U_ANGLE1) MSG_WriteAngle8i(&buf, s->angles[0]);
+ if (bits & U_ORIGIN2) MSG_WriteCoord13i(&buf, s->origin[1]);
+ if (bits & U_ANGLE2) MSG_WriteAngle8i(&buf, s->angles[1]);
+ if (bits & U_ORIGIN3) MSG_WriteCoord13i(&buf, s->origin[2]);
+ if (bits & U_ANGLE3) MSG_WriteAngle8i(&buf, s->angles[2]);
+ if (bits & U_ALPHA) MSG_WriteByte(&buf, s->alpha);
+ if (bits & U_SCALE) MSG_WriteByte(&buf, s->scale);
+ if (bits & U_EFFECTS2) MSG_WriteByte(&buf, s->effects >> 8);
+ if (bits & U_GLOWSIZE) MSG_WriteByte(&buf, s->glowsize);
+ if (bits & U_GLOWCOLOR) MSG_WriteByte(&buf, s->glowcolor);
+ if (bits & U_COLORMOD) MSG_WriteByte(&buf, s->colormod);
+ if (bits & U_FRAME2) MSG_WriteByte(&buf, s->frame >> 8);
+ if (bits & U_MODEL2) MSG_WriteByte(&buf, s->modelindex >> 8);
+
+ // if the commit is full, we're done this frame
+ if (msg->cursize + buf.cursize > msg->maxsize)
+ {
+ // next frame we will continue where we left off
+ break;
+ }
+ // write the message to the packet
+ SZ_Write(msg, buf.data, buf.cursize);
+ }
}
int EntityState_DeltaBits(const entity_state_t *o, const entity_state_t *n)
}
}
-void EntityState_WriteFields(entity_state_t *ent, sizebuf_t *msg, unsigned int bits)
+void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned int bits)
{
- // LordHavoc: have to write flags first, as they can modify protocol
- if (bits & E_FLAGS)
- MSG_WriteByte(msg, ent->flags);
- if (ent->flags & RENDER_LOWPRECISION)
+ if (sv.protocol == PROTOCOL_DARKPLACES2)
{
if (bits & E_ORIGIN1)
- MSG_WriteShort(msg, ent->origin[0]);
+ MSG_WriteCoord16i(msg, ent->origin[0]);
if (bits & E_ORIGIN2)
- MSG_WriteShort(msg, ent->origin[1]);
+ MSG_WriteCoord16i(msg, ent->origin[1]);
if (bits & E_ORIGIN3)
- MSG_WriteShort(msg, ent->origin[2]);
+ MSG_WriteCoord16i(msg, ent->origin[2]);
+ }
+ else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+ {
+ // LordHavoc: have to write flags first, as they can modify protocol
+ if (bits & E_FLAGS)
+ MSG_WriteByte(msg, ent->flags);
+ if (ent->flags & RENDER_LOWPRECISION)
+ {
+ if (bits & E_ORIGIN1)
+ MSG_WriteCoord16i(msg, ent->origin[0]);
+ if (bits & E_ORIGIN2)
+ MSG_WriteCoord16i(msg, ent->origin[1]);
+ if (bits & E_ORIGIN3)
+ MSG_WriteCoord16i(msg, ent->origin[2]);
+ }
+ else
+ {
+ if (bits & E_ORIGIN1)
+ MSG_WriteCoord32f(msg, ent->origin[0]);
+ if (bits & E_ORIGIN2)
+ MSG_WriteCoord32f(msg, ent->origin[1]);
+ if (bits & E_ORIGIN3)
+ MSG_WriteCoord32f(msg, ent->origin[2]);
+ }
+ }
+ if (sv.protocol == PROTOCOL_DARKPLACES5 && !(ent->flags & RENDER_LOWPRECISION))
+ {
if (bits & E_ANGLE1)
- MSG_WriteAngle(msg, ent->angles[0]);
+ MSG_WriteAngle16i(msg, ent->angles[0]);
if (bits & E_ANGLE2)
- MSG_WriteAngle(msg, ent->angles[1]);
+ MSG_WriteAngle16i(msg, ent->angles[1]);
if (bits & E_ANGLE3)
- MSG_WriteAngle(msg, ent->angles[2]);
+ MSG_WriteAngle16i(msg, ent->angles[2]);
}
else
{
- if (bits & E_ORIGIN1)
- MSG_WriteFloat(msg, ent->origin[0]);
- if (bits & E_ORIGIN2)
- MSG_WriteFloat(msg, ent->origin[1]);
- if (bits & E_ORIGIN3)
- MSG_WriteFloat(msg, ent->origin[2]);
if (bits & E_ANGLE1)
- MSG_WritePreciseAngle(msg, ent->angles[0]);
+ MSG_WriteAngle8i(msg, ent->angles[0]);
if (bits & E_ANGLE2)
- MSG_WritePreciseAngle(msg, ent->angles[1]);
+ MSG_WriteAngle8i(msg, ent->angles[1]);
if (bits & E_ANGLE3)
- MSG_WritePreciseAngle(msg, ent->angles[2]);
+ MSG_WriteAngle8i(msg, ent->angles[2]);
}
if (bits & E_MODEL1)
MSG_WriteByte(msg, ent->modelindex & 0xFF);
MSG_WriteByte(msg, ent->glowsize);
if (bits & E_GLOWCOLOR)
MSG_WriteByte(msg, ent->glowcolor);
+ if (sv.protocol == PROTOCOL_DARKPLACES2)
+ if (bits & E_FLAGS)
+ MSG_WriteByte(msg, ent->flags);
if (bits & E_TAGATTACHMENT)
{
MSG_WriteShort(msg, ent->tagentity);
MSG_WriteByte(msg, ent->lightpflags);
}
-void EntityState_WriteUpdate(entity_state_t *ent, sizebuf_t *msg, entity_state_t *delta)
+void EntityState_WriteUpdate(const entity_state_t *ent, sizebuf_t *msg, const entity_state_t *delta)
{
unsigned int bits;
if (ent->active)
if (cl.protocol == PROTOCOL_DARKPLACES2)
{
if (bits & E_ORIGIN1)
- e->origin[0] = (signed short) MSG_ReadShort();
+ e->origin[0] = MSG_ReadCoord16i();
if (bits & E_ORIGIN2)
- e->origin[1] = (signed short) MSG_ReadShort();
+ e->origin[1] = MSG_ReadCoord16i();
if (bits & E_ORIGIN3)
- e->origin[2] = (signed short) MSG_ReadShort();
+ e->origin[2] = MSG_ReadCoord16i();
}
- else
+ else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
{
if (bits & E_FLAGS)
e->flags = MSG_ReadByte();
- if (e->flags & RENDER_LOWPRECISION || cl.protocol == PROTOCOL_DARKPLACES2)
+ if (e->flags & RENDER_LOWPRECISION)
{
if (bits & E_ORIGIN1)
- e->origin[0] = (signed short) MSG_ReadShort();
+ e->origin[0] = MSG_ReadCoord16i();
if (bits & E_ORIGIN2)
- e->origin[1] = (signed short) MSG_ReadShort();
+ e->origin[1] = MSG_ReadCoord16i();
if (bits & E_ORIGIN3)
- e->origin[2] = (signed short) MSG_ReadShort();
+ e->origin[2] = MSG_ReadCoord16i();
}
else
{
if (bits & E_ORIGIN1)
- e->origin[0] = MSG_ReadFloat();
+ e->origin[0] = MSG_ReadCoord32f();
if (bits & E_ORIGIN2)
- e->origin[1] = MSG_ReadFloat();
+ e->origin[1] = MSG_ReadCoord32f();
if (bits & E_ORIGIN3)
- e->origin[2] = MSG_ReadFloat();
+ e->origin[2] = MSG_ReadCoord32f();
}
}
if (cl.protocol == PROTOCOL_DARKPLACES5 && !(e->flags & RENDER_LOWPRECISION))
{
if (bits & E_ANGLE1)
- e->angles[0] = MSG_ReadPreciseAngle();
+ e->angles[0] = MSG_ReadAngle16i();
if (bits & E_ANGLE2)
- e->angles[1] = MSG_ReadPreciseAngle();
+ e->angles[1] = MSG_ReadAngle16i();
if (bits & E_ANGLE3)
- e->angles[2] = MSG_ReadPreciseAngle();
+ e->angles[2] = MSG_ReadAngle16i();
}
else
{
if (bits & E_ANGLE1)
- e->angles[0] = MSG_ReadAngle();
+ e->angles[0] = MSG_ReadAngle8i();
if (bits & E_ANGLE2)
- e->angles[1] = MSG_ReadAngle();
+ e->angles[1] = MSG_ReadAngle8i();
if (bits & E_ANGLE3)
- e->angles[2] = MSG_ReadAngle();
+ e->angles[2] = MSG_ReadAngle8i();
}
if (bits & E_MODEL1)
e->modelindex = (e->modelindex & 0xFF00) | (unsigned int) MSG_ReadByte();
e->flags = MSG_ReadByte();
if (bits & E_TAGATTACHMENT)
{
- e->tagentity = MSG_ReadShort();
+ e->tagentity = (unsigned short) MSG_ReadShort();
e->tagindex = MSG_ReadByte();
}
if (bits & E_LIGHT)
{
- e->light[0] = MSG_ReadShort();
- e->light[1] = MSG_ReadShort();
- e->light[2] = MSG_ReadShort();
- e->light[3] = MSG_ReadShort();
+ e->light[0] = (unsigned short) MSG_ReadShort();
+ e->light[1] = (unsigned short) MSG_ReadShort();
+ e->light[2] = (unsigned short) MSG_ReadShort();
+ e->light[3] = (unsigned short) MSG_ReadShort();
}
if (bits & E_LIGHTSTYLE)
e->lightstyle = MSG_ReadByte();
}
}
+// (client and server) allocates a new empty database
+entityframe_database_t *EntityFrame_AllocDatabase(mempool_t *mempool)
+{
+ return Mem_Alloc(mempool, sizeof(entityframe_database_t));
+}
+
+// (client and server) frees the database
+void EntityFrame_FreeDatabase(entityframe_database_t *d)
+{
+ Mem_Free(d);
+}
+
// (server) clears the database to contain no frames (thus delta compression compresses against nothing)
-void EntityFrame_ClearDatabase(entity_database_t *d)
+void EntityFrame_ClearDatabase(entityframe_database_t *d)
{
memset(d, 0, sizeof(*d));
}
// (server and client) removes frames older than 'frame' from database
-void EntityFrame_AckFrame(entity_database_t *d, int frame)
+void EntityFrame_AckFrame(entityframe_database_t *d, int frame)
{
int i;
- if (d->ackframe < frame)
- d->ackframe = frame;
+ if (d->ackframenum < frame)
+ d->ackframenum = frame;
for (i = 0;i < d->numframes && d->frames[i].framenum < frame;i++);
// ignore outdated frame acks (out of order packets)
if (i == 0)
f->framenum = framenum;
f->numentities = 0;
if (eye == NULL)
- {
VectorClear(f->eye);
- }
else
- {
VectorCopy(eye, f->eye);
- }
-}
-
-// (server) adds an entity to frame
-void EntityFrame_AddEntity(entity_frame_t *f, entity_state_t *s)
-{
- if (f->numentities < MAX_ENTITY_DATABASE)
- {
- f->entitydata[f->numentities] = *s;
- f->entitydata[f->numentities++].active = true;
- }
}
// (server and client) reads a frame from the database
-void EntityFrame_FetchFrame(entity_database_t *d, int framenum, entity_frame_t *f)
+void EntityFrame_FetchFrame(entityframe_database_t *d, int framenum, entity_frame_t *f)
{
int i, n;
EntityFrame_Clear(f, NULL, -1);
}
// (server and client) adds a entity_frame to the database, for future reference
-void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f)
+void EntityFrame_AddFrame(entityframe_database_t *d, vec3_t eye, int framenum, int numentities, const entity_state_t *entitydata)
{
int n, e;
entity_frameinfo_t *info;
- VectorCopy(f->eye, d->eye);
+ VectorCopy(eye, d->eye);
// figure out how many entity slots are used already
if (d->numframes)
{
n = d->frames[d->numframes - 1].endentity - d->frames[0].firstentity;
- if (n + f->numentities > MAX_ENTITY_DATABASE || d->numframes >= MAX_ENTITY_HISTORY)
+ if (n + numentities > MAX_ENTITY_DATABASE || d->numframes >= MAX_ENTITY_HISTORY)
{
// ran out of room, dump database
EntityFrame_ClearDatabase(d);
}
info = &d->frames[d->numframes];
- info->framenum = f->framenum;
+ info->framenum = framenum;
e = -1000;
// make sure we check the newly added frame as well, but we haven't incremented numframes yet
for (n = 0;n <= d->numframes;n++)
{
if (e >= d->frames[n].framenum)
{
- if (e == f->framenum)
+ if (e == framenum)
Con_Print("EntityFrame_AddFrame: tried to add out of sequence frame to database\n");
else
Con_Print("EntityFrame_AddFrame: out of sequence frames in database\n");
info->firstentity = d->frames[d->numframes - 1].endentity;
else
info->firstentity = 0;
- info->endentity = info->firstentity + f->numentities;
+ info->endentity = info->firstentity + numentities;
d->numframes++;
n = info->firstentity % MAX_ENTITY_DATABASE;
e = MAX_ENTITY_DATABASE - n;
- if (e > f->numentities)
- e = f->numentities;
- memcpy(d->entitydata + n, f->entitydata, sizeof(entity_state_t) * e);
- if (f->numentities > e)
- memcpy(d->entitydata, f->entitydata + e, sizeof(entity_state_t) * (f->numentities - e));
+ if (e > numentities)
+ e = numentities;
+ memcpy(d->entitydata + n, entitydata, sizeof(entity_state_t) * e);
+ if (numentities > e)
+ memcpy(d->entitydata, entitydata + e, sizeof(entity_state_t) * (numentities - e));
}
// (server) writes a frame to network stream
static entity_frame_t deltaframe; // FIXME?
-void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg)
+void EntityFrame_WriteFrame(sizebuf_t *msg, entityframe_database_t *d, int numstates, const entity_state_t *states, int viewentnum)
{
int i, onum, number;
entity_frame_t *o = &deltaframe;
- entity_state_t *ent, *delta;
+ const entity_state_t *ent, *delta;
+ vec3_t eye;
+
+ d->latestframenum++;
+
+ VectorClear(eye);
+ for (i = 0;i < numstates;i++)
+ {
+ if (states[i].number == viewentnum)
+ {
+ VectorSet(eye, states[i].origin[0], states[i].origin[1], states[i].origin[2] + 22);
+ break;
+ }
+ }
- EntityFrame_AddFrame(d, f);
+ EntityFrame_AddFrame(d, eye, d->latestframenum, numstates, states);
+
+ EntityFrame_FetchFrame(d, d->ackframenum > 0 ? d->ackframenum : -1, o);
- EntityFrame_FetchFrame(d, d->ackframe > 0 ? d->ackframe : -1, o);
MSG_WriteByte (msg, svc_entities);
MSG_WriteLong (msg, o->framenum);
- MSG_WriteLong (msg, f->framenum);
- MSG_WriteFloat (msg, f->eye[0]);
- MSG_WriteFloat (msg, f->eye[1]);
- MSG_WriteFloat (msg, f->eye[2]);
+ MSG_WriteLong (msg, d->latestframenum);
+ MSG_WriteFloat (msg, eye[0]);
+ MSG_WriteFloat (msg, eye[1]);
+ MSG_WriteFloat (msg, eye[2]);
onum = 0;
- for (i = 0;i < f->numentities;i++)
+ for (i = 0;i < numstates;i++)
{
- ent = f->entitydata + i;
+ ent = states + i;
number = ent->number;
for (;onum < o->numentities && o->entitydata[onum].number < number;onum++)
{
// (client) reads a frame from network stream
static entity_frame_t framedata; // FIXME?
-void EntityFrame_Read(entity_database_t *d)
+void EntityFrame_CL_ReadFrame(void)
{
- int number, removed;
+ int i, number, removed;
entity_frame_t *f = &framedata, *delta = &deltaframe;
entity_state_t *e, *old, *oldend;
+ entity_t *ent;
+ entityframe_database_t *d;
+ if (!cl.entitydatabase)
+ cl.entitydatabase = EntityFrame_AllocDatabase(cl_entities_mempool);
+ d = cl.entitydatabase;
EntityFrame_Clear(f, NULL, -1);
old = delta->entitydata;
oldend = old + delta->numentities;
// read entities until we hit the magic 0xFFFF end tag
- while ((number = (unsigned short) MSG_ReadShort()) != 0xFFFF)
+ while ((number = (unsigned short) MSG_ReadShort()) != 0xFFFF && !msg_badread)
{
if (msg_badread)
Host_Error("EntityFrame_Read: read error\n");
f->entitydata[f->numentities] = *old++;
f->entitydata[f->numentities++].time = cl.mtime[0];
}
- EntityFrame_AddFrame(d, f);
+ EntityFrame_AddFrame(d, f->eye, f->framenum, f->numentities, f->entitydata);
+
+ memset(cl_entities_active, 0, cl_max_entities * sizeof(qbyte));
+ number = 1;
+ for (i = 0;i < f->numentities;i++)
+ {
+ for (;number < f->entitydata[i].number;number++)
+ {
+ if (cl_entities_active[number])
+ {
+ cl_entities_active[number] = false;
+ cl_entities[number].state_current.active = false;
+ }
+ }
+ // update the entity
+ ent = &cl_entities[number];
+ ent->state_previous = ent->state_current;
+ ent->state_current = f->entitydata[i];
+ CL_MoveLerpEntityStates(ent);
+ // the entity lives again...
+ cl_entities_active[number] = true;
+ number++;
+ }
+ for (;number < cl_max_entities;number++)
+ {
+ if (cl_entities_active[number])
+ {
+ cl_entities_active[number] = false;
+ cl_entities[number].state_current.active = false;
+ }
+ }
}
// (client) returns the frame number of the most recent frame recieved
-int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d)
+int EntityFrame_MostRecentlyRecievedFrameNum(entityframe_database_t *d)
{
if (d->numframes)
return d->frames[d->numframes - 1].framenum;
-entity_state_t *EntityFrame4_GetReferenceEntity(entity_database4_t *d, int number)
+entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number)
{
if (d->maxreferenceentities <= number)
{
return d->referenceentity + number;
}
-void EntityFrame4_AddCommitEntity(entity_database4_t *d, entity_state_t *s)
+void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s)
{
// resize commit's entity list if full
if (d->currentcommit->maxentities <= d->currentcommit->numentities)
d->currentcommit->entity[d->currentcommit->numentities++] = *s;
}
-entity_database4_t *EntityFrame4_AllocDatabase(mempool_t *pool)
+entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool)
{
- entity_database4_t *d;
+ entityframe4_database_t *d;
d = Mem_Alloc(pool, sizeof(*d));
d->mempool = pool;
EntityFrame4_ResetDatabase(d);
return d;
}
-void EntityFrame4_FreeDatabase(entity_database4_t *d)
+void EntityFrame4_FreeDatabase(entityframe4_database_t *d)
{
int i;
for (i = 0;i < MAX_ENTITY_HISTORY;i++)
Mem_Free(d);
}
-void EntityFrame4_ResetDatabase(entity_database4_t *d)
+void EntityFrame4_ResetDatabase(entityframe4_database_t *d)
{
int i;
d->ackframenum = -1;
d->referenceentity[i] = defaultstate;
}
-int EntityFrame4_AckFrame(entity_database4_t *d, int framenum)
+int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum)
{
int i, j, found;
entity_database4_commit_t *commit;
return found;
}
-int EntityFrame4_SV_WriteFrame_Entity(entity_database4_t *d, sizebuf_t *msg, int maxbytes, entity_state_t *s)
-{
- qbyte data[128];
- sizebuf_t buf;
- entity_state_t *e;
- // prepare the buffer
- memset(&buf, 0, sizeof(buf));
- buf.data = data;
- buf.maxsize = sizeof(data);
- // make the update message
- e = EntityFrame4_GetReferenceEntity(d, s->number);
- EntityState_WriteUpdate(s, &buf, e);
- // if the message is empty, skip out now
- if (!buf.cursize)
- return true;
- // if the commit is full, we're done
- if (msg->cursize + buf.cursize + 2 >= min(msg->maxsize, maxbytes))
- return false;
- // add the entity to the commit
- EntityFrame4_AddCommitEntity(d, s);
- // write the message to the packet
- SZ_Write(msg, buf.data, buf.cursize);
- // carry on
- return true;
-}
-
-extern void CL_MoveLerpEntityStates(entity_t *ent);
-void EntityFrame4_CL_ReadFrame(entity_database4_t *d)
+void EntityFrame4_CL_ReadFrame(void)
{
int i, n, cnumber, referenceframenum, framenum, enumber, done, stopnumber, skip = false;
entity_state_t *s;
+ entityframe4_database_t *d;
+ if (!cl.entitydatabase4)
+ cl.entitydatabase4 = EntityFrame4_AllocDatabase(cl_entities_mempool);
+ d = cl.entitydatabase4;
// read the number of the frame this refers to
referenceframenum = MSG_ReadLong();
// read the number of this frame
framenum = MSG_ReadLong();
// read the start number
- enumber = MSG_ReadShort();
+ enumber = (unsigned short) MSG_ReadShort();
if (developer_networkentities.integer >= 1)
{
Con_Printf("recv svc_entities num:%i ref:%i database: ref:%i commits:", framenum, referenceframenum, d->referenceframenum);
EntityFrame4_ResetDatabase(d);
}
+void EntityFrame4_WriteFrame(sizebuf_t *msg, entityframe4_database_t *d, int numstates, const entity_state_t *states)
+{
+ const entity_state_t *e, *s;
+ entity_state_t inactiveentitystate;
+ int i, n, startnumber;
+ sizebuf_t buf;
+ qbyte data[128];
+ // if there isn't enough space to accomplish anything, skip it
+ if (msg->cursize + 24 > msg->maxsize)
+ return;
+ // prepare the buffer
+ memset(&buf, 0, sizeof(buf));
+ buf.data = data;
+ buf.maxsize = sizeof(data);
+ for (i = 0;i < MAX_ENTITY_HISTORY;i++)
+ if (!d->commit[i].numentities)
+ break;
+ // if commit buffer full, just don't bother writing an update this frame
+ if (i == MAX_ENTITY_HISTORY)
+ return;
+ d->currentcommit = d->commit + i;
-/*
-int EntityState5_PriorityForChangedBits(int changedbits)
-{
- if (changedbits & E5_ISACTIVE)
- return 2;
- else if (changedbits & (E5_FLAGS | E5_ATTACHMENT | E5_MODEL | E5_SKIN | E5_EXTERIORFORENTITY | E5_COLORMAP | E5_LIGHT | E5_GLOW | E5_EFFECTS | E5_ORIGIN | E5_ANGLES | E5_FRAME | E5_ALPHA | E5_SCALE))
- return 1;
- else
- return 0;
-}
+ // this state's number gets played around with later
+ inactiveentitystate = defaultstate;
-void EntityState5_WriteUpdate(int number, entitystate_t *s, int changedbits, sizebuf_t *msg)
-{
- bits = 0;
- if (!s->active)
- MSG_WriteShort(msg, number | 0x8000);
+ d->currentcommit->numentities = 0;
+ d->currentcommit->framenum = ++d->latestframenumber;
+ MSG_WriteByte(msg, svc_entities);
+ MSG_WriteLong(msg, d->referenceframenum);
+ MSG_WriteLong(msg, d->currentcommit->framenum);
+ if (developer_networkentities.integer >= 1)
+ {
+ Con_Printf("send svc_entities num:%i ref:%i (database: ref:%i commits:", d->currentcommit->framenum, d->referenceframenum, d->referenceframenum);
+ for (i = 0;i < MAX_ENTITY_HISTORY;i++)
+ if (d->commit[i].numentities)
+ Con_Printf(" %i", d->commit[i].framenum);
+ Con_Print(")\n");
+ }
+ if (d->currententitynumber >= sv.max_edicts)
+ startnumber = 1;
else
+ startnumber = bound(1, d->currententitynumber, sv.max_edicts - 1);
+ MSG_WriteShort(msg, startnumber);
+ // reset currententitynumber so if the loop does not break it we will
+ // start at beginning next frame (if it does break, it will set it)
+ d->currententitynumber = 1;
+ for (i = 0, n = startnumber;n < sv.max_edicts;n++)
{
- bits |= E5_ISACTIVE;
- if (changedbits & E5_ORIGIN)
+ // find the old state to delta from
+ e = EntityFrame4_GetReferenceEntity(d, n);
+ // prepare the buffer
+ SZ_Clear(&buf);
+ // entity exists, build an update (if empty there is no change)
+ // find the state in the list
+ for (;i < numstates && states[i].number < n;i++);
+ // make the message
+ s = states + i;
+ if (s->number == n)
{
- bits |= E5_ORIGIN;
- if (s->origin[0] < -4096 || s->origin[0] >= 4096 || s->origin[1] < -4096 || s->origin[1] >= 4096 || s->origin[2] < -4096 || s->origin[2] >= 4096)
- bits |= E5_ORIGIN32;
+ // build the update
+ EntityState_WriteUpdate(s, &buf, e);
}
- if (changedbits & E5_ANGLES)
+ else
{
- bits |= E5_ANGLES;
- if (!(s->flags & RENDERFLAGS_LOWPRECISION))
- bits |= E5_ANGLES16;
+ inactiveentitystate.number = n;
+ s = &inactiveentitystate;
+ if (e->active)
+ {
+ // entity used to exist but doesn't anymore, send remove
+ MSG_WriteShort(&buf, n | 0x8000);
+ }
}
- if (changedbits & E5_MODEL)
+ // if the commit is full, we're done this frame
+ if (msg->cursize + buf.cursize > msg->maxsize - 4)
{
- bits |= E5_MODEL;
- if (s->modelindex >= 256)
- bits |= E5_MODEL16;
+ // next frame we will continue where we left off
+ break;
}
- if (changedbits & E5_FRAME)
+ // add the entity to the commit
+ EntityFrame4_AddCommitEntity(d, s);
+ // if the message is empty, skip out now
+ if (buf.cursize)
{
- bits |= E5_FRAME;
- if (s->frame >= 256)
- bits |= E5_FRAME16;
+ // write the message to the packet
+ SZ_Write(msg, buf.data, buf.cursize);
}
- if (changedbits & E5_SKIN)
- bits |= E5_SKIN;
- if (changedbits & E5_EFFECTS)
+ }
+ d->currententitynumber = n;
+
+ // remove world message (invalid, and thus a good terminator)
+ MSG_WriteShort(msg, 0x8000);
+ // write the number of the end entity
+ MSG_WriteShort(msg, d->currententitynumber);
+ // just to be sure
+ d->currentcommit = NULL;
+}
+
+
+
+
+#define E5_PROTOCOL_PRIORITYLEVELS 32
+
+entityframe5_database_t *EntityFrame5_AllocDatabase(mempool_t *pool)
+{
+ entityframe5_database_t *d;
+ d = Mem_Alloc(pool, sizeof(*d));
+ EntityFrame5_ResetDatabase(d);
+ return d;
+}
+
+void EntityFrame5_FreeDatabase(entityframe5_database_t *d)
+{
+ Mem_Free(d);
+}
+
+void EntityFrame5_ResetDatabase(entityframe5_database_t *d)
+{
+ int i;
+ memset(d, 0, sizeof(*d));
+ d->latestframenum = 0;
+ d->ackframenum = -1;
+ for (i = 0;i < MAX_EDICTS;i++)
+ d->states[i] = defaultstate;
+}
+
+
+int EntityState5_Priority(entityframe5_database_t *d, entity_state_t *view, entity_state_t *s, int changedbits, int age)
+{
+ int lowprecision, limit, priority;
+ double distance;
+ if (!changedbits)
+ return 0;
+ if (!s->active/* && changedbits & E5_FULLUPDATE*/)
+ return E5_PROTOCOL_PRIORITYLEVELS - 1;
+ // check whole attachment chain to judge relevance to player
+ lowprecision = false;
+ for (limit = 0;limit < 256;limit++)
+ {
+ if (s == view)
+ return E5_PROTOCOL_PRIORITYLEVELS - 1;
+ if (s->flags & RENDER_VIEWMODEL)
+ return E5_PROTOCOL_PRIORITYLEVELS - 1;
+ if (s->flags & RENDER_LOWPRECISION)
+ lowprecision = true;
+ if (!s->tagentity)
{
- bits |= E5_EFFECTS;
- if (s->modelindex >= 256)
- bits |= E5_MODEL16;
+ if (VectorCompare(s->origin, view->origin))
+ return E5_PROTOCOL_PRIORITYLEVELS - 1;
+ break;
+ }
+ s = d->states + s->tagentity;
+ }
+ if (limit >= 256)
+ Con_Printf("Protocol: Runaway loop recursing tagentity links on entity %i\n", s->number);
+ // it's not a viewmodel for this client
+ distance = VectorDistance(view->origin, s->origin);
+ priority = (E5_PROTOCOL_PRIORITYLEVELS / 2) + age - (int)(distance * (E5_PROTOCOL_PRIORITYLEVELS / 16384.0f));
+ if (lowprecision)
+ priority -= (E5_PROTOCOL_PRIORITYLEVELS / 4);
+ //if (changedbits & E5_FULLUPDATE)
+ // priority += 4;
+ //if (changedbits & (E5_ATTACHMENT | E5_MODEL | E5_FLAGS | E5_COLORMAP))
+ // priority += 4;
+ return (int) bound(1, priority, E5_PROTOCOL_PRIORITYLEVELS - 1);
+}
+
+void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbits, sizebuf_t *msg)
+{
+ unsigned int bits = 0;
+ if (!s->active)
+ MSG_WriteShort(msg, number | 0x8000);
+ else
+ {
+ bits = changedbits;
+ if ((bits & E5_ORIGIN) && (s->origin[0] < -4096 || s->origin[0] >= 4096 || s->origin[1] < -4096 || s->origin[1] >= 4096 || s->origin[2] < -4096 || s->origin[2] >= 4096))
+ bits |= E5_ORIGIN32;
+ if ((bits & E5_ANGLES) && !(s->flags & RENDER_LOWPRECISION))
+ bits |= E5_ANGLES16;
+ if ((bits & E5_MODEL) && s->modelindex >= 256)
+ bits |= E5_MODEL16;
+ if ((bits & E5_FRAME) && s->frame >= 256)
+ bits |= E5_FRAME16;
+ if (bits & E5_EFFECTS)
+ {
+ if (s->effects >= 65536)
+ bits |= E5_EFFECTS32;
+ else if (s->effects >= 256)
+ bits |= E5_EFFECTS16;
}
- if (changedbits & E5_FLAGS)
- bits |= E5_FLAGS;
- if (changedbits & E5_ALPHA)
- bits |= E5_ALPHA;
- if (changedbits & E5_SCALE)
- bits |= E5_SCALE;
- if (changedbits & E5_ATTACHMENT)
- bits |= E5_ATTACHMENT;
- if (changedbits & E5_EXTERIORFORENTITY)
- bits |= E5_EXTERIORFORENTITY;
- if (changedbits & E5_LIGHT)
- bits |= E5_LIGHT;
- if (changedbits & E5_COLORMAP)
- bits |= E5_COLORMAP;
- if (changedbits & E5_GLOW)
- bits |= E5_GLOW;
if (bits >= 256)
bits |= E5_EXTEND1;
if (bits >= 65536)
{
if (bits & E5_ORIGIN32)
{
- MSG_WriteFloat(msg, s->origin[0]);
- MSG_WriteFloat(msg, s->origin[1]);
- MSG_WriteFloat(msg, s->origin[2]);
+ MSG_WriteCoord32f(msg, s->origin[0]);
+ MSG_WriteCoord32f(msg, s->origin[1]);
+ MSG_WriteCoord32f(msg, s->origin[2]);
}
else
{
- MSG_WriteShort(msg, (int)floor(s->origin[0] * 8 + 0.5f));
- MSG_WriteShort(msg, (int)floor(s->origin[1] * 8 + 0.5f));
- MSG_WriteShort(msg, (int)floor(s->origin[2] * 8 + 0.5f));
+ MSG_WriteCoord13i(msg, s->origin[0]);
+ MSG_WriteCoord13i(msg, s->origin[1]);
+ MSG_WriteCoord13i(msg, s->origin[2]);
}
}
if (bits & E5_ANGLES)
{
if (bits & E5_ANGLES16)
{
- MSG_WriteShort(msg, (int)floor(s->angles[0] * (65536.0f / 360.0f) + 0.5f));
- MSG_WriteShort(msg, (int)floor(s->angles[1] * (65536.0f / 360.0f) + 0.5f));
- MSG_WriteShort(msg, (int)floor(s->angles[2] * (65536.0f / 360.0f) + 0.5f));
+ MSG_WriteAngle16i(msg, s->angles[0]);
+ MSG_WriteAngle16i(msg, s->angles[1]);
+ MSG_WriteAngle16i(msg, s->angles[2]);
}
else
{
- MSG_WriteByte(msg, (int)floor(s->angles[0] * (256.0f / 360.0f) + 0.5f));
- MSG_WriteByte(msg, (int)floor(s->angles[1] * (256.0f / 360.0f) + 0.5f));
- MSG_WriteByte(msg, (int)floor(s->angles[2] * (256.0f / 360.0f) + 0.5f));
+ MSG_WriteAngle8i(msg, s->angles[0]);
+ MSG_WriteAngle8i(msg, s->angles[1]);
+ MSG_WriteAngle8i(msg, s->angles[2]);
}
}
if (bits & E5_MODEL)
MSG_WriteByte(msg, s->frame);
}
if (bits & E5_SKIN)
- MSG_WriteByte(msg, s->flags);
+ MSG_WriteByte(msg, s->skin);
if (bits & E5_EFFECTS)
{
if (bits & E5_EFFECTS32)
MSG_WriteByte(msg, s->effects);
}
if (bits & E5_ALPHA)
- MSG_WriteByte(msg, s->flags);
+ MSG_WriteByte(msg, s->alpha);
if (bits & E5_SCALE)
- MSG_WriteByte(msg, s->flags);
+ MSG_WriteByte(msg, s->scale);
+ if (bits & E5_COLORMAP)
+ MSG_WriteByte(msg, s->colormap);
if (bits & E5_ATTACHMENT)
{
MSG_WriteShort(msg, s->tagentity);
MSG_WriteByte(msg, s->tagindex);
}
- if (bits & E5_EXTERIORFORENTITY)
- MSG_WriteShort(msg, s->tagentity);
if (bits & E5_LIGHT)
{
MSG_WriteShort(msg, s->light[0]);
MSG_WriteShort(msg, s->light[1]);
MSG_WriteShort(msg, s->light[2]);
MSG_WriteShort(msg, s->light[3]);
+ MSG_WriteByte(msg, s->lightstyle);
+ MSG_WriteByte(msg, s->lightpflags);
}
- if (bits & E5_COLORMAP)
- MSG_WriteByte(msg, s->colormap);
if (bits & E5_GLOW)
{
MSG_WriteByte(msg, s->glowsize);
}
}
-int EntityFrame5_ReadUpdate(void)
+void EntityState5_ReadUpdate(entity_state_t *s)
{
- number = MSG_ReadShort();
- e = cl_entities + (number & 0x7FFF);
- e->state_previous = e->state_current;
- if (number & 0x8000)
+ int bits;
+ bits = MSG_ReadByte();
+ if (bits & E5_EXTEND1)
{
- if (number == 0x8000)
+ bits |= MSG_ReadByte() << 8;
+ if (bits & E5_EXTEND2)
{
- // end of entity list
- return false;
+ bits |= MSG_ReadByte() << 16;
+ if (bits & E5_EXTEND3)
+ bits |= MSG_ReadByte() << 24;
}
- // remove
- number &= 0x7FFF;
- e->state_current = defaultstate;
- e->state_current.number = number;
- return true;
}
- else
+ if (bits & E5_FULLUPDATE)
+ {
+ *s = defaultstate;
+ s->active = true;
+ }
+ if (bits & E5_FLAGS)
+ s->flags = MSG_ReadByte();
+ if (bits & E5_ORIGIN)
+ {
+ if (bits & E5_ORIGIN32)
+ {
+ s->origin[0] = MSG_ReadCoord32f();
+ s->origin[1] = MSG_ReadCoord32f();
+ s->origin[2] = MSG_ReadCoord32f();
+ }
+ else
+ {
+ s->origin[0] = MSG_ReadCoord13i();
+ s->origin[1] = MSG_ReadCoord13i();
+ s->origin[2] = MSG_ReadCoord13i();
+ }
+ }
+ if (bits & E5_ANGLES)
+ {
+ if (bits & E5_ANGLES16)
+ {
+ s->angles[0] = MSG_ReadAngle16i();
+ s->angles[1] = MSG_ReadAngle16i();
+ s->angles[2] = MSG_ReadAngle16i();
+ }
+ else
+ {
+ s->angles[0] = MSG_ReadAngle8i();
+ s->angles[1] = MSG_ReadAngle8i();
+ s->angles[2] = MSG_ReadAngle8i();
+ }
+ }
+ if (bits & E5_MODEL)
+ {
+ if (bits & E5_MODEL16)
+ s->modelindex = (unsigned short) MSG_ReadShort();
+ else
+ s->modelindex = MSG_ReadByte();
+ }
+ if (bits & E5_FRAME)
{
+ if (bits & E5_FRAME16)
+ s->frame = (unsigned short) MSG_ReadShort();
+ else
+ s->frame = MSG_ReadByte();
+ }
+ if (bits & E5_SKIN)
+ s->skin = MSG_ReadByte();
+ if (bits & E5_EFFECTS)
+ {
+ if (bits & E5_EFFECTS32)
+ s->effects = (unsigned int) MSG_ReadLong();
+ else if (bits & E5_EFFECTS16)
+ s->effects = (unsigned short) MSG_ReadShort();
+ else
+ s->effects = MSG_ReadByte();
+ }
+ if (bits & E5_ALPHA)
+ s->alpha = MSG_ReadByte();
+ if (bits & E5_SCALE)
+ s->alpha = MSG_ReadByte();
+ if (bits & E5_COLORMAP)
+ s->colormap = MSG_ReadByte();
+ if (bits & E5_ATTACHMENT)
+ {
+ s->tagentity = (unsigned short) MSG_ReadShort();
+ s->tagindex = MSG_ReadByte();
+ }
+ if (bits & E5_LIGHT)
+ {
+ s->light[0] = (unsigned short) MSG_ReadShort();
+ s->light[1] = (unsigned short) MSG_ReadShort();
+ s->light[2] = (unsigned short) MSG_ReadShort();
+ s->light[3] = (unsigned short) MSG_ReadShort();
+ s->lightstyle = MSG_ReadByte();
+ s->lightpflags = MSG_ReadByte();
+ }
+ if (bits & E5_GLOW)
+ {
+ s->glowsize = MSG_ReadByte();
+ s->glowcolor = MSG_ReadByte();
+ }
+
+
+ if (developer_networkentities.integer >= 2)
+ {
+ Con_Printf("ReadFields e%i", s->number);
+
+ if (bits & E5_ORIGIN)
+ Con_Printf(" E5_ORIGIN %f %f %f", s->origin[0], s->origin[1], s->origin[2]);
+ if (bits & E5_ANGLES)
+ Con_Printf(" E5_ANGLES %f %f %f", s->angles[0], s->angles[1], s->angles[2]);
+ if (bits & E5_MODEL)
+ Con_Printf(" E5_MODEL %i", s->modelindex);
+ if (bits & E5_FRAME)
+ Con_Printf(" E5_FRAME %i", s->frame);
+ if (bits & E5_SKIN)
+ Con_Printf(" E5_SKIN %i", s->skin);
+ if (bits & E5_EFFECTS)
+ Con_Printf(" E5_EFFECTS %i", s->effects);
+ if (bits & E5_FLAGS)
+ {
+ Con_Printf(" E5_FLAGS %i (", s->flags);
+ if (s->flags & RENDER_STEP)
+ Con_Print(" STEP");
+ if (s->flags & RENDER_GLOWTRAIL)
+ Con_Print(" GLOWTRAIL");
+ if (s->flags & RENDER_VIEWMODEL)
+ Con_Print(" VIEWMODEL");
+ if (s->flags & RENDER_EXTERIORMODEL)
+ Con_Print(" EXTERIORMODEL");
+ if (s->flags & RENDER_LOWPRECISION)
+ Con_Print(" LOWPRECISION");
+ if (s->flags & RENDER_COLORMAPPED)
+ Con_Print(" COLORMAPPED");
+ if (s->flags & RENDER_SHADOW)
+ Con_Print(" SHADOW");
+ if (s->flags & RENDER_LIGHT)
+ Con_Print(" LIGHT");
+ Con_Print(")");
+ }
+ if (bits & E5_ALPHA)
+ Con_Printf(" E5_ALPHA %f", s->alpha / 255.0f);
+ if (bits & E5_SCALE)
+ Con_Printf(" E5_SCALE %f", s->scale / 16.0f);
+ if (bits & E5_COLORMAP)
+ Con_Printf(" E5_COLORMAP %i", s->colormap);
+ if (bits & E5_ATTACHMENT)
+ Con_Printf(" E5_ATTACHMENT e%i:%i", s->tagentity, s->tagindex);
+ if (bits & E5_LIGHT)
+ Con_Printf(" E5_LIGHT %i:%i:%i:%i %i:%i", s->light[0], s->light[1], s->light[2], s->light[3], s->lightstyle, s->lightpflags);
+ if (bits & E5_GLOW)
+ Con_Printf(" E5_GLOW %i:%i", s->glowsize * 4, s->glowcolor);
+ Con_Print("\n");
}
}
-int cl_entityframe5_lastreceivedframenum;
+int EntityState5_DeltaBits(const entity_state_t *o, const entity_state_t *n)
+{
+ unsigned int bits = 0;
+ if (n->active)
+ {
+ if (!o->active)
+ bits |= E5_FULLUPDATE;
+ if (!VectorCompare(o->origin, n->origin))
+ bits |= E5_ORIGIN;
+ if (!VectorCompare(o->angles, n->angles))
+ bits |= E5_ANGLES;
+ if (o->modelindex != n->modelindex)
+ bits |= E5_MODEL;
+ if (o->frame != n->frame)
+ bits |= E5_FRAME;
+ if (o->skin != n->skin)
+ bits |= E5_SKIN;
+ if (o->effects != n->effects)
+ bits |= E5_EFFECTS;
+ if (o->flags != n->flags)
+ bits |= E5_FLAGS;
+ if (o->alpha != n->alpha)
+ bits |= E5_ALPHA;
+ if (o->scale != n->scale)
+ bits |= E5_SCALE;
+ if (o->colormap != n->colormap)
+ bits |= E5_COLORMAP;
+ if (o->tagentity != n->tagentity || o->tagindex != n->tagindex)
+ bits |= E5_ATTACHMENT;
+ if (o->light[0] != n->light[0] || o->light[1] != n->light[1] || o->light[2] != n->light[2] || o->light[3] != n->light[3] || o->lightstyle != n->lightstyle || o->lightpflags != n->lightpflags)
+ bits |= E5_LIGHT;
+ if (o->glowsize != n->glowsize || o->glowcolor != n->glowcolor)
+ bits |= E5_GLOW;
+ }
+ else
+ if (o->active)
+ bits |= E5_FULLUPDATE;
+ return bits;
+}
void EntityFrame5_CL_ReadFrame(void)
{
entity_t *ent;
entity_state_t *s;
// read the number of this frame to echo back in next input packet
- cl_entityframe5_lastreceivedframenum = MSG_ReadLong();
+ cl.latestframenum = MSG_ReadLong();
// read entity numbers until we find a 0x8000
// (which would be remove world entity, but is actually a terminator)
- while ((n = MSG_ReadShort()) != 0x8000)
+ while ((n = (unsigned short)MSG_ReadShort()) != 0x8000 && !msg_badread)
{
// get the entity number and look it up
enumber = n & 0x7FFF;
else
{
// update entity
- s->active = true;
- EntityState_ReadFields(s, EntityState_ReadExtendBits());
+ EntityState5_ReadUpdate(s);
}
// set the cl_entities_active flag
cl_entities_active[enumber] = s->active;
}
}
-#define ENTITYFRAME5_MAXPACKETLOGS 64
-#define ENTITYFRAME5_MAXSTATES 128
-
-typedef struct entityframe5_state_s
-{
- unsigned short entitynumber;
- qbyte active;
- qbyte activedirtybit;
- int dirtybits;
-}
-entityframe5_state_t;
-
-typedef struct entityframe5_packetlog_s
-{
- int packetnumber;
- int numstates;
- entityframe5_state_t states[ENTITYFRAME5_MAXSTATES];
-}
-entityframe5_packetlog_t;
-
-typedef struct entityframe5_s
-{
- int ackedframenum;
- entityframe5_packetlog_t packetlog[ENTITYFRAME5_MAXPACKETLOGS];
- qbyte activedirtybits[(MAX_EDICTS + 7) / 8];
- int dirtybits[MAX_EDICTS];
-}
-entityframe5_t;
-
-void EntityFrame5_AckFrame(entityframe5_t *d, int framenum)
+void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum, int viewentnum)
{
- int i, j, k, l, dirtybits, activedirtybit;
- entityframe5_state_t *s, *s2;
+ int i, j, k, l, bits;
+ entityframe5_changestate_t *s, *s2;
entityframe5_packetlog_t *p, *p2;
- if (framenum >= d->ackedframenum)
+ if (framenum <= d->ackframenum)
return;
- d->ackedframenum = framenum;
+ d->ackframenum = framenum;
// scan for packets made obsolete by this ack
for (i = 0, p = d->packetlog;i < ENTITYFRAME5_MAXPACKETLOGS;i++, p++)
{
// already obsolete due to a later update.
if (p->packetnumber < framenum)
{
- // packet was lost - merge dirtybits into the main array so they
+ // packet was lost - merge deltabits into the main array so they
// will be re-sent, but only if there is no newer update of that
// bit in the logs (as those will arrive before this update)
for (j = 0, s = p->states;j < p->numstates;j++, s++)
{
- activedirtybit = s->activedirtybit;
- dirtybits = s->dirtybits;
- // check for any newer updates to this entity
- for (k = 0, p2 = d->packetlog;k < ENTITYFRAME5_MAXPACKETLOGS;k++, p2++)
+ // check for any newer updates to this entity and mask off any
+ // overlapping bits (we don't need to send something again if
+ // it has already been sent more recently)
+ bits = s->bits & ~d->deltabits[s->number];
+ for (k = 0, p2 = d->packetlog;k < ENTITYFRAME5_MAXPACKETLOGS && bits;k++, p2++)
{
if (p2->packetnumber > framenum)
{
for (l = 0, s2 = p2->states;l < p2->numstates;l++, p2++)
{
- if (s2->entitynumber == s->entitynumber)
+ if (s2->number == s->number)
{
- activedirtybit &= ~s2->activedirtybit;
- dirtybits &= ~s2->dirtybits;
+ bits &= ~s2->bits;
break;
}
}
- if (!activedirtybit && !dirtybits)
- break;
}
}
// if the bits haven't all been cleared, there were some bits
// lost with this packet, so set them again now
- if (activedirtybit)
- d->activedirtybits[s->entitynumber / 8] |= 1 << (s->entitynumber & 7);
- if (dirtybits)
- d->dirtybits[s->entitynumber] |= dirtybits;
+ if (bits)
+ {
+ d->deltabits[s->number] |= bits;
+ d->priorities[s->number] = EntityState5_Priority(d, d->states + viewentnum, d->states + s->number, d->deltabits[s->number], d->latestframenum - d->updateframenum[s->number]);
+ }
}
}
// delete this packet log as it is now obsolete
}
}
-void EntityFrame5_WriteFrame(sizebuf_t *msg, int numstates, entity_state_t *states)
+int entityframe5_prioritychaincounts[E5_PROTOCOL_PRIORITYLEVELS];
+unsigned short entityframe5_prioritychains[E5_PROTOCOL_PRIORITYLEVELS][ENTITYFRAME5_MAXSTATES];
+
+void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum)
{
+ const entity_state_t *n;
+ int i, num, l, framenum, packetlognumber, priority;
+ sizebuf_t buf;
+ qbyte data[128];
+ entityframe5_packetlog_t *packetlog;
+
+ framenum = d->latestframenum + 1;
+
+ // prepare the buffer
+ memset(&buf, 0, sizeof(buf));
+ buf.data = data;
+ buf.maxsize = sizeof(data);
+
+ // detect changes in states
+ num = 0;
+ for (i = 0, n = states;i < numstates;i++, n++)
+ {
+ // mark gaps in entity numbering as removed entities
+ for (;num < n->number;num++)
+ {
+ // if the entity used to exist, clear it
+ if (CHECKPVSBIT(d->visiblebits, num))
+ {
+ CLEARPVSBIT(d->visiblebits, num);
+ d->deltabits[num] = E5_FULLUPDATE;
+ d->priorities[num] = EntityState5_Priority(d, d->states + viewentnum, d->states + num, d->deltabits[num], framenum - d->updateframenum[num]);
+ d->states[num] = defaultstate;
+ d->states[num].number = num;
+ }
+ }
+ // update the entity state data
+ if (!CHECKPVSBIT(d->visiblebits, num))
+ {
+ // entity just spawned in, don't let it completely hog priority
+ // because of being ancient on the first frame
+ d->updateframenum[num] = framenum;
+ }
+ SETPVSBIT(d->visiblebits, num);
+ d->deltabits[num] |= EntityState5_DeltaBits(d->states + num, n);
+ d->priorities[num] = EntityState5_Priority(d, d->states + viewentnum, d->states + num, d->deltabits[num], framenum - d->updateframenum[num]);
+ d->states[num] = *n;
+ d->states[num].number = num;
+ // advance to next entity so the next iteration doesn't immediately remove it
+ num++;
+ }
+ // all remaining entities are dead
+ for (;num < MAX_EDICTS;num++)
+ {
+ if (CHECKPVSBIT(d->visiblebits, num))
+ {
+ CLEARPVSBIT(d->visiblebits, num);
+ d->deltabits[num] = E5_FULLUPDATE;
+ d->priorities[num] = EntityState5_Priority(d, d->states + viewentnum, d->states + num, d->deltabits[num], framenum - d->updateframenum[num]);
+ d->states[num] = defaultstate;
+ d->states[num].number = num;
+ }
+ }
+
+ // build lists of entities by priority level
+ memset(entityframe5_prioritychaincounts, 0, sizeof(entityframe5_prioritychaincounts));
+ l = 0;
+ for (num = 0;num < MAX_EDICTS;num++)
+ {
+ if (d->priorities[num])
+ {
+ l = num;
+ priority = d->priorities[num];
+ if (entityframe5_prioritychaincounts[priority] < ENTITYFRAME5_MAXSTATES)
+ entityframe5_prioritychains[priority][entityframe5_prioritychaincounts[priority]++] = num;
+ }
+ }
+
+ // return early if there are no entities to send this time
+ if (l == 0)
+ return;
+
+ d->latestframenum = framenum;
+ MSG_WriteByte(msg, svc_entities);
+ MSG_WriteLong(msg, framenum);
+
+ // if packet log is full, an empty update is still written
+ // (otherwise the client might have nothing to ack to remove packetlogs)
+ for (packetlognumber = 0, packetlog = d->packetlog;packetlognumber < ENTITYFRAME5_MAXPACKETLOGS;packetlognumber++, packetlog++)
+ if (packetlog->packetnumber == 0)
+ break;
+ if (packetlognumber < ENTITYFRAME5_MAXPACKETLOGS)
+ {
+ // write to packet and log
+ packetlog->packetnumber = framenum;
+ packetlog->numstates = 0;
+ for (priority = E5_PROTOCOL_PRIORITYLEVELS - 1;priority >= 0 && packetlog->numstates < ENTITYFRAME5_MAXSTATES;priority--)
+ {
+ for (i = 0;i < entityframe5_prioritychaincounts[priority] && packetlog->numstates < ENTITYFRAME5_MAXSTATES;i++)
+ {
+ num = entityframe5_prioritychains[priority][i];
+ n = d->states + num;
+ if (d->deltabits[num] & E5_FULLUPDATE)
+ d->deltabits[num] = E5_FULLUPDATE | EntityState5_DeltaBits(&defaultstate, n);
+ buf.cursize = 0;
+ EntityState5_WriteUpdate(num, n, d->deltabits[num], &buf);
+ // if the entity won't fit, try the next one
+ if (msg->cursize + buf.cursize + 2 > msg->maxsize)
+ continue;
+ // write entity to the packet
+ SZ_Write(msg, buf.data, buf.cursize);
+ // mark age on entity for prioritization
+ d->updateframenum[num] = framenum;
+ // log entity so deltabits can be restored later if lost
+ packetlog->states[packetlog->numstates].number = num;
+ packetlog->states[packetlog->numstates].bits = d->deltabits[num];
+ packetlog->numstates++;
+ // clear deltabits and priority so it won't be sent again
+ d->deltabits[num] = 0;
+ d->priorities[num] = 0;
+ }
+ }
+ }
+
+ MSG_WriteShort(msg, 0x8000);
}
-*/
#ifndef PROTOCOL_H
#define PROTOCOL_H
+// LordHavoc: I own protocol ranges 96, 97, 3500-3599
+
+// quake or darkplaces extended quake entity protocol
+// (still used by TomazQuake and others)
#define PROTOCOL_QUAKE 15
+
+// neh_gl entity protocol
+// (failed QSG protocol, used only by nehahra movie)
#define PROTOCOL_NEHAHRAMOVIE 250
+
+// entityframe protocol
#define PROTOCOL_DARKPLACES1 96
#define PROTOCOL_DARKPLACES2 97
-// LordHavoc: I think the 96-99 range was going to run out too soon...
-// so here I jump to 3500
+
+// entityframe4 protocol
#define PROTOCOL_DARKPLACES3 3500
#define PROTOCOL_DARKPLACES4 3501
+
+// entityframe5 protocol
#define PROTOCOL_DARKPLACES5 3502
// model effects
// this is 80 bytes
typedef struct
{
- // ! means this is sent to client
- double time; // time this state was built (used on client for interpolation)
- float origin[3]; // !
- float angles[3]; // !
- int number; // ! entity number this state is for
- int effects; // !
- unsigned short modelindex; // !
- unsigned short frame; // !
- unsigned short tagentity; // !
- unsigned short specialvisibilityradius; // larger if it has effects/light
- unsigned short viewmodelforclient;
- unsigned short exteriormodelforclient; // not shown if first person viewing from this entity, shown in all other cases
- unsigned short nodrawtoclient;
- unsigned short drawonlytoclient;
- unsigned short light[4]; // ! color*256 (0.00 to 255.996), and radius*1
- unsigned char active; // ! true if a valid state
- unsigned char lightstyle; // !
- unsigned char lightpflags; // !
- unsigned char colormap; // !
- unsigned char skin; // ! also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC
- unsigned char alpha; // !
- unsigned char scale; // !
- unsigned char glowsize; // !
- unsigned char glowcolor; // !
- unsigned char flags; // !
- unsigned char tagindex; // !
+ // ! means this is not sent to client
+ double time; // ! time this state was built (used on client for interpolation)
+ float origin[3];
+ float angles[3];
+ int number; // entity number this state is for
+ int effects;
+ unsigned short modelindex;
+ unsigned short frame;
+ unsigned short tagentity;
+ unsigned short specialvisibilityradius; // ! larger if it has effects/light
+ unsigned short viewmodelforclient; // !
+ unsigned short exteriormodelforclient; // ! not shown if first person viewing from this entity, shown in all other cases
+ unsigned short nodrawtoclient; // !
+ unsigned short drawonlytoclient; // !
+ unsigned short light[4]; // color*256 (0.00 to 255.996), and radius*1
+ unsigned char active; // true if a valid state
+ unsigned char lightstyle;
+ unsigned char lightpflags;
+ unsigned char colormap;
+ unsigned char skin; // also chooses cubemap for rtlights if lightpflags & LIGHTPFLAGS_FULLDYNAMIC
+ unsigned char alpha;
+ unsigned char scale;
+ unsigned char glowsize;
+ unsigned char glowcolor;
+ unsigned char flags;
+ unsigned char tagindex;
+ unsigned char colormod;
// padding to a multiple of 8 bytes (to align the double time)
- unsigned char unused[5];
+ unsigned char unused[4];
}
entity_state_t;
+// baseline state values
+entity_state_t defaultstate;
+// reads a quake entity from the network stream
+void EntityFrameQuake_ReadEntity(int bits);
+// writes a list of quake entities to the network stream
+// (or as many will fit)
+void EntityFrameQuake_WriteFrame(sizebuf_t *msg, int numstates, const entity_state_t *states);
+// cleans up dead entities each frame after ReadEntity (which doesn't clear unused entities)
+void EntityFrameQuake_ISeeDeadEntities(void);
+
/*
PROTOCOL_DARKPLACES3
server updates entities according to some (unmentioned) scheme.
// note: if numframes == 0, insert at start (0 in entitydata)
// the only reason this system is used is to avoid copying memory when frames are removed
int numframes;
+ // server only: last sent frame
+ int latestframenum;
// server only: last acknowledged frame
- int ackframe;
+ int ackframenum;
// the current state in the database
vec3_t eye;
// table of entities in the entityhistorydata
// entities
entity_state_t entitydata[MAX_ENTITY_DATABASE];
}
-entity_database_t;
+entityframe_database_t;
// build entity data in this, to pass to entity read/write functions
typedef struct
#define E_UNUSED7 (1<<30)
#define E_EXTEND4 (1<<31)
-// baseline state values
-entity_state_t defaultstate;
-
-// clears a state to baseline values
-void ClearStateToDefault(entity_state_t *s);
// returns difference between two states as E_ flags
int EntityState_DeltaBits(const entity_state_t *o, const entity_state_t *n);
// write E_ flags to a msg
void EntityState_WriteExtendBits(sizebuf_t *msg, unsigned int bits);
// write values for the E_ flagged fields to a msg
-void EntityState_WriteFields(entity_state_t *ent, sizebuf_t *msg, unsigned int bits);
+void EntityState_WriteFields(const entity_state_t *ent, sizebuf_t *msg, unsigned int bits);
// write entity number and E_ flags and their values, or a remove number, describing the change from delta to ent
-void EntityState_WriteUpdate(entity_state_t *ent, sizebuf_t *msg, entity_state_t *delta);
+void EntityState_WriteUpdate(const entity_state_t *ent, sizebuf_t *msg, const entity_state_t *delta);
// read E_ flags
int EntityState_ReadExtendBits(void);
// read values for E_ flagged fields and apply them to a state
void EntityState_ReadFields(entity_state_t *e, unsigned int bits);
+// (client and server) allocates a new empty database
+entityframe_database_t *EntityFrame_AllocDatabase(mempool_t *mempool);
+// (client and server) frees the database
+void EntityFrame_FreeDatabase(entityframe_database_t *d);
// (server) clears the database to contain no frames (thus delta compression
// compresses against nothing)
-void EntityFrame_ClearDatabase(entity_database_t *d);
+void EntityFrame_ClearDatabase(entityframe_database_t *d);
// (server and client) removes frames older than 'frame' from database
-void EntityFrame_AckFrame(entity_database_t *d, int frame);
+void EntityFrame_AckFrame(entityframe_database_t *d, int frame);
// (server) clears frame, to prepare for adding entities
void EntityFrame_Clear(entity_frame_t *f, vec3_t eye, int framenum);
-// (server) adds an entity to frame
-void EntityFrame_AddEntity(entity_frame_t *f, entity_state_t *s);
// (server and client) reads a frame from the database
-void EntityFrame_FetchFrame(entity_database_t *d, int framenum, entity_frame_t *f);
+void EntityFrame_FetchFrame(entityframe_database_t *d, int framenum, entity_frame_t *f);
// (server and client) adds a entity_frame to the database, for future
// reference
-void EntityFrame_AddFrame(entity_database_t *d, entity_frame_t *f);
+void EntityFrame_AddFrame(entityframe_database_t *d, vec3_t eye, int framenum, int numentities, const entity_state_t *entitydata);
// (server) writes a frame to network stream
-void EntityFrame_Write(entity_database_t *d, entity_frame_t *f, sizebuf_t *msg);
+void EntityFrame_WriteFrame(sizebuf_t *msg, entityframe_database_t *d, int numstates, const entity_state_t *states, int viewentnum);
// (client) reads a frame from network stream
-void EntityFrame_Read(entity_database_t *d);
+void EntityFrame_CL_ReadFrame(void);
// (client) returns the frame number of the most recent frame recieved
-int EntityFrame_MostRecentlyRecievedFrameNum(entity_database_t *d);
+int EntityFrame_MostRecentlyRecievedFrameNum(entityframe_database_t *d);
typedef struct entity_database4_commit_s
{
// (server only) if a commit won't fit entirely, continue where it left
// off next frame
int currententitynumber;
+ // (server only)
+ int latestframenumber;
// (client only) most recently received frame number to be sent in next
// input update
int ackframenum;
}
-entity_database4_t;
+entityframe4_database_t;
// should-be-private functions that aren't
-entity_state_t *EntityFrame4_GetReferenceEntity(entity_database4_t *d, int number);
-void EntityFrame4_AddCommitEntity(entity_database4_t *d, entity_state_t *s);
+entity_state_t *EntityFrame4_GetReferenceEntity(entityframe4_database_t *d, int number);
+void EntityFrame4_AddCommitEntity(entityframe4_database_t *d, const entity_state_t *s);
// allocate a database
-entity_database4_t *EntityFrame4_AllocDatabase(mempool_t *pool);
+entityframe4_database_t *EntityFrame4_AllocDatabase(mempool_t *pool);
// free a database
-void EntityFrame4_FreeDatabase(entity_database4_t *d);
+void EntityFrame4_FreeDatabase(entityframe4_database_t *d);
// reset a database (resets compression but does not reallocate anything)
-void EntityFrame4_ResetDatabase(entity_database4_t *d);
+void EntityFrame4_ResetDatabase(entityframe4_database_t *d);
// updates database to account for a frame-received acknowledgment
-int EntityFrame4_AckFrame(entity_database4_t *d, int framenum);
-
-// write an entity in the frame
-// returns false if full
-int EntityFrame4_SV_WriteFrame_Entity(entity_database4_t *d, sizebuf_t *msg, int maxbytes, entity_state_t *s);
-
+int EntityFrame4_AckFrame(entityframe4_database_t *d, int framenum);
+// writes a frame to the network stream
+void EntityFrame4_WriteFrame(sizebuf_t *msg, entityframe4_database_t *d, int numstates, const entity_state_t *states);
// reads a frame from the network stream
-void EntityFrame4_CL_ReadFrame(entity_database4_t *d);
+void EntityFrame4_CL_ReadFrame(void);
// reset all entity fields (typically used if status changed)
#define E5_FULLUPDATE (1<<0)
// bits >= (1<<8)
#define E5_EXTEND1 (1<<7)
-// flag
-#define E5_ORIGIN32 (1<<9)
-// flag
-#define E5_ANGLES16 (1<<10)
-// flag
-#define E5_MODEL16 (1<<11)
// byte = s->renderflags
-#define E5_FLAGS (1<<6)
+#define E5_FLAGS (1<<8)
// byte = bound(0, s->alpha * 255, 255)
-#define E5_ALPHA (1<<13)
+#define E5_ALPHA (1<<9)
// byte = bound(0, s->scale * 16, 255)
-#define E5_SCALE (1<<14)
+#define E5_SCALE (1<<10)
+// flag
+#define E5_ORIGIN32 (1<<11)
+// flag
+#define E5_ANGLES16 (1<<12)
+// flag
+#define E5_MODEL16 (1<<13)
+// byte = s->colormap
+#define E5_COLORMAP (1<<14)
// bits >= (1<<16)
#define E5_EXTEND2 (1<<15)
// short = s->tagentity
// byte = s->tagindex
#define E5_ATTACHMENT (1<<16)
-// short = s->exteriormodelforentity
-#define E5_EXTERIORFORENTITY (1<<17)
// short[4] = s->light[0], s->light[1], s->light[2], s->light[3]
-#define E5_LIGHT (1<<18)
-// byte = s->colormap
-#define E5_COLORMAP (1<<19)
+// byte = s->lightstyle
+// byte = s->lightpflags
+#define E5_LIGHT (1<<17)
// byte = s->glowsize
// byte = s->glowcolor
-#define E5_GLOW (1<<20)
+#define E5_GLOW (1<<18)
// short = s->effects
-#define E5_EFFECTS16 (1<<21)
+#define E5_EFFECTS16 (1<<19)
// int = s->effects
-#define E5_EFFECTS32 (1<<22)
+#define E5_EFFECTS32 (1<<20)
+// flag
+#define E5_FRAME16 (1<<21)
+// unused
+#define E5_UNUSED22 (1<<22)
// bits >= (1<<24)
#define E5_EXTEND3 (1<<23)
-// flag
-#define E5_FRAME16 (1<<24)
+// unused
+#define E5_UNUSED24 (1<<24)
// unused
#define E5_UNUSED25 (1<<25)
// unused
// bits2 > 0
#define E5_EXTEND4 (1<<31)
-typedef struct entity_database5_client_s
+#define ENTITYFRAME5_MAXPACKETLOGS 64
+#define ENTITYFRAME5_MAXSTATES 1024
+
+typedef struct entityframe5_changestate_s
+{
+ unsigned int number;
+ unsigned int bits;
+}
+entityframe5_changestate_t;
+
+typedef struct entityframe5_packetlog_s
{
- qbyte visible[MAX_EDICTS];
- qbyte visibledelta[MAX_EDICTS];
- int statedelta[MAX_EDICTS];
+ int packetnumber;
+ int numstates;
+ entityframe5_changestate_t states[ENTITYFRAME5_MAXSTATES];
}
-entity_database5_t;
+entityframe5_packetlog_t;
-typedef struct entity_database5_server_s
+typedef struct entityframe5_database_s
{
- // temporary working space for client data building
- // 0-255 priority level, 0 = don't send
+ // number of the latest message sent to client
+ int latestframenum;
+ // number of the latest message acknowledged by client
+ int ackframenum;
+
+ // logs of all recently sent messages (between acked and latest)
+ entityframe5_packetlog_t packetlog[ENTITYFRAME5_MAXPACKETLOGS];
+
+ // which properties of each entity have changed since last send
+ int deltabits[MAX_EDICTS];
+ // priorities of entities (updated whenever deltabits change)
+ // (derived from deltabits)
qbyte priorities[MAX_EDICTS];
- // this is the visible entity numbers, sorted by their priority level
- int numentitylist;
- int entitylist[MAX_EDICTS];
+ // last frame this entity was sent on, for prioritzation
+ int updateframenum[MAX_EDICTS];
+
+ // database of current status of all entities
+ // (FIXME: this is 2.5mb per client even if most is unused!)
+ entity_state_t states[MAX_EDICTS];
+ // which entities are currently active
+ // (duplicate of the active bit of every state in states[])
+ // (derived from states)
+ qbyte visiblebits[(MAX_EDICTS+7)/8];
+
+ // old notes
+
+ // this is used to decide which changestates to set each frame
+ //int numvisiblestates;
+ //entity_state_t visiblestates[MAX_EDICTS];
+
+ // sorted changing states that need to be sent to the client
+ // kept sorted in lowest to highest priority order, because this allows
+ // the numchangestates to simply be decremented whenever an state is sent,
+ // rather than a memmove to remove them from the start.
+ //int numchangestates;
+ //entityframe5_changestate_t changestates[MAX_EDICTS];
}
-entity_database5_server_t;
+entityframe5_database_t;
+
+entityframe5_database_t *EntityFrame5_AllocDatabase(mempool_t *pool);
+void EntityFrame5_FreeDatabase(entityframe5_database_t *d);
+void EntityFrame5_ResetDatabase(entityframe5_database_t *d);
+int EntityState5_Priority(entityframe5_database_t *d, entity_state_t *view, entity_state_t *s, int changedbits, int age);
+void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbits, sizebuf_t *msg);
+int EntityState5_DeltaBitsForState(entity_state_t *o, entity_state_t *n);
+void EntityFrame5_CL_ReadFrame(void);
+void EntityFrame5_AckFrame(entityframe5_database_t *d, int framenum, int viewentnum);
+void EntityFrame5_WriteFrame(sizebuf_t *msg, entityframe5_database_t *d, int numstates, const entity_state_t *states, int viewentnum);
extern cvar_t developer_networkentities;
void VM_WriteAngle (void)
{
- MSG_WriteAngle (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
+ MSG_WriteAngle16i (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
}
void VM_WriteCoord (void)
{
- MSG_WriteDPCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
+ MSG_WriteCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0), sv.protocol);
}
void VM_WriteString (void)
#define MAX_PACKETFRAGMENT 1024 // max length of packet fragment
#define NET_MAXMESSAGE 65536
-#define NET_MINRATE 500 // limits "rate" and "sv_maxrate" cvars
+#define NET_MINRATE 1000 // limits "rate" and "sv_maxrate" cvars
#define NET_MAXRATE 25000 // limits "rate" and "sv_maxrate" cvars
//
// handle connections specially
qboolean loadgame;
+ // one of the PROTOCOL_ values
+ int protocol;
+ // this disables extensions when using PROTOCOL_QUAKE
+ qboolean netquakecompatible;
+
double time;
double frametime;
// prevent animated names
float nametime;
-#ifdef QUAKEENTITIES
- // delta compression state
- float nextfullupdate[MAX_EDICTS];
-#elif 0
- entity_database_t entitydatabase;
- int entityframenumber; // incremented each time an entity frame is sent
-#else
- entity_database4_t *entitydatabase4;
- int entityframenumber; // incremented each time an entity frame is sent
-#endif
+ entityframe_database_t *entitydatabase;
+ entityframe4_database_t *entitydatabase4;
+ entityframe5_database_t *entitydatabase5;
} client_t;
extern cvar_t sv_aim;
extern cvar_t sv_stepheight;
extern cvar_t sv_jumpstep;
+extern cvar_t sv_public;
+extern cvar_t sv_maxrate;
extern cvar_t sv_gameplayfix_grenadebouncedownslopes;
extern cvar_t sv_gameplayfix_noairborncorpse;
#include "quakedef.h"
+// select which protocol to host, by name
+// this is named the same as PROTOCOL_DARKPLACES5 for example, minus the PROTOCOL_ prefix
+cvar_t sv_protocolname = {0, "sv_protocolname", "DARKPLACES5"};
+cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0"};
+cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000"};
+
static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1"}; // fast but loose
static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden
static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0"};
Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
+ Cvar_RegisterVariable (&sv_protocolname);
+ Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
+ Cvar_RegisterVariable (&sv_maxrate);
SV_Phys_Init();
SV_World_Init();
if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
return;
MSG_WriteByte (&sv.datagram, svc_particle);
- MSG_WriteDPCoord (&sv.datagram, org[0]);
- MSG_WriteDPCoord (&sv.datagram, org[1]);
- MSG_WriteDPCoord (&sv.datagram, org[2]);
+ MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
+ MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
+ MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
for (i=0 ; i<3 ; i++)
{
v = dir[i]*16;
if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
return;
MSG_WriteByte (&sv.datagram, svc_effect2);
- MSG_WriteDPCoord (&sv.datagram, org[0]);
- MSG_WriteDPCoord (&sv.datagram, org[1]);
- MSG_WriteDPCoord (&sv.datagram, org[2]);
+ MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
+ MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
+ MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
MSG_WriteShort (&sv.datagram, modelindex);
MSG_WriteShort (&sv.datagram, startframe);
MSG_WriteByte (&sv.datagram, framecount);
if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
return;
MSG_WriteByte (&sv.datagram, svc_effect);
- MSG_WriteDPCoord (&sv.datagram, org[0]);
- MSG_WriteDPCoord (&sv.datagram, org[1]);
- MSG_WriteDPCoord (&sv.datagram, org[2]);
+ MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
+ MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
+ MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
MSG_WriteByte (&sv.datagram, modelindex);
MSG_WriteByte (&sv.datagram, startframe);
MSG_WriteByte (&sv.datagram, framecount);
else
MSG_WriteByte (&sv.datagram, sound_num);
for (i = 0;i < 3;i++)
- MSG_WriteDPCoord (&sv.datagram, entity->v->origin[i]+0.5*(entity->v->mins[i]+entity->v->maxs[i]));
+ MSG_WriteCoord (&sv.datagram, entity->v->origin[i]+0.5*(entity->v->mins[i]+entity->v->maxs[i]), sv.protocol);
}
/*
// edicts get reallocated on level changes, so we need to update it here
client->edict = EDICT_NUM(client->number + 1);
+
// LordHavoc: clear entityframe tracking
- client->entityframenumber = 0;
+
+ if (client->entitydatabase)
+ EntityFrame_FreeDatabase(client->entitydatabase);
if (client->entitydatabase4)
EntityFrame4_FreeDatabase(client->entitydatabase4);
- client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool);
+ if (client->entitydatabase5)
+ EntityFrame5_FreeDatabase(client->entitydatabase5);
+
+ if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
+ client->entitydatabase = EntityFrame_AllocDatabase(sv_clients_mempool);
+ if (sv.protocol == PROTOCOL_DARKPLACES4)
+ client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool);
+ if (sv.protocol == PROTOCOL_DARKPLACES5)
+ client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_clients_mempool);
MSG_WriteByte (&client->message, svc_print);
snprintf (message, sizeof (message), "\002\nServer: %s build %s (progs %i crc)", gamename, buildstring, pr_crc);
MSG_WriteString (&client->message,message);
MSG_WriteByte (&client->message, svc_serverinfo);
- MSG_WriteLong (&client->message, PROTOCOL_DARKPLACES5);
+ MSG_WriteLong (&client->message, sv.protocol);
MSG_WriteByte (&client->message, svs.maxclients);
if (!coop.integer && deathmatch.integer)
=============
*/
-#ifdef QUAKEENTITIES
-void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg)
+/*
+void SV_WriteEntitiesToClient_QUAKE (client_t *client, edict_t *clent, sizebuf_t *msg)
{
int e, clentnum, bits, alpha, glowcolor, glowsize, scale, effects, lightsize;
int culled_pvs, culled_trace, visibleentities, totalentities;
if (bits & U_COLORMAP) MSG_WriteByte(msg, ent->v->colormap);
if (bits & U_SKIN) MSG_WriteByte(msg, ent->v->skin);
if (bits & U_EFFECTS) MSG_WriteByte(msg, ent->v->effects);
- if (bits & U_ORIGIN1) MSG_WriteDPCoord(msg, origin[0]);
- if (bits & U_ANGLE1) MSG_WriteAngle(msg, angles[0]);
- if (bits & U_ORIGIN2) MSG_WriteDPCoord(msg, origin[1]);
- if (bits & U_ANGLE2) MSG_WriteAngle(msg, angles[1]);
- if (bits & U_ORIGIN3) MSG_WriteDPCoord(msg, origin[2]);
- if (bits & U_ANGLE3) MSG_WriteAngle(msg, angles[2]);
+ if (bits & U_ORIGIN1) MSG_WriteCoord13i(msg, origin[0]);
+ if (bits & U_ANGLE1) MSG_WriteAngle8i(msg, angles[0]);
+ if (bits & U_ORIGIN2) MSG_WriteCoord13i(msg, origin[1]);
+ if (bits & U_ANGLE2) MSG_WriteAngle8i(msg, angles[1]);
+ if (bits & U_ORIGIN3) MSG_WriteCoord13i(msg, origin[2]);
+ if (bits & U_ANGLE3) MSG_WriteAngle8i(msg, angles[2]);
// LordHavoc: new stuff
if (bits & U_ALPHA) MSG_WriteByte(msg, alpha);
if (sv_cullentities_stats.integer)
Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, totalentities, visibleentities, culled_pvs + culled_trace, culled_pvs, culled_trace);
}
-#else
+*/
+
static int numsendentities;
static entity_state_t sendentities[MAX_EDICTS];
static entity_state_t *sendentitiesindex[MAX_EDICTS];
if (ent->e->free)
continue;
- ClearStateToDefault(&cs);
+ cs = defaultstate;
cs.active = true;
cs.number = e;
VectorCopy(ent->v->origin, cs.origin);
void SV_MarkWriteEntityStateToClient(entity_state_t *s)
{
+ int isbmodel;
vec3_t entmins, entmaxs, lightmins, lightmaxs, testorigin;
model_t *model;
trace_t trace;
// LordHavoc: only send entities with a model or important effects
if (!s->modelindex && s->specialvisibilityradius == 0)
return;
+ isbmodel = (model = sv.models[s->modelindex]) == NULL || model->name[0] != '*';
if (s->tagentity)
{
// tag attached entities simply check their parent
return;
}
// always send world submodels, they don't generate much traffic
- else if ((model = sv.models[s->modelindex]) == NULL || model->name[0] != '*')
+ else if (!isbmodel || sv.protocol == PROTOCOL_QUAKE)
{
Mod_CheckLoaded(model);
// entity has survived every check so far, check if visible
return;
}
// or not seen by random tracelines
- if (sv_cullentities_trace.integer)
+ if (sv_cullentities_trace.integer && !isbmodel)
{
// LordHavoc: test center first
testorigin[0] = (entmins[0] + entmaxs[0]) * 0.5f;
sententities[s->number] = sententitiesmark;
}
-void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg)
+entity_state_t sendstates[MAX_EDICTS];
+
+/*
+// entityframe4 protocol
+void SV_WriteEntitiesToClient_EF4(client_t *client, edict_t *clent, sizebuf_t *msg)
{
int i;
vec3_t testorigin;
entity_state_t *s;
- entity_database4_t *d;
+ entityframe4_database_t *d;
int n, startnumber;
entity_state_t *e, inactiveentitystate;
sizebuf_t buf;
d->currentcommit = d->commit + i;
// this state's number gets played around with later
- ClearStateToDefault(&inactiveentitystate);
- //inactiveentitystate = defaultstate;
+ inactiveentitystate = defaultstate;
sv_writeentitiestoclient_client = client;
SV_MarkWriteEntityStateToClient(sendentities + i);
d->currentcommit->numentities = 0;
- d->currentcommit->framenum = ++client->entityframenumber;
+ d->currentcommit->framenum = ++d->latestframenumber;
MSG_WriteByte(msg, svc_entities);
MSG_WriteLong(msg, d->referenceframenum);
MSG_WriteLong(msg, d->currentcommit->framenum);
if (sv_cullentities_stats.integer)
Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_trace);
}
-#endif
+*/
+
+void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg)
+{
+ int i, numsendstates;
+ entity_state_t *s;
+
+ // if there isn't enough space to accomplish anything, skip it
+ if (msg->cursize + 25 > msg->maxsize)
+ return;
+
+ sv_writeentitiestoclient_client = client;
+
+ sv_writeentitiestoclient_culled_pvs = 0;
+ sv_writeentitiestoclient_culled_trace = 0;
+ sv_writeentitiestoclient_visibleentities = 0;
+ sv_writeentitiestoclient_totalentities = 0;
+
+ Mod_CheckLoaded(sv.worldmodel);
+
+// find the client's PVS
+ // the real place being tested from
+ VectorAdd(clent->v->origin, clent->v->view_ofs, sv_writeentitiestoclient_testeye);
+ sv_writeentitiestoclient_pvsbytes = 0;
+ if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
+ sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
+
+ sv_writeentitiestoclient_clentnum = EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
+
+ sententitiesmark++;
+
+ for (i = 0;i < numsendentities;i++)
+ SV_MarkWriteEntityStateToClient(sendentities + i);
+
+ numsendstates = 0;
+ for (i = 0;i < numsendentities;i++)
+ {
+ if (sententities[sendentities[i].number] == sententitiesmark)
+ {
+ s = &sendstates[numsendstates++];
+ *s = sendentities[i];
+ if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
+ s->flags |= RENDER_EXTERIORMODEL;
+ }
+ }
+
+ if (sv_cullentities_stats.integer)
+ Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_trace);
+
+ if (client->entitydatabase5)
+ EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1);
+ else if (client->entitydatabase4)
+ EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
+ else if (client->entitydatabase)
+ EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
+ else
+ EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
+}
/*
=============
MSG_WriteByte (msg, ent->v->dmg_save);
MSG_WriteByte (msg, ent->v->dmg_take);
for (i=0 ; i<3 ; i++)
- MSG_WriteDPCoord (msg, other->v->origin[i] + 0.5*(other->v->mins[i] + other->v->maxs[i]));
+ MSG_WriteCoord (msg, other->v->origin[i] + 0.5*(other->v->mins[i] + other->v->maxs[i]), sv.protocol);
ent->v->dmg_take = 0;
ent->v->dmg_save = 0;
{
MSG_WriteByte (msg, svc_setangle);
for (i=0 ; i < 3 ; i++)
- MSG_WriteAngle (msg, ent->v->angles[i] );
+ {
+ if (sv.protocol == PROTOCOL_DARKPLACES5)
+ MSG_WriteAngle16i (msg, ent->v->angles[i] );
+ else
+ MSG_WriteAngle8i (msg, ent->v->angles[i] );
+ }
ent->v->fixangle = 0;
}
if (i == 0)
i = 255;
else
- i = bound(0, i, 255);
+ i = bound(0, i, 65535);
}
viewzoom = i;
- if (viewzoom != 255)
- bits |= SU_VIEWZOOM;
+ // FIXME: which protocols support this? does PROTOCOL_DARKPLACES3 support viewzoom?
+ if (sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+ if (viewzoom != 255)
+ bits |= SU_VIEWZOOM;
for (i=0 ; i<3 ; i++)
{
if (ent->v->punchangle[i])
bits |= (SU_PUNCH1<<i);
- if (punchvector[i]) // PROTOCOL_DARKPLACES
- bits |= (SU_PUNCHVEC1<<i); // PROTOCOL_DARKPLACES
+ if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+ if (punchvector[i])
+ bits |= (SU_PUNCHVEC1<<i);
if (ent->v->velocity[i])
bits |= (SU_VELOCITY1<<i);
}
for (i=0 ; i<3 ; i++)
{
if (bits & (SU_PUNCH1<<i))
- MSG_WritePreciseAngle(msg, ent->v->punchangle[i]); // PROTOCOL_DARKPLACES
- if (bits & (SU_PUNCHVEC1<<i)) // PROTOCOL_DARKPLACES
- MSG_WriteFloat(msg, punchvector[i]); // PROTOCOL_DARKPLACES
+ {
+ if (sv.protocol == PROTOCOL_QUAKE)
+ MSG_WriteChar(msg, ent->v->punchangle[i]);
+ else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+ MSG_WriteAngle16i(msg, ent->v->punchangle[i]);
+ }
+ if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+ {
+ if (bits & (SU_PUNCHVEC1<<i))
+ {
+ if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
+ MSG_WriteCoord16i(msg, punchvector[i]);
+ else if (sv.protocol == PROTOCOL_DARKPLACES5)
+ MSG_WriteCoord32f(msg, punchvector[i]);
+ }
+ }
if (bits & (SU_VELOCITY1<<i))
- MSG_WriteFloat(msg, ent->v->velocity[i]);
+ {
+ if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
+ MSG_WriteChar(msg, ent->v->velocity[i] * (1.0f / 16.0f));
+ else if (sv.protocol == PROTOCOL_DARKPLACES5)
+ MSG_WriteCoord32f(msg, ent->v->velocity[i]);
+ }
}
// [always sent] if (bits & SU_ITEMS)
MSG_WriteLong (msg, items);
- if (bits & SU_WEAPONFRAME)
- MSG_WriteByte (msg, ent->v->weaponframe);
- if (bits & SU_ARMOR)
- MSG_WriteByte (msg, ent->v->armorvalue);
- if (bits & SU_WEAPON)
- MSG_WriteByte (msg, SV_ModelIndex(PR_GetString(ent->v->weaponmodel)));
-
- MSG_WriteShort (msg, ent->v->health);
- MSG_WriteByte (msg, ent->v->currentammo);
- MSG_WriteByte (msg, ent->v->ammo_shells);
- MSG_WriteByte (msg, ent->v->ammo_nails);
- MSG_WriteByte (msg, ent->v->ammo_rockets);
- MSG_WriteByte (msg, ent->v->ammo_cells);
-
- if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
+ if (sv.protocol == PROTOCOL_DARKPLACES5)
{
- for(i=0;i<32;i++)
+ if (bits & SU_WEAPONFRAME)
+ MSG_WriteShort (msg, ent->v->weaponframe);
+ if (bits & SU_ARMOR)
+ MSG_WriteShort (msg, ent->v->armorvalue);
+ if (bits & SU_WEAPON)
{
- if ( ((int)ent->v->weapon) & (1<<i) )
+ i = SV_ModelIndex(PR_GetString(ent->v->weaponmodel));
+ if (i < 0)
{
- MSG_WriteByte (msg, i);
- break;
+ Con_DPrintf("weaponmodel \"%s\" not precached\n", PR_GetString(ent->v->weaponmodel));
+ i = 0;
}
+ MSG_WriteShort (msg, i);
}
+
+ MSG_WriteShort (msg, ent->v->health);
+ MSG_WriteShort (msg, ent->v->currentammo);
+ MSG_WriteShort (msg, ent->v->ammo_shells);
+ MSG_WriteShort (msg, ent->v->ammo_nails);
+ MSG_WriteShort (msg, ent->v->ammo_rockets);
+ MSG_WriteShort (msg, ent->v->ammo_cells);
+
+ MSG_WriteShort (msg, ent->v->weapon);
+
+ if (bits & SU_VIEWZOOM)
+ MSG_WriteShort (msg, viewzoom);
}
else
{
- MSG_WriteByte (msg, ent->v->weapon);
- }
+ if (bits & SU_WEAPONFRAME)
+ MSG_WriteByte (msg, ent->v->weaponframe);
+ if (bits & SU_ARMOR)
+ MSG_WriteByte (msg, ent->v->armorvalue);
+ if (bits & SU_WEAPON)
+ {
+ i = SV_ModelIndex(PR_GetString(ent->v->weaponmodel));
+ if (i < 0)
+ {
+ Con_DPrintf("weaponmodel \"%s\" not precached\n", PR_GetString(ent->v->weaponmodel));
+ i = 0;
+ }
+ MSG_WriteByte (msg, i);
+ }
+
+ MSG_WriteShort (msg, ent->v->health);
+ MSG_WriteByte (msg, ent->v->currentammo);
+ MSG_WriteByte (msg, ent->v->ammo_shells);
+ MSG_WriteByte (msg, ent->v->ammo_nails);
+ MSG_WriteByte (msg, ent->v->ammo_rockets);
+ MSG_WriteByte (msg, ent->v->ammo_cells);
- if (bits & SU_VIEWZOOM)
- MSG_WriteByte (msg, viewzoom);
+ if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
+ {
+ for(i=0;i<32;i++)
+ {
+ if ( ((int)ent->v->weapon) & (1<<i) )
+ {
+ MSG_WriteByte (msg, i);
+ break;
+ }
+ }
+ }
+ else
+ {
+ MSG_WriteByte (msg, ent->v->weapon);
+ }
+
+ if (bits & SU_VIEWZOOM)
+ {
+ if (sv.protocol == PROTOCOL_DARKPLACES4)
+ {
+ viewzoom = min(viewzoom, 255);
+ MSG_WriteByte (msg, viewzoom);
+ }
+ else if (sv.protocol == PROTOCOL_DARKPLACES5)
+ MSG_WriteShort (msg, viewzoom);
+ }
+ }
}
/*
static qbyte sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
qboolean SV_SendClientDatagram (client_t *client)
{
- sizebuf_t msg;
+ int rate, maxrate, maxsize, maxsize2;
+ sizebuf_t msg;
+
+ if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
+ {
+ // for good singleplayer, send huge packets
+ maxsize = sizeof(sv_sendclientdatagram_buf);
+ maxsize2 = sizeof(sv_sendclientdatagram_buf);
+ }
+ else if (sv.protocol == PROTOCOL_DARKPLACES5)
+ {
+ // PROTOCOL_DARKPLACES5 supports packet size limiting of updates
+ maxrate = bound(NET_MINRATE, sv_maxrate.integer, NET_MAXRATE);
+ if (sv_maxrate.integer != maxrate)
+ Cvar_SetValueQuick(&sv_maxrate, maxrate);
+
+ rate = bound(NET_MINRATE, client->netconnection->rate, maxrate);
+ rate = (int)(client->netconnection->rate * sys_ticrate.value);
+ maxsize = bound(100, rate, 1400);
+ maxsize2 = 1400;
+ }
+ else
+ {
+ // no rate limiting support on older protocols because dp protocols
+ // 1-4 kick the client off if they overflow, and quake protocol shows
+ // less than the full entity set if rate limited
+ maxsize = 1400;
+ maxsize2 = 1400;
+ }
msg.data = sv_sendclientdatagram_buf;
- msg.maxsize = (int)bound(50.0, client->netconnection->rate * host_realframetime, (double)sizeof(sv_sendclientdatagram_buf));
+ msg.maxsize = maxsize;
msg.cursize = 0;
MSG_WriteByte (&msg, svc_time);
SV_WriteEntitiesToClient (client, client->edict, &msg);
+ // expand packet size to allow effects to go over the rate limit
+ // (dropping them is FAR too ugly)
+ msg.maxsize = maxsize2;
+
// copy the server datagram if there is space
// FIXME: put in delayed queue of effects to send
- if (msg.cursize + sv.datagram.cursize <= msg.maxsize)
+ if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
// send the datagram
if (!strcmp(sv.model_precache[i], name))
return i;
if (i==MAX_MODELS || !sv.model_precache[i])
- Host_Error ("SV_ModelIndex: model %s not precached", name);
+ {
+ Con_DPrintf ("SV_ModelIndex: model %s not precached", name);
+ return -1;
+ }
return i;
}
-#ifdef SV_QUAKEENTITIES
/*
================
SV_CreateBaseline
svent = EDICT_NUM(entnum);
// LordHavoc: always clear state values, whether the entity is in use or not
- ClearStateToDefault(&svent->e->baseline);
+ svent->e->baseline = defaultstate;
if (svent->e->free)
continue;
if (entnum > 0 && entnum <= svs.maxclients)
{
svent->e->baseline.colormap = entnum;
- svent->e->baseline.modelindex = SV_ModelIndex("progs/player.mdl");
+ i = SV_ModelIndex("progs/player.mdl");
+ if (i < 0)
+ i = 0;
+ svent->e->baseline.modelindex = i;
}
else
{
MSG_WriteByte (&sv.signon, svent->e->baseline.skin);
for (i=0 ; i<3 ; i++)
{
- MSG_WriteDPCoord(&sv.signon, svent->e->baseline.origin[i]);
- MSG_WriteAngle(&sv.signon, svent->e->baseline.angles[i]);
+ MSG_WriteCoord(&sv.signon, svent->e->baseline.origin[i], sv.protocol);
+ MSG_WriteAngle8i(&sv.signon, svent->e->baseline.angles[i]);
}
}
}
-#endif
/*
strlcpy (sv.name, server, sizeof (sv.name));
+ // FIXME: cvar
+ if (!strcasecmp(sv_protocolname.string, "QUAKE"))
+ {
+ sv.protocol = PROTOCOL_QUAKE;
+ sv.netquakecompatible = true;
+ }
+ else if (!strcasecmp(sv_protocolname.string, "QUAKEDP"))
+ {
+ sv.protocol = PROTOCOL_QUAKE;
+ sv.netquakecompatible = false;
+ }
+ else if (!strcasecmp(sv_protocolname.string, "DARKPLACES1"))
+ {
+ sv.protocol = PROTOCOL_DARKPLACES1;
+ sv.netquakecompatible = false;
+ }
+ else if (!strcasecmp(sv_protocolname.string, "DARKPLACES2"))
+ {
+ sv.protocol = PROTOCOL_DARKPLACES2;
+ sv.netquakecompatible = false;
+ }
+ else if (!strcasecmp(sv_protocolname.string, "DARKPLACES3"))
+ {
+ sv.protocol = PROTOCOL_DARKPLACES3;
+ sv.netquakecompatible = false;
+ }
+ else if (!strcasecmp(sv_protocolname.string, "DARKPLACES4"))
+ {
+ sv.protocol = PROTOCOL_DARKPLACES4;
+ sv.netquakecompatible = false;
+ }
+ else if (!strcasecmp(sv_protocolname.string, "DARKPLACES5"))
+ {
+ sv.protocol = PROTOCOL_DARKPLACES5;
+ sv.netquakecompatible = false;
+ }
+ else
+ {
+ sv.protocol = PROTOCOL_DARKPLACES5;
+ sv.netquakecompatible = false;
+ Con_Printf("Unknown sv_protocolname \"%s\", valid values are QUAKE, QUAKEDP, DARKPLACES1, DARKPLACES2, DARKPLACES3, DARKPLACES4, DARKPLACES5, falling back to DARKPLACES5 protocol\n", sv_protocolname.string);
+ }
+
// load progs to get entity field count
PR_LoadProgs ();
Mod_PurgeUnused();
-#ifdef QUAKEENTITIES
// create a baseline for more efficient communications
- SV_CreateBaseline ();
-#endif
+ if (sv.protocol == PROTOCOL_QUAKE)
+ SV_CreateBaseline ();
// send serverinfo to all connected clients
for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
float total;
// read ping time
+ if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
host_client->ping_times[host_client->num_pings % NUM_PING_TIMES] = sv.time - MSG_ReadFloat ();
+ if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
host_client->num_pings++;
for (i=0, total = 0;i < NUM_PING_TIMES;i++)
total += host_client->ping_times[i];
val->_float = host_client->ping * 1000.0;
// read current angles
- // PROTOCOL_DARKPLACES4
for (i = 0;i < 3;i++)
- angle[i] = MSG_ReadPreciseAngle();
+ {
+ if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+ if (sv.protocol == PROTOCOL_QUAKE)
+ angle[i] = MSG_ReadAngle8i();
+ else if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
+ angle[i] = MSG_ReadAngle32f();
+ else if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
+ angle[i] = MSG_ReadAngle16i();
+ if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+ }
VectorCopy (angle, sv_player->v->v_angle);
// read movement
- move->forwardmove = MSG_ReadShort ();
- move->sidemove = MSG_ReadShort ();
- move->upmove = MSG_ReadShort ();
+ if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+ move->forwardmove = MSG_ReadCoord16i ();
+ if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+ move->sidemove = MSG_ReadCoord16i ();
+ if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+ move->upmove = MSG_ReadCoord16i ();
+ if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
if ((val = GETEDICTFIELDVALUE(sv_player, eval_movement)))
{
val->vector[0] = move->forwardmove;
// read buttons
bits = MSG_ReadByte ();
+ if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
sv_player->v->button0 = bits & 1;
sv_player->v->button2 = (bits & 2)>>1;
// LordHavoc: added 6 new buttons
if ((val = GETEDICTFIELDVALUE(sv_player, eval_button8))) val->_float = ((bits >> 7) & 1);
i = MSG_ReadByte ();
+ if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
if (i)
sv_player->v->impulse = i;
}
extern void SV_SendServerinfo(client_t *client);
void SV_ReadClientMessage(void)
{
- int cmd;
+ int cmd, num;
char *s;
//MSG_BeginReading ();
break;
case clc_ackentities:
- host_client->entitydatabase4->ackframenum = MSG_ReadLong();
+ if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
+ num = MSG_ReadLong();
+ if (msg_badread) Con_Printf("SV_ReadClientMessage: badread at %s:%i\n", __FILE__, __LINE__);
if (developer_networkentities.integer >= 1)
- Con_Printf("recv clc_ackentities %i\n", host_client->entitydatabase4->ackframenum);
- EntityFrame4_AckFrame(host_client->entitydatabase4, host_client->entitydatabase4->ackframenum);
+ Con_Printf("recv clc_ackentities %i\n", num);
+ if (host_client->entitydatabase)
+ EntityFrame_AckFrame(host_client->entitydatabase, num);
+ else if (host_client->entitydatabase4)
+ EntityFrame4_AckFrame(host_client->entitydatabase4, host_client->entitydatabase4->ackframenum);
+ else if (host_client->entitydatabase5)
+ EntityFrame5_AckFrame(host_client->entitydatabase5, num, host_client - svs.clients + 1);
break;
}
}
armor = MSG_ReadByte ();
blood = MSG_ReadByte ();
- MSG_ReadVector(from);
+ MSG_ReadVector(from, cl.protocol);
count = blood*0.5 + armor*0.5;
if (count < 10)