public static void SV_BuildClientFrame(client_t client) { Int32 e, i; Single[] org = new Single[] { 0, 0, 0 }; edict_t ent; edict_t clent; client_frame_t frame; entity_state_t state; Int32 l; Int32 clientarea, clientcluster; Int32 leafnum; Int32 c_fullsend; Byte[] clientphs; Byte[] bitvector; clent = client.edict; if (clent.client == null) { return; } frame = client.frames[SV_INIT.sv.framenum & Defines.UPDATE_MASK]; frame.senttime = SV_INIT.svs.realtime; for (i = 0; i < 3; i++) { org[i] = clent.client.ps.pmove.origin[i] * 0.125F + clent.client.ps.viewoffset[i]; } leafnum = CM.CM_PointLeafnum(org); clientarea = CM.CM_LeafArea(leafnum); clientcluster = CM.CM_LeafCluster(leafnum); frame.areabytes = CM.CM_WriteAreaBits(frame.areabits, clientarea); frame.ps.Set(clent.client.ps); SV_FatPVS(org); clientphs = CM.CM_ClusterPHS(clientcluster); frame.num_entities = 0; frame.first_entity = SV_INIT.svs.next_client_entities; c_fullsend = 0; for (e = 1; e < GameBase.num_edicts; e++) { ent = GameBase.g_edicts[e]; if ((ent.svflags & Defines.SVF_NOCLIENT) != 0) { continue; } if (0 == ent.s.modelindex && 0 == ent.s.effects && 0 == ent.s.sound && 0 == ent.s.event_renamed) { continue; } if (ent != clent) { if (!CM.CM_AreasConnected(clientarea, ent.areanum)) { if (0 == ent.areanum2 || !CM.CM_AreasConnected(clientarea, ent.areanum2)) { continue; } } if ((ent.s.renderfx & Defines.RF_BEAM) != 0) { l = ent.clusternums[0]; if (0 == (clientphs[l >> 3] & (1 << (l & 7)))) { continue; } } else { if (ent.s.sound == 0) { bitvector = SV_ENTS.fatpvs; } else { bitvector = SV_ENTS.fatpvs; } if (ent.num_clusters == -1) { if (!CM.CM_HeadnodeVisible(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))) != 0) { break; } } if (i == ent.num_clusters) { continue; } } if (ent.s.modelindex == 0) { Single[] delta = new Single[] { 0, 0, 0 }; Single len; Math3D.VectorSubtract(org, ent.s.origin, delta); len = Math3D.VectorLength(delta); if (len > 400) { continue; } } } } var ix = SV_INIT.svs.next_client_entities % SV_INIT.svs.num_client_entities; state = SV_INIT.svs.client_entities[ix]; if (ent.s.number != e) { Com.DPrintf("FIXING ENT.S.NUMBER!!!\\n"); ent.s.number = e; } SV_INIT.svs.client_entities[ix].Set(ent.s); if (ent.owner == client.edict) { state.solid = 0; } SV_INIT.svs.next_client_entities++; frame.num_entities++; } }
/** * Decides which entities are going to be visible to the client, and copies * off the playerstat and areabits. */ public static void SV_BuildClientFrame(client_t client) { int e, i; float[] org = { 0, 0, 0 }; 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 == null) { return; // not in game yet } // this is the frame we are creating frame = client.frames[SV_INIT.sv.framenum & Defines.UPDATE_MASK]; frame.senttime = SV_INIT.svs.realtime; // save it for ping calc later // find the client's PVS for (i = 0; i < 3; i++) { org[i] = clent.client.ps.pmove.origin[i] * 0.125f + clent.client.ps.viewoffset[i]; } leafnum = CM.CM_PointLeafnum(org); clientarea = CM.CM_LeafArea(leafnum); clientcluster = CM.CM_LeafCluster(leafnum); // calculate the visible areas frame.areabytes = CM.CM_WriteAreaBits(frame.areabits, clientarea); // grab the current player_state_t frame.ps.set(clent.client.ps); SV_ENTS.SV_FatPVS(org); clientphs = CM.CM_ClusterPHS(clientcluster); // build up the list of visible entities frame.num_entities = 0; frame.first_entity = SV_INIT.svs.next_client_entities; c_fullsend = 0; for (e = 1; e < GameBase.num_edicts; e++) { ent = GameBase.g_edicts[e]; // ignore ents without visible models if ((ent.svflags & Defines.SVF_NOCLIENT) != 0) { continue; } // ignore ents without visible models unless they have an effect if (0 == ent.s.modelindex && 0 == ent.s.effects && 0 == ent.s.sound && 0 == ent.s.@event) { continue; } // ignore if not touching a PV leaf // check area if (ent != clent) { if (!CM.CM_AreasConnected(clientarea, ent.areanum)) { // doors can legally straddle two areas, so we may need to check another one if (0 == ent.areanum2 || !CM.CM_AreasConnected(clientarea, ent.areanum2)) { continue; // blocked by a door } } // beams just check one point for PHS if ((ent.s.renderfx & Defines.RF_BEAM) != 0) { l = ent.clusternums[0]; if (0 == (clientphs[l >> 3] & (1 << (l & 7)))) { continue; } } else { // FIXME: if an ent has a model and a sound, but isn't // in the PVS, only the PHS, clear the model if (ent.s.sound == 0) { bitvector = SV_ENTS.fatpvs; //clientphs; } else { bitvector = SV_ENTS.fatpvs; } if (ent.num_clusters == -1) { // too many leafs for // individual check, go by // headnode if (!CM.CM_HeadnodeVisible(ent.headnode, bitvector)) { continue; } c_fullsend++; } else { // check individual leafs for (i = 0; i < ent.num_clusters; i++) { l = ent.clusternums[i]; if ((bitvector[l >> 3] & (1 << (l & 7))) != 0) { break; } } if (i == ent.num_clusters) { continue; // not visible } } if (ent.s.modelindex == 0) { // don't send sounds if they // will be attenuated away float[] delta = { 0, 0, 0 }; float len; Math3D.VectorSubtract(org, ent.s.origin, delta); len = Math3D.VectorLength(delta); if (len > 400) { continue; } } } } // add it to the circular client_entities array var ix = SV_INIT.svs.next_client_entities % SV_INIT.svs.num_client_entities; state = SV_INIT.svs.client_entities[ix]; if (ent.s.number != e) { Com.DPrintf("FIXING ENT.S.NUMBER!!!\n"); ent.s.number = e; } //*state = ent.s; SV_INIT.svs.client_entities[ix].set(ent.s); // don't mark players missiles as solid if (ent.owner == client.edict) { state.solid = 0; } SV_INIT.svs.next_client_entities++; frame.num_entities++; } }