?? cl_ents.c
字號:
{
int flags;
player_state_t *state;
int i;
int statbits;
state = &newframe->playerstate;
// clear to old value before delta parsing
if (oldframe)
*state = oldframe->playerstate;
else
memset (state, 0, sizeof(*state));
flags = MSG_ReadShort (&net_message);
//
// parse the pmove_state_t
//
if (flags & PS_M_TYPE)
state->pmove.pm_type = MSG_ReadByte (&net_message);
if (flags & PS_M_ORIGIN)
{
state->pmove.origin[0] = MSG_ReadShort (&net_message);
state->pmove.origin[1] = MSG_ReadShort (&net_message);
state->pmove.origin[2] = MSG_ReadShort (&net_message);
}
if (flags & PS_M_VELOCITY)
{
state->pmove.velocity[0] = MSG_ReadShort (&net_message);
state->pmove.velocity[1] = MSG_ReadShort (&net_message);
state->pmove.velocity[2] = MSG_ReadShort (&net_message);
}
if (flags & PS_M_TIME)
state->pmove.pm_time = MSG_ReadByte (&net_message);
if (flags & PS_M_FLAGS)
state->pmove.pm_flags = MSG_ReadByte (&net_message);
if (flags & PS_M_GRAVITY)
state->pmove.gravity = MSG_ReadShort (&net_message);
if (flags & PS_M_DELTA_ANGLES)
{
state->pmove.delta_angles[0] = MSG_ReadShort (&net_message);
state->pmove.delta_angles[1] = MSG_ReadShort (&net_message);
state->pmove.delta_angles[2] = MSG_ReadShort (&net_message);
}
if (cl.attractloop)
state->pmove.pm_type = PM_FREEZE; // demo playback
//
// parse the rest of the player_state_t
//
if (flags & PS_VIEWOFFSET)
{
state->viewoffset[0] = MSG_ReadChar (&net_message) * 0.25;
state->viewoffset[1] = MSG_ReadChar (&net_message) * 0.25;
state->viewoffset[2] = MSG_ReadChar (&net_message) * 0.25;
}
if (flags & PS_VIEWANGLES)
{
state->viewangles[0] = MSG_ReadAngle16 (&net_message);
state->viewangles[1] = MSG_ReadAngle16 (&net_message);
state->viewangles[2] = MSG_ReadAngle16 (&net_message);
}
if (flags & PS_KICKANGLES)
{
state->kick_angles[0] = MSG_ReadChar (&net_message) * 0.25;
state->kick_angles[1] = MSG_ReadChar (&net_message) * 0.25;
state->kick_angles[2] = MSG_ReadChar (&net_message) * 0.25;
}
if (flags & PS_WEAPONINDEX)
{
state->gunindex = MSG_ReadByte (&net_message);
}
if (flags & PS_WEAPONFRAME)
{
state->gunframe = MSG_ReadByte (&net_message);
state->gunoffset[0] = MSG_ReadChar (&net_message)*0.25;
state->gunoffset[1] = MSG_ReadChar (&net_message)*0.25;
state->gunoffset[2] = MSG_ReadChar (&net_message)*0.25;
state->gunangles[0] = MSG_ReadChar (&net_message)*0.25;
state->gunangles[1] = MSG_ReadChar (&net_message)*0.25;
state->gunangles[2] = MSG_ReadChar (&net_message)*0.25;
}
if (flags & PS_BLEND)
{
state->blend[0] = MSG_ReadByte (&net_message)/255.0;
state->blend[1] = MSG_ReadByte (&net_message)/255.0;
state->blend[2] = MSG_ReadByte (&net_message)/255.0;
state->blend[3] = MSG_ReadByte (&net_message)/255.0;
}
if (flags & PS_FOV)
state->fov = MSG_ReadByte (&net_message);
if (flags & PS_RDFLAGS)
state->rdflags = MSG_ReadByte (&net_message);
// parse stats
statbits = MSG_ReadLong (&net_message);
for (i=0 ; i<MAX_STATS ; i++)
if (statbits & (1<<i) )
state->stats[i] = MSG_ReadShort(&net_message);
}
/*
==================
CL_FireEntityEvents
==================
*/
void CL_FireEntityEvents (frame_t *frame)
{
entity_state_t *s1;
int pnum, num;
for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
{
num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1);
s1 = &cl_parse_entities[num];
if (s1->event)
CL_EntityEvent (s1);
// EF_TELEPORTER acts like an event, but is not cleared each frame
if (s1->effects & EF_TELEPORTER)
CL_TeleporterParticles (s1);
}
}
/*
================
CL_ParseFrame
================
*/
void CL_ParseFrame (void)
{
int cmd;
int len;
frame_t *old;
memset (&cl.frame, 0, sizeof(cl.frame));
#if 0
CL_ClearProjectiles(); // clear projectiles for new frame
#endif
cl.frame.serverframe = MSG_ReadLong (&net_message);
cl.frame.deltaframe = MSG_ReadLong (&net_message);
cl.frame.servertime = cl.frame.serverframe*100;
// BIG HACK to let old demos continue to work
if (cls.serverProtocol != 26)
cl.surpressCount = MSG_ReadByte (&net_message);
if (cl_shownet->value == 3)
Com_Printf (" frame:%i delta:%i\n", cl.frame.serverframe,
cl.frame.deltaframe);
// If the frame is delta compressed from data that we
// no longer have available, we must suck up the rest of
// the frame, but not use it, then ask for a non-compressed
// message
if (cl.frame.deltaframe <= 0)
{
cl.frame.valid = true; // uncompressed frame
old = NULL;
cls.demowaiting = false; // we can start recording now
}
else
{
old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
if (!old->valid)
{ // should never happen
Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
}
if (old->serverframe != cl.frame.deltaframe)
{ // The frame that the server did the delta from
// is too old, so we can't reconstruct it properly.
Com_Printf ("Delta frame too old.\n");
}
else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128)
{
Com_Printf ("Delta parse_entities too old.\n");
}
else
cl.frame.valid = true; // valid delta parse
}
// clamp time
if (cl.time > cl.frame.servertime)
cl.time = cl.frame.servertime;
else if (cl.time < cl.frame.servertime - 100)
cl.time = cl.frame.servertime - 100;
// read areabits
len = MSG_ReadByte (&net_message);
MSG_ReadData (&net_message, &cl.frame.areabits, len);
// read playerinfo
cmd = MSG_ReadByte (&net_message);
SHOWNET(svc_strings[cmd]);
if (cmd != svc_playerinfo)
Com_Error (ERR_DROP, "CL_ParseFrame: not playerinfo");
CL_ParsePlayerstate (old, &cl.frame);
// read packet entities
cmd = MSG_ReadByte (&net_message);
SHOWNET(svc_strings[cmd]);
if (cmd != svc_packetentities)
Com_Error (ERR_DROP, "CL_ParseFrame: not packetentities");
CL_ParsePacketEntities (old, &cl.frame);
#if 0
if (cmd == svc_packetentities2)
CL_ParseProjectiles();
#endif
// save the frame off in the backup array for later delta comparisons
cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;
if (cl.frame.valid)
{
// getting a valid frame message ends the connection process
if (cls.state != ca_active)
{
cls.state = ca_active;
cl.force_refdef = true;
cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125;
VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles);
if (cls.disable_servercount != cl.servercount
&& cl.refresh_prepped)
SCR_EndLoadingPlaque (); // get rid of loading plaque
}
cl.sound_prepped = true; // can start mixing ambient sounds
// fire entity events
CL_FireEntityEvents (&cl.frame);
CL_CheckPredictionError ();
}
}
/*
==========================================================================
INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
==========================================================================
*/
struct model_s *S_RegisterSexedModel (entity_state_t *ent, char *base)
{
int n;
char *p;
struct model_s *mdl;
char model[MAX_QPATH];
char buffer[MAX_QPATH];
// determine what model the client is using
model[0] = 0;
n = CS_PLAYERSKINS + ent->number - 1;
if (cl.configstrings[n][0])
{
p = strchr(cl.configstrings[n], '\\');
if (p)
{
p += 1;
strcpy(model, p);
p = strchr(model, '/');
if (p)
*p = 0;
}
}
// if we can't figure it out, they're male
if (!model[0])
strcpy(model, "male");
Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", model, base+1);
mdl = re.RegisterModel(buffer);
if (!mdl) {
// not found, try default weapon model
Com_sprintf (buffer, sizeof(buffer), "players/%s/weapon.md2", model);
mdl = re.RegisterModel(buffer);
if (!mdl) {
// no, revert to the male model
Com_sprintf (buffer, sizeof(buffer), "players/%s/%s", "male", base+1);
mdl = re.RegisterModel(buffer);
if (!mdl) {
// last try, default male weapon.md2
Com_sprintf (buffer, sizeof(buffer), "players/male/weapon.md2");
mdl = re.RegisterModel(buffer);
}
}
}
return mdl;
}
// PMM - used in shell code
extern int Developer_searchpath (int who);
// pmm
/*
===============
CL_AddPacketEntities
===============
*/
void CL_AddPacketEntities (frame_t *frame)
{
entity_t ent;
entity_state_t *s1;
float autorotate;
int i;
int pnum;
centity_t *cent;
int autoanim;
clientinfo_t *ci;
unsigned int effects, renderfx;
// bonus items rotate at a fixed rate
autorotate = anglemod(cl.time/10);
// brush models can auto animate their frames
autoanim = 2*cl.time/1000;
memset (&ent, 0, sizeof(ent));
for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
{
s1 = &cl_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)];
cent = &cl_entities[s1->number];
effects = s1->effects;
renderfx = s1->renderfx;
// set frame
if (effects & EF_ANIM01)
ent.frame = autoanim & 1;
else if (effects & EF_ANIM23)
ent.frame = 2 + (autoanim & 1);
else if (effects & EF_ANIM_ALL)
ent.frame = autoanim;
else if (effects & EF_ANIM_ALLFAST)
ent.frame = cl.time / 100;
else
ent.frame = s1->frame;
// quad and pent can do different things on client
if (effects & EF_PENT)
{
effects &= ~EF_PENT;
effects |= EF_COLOR_SHELL;
renderfx |= RF_SHELL_RED;
}
if (effects & EF_QUAD)
{
effects &= ~EF_QUAD;
effects |= EF_COLOR_SHELL;
renderfx |= RF_SHELL_BLUE;
}
//======
// PMM
if (effects & EF_DOUBLE)
{
effects &= ~EF_DOUBLE;
effects |= EF_COLOR_SHELL;
renderfx |= RF_SHELL_DOUBLE;
}
if (effects & EF_HALF_DAMAGE)
{
effects &= ~EF_HALF_DAMAGE;
effects |= EF_COLOR_SHELL;
renderfx |= RF_SHELL_HALF_DAM;
}
// pmm
//======
ent.oldframe = cent->prev.frame;
ent.backlerp = 1.0 - cl.lerpfrac;
if (renderfx & (RF_FRAMELERP|RF_BEAM))
{ // step origin discretely, because the frames
// do the animation properly
VectorCopy (cent->current.origin, ent.origin);
VectorCopy (cent->current.old_origin, ent.oldorigin);
}
else
{ // interpolate origin
for (i=0 ; i<3 ; i++)
{
ent.origin[i] = ent.oldorigin[i] = cent->prev.origin[i] + cl.lerpfrac *
(cent->current.origin[i] - cent->prev.origin[i]);
}
}
// create a new entity
// tweak the color of beams
if ( renderfx & RF_BEAM )
{ // the four beam colors are encoded in 32 bits of skinnum (hack)
ent.alpha = 0.30;
ent.skinnum = (s1->skinnum >> ((rand() % 4)*8)) & 0xff;
ent.model = NULL;
}
else
{
// set skin
if (s1->modelindex == 255)
{ // use custom player skin
ent.skinnum = 0;
ci = &cl.clientinfo[s1->skinnum & 0xff];
ent.skin = ci->skin;
ent.model = ci->model;
if (!ent.skin || !ent.model)
{
ent.skin = cl.baseclientinfo.skin;
ent.model = cl.baseclientinfo.model;
}
//============
//PGM
if (renderfx & RF_USE_DISGUISE)
{
if(!strncmp((char *)ent.skin, "players/male", 12))
{
ent.skin = re.RegisterSkin ("players/male/disguise.pcx");
ent.model = re.RegisterModel ("players/male/tris.md2");
}
else if(!strncmp((char *)ent.skin, "players/female", 14))
{
ent.skin = re.RegisterSkin ("players/female/disguise.pcx");
ent.model = re.RegisterModel ("players/female/tris.md2");
}
else if(!strncmp((char *)ent.skin, "players/cyborg", 14))
{
ent.skin = re.RegisterSkin ("players/cyborg/disguise.pcx");
ent.model = re.RegisterModel ("players/cyborg/tris.md2");
}
}
//PGM
//============
}
else
{
ent.skinnum = s1->skinnum;
ent.skin = NULL;
ent.model = cl.model_draw[s1->modelindex];
}
}
// only used for black hole model right now, FIXME: do better
if (renderfx == RF_TRANSLUCENT)
ent.alpha = 0.70;
// render effects (fullbright, translucent, etc)
if ((effects & EF_COLOR_SHELL))
ent.flags = 0; // renderfx go on color shell entity
else
ent.flags = renderfx;
// calculate angles
if (effects & EF_ROTATE)
{ // some bonus items auto-rotate
ent.angles[0] = 0;
ent.angles[1] = autorotate;
ent.angles[2] = 0;
}
// RAFAEL
else if (effects & EF_SPINNINGLIGHTS)
{
ent.angles[0] = 0;
ent.angles[1] = anglemod(cl.time/2) + s1->angles[1];
ent.angles[2] = 180;
{
vec3_t forward;
vec3_t start;
AngleVectors (ent.angles, forward, NULL, NULL);
VectorMA (ent.origin, 64, forward, start);
V_AddLight (start, 100, 1, 0, 0);
}
}
else
{ // interpolate angles
float a1, a2;
for (i=0 ; i<3 ; i++)
{
a1 = cent->current.angles[i];
a2 = cent->prev.angles[i];
ent.angles[i] = LerpAngle (a2, a1, cl.lerpfrac);
}
}
if (s1->number == cl.playernum+1)
{
ent.flags |= RF_VIEWERMODEL; // only draw from mirrors
// FIXME: still pass to refresh
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -