static readonly int SNAPFLAG_SERVERCOUNT = 4; // toggled every map_restart so transitions can be detected #endregion Fields #region Methods void AddEntitiesVisibleFromPoint(Vector3 origin, ref clientSnapshot_t frame, List<int> snapshotEntitiesNumbers, bool portal) { // during an error shutdown message we may need to transmit // the shutdown message after the server has shutdown, so // specfically check for it if ((int)sv.state == 0) return; int leafnum = ClipMap.Instance.PointLeafnum(origin); int clientarea = ClipMap.Instance.LeafArea(leafnum); int clientcluster = ClipMap.Instance.LeafCluster(leafnum); // calculate the visible areas frame.areabytes = ClipMap.Instance.WriteAreaBits(ref frame.areabits, clientarea); bool[] clientpvs = ClipMap.Instance.ClusterPVS(clientcluster); sharedEntity ent; for (int i = 0; i < sv.num_entities; i++) { ent = sv.gentities[i]; // never send entities that aren't linked in if (!ent.r.linked) continue; if (ent.s.number != i) { Common.Instance.WriteLine("FIXING ENT.S.NUMBER!!!"); ent.s.number = i; } // entities can be flagged to explicitly not be sent to the client if ((ent.r.svFlags & Common.svFlags.NOCLIENT) == Common.svFlags.NOCLIENT) continue; // entities can be flagged to be sent to only one client if ((ent.r.svFlags & Common.svFlags.SINGLECLIENT) == Common.svFlags.SINGLECLIENT) if (ent.r.singleClient != frame.ps.clientNum) continue; // entities can be flagged to be sent to everyone but one client if ((ent.r.svFlags & Common.svFlags.NOTSINGLECLIENT) == Common.svFlags.NOTSINGLECLIENT) if (ent.r.singleClient == frame.ps.clientNum) continue; // entities can be flagged to be sent to a given mask of clients if ((ent.r.svFlags & Common.svFlags.CLIENTMASK) == Common.svFlags.CLIENTMASK) { if (frame.ps.clientNum >= 32) Common.Instance.Error("CLIENTMASK: clientNum > 32"); if ((~ent.r.singleClient & (1 << frame.ps.clientNum)) == (1 << frame.ps.clientNum)) continue; } svEntity_t svEnt = Game.Instance.SvEntityForGentity(ent); // don't double add an entity through portals if (svEnt.snapshotCounter == sv.snapshotCounter) continue; // broadcast entities are always sent if ((ent.r.svFlags & Common.svFlags.BROADCAST) == Common.svFlags.BROADCAST) { AddEntToSnapshot(svEnt, ent, snapshotEntitiesNumbers); continue; } //// ignore if not touching a PV leaf //// check area //if (!ClipMap.Instance.AreasConnected(clientarea, svEnt.areanum)) //{ // // doors can legally straddle two areas, so // // we may need to check another one // if (!ClipMap.Instance.AreasConnected(clientarea, svEnt.areanum2)) // continue; // blocked by a door //} if (svEnt.numClusters <= 0) continue; int l; int j; for (j = 0; j < svEnt.numClusters; j++) { l = svEnt.clusternums[j]; if (clientpvs != null && clientpvs[l]) break; } // not visible if (j == svEnt.numClusters) continue; // add it AddEntToSnapshot(svEnt, ent, snapshotEntitiesNumbers); // if its a portal entity, add everything visible from its camera position if ((ent.r.svFlags & Common.svFlags.PORTAL) == Common.svFlags.PORTAL) { if (ent.s.generic1 > 0) { Vector3 dir = ent.s.origin - origin; if (dir.LengthSquared() > (float)ent.s.generic1 * ent.s.generic1) continue; } AddEntitiesVisibleFromPoint(ent.s.origin2, ref frame, snapshotEntitiesNumbers, true); } } }
/* ============= SV_EmitPacketEntities Writes a delta update of an entityState_t list to the message. ============= */ void EmitPacketEntities(clientSnapshot_t from, clientSnapshot_t to, NetBuffer msg) { int fromnumentities = 0; if (from != null) fromnumentities = from.num_entities; Common.entityState_t oldent = null, newent = null; int oldindex = 0, newindex = 0; int newnum, oldnum; while (newindex < to.num_entities || oldindex < fromnumentities) { if (newindex >= to.num_entities) newnum = 9999; else { newent = snapshotEntities[(to.first_entity + newindex) % numSnapshotEntities]; newnum = newent.number; } if (oldindex >= fromnumentities) oldnum = 9999; else { oldent = snapshotEntities[(from.first_entity + oldindex) % numSnapshotEntities]; oldnum = oldent.number; } if (newnum == oldnum) { // delta update from old position // because the force parm is qfalse, this will not result // in any bytes being emited if the entity has not changed at all Net.Instance.MSG_WriteDeltaEntity(msg, ref oldent, ref newent, false); oldindex++; newindex++; continue; } if (newnum < oldnum) { // this is a new entity, send it from the baseline Net.Instance.MSG_WriteDeltaEntity(msg, ref sv.svEntities[newnum].baseline, ref newent, true); newindex++; continue; } if (newnum > oldnum) { // the old entity isn't present in the new message Common.entityState_t nullEnt = null; Net.Instance.MSG_WriteDeltaEntity(msg, ref oldent, ref nullEnt, true); oldindex++; continue; } } msg.Write(1023); // end of packetentities }
public string userinfo; // 1024 name, etc #endregion Fields #region Constructors public client_t() { for (int i = 0; i < 32; i++) { frames[i] = new clientSnapshot_t(); } }