#include "server.h"
#if 0#endif
void SV_EmitPacketEntities(client_frame_t *from, client_frame_t *to, sizebuf_t *msg) {
entity_state_t *oldent, *newent;
int oldindex, newindex;
int oldnum, newnum;
int from_num_entities;
int bits;
#if 0#endif
MSG_WriteByte(msg, svc_packetentities);
if(!from)
from_num_entities = 0;
else
from_num_entities = from->num_entities;
newindex = 0;
oldindex = 0;
while(newindex < to->num_entities || oldindex < from_num_entities) {
if(newindex >= to->num_entities)
newnum = 9999;
else {
newent = &svs.client_entities[(to->first_entity + newindex) % svs.num_client_entities];
newnum = newent->number;
}
if(oldindex >= from_num_entities)
oldnum = 9999;
else {
oldent = &svs.client_entities[(from->first_entity + oldindex) % svs.num_client_entities];
oldnum = oldent->number;
}
if(newnum == oldnum) { MSG_WriteDeltaEntity(oldent, newent, msg, false, newent->number <= maxclients->value);
oldindex++;
newindex++;
continue;
}
if(newnum < oldnum) { MSG_WriteDeltaEntity(&sv.baselines[newnum], newent, msg, true, true);
newindex++;
continue;
}
if(newnum > oldnum) { bits = U_REMOVE;
if(oldnum >= 256)
bits |= U_NUMBER16 | U_MOREBITS1;
MSG_WriteByte(msg, bits & 255);
if(bits & 0x0000ff00)
MSG_WriteByte(msg, (bits >> 8) & 255);
if(bits & U_NUMBER16)
MSG_WriteShort(msg, oldnum);
else
MSG_WriteByte(msg, oldnum);
oldindex++;
continue;
}
}
MSG_WriteShort(msg, 0);
#if 0#endif
}
void SV_WritePlayerstateToClient(client_frame_t *from, client_frame_t *to, sizebuf_t *msg) {
int i;
int pflags;
player_state_t *ps, *ops;
player_state_t dummy;
int statbits;
ps = &to->ps;
if(!from) {
memset(&dummy, 0, sizeof(dummy));
ops = &dummy;
} else
ops = &from->ps;
pflags = 0;
if(ps->pmove.pm_type != ops->pmove.pm_type)
pflags |= PS_M_TYPE;
if(ps->pmove.origin[0] != ops->pmove.origin[0] || ps->pmove.origin[1] != ops->pmove.origin[1] ||
ps->pmove.origin[2] != ops->pmove.origin[2])
pflags |= PS_M_ORIGIN;
if(ps->pmove.velocity[0] != ops->pmove.velocity[0] || ps->pmove.velocity[1] != ops->pmove.velocity[1] ||
ps->pmove.velocity[2] != ops->pmove.velocity[2])
pflags |= PS_M_VELOCITY;
if(ps->pmove.pm_time != ops->pmove.pm_time)
pflags |= PS_M_TIME;
if(ps->pmove.pm_flags != ops->pmove.pm_flags)
pflags |= PS_M_FLAGS;
if(ps->pmove.gravity != ops->pmove.gravity)
pflags |= PS_M_GRAVITY;
if(ps->pmove.delta_angles[0] != ops->pmove.delta_angles[0] ||
ps->pmove.delta_angles[1] != ops->pmove.delta_angles[1] || ps->pmove.delta_angles[2] != ops->pmove.delta_angles[2])
pflags |= PS_M_DELTA_ANGLES;
if(ps->viewoffset[0] != ops->viewoffset[0] || ps->viewoffset[1] != ops->viewoffset[1] ||
ps->viewoffset[2] != ops->viewoffset[2])
pflags |= PS_VIEWOFFSET;
if(ps->viewangles[0] != ops->viewangles[0] || ps->viewangles[1] != ops->viewangles[1] ||
ps->viewangles[2] != ops->viewangles[2])
pflags |= PS_VIEWANGLES;
if(ps->kick_angles[0] != ops->kick_angles[0] || ps->kick_angles[1] != ops->kick_angles[1] ||
ps->kick_angles[2] != ops->kick_angles[2])
pflags |= PS_KICKANGLES;
if(ps->blend[0] != ops->blend[0] || ps->blend[1] != ops->blend[1] || ps->blend[2] != ops->blend[2] ||
ps->blend[3] != ops->blend[3])
pflags |= PS_BLEND;
if(ps->fov != ops->fov)
pflags |= PS_FOV;
if(ps->rdflags != ops->rdflags)
pflags |= PS_RDFLAGS;
if(ps->gunframe != ops->gunframe)
pflags |= PS_WEAPONFRAME;
if(ps->cmodel_index != ops->cmodel_index)
pflags |= PS_CMODEL_INDEX;
pflags |= PS_WEAPONINDEX;
MSG_WriteByte(msg, svc_playerinfo);
MSG_WriteShort(msg, pflags);
if(pflags & PS_M_TYPE)
MSG_WriteByte(msg, ps->pmove.pm_type);
if(pflags & PS_M_ORIGIN) {
MSG_WriteShort(msg, ps->pmove.origin[0]);
MSG_WriteShort(msg, ps->pmove.origin[1]);
MSG_WriteShort(msg, ps->pmove.origin[2]);
}
if(pflags & PS_M_VELOCITY) {
MSG_WriteShort(msg, ps->pmove.velocity[0]);
MSG_WriteShort(msg, ps->pmove.velocity[1]);
MSG_WriteShort(msg, ps->pmove.velocity[2]);
}
if(pflags & PS_M_TIME)
MSG_WriteByte(msg, ps->pmove.pm_time);
if(pflags & PS_M_FLAGS)
MSG_WriteByte(msg, ps->pmove.pm_flags);
if(pflags & PS_M_GRAVITY)
MSG_WriteShort(msg, ps->pmove.gravity);
if(pflags & PS_M_DELTA_ANGLES) {
MSG_WriteShort(msg, ps->pmove.delta_angles[0]);
MSG_WriteShort(msg, ps->pmove.delta_angles[1]);
MSG_WriteShort(msg, ps->pmove.delta_angles[2]);
}
if(pflags & PS_VIEWOFFSET) {
MSG_WriteChar(msg, ps->viewoffset[0] * 4);
MSG_WriteChar(msg, ps->viewoffset[1] * 4);
MSG_WriteChar(msg, ps->viewoffset[2] * 4);
}
if(pflags & PS_VIEWANGLES) {
MSG_WriteAngle16(msg, ps->viewangles[0]);
MSG_WriteAngle16(msg, ps->viewangles[1]);
MSG_WriteAngle16(msg, ps->viewangles[2]);
}
if(pflags & PS_KICKANGLES) {
MSG_WriteChar(msg, ps->kick_angles[0] * 4);
MSG_WriteChar(msg, ps->kick_angles[1] * 4);
MSG_WriteChar(msg, ps->kick_angles[2] * 4);
}
if(pflags & PS_WEAPONINDEX) {
MSG_WriteByte(msg, ps->gunindex);
}
if(pflags & PS_WEAPONFRAME) {
MSG_WriteByte(msg, ps->gunframe);
MSG_WriteChar(msg, ps->gunoffset[0] * 4);
MSG_WriteChar(msg, ps->gunoffset[1] * 4);
MSG_WriteChar(msg, ps->gunoffset[2] * 4);
MSG_WriteChar(msg, ps->gunangles[0] * 4);
MSG_WriteChar(msg, ps->gunangles[1] * 4);
MSG_WriteChar(msg, ps->gunangles[2] * 4);
}
if(pflags & PS_BLEND) {
MSG_WriteByte(msg, ps->blend[0] * 255);
MSG_WriteByte(msg, ps->blend[1] * 255);
MSG_WriteByte(msg, ps->blend[2] * 255);
MSG_WriteByte(msg, ps->blend[3] * 255);
}
if(pflags & PS_FOV)
MSG_WriteByte(msg, ps->fov);
if(pflags & PS_RDFLAGS)
MSG_WriteByte(msg, ps->rdflags);
if(pflags & PS_CMODEL_INDEX)
MSG_WriteByte(msg, ps->cmodel_index);
statbits = 0;
for(i = 0; i < MAX_STATS; i++)
if(ps->stats[i] != ops->stats[i])
statbits |= 1 << i;
MSG_WriteLong(msg, statbits);
for(i = 0; i < MAX_STATS; i++)
if(statbits & (1 << i))
MSG_WriteShort(msg, ps->stats[i]);
}
void SV_WriteFrameToClient(client_t *client, sizebuf_t *msg) {
client_frame_t *frame, *oldframe;
int lastframe;
frame = &client->frames[sv.framenum & UPDATE_MASK];
if(client->lastframe <= 0) { oldframe = NULL;
lastframe = -1;
} else if(sv.framenum - client->lastframe >=
(UPDATE_BACKUP - 3)) { oldframe = NULL;
lastframe = -1;
} else { oldframe = &client->frames[client->lastframe & UPDATE_MASK];
lastframe = client->lastframe;
}
MSG_WriteByte(msg, svc_frame);
MSG_WriteLong(msg, sv.framenum);
MSG_WriteLong(msg, lastframe); MSG_WriteByte(msg, client->surpressCount); client->surpressCount = 0;
MSG_WriteByte(msg, frame->areabytes);
SZ_Write(msg, frame->areabits, frame->areabytes);
SV_WritePlayerstateToClient(oldframe, frame, msg);
SV_EmitPacketEntities(oldframe, frame, msg);
}
byte fatpvs[65536 / 8];
void SV_FatPVS(int cmodel_index, vec3_t org) {
int leafs[64];
int i, j, count;
int longs;
byte *src;
vec3_t mins, maxs;
for(i = 0; i < 3; i++) {
mins[i] = org[i] - 8;
maxs[i] = org[i] + 8;
}
count = CM_BoxLeafnums(cmodel_index, mins, maxs, leafs, 64, NULL);
if(count < 1)
Com_Error(ERR_FATAL, "SV_FatPVS: count < 1");
longs = (CM_NumClusters(cmodel_index) + 31) >> 5;
for(i = 0; i < count; i++)
leafs[i] = CM_LeafCluster(cmodel_index, leafs[i]);
memcpy(fatpvs, CM_ClusterPVS(cmodel_index, leafs[0]), longs << 2);
for(i = 1; i < count; i++) {
for(j = 0; j < i; j++)
if(leafs[i] == leafs[j])
break;
if(j != i)
continue; src = CM_ClusterPVS(cmodel_index, leafs[i]);
for(j = 0; j < longs; j++)
((long *)fatpvs)[j] |= ((long *)src)[j];
}
}
void SV_BuildClientFrame(client_t *client) {
int e, i;
vec3_t org;
edict_t *ent;
edict_t *clent;
client_frame_t *frame;
entity_state_t *state;
int l;
int clientarea, clientcluster;
int leafnum;
int c_fullsend;
byte *clientphs;
byte *bitvector;
clent = client->edict;
if(!clent->client)
return;
int cmodel_index = clent->s.cmodel_index;
#if 0#endif
frame = &client->frames[sv.framenum & UPDATE_MASK];
frame->senttime = svs.realtime;
for(i = 0; i < 3; i++)
org[i] = clent->client->ps.pmove.origin[i] * 0.125 + clent->client->ps.viewoffset[i];
leafnum = CM_PointLeafnum(cmodel_index, org);
clientarea = CM_LeafArea(cmodel_index, leafnum);
clientcluster = CM_LeafCluster(cmodel_index, leafnum);
frame->areabytes = CM_WriteAreaBits(cmodel_index, frame->areabits, clientarea);
frame->ps = clent->client->ps;
SV_FatPVS(cmodel_index, org);
clientphs = CM_ClusterPHS(cmodel_index, clientcluster);
frame->num_entities = 0;
frame->first_entity = svs.next_client_entities;
c_fullsend = 0;
for(e = 1; e < ge->num_edicts; e++) {
ent = EDICT_NUM(e);
if(ent->svflags & SVF_NOCLIENT)
continue;
if(ent->s.cmodel_index != clent->s.cmodel_index)
continue;
if(!ent->s.modelindex && !ent->s.effects && !ent->s.sound && !ent->s.event)
continue;
if(ent != clent) {
if(!CM_AreasConnected(cmodel_index, clientarea, ent->areanum)) { if(!ent->areanum2 || !CM_AreasConnected(cmodel_index, clientarea, ent->areanum2))
continue; }
if(ent->s.renderfx & RF_BEAM) {
l = ent->clusternums[0];
if(!(clientphs[l >> 3] & (1 << (l & 7))))
continue;
} else {
if(ent->s.sound) {
bitvector = fatpvs; } else
bitvector = fatpvs;
if(ent->num_clusters == -1) { if(!CM_HeadnodeVisible(cmodel_index, ent->headnode, bitvector))
continue;
c_fullsend++;
} else { for(i = 0; i < ent->num_clusters; i++) {
l = ent->clusternums[i];
if(bitvector[l >> 3] & (1 << (l & 7)))
break;
}
if(i == ent->num_clusters)
continue; }
if(!ent->s.modelindex) { vec3_t delta;
float len;
VectorSubtract(org, ent->s.origin, delta);
len = VectorLength(delta);
if(len > 400)
continue;
}
}
}
#if 0#endif
state = &svs.client_entities[svs.next_client_entities % svs.num_client_entities];
if(ent->s.number != e) {
Com_DPrintf("FIXING ENT->S.NUMBER!!!\n");
ent->s.number = e;
}
*state = ent->s;
if(ent->owner == client->edict)
state->solid = 0;
svs.next_client_entities++;
frame->num_entities++;
}
}
void SV_RecordDemoMessage(void) {
int e;
edict_t *ent;
entity_state_t nostate;
sizebuf_t buf;
byte buf_data[32768];
int len;
if(!svs.demofile)
return;
memset(&nostate, 0, sizeof(nostate));
SZ_Init(&buf, buf_data, sizeof(buf_data));
MSG_WriteByte(&buf, svc_frame);
MSG_WriteLong(&buf, sv.framenum);
MSG_WriteByte(&buf, svc_packetentities);
e = 1;
ent = EDICT_NUM(e);
while(e < ge->num_edicts) {
if(ent->inuse && ent->s.number && (ent->s.modelindex || ent->s.effects || ent->s.sound || ent->s.event) &&
!(ent->svflags & SVF_NOCLIENT))
MSG_WriteDeltaEntity(&nostate, &ent->s, &buf, false, true);
e++;
ent = EDICT_NUM(e);
}
MSG_WriteShort(&buf, 0);
SZ_Write(&buf, svs.demo_multicast.data, svs.demo_multicast.cursize);
SZ_Clear(&svs.demo_multicast);
len = LittleLong(buf.cursize);
fwrite(&len, 4, 1, svs.demofile);
fwrite(buf.data, buf.cursize, 1, svs.demofile);
}