diff --git a/qw/include/cl_ents.h b/qw/include/cl_ents.h index ec1196f90..33e53ecc7 100644 --- a/qw/include/cl_ents.h +++ b/qw/include/cl_ents.h @@ -36,7 +36,8 @@ void CL_SetUpPlayerPrediction(qboolean dopred); void CL_EmitEntities (void); void CL_ClearProjectiles (void); void CL_ParseProjectiles (void); -void CL_ParsePacketEntities (qboolean delta); +void CL_ParsePacketEntities (void); +void CL_ParseDeltaPacketEntities (qboolean delta); void CL_SetSolidEntities (void); void CL_ParsePlayerinfo (void); void CL_Ents_Init (void); diff --git a/qw/include/net_svc.h b/qw/include/net_svc.h index 09e4e1434..f82f70e70 100644 --- a/qw/include/net_svc.h +++ b/qw/include/net_svc.h @@ -161,19 +161,30 @@ typedef struct net_svc_nails_s } nails[MAX_PROJECTILES]; } net_svc_nails_t; +typedef struct net_svc_modellist_s +{ + byte startmodel; + const char *models[MAX_MODELS + 1]; // space left for terminating + // empty string + byte nextmodel; +} net_svc_modellist_t; + typedef struct net_svc_soundlist_s { byte startsound; - const char *sounds[MAX_SOUNDS + 1]; // space left for terminating empty string + const char *sounds[MAX_SOUNDS + 1]; // space left for terminating + // empty string byte nextsound; } net_svc_soundlist_t; -typedef struct net_svc_modellist_s +typedef struct net_svc_packetentities_s { - byte startmodel; - const char *models[MAX_MODELS + 1]; // space left for terminating empty string - byte nextmodel; -} net_svc_modellist_t; + int num; + struct { + unsigned short word; + entity_state_t state; + } vars[MAX_PACKET_ENTITIES]; +} net_svc_packetentities_t; qboolean NET_SVC_Print_Parse (net_svc_print_t *block, msg_t *msg); qboolean NET_SVC_Damage_Parse (net_svc_damage_t *block, msg_t *msg); @@ -192,7 +203,9 @@ qboolean NET_SVC_ServerInfo_Parse (net_svc_serverinfo_t *block, msg_t *msg); qboolean NET_SVC_Download_Parse (net_svc_download_t *block, msg_t *msg); qboolean NET_SVC_Playerinfo_Parse (net_svc_playerinfo_t *block, msg_t *msg); qboolean NET_SVC_Nails_Parse (net_svc_nails_t *block, msg_t *msg); -qboolean NET_SVC_Soundlist_Parse (net_svc_soundlist_t *block, msg_t *msg); qboolean NET_SVC_Modellist_Parse (net_svc_modellist_t *block, msg_t *msg); +qboolean NET_SVC_Soundlist_Parse (net_svc_soundlist_t *block, msg_t *msg); +qboolean NET_SVC_PacketEntities_Parse (net_svc_packetentities_t *block, + msg_t *msg); #endif // NET_SVC_H diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index cf8591913..ef1dd73be 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -234,6 +234,53 @@ CL_ParseDelta (entity_state_t *from, entity_state_t *to, int bits) */ } +void +CL_EntityState_Copy (entity_state_t *src, entity_state_t *dest, int bits) +{ + if (bits & U_MODEL) + dest->modelindex = src->modelindex; + if (bits & U_FRAME) + dest->frame = (dest->frame & 0xFF00) | (src->frame & 0xFF); + if (bits & U_COLORMAP) + dest->colormap = src->colormap; + if (bits & U_SKIN) + dest->skinnum = src->skinnum; + if (bits & U_EFFECTS) + dest->effects = (dest->effects & 0xFF00) | (src->effects & 0xFF); + + if (bits & U_ORIGIN1) + dest->origin[0] = src->origin[0]; + if (bits & U_ANGLE1) + dest->angles[0] = src->angles[0]; + if (bits & U_ORIGIN2) + dest->origin[1] = src->origin[1]; + if (bits & U_ANGLE2) + dest->angles[1] = src->angles[1]; + if (bits & U_ORIGIN3) + dest->origin[2] = src->origin[2]; + if (bits & U_ANGLE3) + dest->angles[2] = src->angles[2]; + + if (bits & U_ALPHA) + dest->alpha = src->alpha; + if (bits & U_SCALE) + dest->scale = src->scale; + if (bits & U_EFFECTS2) + dest->effects = (dest->effects & 0xFF) | (src->effects & 0xFF00); + if (bits & U_GLOWSIZE) + dest->glow_size = src->glow_size; + if (bits & U_GLOWCOLOR) + dest->glow_color = src->glow_color; + if (bits & U_COLORMOD) + dest->colormod = src->colormod; + if (bits & U_FRAME2) + dest->frame = (dest->frame & 0xFF) | (src->frame & 0xFF00); + + if (bits & U_SOLID) { + // FIXME + } +} + void FlushEntityPacket (void) { @@ -262,14 +309,61 @@ FlushEntityPacket (void) } } +void +CL_ParsePacketEntities (void) +{ + int index, packetnum; + packet_entities_t *newp; + net_svc_packetentities_t block; + + packetnum = cls.netchan.incoming_sequence & UPDATE_MASK; + newp = &cl.frames[packetnum].packet_entities; + cl.frames[packetnum].invalid = false; + + cl.validsequence = cls.netchan.incoming_sequence; + + newp->num_entities = 0; + + if (NET_SVC_PacketEntities_Parse (&block, net_message)) { + Host_EndGame ("CL_ParsePacketEntities: Bad Read"); + return; + } + + for (index = 0; block.vars[index].word; index++) { + if (block.vars[index].word & U_REMOVE) { + cl.validsequence = 0; + Con_Printf ("CL_ParsePacketEntities: WARNING: U_REMOVE on " + "full update\n"); + return; + } + + if (index >= MAX_PACKET_ENTITIES) { + Host_EndGame ("CL_ParsePacketEntities: index == " + "MAX_PACKET_ENTITIES"); + return; + } + + CL_EntityState_Copy (&cl_baselines[block.vars[index].word & 511], + &newp->entities[index], + ~block.vars[index].state.flags); + CL_EntityState_Copy (&block.vars[index].state, + &newp->entities[index], + block.vars[index].state.flags); + newp->entities[index].number = block.vars[index].state.number; + continue; + } + + newp->num_entities = index; +} + /* - CL_ParsePacketEntities + CL_ParseDeltaPacketEntities An svc_packetentities has just been parsed, deal with the rest of the data stream. */ void -CL_ParsePacketEntities (qboolean delta) +CL_ParseDeltaPacketEntities (qboolean delta) { byte from; int oldindex, newindex, newnum, oldnum, oldpacket, newpacket, word; @@ -320,9 +414,11 @@ CL_ParsePacketEntities (qboolean delta) if (!word) { // copy rest of ents from old packet while (oldindex < oldp->num_entities) { // Con_Printf ("copy %i\n", oldp->entities[oldindex].number); - if (newindex >= MAX_PACKET_ENTITIES) - Host_EndGame ("CL_ParsePacketEntities: newindex == " + if (newindex >= MAX_PACKET_ENTITIES) { + Host_EndGame ("CL_ParseDeltaPacketEntities: newindex == " "MAX_PACKET_ENTITIES"); + return; + } newp->entities[newindex] = oldp->entities[oldindex]; newindex++; oldindex++; @@ -341,9 +437,11 @@ CL_ParsePacketEntities (qboolean delta) } // Con_Printf ("copy %i\n", oldnum); // copy one of the old entities over to the new packet unchanged - if (newindex >= MAX_PACKET_ENTITIES) - Host_EndGame ("CL_ParsePacketEntities: newindex == " + if (newindex >= MAX_PACKET_ENTITIES) { + Host_EndGame ("CL_ParseDeltaPacketEntities: newindex == " "MAX_PACKET_ENTITIES"); + return; + } newp->entities[newindex] = oldp->entities[oldindex]; newindex++; oldindex++; @@ -363,9 +461,11 @@ CL_ParsePacketEntities (qboolean delta) continue; } - if (newindex >= MAX_PACKET_ENTITIES) - Host_EndGame ("CL_ParsePacketEntities: newindex == " + if (newindex >= MAX_PACKET_ENTITIES) { + Host_EndGame ("CL_ParseDeltaPacketEntities: newindex == " "MAX_PACKET_ENTITIES"); + return; + } CL_ParseDelta (&cl_baselines[newnum], &newp->entities[newindex], word); newindex++; diff --git a/qw/source/cl_parse.c b/qw/source/cl_parse.c index 7e8d87ded..1cf15e90f 100644 --- a/qw/source/cl_parse.c +++ b/qw/source/cl_parse.c @@ -1356,11 +1356,11 @@ CL_ParseServerMessage (void) break; case svc_packetentities: - CL_ParsePacketEntities (false); + CL_ParsePacketEntities (); break; case svc_deltapacketentities: - CL_ParsePacketEntities (true); + CL_ParseDeltaPacketEntities (true); break; case svc_maxspeed: diff --git a/qw/source/net_svc.c b/qw/source/net_svc.c index 80ac374f3..8c5a71d1b 100644 --- a/qw/source/net_svc.c +++ b/qw/source/net_svc.c @@ -360,6 +360,26 @@ NET_SVC_Nails_Parse (net_svc_nails_t *block, msg_t *msg) return msg->badread; } +qboolean +NET_SVC_Modellist_Parse (net_svc_modellist_t *block, msg_t *msg) +{ + int i; + + block->startmodel = MSG_ReadByte (msg); + + for (i = 0; i < MAX_MODELS; i++) { + block->models[i] = MSG_ReadString (msg); + if (!*block->models[i]) + break; + } + // this is a bit redundant, but I think the robustness is a good thing + block->models[MAX_MODELS] = ""; + + block->nextmodel = MSG_ReadByte (msg); + + return msg->badread; +} + qboolean NET_SVC_Soundlist_Parse (net_svc_soundlist_t *block, msg_t *msg) { @@ -381,22 +401,86 @@ NET_SVC_Soundlist_Parse (net_svc_soundlist_t *block, msg_t *msg) } qboolean -NET_SVC_Modellist_Parse (net_svc_modellist_t *block, msg_t *msg) +NET_SVC_PacketEntities_Parse (net_svc_packetentities_t *block, msg_t *msg) { - int i; + int i; + unsigned int bits; // bytes of bits: [EXT2][EXT1][ORIG][MORE] + entity_state_t *es; - block->startmodel = MSG_ReadByte (msg); - - for (i = 0; i < MAX_MODELS; i++) { - block->models[i] = MSG_ReadString (msg); - if (!*block->models[i]) + for (i = 0; i < MAX_PACKET_ENTITIES; i++) { + block->vars[i].word = bits = (unsigned short) MSG_ReadShort (msg); + if (!bits || msg->badread) break; - } - // this is a bit redundant, but I think the robustness is a good thing - block->models[MAX_MODELS] = ""; + es = &block->vars[i].state; + es->number = bits & 511; + bits &= ~511; - block->nextmodel = MSG_ReadByte (msg); + es->frame = 0; + es->effects = 0; + + if (bits & U_MOREBITS) + bits |= MSG_ReadByte (msg); + if (bits & U_EXTEND1) { + bits |= MSG_ReadByte (msg) << 16; + if (bits & U_EXTEND2) + bits |= MSG_ReadByte (msg) << 24; + } + + es->flags = bits; + + if (bits & U_MODEL) + es->modelindex = MSG_ReadByte (msg); + if (bits & U_FRAME) + es->frame = MSG_ReadByte (msg); + if (bits & U_COLORMAP) + es->colormap = MSG_ReadByte (msg); + if (bits & U_SKIN) + es->skinnum = MSG_ReadByte (msg); + if (bits & U_EFFECTS) + es->effects = MSG_ReadByte (msg); + + if (bits & U_ORIGIN1) + es->origin[0] = MSG_ReadCoord (msg); + if (bits & U_ANGLE1) + es->angles[0] = MSG_ReadAngle (msg); + if (bits & U_ORIGIN2) + es->origin[1] = MSG_ReadCoord (msg); + if (bits & U_ANGLE2) + es->angles[1] = MSG_ReadAngle (msg); + if (bits & U_ORIGIN3) + es->origin[2] = MSG_ReadCoord (msg); + if (bits & U_ANGLE3) + es->angles[2] = MSG_ReadAngle (msg); + + if (bits & U_ALPHA) + es->alpha = MSG_ReadByte (msg); + if (bits & U_SCALE) + es->scale = MSG_ReadByte (msg); + if (bits & U_EFFECTS2) { + if (bits & U_EFFECTS) + es->effects = (es->effects & 0xFF) | (MSG_ReadByte (msg) << 8); + else + es->effects = MSG_ReadByte (msg) << 8; + } + if (bits & U_GLOWSIZE) + es->glow_size = MSG_ReadByte (msg); + if (bits & U_GLOWCOLOR) + es->glow_color = MSG_ReadByte (msg); + if (bits & U_COLORMOD) + es->colormod = MSG_ReadByte (msg); + if (bits & U_FRAME2) { + if (bits & U_FRAME) + es->frame = (es->frame & 0xFF) | (MSG_ReadByte (msg) << 8); + else + es->frame = MSG_ReadByte (msg) << 8; + } + + if (bits & U_SOLID) { + // FIXME + } + } + block->vars[i].word = 0; + block->num = i; return msg->badread; } -