"", // 48
"", // 49
"svc_cgame", // 50 // [short] length [bytes] data
- "svc_fog", // 51 // unfinished and obsolete
+ "svc_unusedlh1", // 51 // unused
"svc_effect", // 52 // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
"svc_effect2", // 53 // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate
"svc_sound2", // 54 // short soundindex instead of byte
qboolean Nehahrademcompatibility; // LordHavoc: to allow playback of the early Nehahra movie segments
int dpprotocol; // LordHavoc: version of network protocol, or 0 if not DarkPlaces
-/*
-===============
-CL_EntityNum
-
-This error checks and tracks the total number of entities
-===============
-*/
-entity_t *CL_EntityNum (int num)
-{
- /*
- if (num >= cl.num_entities)
- {
- if (num >= MAX_EDICTS)
- Host_Error ("CL_EntityNum: %i is an invalid number",num);
- cl.num_entities = num;
-// while (cl.num_entities <= num)
-// {
-// cl_entities[cl.num_entities].colormap = -1; // no special coloring
-// cl.num_entities++;
-// }
- }
- */
- if (num >= MAX_EDICTS)
- Host_Error ("CL_EntityNum: %i is an invalid number",num);
-
- return &cl_entities[num];
-}
-
-
/*
==================
CL_ParseStartSoundPacket
float attenuation;
int i;
- field_mask = MSG_ReadByte();
+ field_mask = MSG_ReadByte();
if (field_mask & SND_VOLUME)
volume = MSG_ReadByte ();
pos[i] = MSG_ReadCoord ();
S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
-}
+}
/*
==================
float time;
static float lastmsg;
int ret;
+ int c;
sizebuf_t old;
qbyte olddata[8192];
switch (ret)
{
default:
- Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed");
+ Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed");
case 0:
break; // nothing waiting
case 1:
Host_Error ("CL_KeepaliveMessage: received a message");
break;
case 2:
- if (MSG_ReadByte() != svc_nop)
+ c = MSG_ReadByte();
+ if (c != svc_nop)
Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop");
break;
}
*/
static void CL_SignonReply (void)
{
- char str[8192];
+ //char str[8192];
Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
}
MSG_WriteByte (&cls.message, clc_stringcmd);
- sprintf (str, "spawn %s", cls.spawnparms);
- MSG_WriteString (&cls.message, str);
+ //sprintf (str, "spawn %s", cls.spawnparms);
+ //MSG_WriteString (&cls.message, str);
+ MSG_WriteString (&cls.message, "spawn");
break;
case 3:
break;
case 4:
- SCR_EndLoadingPlaque (); // allow normal screen updates
Con_ClearNotify();
break;
}
CL_ParseServerInfo
==================
*/
+qbyte entlife[MAX_EDICTS];
void CL_ParseServerInfo (void)
{
- char *str;
- int i;
- int nummodels, numsounds;
- char model_precache[MAX_MODELS][MAX_QPATH];
- char sound_precache[MAX_SOUNDS][MAX_QPATH];
+ char *str;
+ int i;
+ int nummodels, numsounds;
+ char model_precache[MAX_MODELS][MAX_QPATH];
+ char sound_precache[MAX_SOUNDS][MAX_QPATH];
+ entity_t *ent;
Con_DPrintf ("Serverinfo packet received.\n");
//
// parse protocol version number
i = MSG_ReadLong ();
- if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION1 && i != DPPROTOCOL_VERSION2 && i != 250)
+ if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION1 && i != DPPROTOCOL_VERSION2 && i != DPPROTOCOL_VERSION3 && i != 250)
{
- Con_Printf ("Server is protocol %i, not %i, %i or %i", i, DPPROTOCOL_VERSION1, DPPROTOCOL_VERSION2, PROTOCOL_VERSION);
+ Con_Printf ("Server is protocol %i, not %i, %i, %i or %i", i, DPPROTOCOL_VERSION1, DPPROTOCOL_VERSION2, DPPROTOCOL_VERSION3, PROTOCOL_VERSION);
return;
}
Nehahrademcompatibility = false;
if (cls.demoplayback && demo_nehahra.integer)
Nehahrademcompatibility = true;
dpprotocol = i;
- if (dpprotocol != DPPROTOCOL_VERSION1 && dpprotocol != DPPROTOCOL_VERSION2)
+ if (dpprotocol != DPPROTOCOL_VERSION1 && dpprotocol != DPPROTOCOL_VERSION2 && dpprotocol != DPPROTOCOL_VERSION3)
dpprotocol = 0;
// parse maxclients
S_BeginPrecaching ();
for (i=1 ; i<numsounds ; i++)
{
- cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]);
+ cl.sound_precache[i] = S_PrecacheSound (sound_precache[i], true);
CL_KeepaliveMessage ();
}
S_EndPrecaching ();
// local state
- cl_entities[0].render.model = cl.worldmodel = cl.model_precache[1];
- cl_entities[0].render.scale = 1;
- cl_entities[0].render.alpha = 1;
+ ent = &cl_entities[0];
+ // entire entity array was cleared, so just fill in a few fields
+ ent->state_current.active = true;
+ ent->render.model = cl.worldmodel = cl.model_precache[1];
+ ent->render.scale = 1;
+ ent->render.alpha = 1;
+ VectorAdd(ent->render.origin, ent->render.model->normalmins, ent->render.mins);
+ VectorAdd(ent->render.origin, ent->render.model->normalmaxs, ent->render.maxs);
+ // clear entlife array
+ memset(entlife, 0, MAX_EDICTS);
+
+ cl_num_entities = 1;
R_NewMap ();
Mod_CheckLoaded(model);
if (model && s->frame >= model->numframes)
{
- Con_Printf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
+ Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
s->frame = 0;
}
if (model && s->skin > 0 && s->skin >= model->numskins)
{
- Con_Printf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
+ Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
s->skin = 0;
}
}
+void CL_MoveLerpEntityStates(entity_t *ent)
+{
+ float odelta[3], adelta[3];
+ 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)
+ {
+ // we definitely shouldn't lerp
+ ent->persistent.lerpdeltatime = 0;
+ ent->persistent.lerpstarttime = cl.mtime[1];
+ VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
+ VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
+ VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
+ VectorCopy(ent->state_current.angles, ent->persistent.newangles);
+ }
+ else// if (ent->state_current.flags & RENDER_STEP)
+ {
+ // monster interpolation
+ if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01)
+ {
+ ent->persistent.lerpdeltatime = cl.time - ent->persistent.lerpstarttime;
+ ent->persistent.lerpstarttime = cl.mtime[1];
+ VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
+ VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
+ VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
+ VectorCopy(ent->state_current.angles, ent->persistent.newangles);
+ }
+ }
+ /*
+ else
+ {
+ // not a monster
+ ent->persistent.lerpstarttime = cl.mtime[1];
+ // no lerp if it's singleplayer
+ //if (sv.active && svs.maxclients == 1 && !ent->state_current.flags & RENDER_STEP)
+ // ent->persistent.lerpdeltatime = 0;
+ //else
+ ent->persistent.lerpdeltatime = cl.mtime[0] - cl.mtime[1];
+ VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
+ VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
+ VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
+ VectorCopy(ent->state_current.angles, ent->persistent.newangles);
+ }
+ */
+}
+
/*
==================
CL_ParseUpdate
relinked. Other attributes can change without relinking.
==================
*/
-qbyte entkill[MAX_EDICTS];
int bitprofile[32], bitprofilecount = 0;
void CL_ParseUpdate (int bits)
{
- int i, num, deltadie;
+ int i, num;
entity_t *ent;
entity_state_t new;
if (num < 1)
Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
- // mark as visible (no kill)
- entkill[num] = 0;
-
- ent = CL_EntityNum (num);
+ ent = cl_entities + num;
for (i = 0;i < 32;i++)
if (bits & (1 << i))
bitprofile[i]++;
bitprofilecount++;
- deltadie = false;
+ // 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;
- if (!new.active)
- deltadie = true; // was not present in previous frame, leave hidden until next full update
- }
else
+ {
new = ent->state_baseline;
+ new.active = true;
+ }
+ new.number = num;
new.time = cl.mtime[0];
-
new.flags = 0;
- new.active = true;
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_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();
-#if 0
- if (bits & U_COLORMOD) {int i = MSG_ReadByte();float r = (((int) i >> 5) & 7) * 1.0 / 7, g = (((int) i >> 2) & 7) * 1.0 / 7, b = ((int) i & 3) * 1.0 / 3;Con_Printf("warning: U_COLORMOD %i (%1.2f %1.2f %1.2f) ignored\n", i, r, g, b);}
-#else
// apparently the dpcrush demo uses this (unintended, and it uses white anyway)
if (bits & U_COLORMOD) MSG_ReadByte();
-#endif
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);
int j = MSG_ReadFloat() * 255.0f;
if (i == 2)
{
- if (MSG_ReadFloat())
+ i = MSG_ReadFloat();
+ if (i)
new.effects |= EF_FULLBRIGHT;
}
if (j < 0)
new.alpha = j;
}
- if (deltadie)
- {
- // hide the entity
- new.active = false;
- }
- else
+ if (new.active)
CL_ValidateState(&new);
- if (new.flags & RENDER_STEP) // FIXME: rename this flag?
+ ent->state_previous = ent->state_current;
+ ent->state_current = new;
+ if (ent->state_current.active)
{
- // make time identical for memcmp
- new.time = ent->state_current.time;
- if (memcmp(&new, &ent->state_current, sizeof(entity_state_t)))
- {
- // set it back to what it should be
- new.time = cl.mtime[0] + 0.1;
- // state has changed
- ent->state_previous = ent->state_current;
- ent->state_current = new;
- // assume 10fps animation
- //ent->state_previous.time = cl.mtime[0] - 0.1;
- }
- }
- else
- {
- ent->state_previous = ent->state_current;
- ent->state_current = new;
+ CL_MoveLerpEntityStates(ent);
+ cl_entities_active[ent->state_current.number] = true;
+ // mark as visible (no kill this frame)
+ entlife[ent->state_current.number] = 2;
}
}
void CL_ReadEntityFrame(void)
{
entity_t *ent;
- entity_state_t *s;
entity_frame_t entityframe;
int i;
EntityFrame_Read(&cl.entitydatabase);
EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
for (i = 0;i < entityframe.numentities;i++)
{
- s = &entityframe.entitydata[i];
- entkill[s->number] = 0;
- ent = &cl_entities[s->number];
- memcpy(&ent->state_previous, &ent->state_current, sizeof(*s));
- memcpy(&ent->state_current, s, sizeof(*s));
- ent->state_current.time = cl.mtime[0];
+ // 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;
}
VectorCopy(cl.viewentoriginnew, cl.viewentoriginold);
VectorCopy(entityframe.eye, cl.viewentoriginnew);
Con_Printf("bitprofile: %i updates\n");
if (bitprofilecount)
for (i = 0;i < 32;i++)
-// if (bitprofile[i])
- Con_Printf("%s: %i %3.2f%%\n", bitprofilenames[i], bitprofile[i], bitprofile[i] * 100.0 / bitprofilecount);
+ Con_Printf("%s: %i %3.2f%%\n", bitprofilenames[i], bitprofile[i], bitprofile[i] * 100.0 / bitprofilecount);
Con_Printf("\n");
for (i = 0;i < 32;i++)
bitprofile[i] = 0;
void CL_EntityUpdateSetup(void)
{
- memset(entkill, 1, MAX_EDICTS);
}
void CL_EntityUpdateEnd(void)
{
int i;
+ // disable entities that disappeared this frame
for (i = 1;i < MAX_EDICTS;i++)
- if (entkill[i])
- cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
+ {
+ // 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;
+ }
+ }
}
/*
{
entity_t *ent;
- if (cl.num_statics >= MAX_STATIC_ENTITIES)
+ if (cl_num_static_entities >= cl_max_static_entities)
Host_Error ("Too many static entities");
- ent = &cl_static_entities[cl.num_statics++];
+ ent = &cl_static_entities[cl_num_static_entities++];
CL_ParseBaseline (ent, large);
// copy it to the current state
ent->render.alpha = 1;
VectorCopy (ent->state_baseline.origin, ent->render.origin);
- VectorCopy (ent->state_baseline.angles, ent->render.angles);
+ VectorCopy (ent->state_baseline.angles, ent->render.angles);
+
+ if (ent->render.angles[0] || ent->render.angles[2])
+ {
+ // pitch or roll
+ VectorAdd(ent->render.origin, ent->render.model->rotatedmins, ent->render.mins);
+ VectorAdd(ent->render.origin, ent->render.model->rotatedmaxs, ent->render.maxs);
+ }
+ else if (ent->render.angles[1])
+ {
+ // yaw
+ VectorAdd(ent->render.origin, ent->render.model->yawmins, ent->render.mins);
+ VectorAdd(ent->render.origin, ent->render.model->yawmaxs, ent->render.maxs);
+ }
+ else
+ {
+ VectorAdd(ent->render.origin, ent->render.model->normalmins, ent->render.mins);
+ VectorAdd(ent->render.origin, ent->render.model->normalmaxs, ent->render.maxs);
+ }
+
+ // This is definitely cheating...
+ if (ent->render.model == NULL)
+ cl_num_static_entities--;
}
/*
MSG_BeginReading ();
entitiesupdated = false;
- CL_EntityUpdateSetup();
while (1)
{
cmdlogname[cmdindex] = temp;
SHOWNET("fast update");
if (cls.signon == SIGNONS - 1)
- { // first update is the final signon stage
+ {
+ // first update is the final signon stage
cls.signon = SIGNONS;
CL_SignonReply ();
}
break;
case svc_nop:
-// Con_Printf ("svc_nop\n");
break;
case svc_time:
- // handle old protocols which do not have entity update ranges
- entitiesupdated = true;
+ 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_version:
i = MSG_ReadLong ();
- if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION1 && i != DPPROTOCOL_VERSION2 && i != 250)
- Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i, %i or %i", i, DPPROTOCOL_VERSION1, DPPROTOCOL_VERSION2, PROTOCOL_VERSION);
+ if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION1 && i != DPPROTOCOL_VERSION2 && i != DPPROTOCOL_VERSION3 && i != 250)
+ Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i, %i, %i or %i", i, DPPROTOCOL_VERSION1, DPPROTOCOL_VERSION2, DPPROTOCOL_VERSION3, PROTOCOL_VERSION);
Nehahrademcompatibility = false;
if (i == 250)
Nehahrademcompatibility = true;
if (cls.demoplayback && demo_nehahra.integer)
Nehahrademcompatibility = true;
dpprotocol = i;
- if (dpprotocol != DPPROTOCOL_VERSION1 && dpprotocol != DPPROTOCOL_VERSION2)
+ if (dpprotocol != DPPROTOCOL_VERSION1 && dpprotocol != DPPROTOCOL_VERSION2 && dpprotocol != DPPROTOCOL_VERSION3)
dpprotocol = 0;
break;
case svc_serverinfo:
CL_ParseServerInfo ();
-// vid.recalc_refdef = true; // leave intermission full screen
break;
case svc_setangle:
case svc_setview:
cl.viewentity = MSG_ReadShort ();
+ // LordHavoc: assume first setview recieved is the real player entity
+ if (!cl.playerentity)
+ cl.playerentity = cl.viewentity;
break;
case svc_lightstyle:
if (i >= cl.maxclients)
Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
cl.scores[i].colors = MSG_ReadByte ();
+ // update our color cvar if our color changed
+ if (i == cl.playerentity - 1)
+ Cvar_SetValue ("_cl_color", cl.scores[i].colors);
break;
case svc_particle:
case svc_spawnbaseline:
i = MSG_ReadShort ();
- // must use CL_EntityNum() to force cl.num_entities up
- CL_ParseBaseline (CL_EntityNum(i), false);
+ 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 ();
- // must use CL_EntityNum() to force cl.num_entities up
- CL_ParseBaseline (CL_EntityNum(i), true);
+ if (i < 0 || i >= MAX_EDICTS)
+ Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
+ CL_ParseBaseline (cl_entities + i, true);
break;
case svc_spawnstatic:
CL_ParseStatic (false);
case svc_intermission:
cl.intermission = 1;
cl.completed_time = cl.time;
-// vid.recalc_refdef = true; // go to full screen
break;
case svc_finale:
cl.intermission = 2;
cl.completed_time = cl.time;
-// vid.recalc_refdef = true; // go to full screen
SCR_CenterPrint (MSG_ReadString ());
break;
case svc_cutscene:
cl.intermission = 3;
cl.completed_time = cl.time;
-// vid.recalc_refdef = true; // go to full screen
SCR_CenterPrint (MSG_ReadString ());
break;
{
int length;
length = (int) ((unsigned short) MSG_ReadShort());
- /*
- if (cgamenetbuffersize < length)
- {
- cgamenetbuffersize = length;
- if (cgamenetbuffer)
- Mem_Free(cgamenetbuffer);
- cgamenetbuffer = Mem_Alloc(cgamenetbuffersize);
- }
- */
for (i = 0;i < length;i++)
cgamenetbuffer[i] = MSG_ReadByte();
if (!msg_badread)
break;
case svc_entities:
if (cls.signon == SIGNONS - 1)
- { // first update is the final signon stage
+ {
+ // first update is the final signon stage
cls.signon = SIGNONS;
CL_SignonReply ();
}
if (entitiesupdated)
CL_EntityUpdateEnd();
}
+