public clientActive() { gamestate = new gameState_t(); gamestate.data = new Dictionary<int, string>(); for (int i = 0; i < parseEntities.Length; i++) { parseEntities[i] = new Common.entityState_t(); } for (int i = 0; i < entityBaselines.Length; i++) { entityBaselines[i] = new Common.entityState_t(); } for (int i = 0; i < snapshots.Length; i++) { snapshots[i] = new clSnapshot_t(); } }
public Common.entityState_t s; // communicated by server to clients #endregion Fields #region Constructors public sharedEntity() { s = new Common.entityState_t(); r = new Common.entityShared_t(); r.s = s; }
void ParseGameState(NetBuffer msg) { clc.connectPacketCount = 0; // wipe local client state ClearState(); // a gamestate always marks a server command sequence clc.serverCommandSequence = msg.ReadInt32(); // parse all the configstrings and baselines while (true) { int cmd = msg.ReadByte(); if (cmd == (int)svc_ops_e.svc_EOF) break; if (cmd == (int)svc_ops_e.svc_configstring) { int index = msg.ReadInt16(); string s = msg.ReadString(); cl.gamestate.data.Add(index, s); } else if (cmd == (int)svc_ops_e.svc_baseline) { int newnum = msg.ReadInt32(); if (newnum < 0 || newnum >= 1024) { Common.Instance.Error("ParseGameState: Baseline number out of range: " + newnum); } Common.entityState_t nullstate = new Common.entityState_t(); Net.Instance.MSG_ReadDeltaEntity(msg, ref nullstate, ref cl.entityBaselines[newnum], newnum); } else { Common.Instance.Error("ParseGameState: bad command byte"); } } clc.clientNum = msg.ReadInt32(); // parse useful values out of CS_SERVERINFO //ParseServerInfo(); // parse serverId and other cvars SystemInfoChanged(); InitDownloads(); }
/* ============= SV_BuildClientSnapshot Decides which entities are going to be visible to the client, and copies off the playerstate and areabits. This properly handles multiple recursive portals, but the render currently doesn't. For viewing through other player's eyes, clent can be something other than client->gentity ============= */ void BuildClientSnapshot(client_t client, int index) { List<int> snapshotEntityNumbers = new List<int>(); // bump the counter used to prevent double adding sv.snapshotCounter++; // this is the frame we are creating clientSnapshot_t frame = client.frames[client.netchan.outgoingSequence & 31]; // clear everything in this snapshot frame.num_entities = 0; frame.areabits = new byte[32]; sharedEntity clent = client.gentity; if (clent == null || client.state == clientState_t.CS_ZOMBIE) { return; } // grab the current playerState_t Common.PlayerState ps = GameClientNum(index); //frame.ps = ps; frame.ps = ps.Clone(); // never send client's own entity, because it can // be regenerated from the playerstate int clientnum = frame.ps.clientNum; if (clientnum < 0 || clientnum >= 1024) { Common.Instance.Error("bad gEnt"); } svEntity_t svEnt = sv.svEntities[clientnum]; svEnt.snapshotCounter = sv.snapshotCounter; // find the client's viewpoint Vector3 org = ps.origin; org[2] += ps.viewheight; // add all the entities directly visible to the eye, which // may include portal entities that merge other viewpoints AddEntitiesVisibleFromPoint(org, ref frame, snapshotEntityNumbers, false); // if there were portals visible, there may be out of order entities // in the list which will need to be resorted for the delta compression // to work correctly. This also catches the error condition // of an entity being included twice. snapshotEntityNumbers.Sort((a, b) => { return a.CompareTo(b); }); // now that all viewpoint's areabits have been OR'd together, invert // all of them to make it a mask vector, which is what the renderer wants for (int i = 0; i < 8; i++) { frame.areabits[i] = (byte)(frame.areabits[i] ^ -1); } // copy the entity states out frame.num_entities = 0; frame.first_entity = nextSnapshotEntities; for (int i = 0; i < snapshotEntityNumbers.Count; i++) { sharedEntity ent = sv.gentities[snapshotEntityNumbers[i]]; snapshotEntities[nextSnapshotEntities++ % numSnapshotEntities] = new Common.entityState_t() { angles = ent.s.angles, angles2 = ent.s.angles2, apos = ent.s.apos, clientNum = ent.s.clientNum, eFlags = ent.s.eFlags, eType = ent.s.eType , frame = ent.s.frame, groundEntityNum = ent.s.groundEntityNum, number = ent.s.number, pos = ent.s.pos, solid = ent.s.solid, origin = ent.s.origin, otherEntityNum = ent.s.otherEntityNum, time = ent.s.time, modelindex = ent.s.modelindex}; //Common.Instance.WriteLine("Sending ent {0} to client {1}", snapshotEntityNumbers[i], index); frame.num_entities++; } }
/* ================== MSG_ReadDeltaEntity The entity number has already been read from the message, which is how the from state is identified. If the delta removes the entity, entityState_t->number will be set to MAX_GENTITIES-1 Can go from either a baseline or a previous packet_entity ================== */ public void MSG_ReadDeltaEntity(NetBuffer msg, ref Common.entityState_t from, ref Common.entityState_t to, int number) { int startBit = msg.Position-32; if (number < 0 || number >= 1024) { Common.Instance.Error("ReadDeltaEntity: number < 0 || number >= 1024"); } // Check for remove if (msg.ReadBoolean()) { to = new Common.entityState_t(); to.number = 1023; Common.Instance.WriteLine("Removed entity: {0}", number); return; } // Check for no delta if (!msg.ReadBoolean()) { to = from; to.number = number; return; } to.number = number; int dataStart = msg.Position; to.eType = msg.ReadBoolean() ? msg.ReadInt32() : from.eType; to.eFlags = msg.ReadBoolean() ? (Common.EntityFlags)msg.ReadInt32() : from.eFlags; int middle = msg.Position; to.pos.trBase.X = msg.ReadBoolean() ? msg.ReadFloat() : from.pos.trBase.X; to.pos.trBase.Y = msg.ReadBoolean() ? msg.ReadFloat() : from.pos.trBase.Y; to.pos.trBase.Z = msg.ReadBoolean() ? msg.ReadFloat() : from.pos.trBase.Z; to.pos.trDelta.X = msg.ReadBoolean() ? msg.ReadFloat() : from.pos.trDelta.X; to.pos.trDelta.Y = msg.ReadBoolean() ? msg.ReadFloat() : from.pos.trDelta.Y; to.pos.trDelta.Z = msg.ReadBoolean() ? msg.ReadFloat() : from.pos.trDelta.Z; to.pos.trDuration = msg.ReadBoolean() ? msg.ReadInt32() : from.pos.trDuration; to.pos.trTime = msg.ReadBoolean() ? msg.ReadInt32() : from.pos.trTime; to.pos.trType = msg.ReadBoolean() ? (Common.trType_t)msg.ReadInt32() : from.pos.trType; to.apos.trBase.X = msg.ReadBoolean() ? msg.ReadFloat() : from.apos.trBase.X; to.apos.trBase.Y = msg.ReadBoolean() ? msg.ReadFloat() : from.apos.trBase.Y; to.apos.trBase.Z = msg.ReadBoolean() ? msg.ReadFloat() : from.apos.trBase.Z; to.apos.trDelta.X = msg.ReadBoolean() ? msg.ReadFloat() : from.apos.trDelta.X; to.apos.trDelta.Y = msg.ReadBoolean() ? msg.ReadFloat() : from.apos.trDelta.Y; to.apos.trDelta.Z = msg.ReadBoolean() ? msg.ReadFloat() : from.apos.trDelta.Z; to.apos.trDuration = msg.ReadBoolean() ? msg.ReadInt32() : from.apos.trDuration; to.apos.trTime = msg.ReadBoolean() ? msg.ReadInt32() : from.apos.trTime; to.apos.trType = msg.ReadBoolean() ? (Common.trType_t)msg.ReadInt32() : from.apos.trType; to.time = msg.ReadBoolean() ? msg.ReadInt32() : from.time; to.time2 = msg.ReadBoolean() ? msg.ReadInt32() : from.time2; to.origin.X = msg.ReadBoolean() ? msg.ReadFloat() : from.origin.X; to.origin.Y = msg.ReadBoolean() ? msg.ReadFloat() : from.origin.Y; to.origin.Z = msg.ReadBoolean() ? msg.ReadFloat() : from.origin.Z; to.origin2.X = msg.ReadBoolean() ? msg.ReadFloat() : from.origin2.X; to.origin2.Y = msg.ReadBoolean() ? msg.ReadFloat() : from.origin2.Y; to.origin2.Z = msg.ReadBoolean() ? msg.ReadFloat() : from.origin2.Z; to.angles.X = msg.ReadBoolean() ? msg.ReadFloat() : from.angles.X; to.angles.Y = msg.ReadBoolean() ? msg.ReadFloat() : from.angles.Y; to.angles.Z = msg.ReadBoolean() ? msg.ReadFloat() : from.angles.Z; to.angles2.X = msg.ReadBoolean() ? msg.ReadFloat() : from.angles2.X; to.angles2.Y = msg.ReadBoolean() ? msg.ReadFloat() : from.angles2.Y; to.angles2.Z = msg.ReadBoolean() ? msg.ReadFloat() : from.angles2.Z; to.otherEntityNum = msg.ReadBoolean() ? msg.ReadInt32() : from.otherEntityNum; to.otherEntityNum2 = msg.ReadBoolean() ? msg.ReadInt32() : from.otherEntityNum2; to.groundEntityNum = msg.ReadBoolean() ? msg.ReadInt32() : from.groundEntityNum; to.modelindex = msg.ReadBoolean() ? msg.ReadInt32() : from.modelindex; to.clientNum = msg.ReadBoolean() ? msg.ReadInt32() : from.clientNum; to.frame = msg.ReadBoolean() ? msg.ReadInt32() : from.frame; to.solid = msg.ReadBoolean() ? msg.ReadInt32() : from.solid; to.generic1 = msg.ReadBoolean() ? msg.ReadInt32() : from.generic1; int lenghtBits = msg.ReadInt32(); dataStart = msg.Position - dataStart; lenghtBits -= dataStart; for (int i = 0; i < lenghtBits; i++) { msg.ReadBoolean(); } middle = msg.Position - middle; //Common.Instance.WriteLine("MSG_ReadDeltaEntity: Read {0} bits", msg.Position - startBit); }
/* ================ SV_SendClientGameState Sends the first message from the server to a connected client. This will be sent on the initial connection and upon each new map load. It will be resent if the client acknowledges a later message but has the wrong gamestate. ================ */ void SendClientGameState(client_t cl) { Common.Instance.WriteLine("SendClientGameState for {0}", cl.name); Common.Instance.WriteLine("Going from CONNECTED to PRIMED for {0}", cl.name); cl.state = clientState_t.CS_PRIMED; cl.pureAuthentic = 0; cl.gotCP = false; // when we receive the first packet from the client, we will // notice that it is from a different serverid and that the // gamestate message was not just sent, forcing a retransmit cl.gamestateMessageNum = cl.netchan.outgoingSequence; NetBuffer msg = new NetBuffer(); // NOTE, MRE: all server->client messages now acknowledge // let the client know which reliable clientCommands we have received msg.Write(cl.lastClientCommand); // send any server commands waiting to be sent first. // we have to do this cause we send the client->reliableSequence // with a gamestate and it sets the clc.serverCommandSequence at // the client side UpdateServerCommandsToClient(cl, msg); // send the gamestate msg.Write((byte)svc_ops_e.svc_gamestate); msg.Write(cl.reliableSequence); // write the configstrings foreach (int i in sv.configstrings.Keys) { msg.Write((byte)svc_ops_e.svc_configstring); msg.Write((short)i); msg.Write(sv.configstrings[i]); } // write the baselines Common.entityState_t nullstate = new Common.entityState_t(); for (int i = 0; i < 1024; i++) { Common.entityState_t bases = sv.svEntities[i].baseline; if (bases == null || bases.number <= 0) continue; msg.Write((byte)svc_ops_e.svc_baseline); Net.Instance.MSG_WriteDeltaEntity(msg, ref nullstate, ref bases, true); } msg.Write((byte)svc_ops_e.svc_EOF); msg.Write(cl.id); SendMessageToClient(msg, cl); }