/// <summary> /// Host_Pause_f /// </summary> static void Pause_f() { if (Cmd.Source == cmd_source_t.src_command) { Cmd.ForwardToServer(); return; } if (_Pausable.Value == 0) { Server.ClientPrint("Pause not allowed.\n"); } else { Server.sv.paused = !Server.sv.paused; if (Server.sv.paused) { Server.BroadcastPrint("{0} paused the game\n", Progs.GetString(Server.Player.v.netname)); } else { Server.BroadcastPrint("{0} unpaused the game\n", Progs.GetString(Server.Player.v.netname)); } // send notification to all clients Server.sv.reliable_datagram.WriteByte(Protocol.svc_setpause); Server.sv.reliable_datagram.WriteByte(Server.sv.paused ? 1 : 0); } }
/// <summary> /// PF_Find /// entity (entity start, .string field, string match) find = #5; /// </summary> static void PF_Find() { int e = GetInt(OFS.OFS_PARM0); int f = GetInt(OFS.OFS_PARM1); string s = GetString(OFS.OFS_PARM2); if (s == null) { Progs.RunError("PF_Find: bad search string"); } for (e++; e < Server.sv.num_edicts; e++) { edict_t ed = Server.EdictNum(e); if (ed.free) { continue; } string t = Progs.GetString(ed.GetInt(f)); // E_STRING(ed, f); if (String.IsNullOrEmpty(t)) { continue; } if (t == s) { ReturnEdict(ed); return; } } ReturnEdict(Server.sv.edicts[0]); }
/// <summary> /// PF_errror /// This is a TERMINAL error, which will kill off the entire server. /// Dumps self. /// error(value) /// </summary> static void PF_error() { string s = PF_VarString(0); Con.Print("======SERVER ERROR in {0}:\n{1}\n", Progs.GetString(Progs.xFunction.s_name), s); edict_t ed = Server.ProgToEdict(Progs.GlobalStruct.self); Progs.Print(ed); Host.Error("Program error"); }
/// <summary> /// SV_CreateBaseline /// </summary> static void CreateBaseline() { for (int entnum = 0; entnum < sv.num_edicts; entnum++) { // get the current server version edict_t svent = EdictNum(entnum); if (svent.free) { continue; } if (entnum > svs.maxclients && svent.v.modelindex == 0) { continue; } // // create entity baseline // svent.baseline.origin = svent.v.origin; svent.baseline.angles = svent.v.angles; svent.baseline.frame = (int)svent.v.frame; svent.baseline.skin = (int)svent.v.skin; if (entnum > 0 && entnum <= svs.maxclients) { svent.baseline.colormap = entnum; svent.baseline.modelindex = ModelIndex("progs/player.mdl"); } else { svent.baseline.colormap = 0; svent.baseline.modelindex = ModelIndex(Progs.GetString(svent.v.model)); } // // add to the message // sv.signon.WriteByte(Protocol.svc_spawnbaseline); sv.signon.WriteShort(entnum); sv.signon.WriteByte(svent.baseline.modelindex); sv.signon.WriteByte(svent.baseline.frame); sv.signon.WriteByte(svent.baseline.colormap); sv.signon.WriteByte(svent.baseline.skin); sv.signon.WriteCoord(svent.baseline.origin.x); sv.signon.WriteAngle(svent.baseline.angles.x); sv.signon.WriteCoord(svent.baseline.origin.y); sv.signon.WriteAngle(svent.baseline.angles.y); sv.signon.WriteCoord(svent.baseline.origin.z); sv.signon.WriteAngle(svent.baseline.angles.z); } }
static edict_t FindViewthing() { for (int i = 0; i < Server.sv.num_edicts; i++) { edict_t e = Server.EdictNum(i); if (Progs.GetString(e.v.classname) == "viewthing") { return(e); } } Con.Print("No viewthing on map\n"); return(null); }
static void PF_makestatic() { edict_t ent = GetEdict(OFS.OFS_PARM0); MsgWriter msg = Server.sv.signon; msg.WriteByte(Protocol.svc_spawnstatic); msg.WriteByte(Server.ModelIndex(Progs.GetString(ent.v.model))); msg.WriteByte((int)ent.v.frame); msg.WriteByte((int)ent.v.colormap); msg.WriteByte((int)ent.v.skin); for (int i = 0; i < 3; i++) { msg.WriteCoord(Mathlib.Comp(ref ent.v.origin, i)); msg.WriteAngle(Mathlib.Comp(ref ent.v.angles, i)); } // throw the entity away now Server.FreeEdict(ent); }
/// <summary> /// SV_CheckVelocity /// </summary> static void CheckVelocity(edict_t ent) { // // bound velocity // if (Mathlib.CheckNaN(ref ent.v.velocity, 0)) { Con.Print("Got a NaN velocity on {0}\n", Progs.GetString(ent.v.classname)); } if (Mathlib.CheckNaN(ref ent.v.origin, 0)) { Con.Print("Got a NaN origin on {0}\n", Progs.GetString(ent.v.classname)); } Vector3 max = Vector3.One * _MaxVelocity.Value; Vector3 min = -Vector3.One * _MaxVelocity.Value; Mathlib.Clamp(ref ent.v.velocity, ref min, ref max, out ent.v.velocity); }
/* * ================= * PF_setmodel * * setmodel(entity, model) * ================= */ static void PF_setmodel() { edict_t e = GetEdict(OFS.OFS_PARM0); int m_idx = GetInt(OFS.OFS_PARM1); string m = Progs.GetString(m_idx); // check to see if model was properly precached for (int i = 0; i < Server.sv.model_precache.Length; i++) { string check = Server.sv.model_precache[i]; if (check == null) { break; } if (check == m) { e.v.model = m_idx; // m - pr_strings; e.v.modelindex = i; model_t mod = Server.sv.models[(int)e.v.modelindex]; if (mod != null) { SetMinMaxSize(e, ref mod.mins, ref mod.maxs, true); } else { SetMinMaxSize(e, ref Common.ZeroVector, ref Common.ZeroVector, true); } return; } } Progs.RunError("no precache: {0}\n", m); }
/// <summary> /// #define G_STRING(o) (pr_strings + *(string_t *)&pr_globals[o]) /// </summary> public static unsafe string GetString(int parm) { int *ptr = (int *)Progs.GlobalStructAddr; return(Progs.GetString(ptr[parm])); }
/// <summary> /// SV_WriteClientdataToMessage /// </summary> public static void WriteClientDataToMessage(edict_t ent, MsgWriter msg) { // // send a damage message // if (ent.v.dmg_take != 0 || ent.v.dmg_save != 0) { edict_t other = ProgToEdict(ent.v.dmg_inflictor); msg.WriteByte(Protocol.svc_damage); msg.WriteByte((int)ent.v.dmg_save); msg.WriteByte((int)ent.v.dmg_take); msg.WriteCoord(other.v.origin.x + 0.5f * (other.v.mins.x + other.v.maxs.x)); msg.WriteCoord(other.v.origin.y + 0.5f * (other.v.mins.y + other.v.maxs.y)); msg.WriteCoord(other.v.origin.z + 0.5f * (other.v.mins.z + other.v.maxs.z)); ent.v.dmg_take = 0; ent.v.dmg_save = 0; } // // send the current viewpos offset from the view entity // SetIdealPitch(); // how much to look up / down ideally // a fixangle might get lost in a dropped packet. Oh well. if (ent.v.fixangle != 0) { msg.WriteByte(Protocol.svc_setangle); msg.WriteAngle(ent.v.angles.x); msg.WriteAngle(ent.v.angles.y); msg.WriteAngle(ent.v.angles.z); ent.v.fixangle = 0; } int bits = 0; if (ent.v.view_ofs.z != Protocol.DEFAULT_VIEWHEIGHT) { bits |= Protocol.SU_VIEWHEIGHT; } if (ent.v.idealpitch != 0) { bits |= Protocol.SU_IDEALPITCH; } // stuff the sigil bits into the high bits of items for sbar, or else // mix in items2 float val = Progs.GetEdictFieldFloat(ent, "items2", 0); int items; if (val != 0) { items = (int)ent.v.items | ((int)val << 23); } else { items = (int)ent.v.items | ((int)Progs.GlobalStruct.serverflags << 28); } bits |= Protocol.SU_ITEMS; if (((int)ent.v.flags & EdictFlags.FL_ONGROUND) != 0) { bits |= Protocol.SU_ONGROUND; } if (ent.v.waterlevel >= 2) { bits |= Protocol.SU_INWATER; } if (ent.v.punchangle.x != 0) { bits |= Protocol.SU_PUNCH1; } if (ent.v.punchangle.y != 0) { bits |= Protocol.SU_PUNCH2; } if (ent.v.punchangle.z != 0) { bits |= Protocol.SU_PUNCH3; } if (ent.v.velocity.x != 0) { bits |= Protocol.SU_VELOCITY1; } if (ent.v.velocity.y != 0) { bits |= Protocol.SU_VELOCITY2; } if (ent.v.velocity.z != 0) { bits |= Protocol.SU_VELOCITY3; } if (ent.v.weaponframe != 0) { bits |= Protocol.SU_WEAPONFRAME; } if (ent.v.armorvalue != 0) { bits |= Protocol.SU_ARMOR; } // if (ent.v.weapon) bits |= Protocol.SU_WEAPON; // send the data msg.WriteByte(Protocol.svc_clientdata); msg.WriteShort(bits); if ((bits & Protocol.SU_VIEWHEIGHT) != 0) { msg.WriteChar((int)ent.v.view_ofs.z); } if ((bits & Protocol.SU_IDEALPITCH) != 0) { msg.WriteChar((int)ent.v.idealpitch); } if ((bits & Protocol.SU_PUNCH1) != 0) { msg.WriteChar((int)ent.v.punchangle.x); } if ((bits & Protocol.SU_VELOCITY1) != 0) { msg.WriteChar((int)(ent.v.velocity.x / 16)); } if ((bits & Protocol.SU_PUNCH2) != 0) { msg.WriteChar((int)ent.v.punchangle.y); } if ((bits & Protocol.SU_VELOCITY2) != 0) { msg.WriteChar((int)(ent.v.velocity.y / 16)); } if ((bits & Protocol.SU_PUNCH3) != 0) { msg.WriteChar((int)ent.v.punchangle.z); } if ((bits & Protocol.SU_VELOCITY3) != 0) { msg.WriteChar((int)(ent.v.velocity.z / 16)); } // always sent msg.WriteLong(items); if ((bits & Protocol.SU_WEAPONFRAME) != 0) { msg.WriteByte((int)ent.v.weaponframe); } if ((bits & Protocol.SU_ARMOR) != 0) { msg.WriteByte((int)ent.v.armorvalue); } if ((bits & Protocol.SU_WEAPON) != 0) { msg.WriteByte(ModelIndex(Progs.GetString(ent.v.weaponmodel))); } msg.WriteShort((int)ent.v.health); msg.WriteByte((int)ent.v.currentammo); msg.WriteByte((int)ent.v.ammo_shells); msg.WriteByte((int)ent.v.ammo_nails); msg.WriteByte((int)ent.v.ammo_rockets); msg.WriteByte((int)ent.v.ammo_cells); if (Common.GameKind == GameKind.StandardQuake) { msg.WriteByte((int)ent.v.weapon); } else { for (int i = 0; i < 32; i++) { if ((((int)ent.v.weapon) & (1 << i)) != 0) { msg.WriteByte(i); break; } } } }
/// <summary> /// SV_WriteEntitiesToClient /// </summary> static void WriteEntitiesToClient(edict_t clent, MsgWriter msg) { // find the client's PVS Vector3 org = Common.ToVector(ref clent.v.origin) + Common.ToVector(ref clent.v.view_ofs); byte[] pvs = FatPVS(ref org); // send over all entities (except the client) that touch the pvs for (int e = 1; e < sv.num_edicts; e++) { edict_t ent = sv.edicts[e]; // ignore if not touching a PV leaf if (ent != clent) // clent is ALLWAYS sent { // ignore ents without visible models string mname = Progs.GetString(ent.v.model); if (String.IsNullOrEmpty(mname)) { continue; } int i; for (i = 0; i < ent.num_leafs; i++) { if ((pvs[ent.leafnums[i] >> 3] & (1 << (ent.leafnums[i] & 7))) != 0) { break; } } if (i == ent.num_leafs) { continue; // not visible } } if (msg.Capacity - msg.Length < 16) { Con.Print("packet overflow\n"); return; } // send an update int bits = 0; v3f miss; Mathlib.VectorSubtract(ref ent.v.origin, ref ent.baseline.origin, out miss); if (miss.x < -0.1f || miss.x > 0.1f) { bits |= Protocol.U_ORIGIN1; } if (miss.y < -0.1f || miss.y > 0.1f) { bits |= Protocol.U_ORIGIN2; } if (miss.z < -0.1f || miss.z > 0.1f) { bits |= Protocol.U_ORIGIN3; } if (ent.v.angles.x != ent.baseline.angles.x) { bits |= Protocol.U_ANGLE1; } if (ent.v.angles.y != ent.baseline.angles.y) { bits |= Protocol.U_ANGLE2; } if (ent.v.angles.z != ent.baseline.angles.z) { bits |= Protocol.U_ANGLE3; } if (ent.v.movetype == Movetypes.MOVETYPE_STEP) { bits |= Protocol.U_NOLERP; // don't mess up the step animation } if (ent.baseline.colormap != ent.v.colormap) { bits |= Protocol.U_COLORMAP; } if (ent.baseline.skin != ent.v.skin) { bits |= Protocol.U_SKIN; } if (ent.baseline.frame != ent.v.frame) { bits |= Protocol.U_FRAME; } if (ent.baseline.effects != ent.v.effects) { bits |= Protocol.U_EFFECTS; } if (ent.baseline.modelindex != ent.v.modelindex) { bits |= Protocol.U_MODEL; } if (e >= 256) { bits |= Protocol.U_LONGENTITY; } if (bits >= 256) { bits |= Protocol.U_MOREBITS; } // // write the message // msg.WriteByte(bits | Protocol.U_SIGNAL); if ((bits & Protocol.U_MOREBITS) != 0) { msg.WriteByte(bits >> 8); } if ((bits & Protocol.U_LONGENTITY) != 0) { msg.WriteShort(e); } else { msg.WriteByte(e); } if ((bits & Protocol.U_MODEL) != 0) { msg.WriteByte((int)ent.v.modelindex); } if ((bits & Protocol.U_FRAME) != 0) { msg.WriteByte((int)ent.v.frame); } if ((bits & Protocol.U_COLORMAP) != 0) { msg.WriteByte((int)ent.v.colormap); } if ((bits & Protocol.U_SKIN) != 0) { msg.WriteByte((int)ent.v.skin); } if ((bits & Protocol.U_EFFECTS) != 0) { msg.WriteByte((int)ent.v.effects); } if ((bits & Protocol.U_ORIGIN1) != 0) { msg.WriteCoord(ent.v.origin.x); } if ((bits & Protocol.U_ANGLE1) != 0) { msg.WriteAngle(ent.v.angles.x); } if ((bits & Protocol.U_ORIGIN2) != 0) { msg.WriteCoord(ent.v.origin.y); } if ((bits & Protocol.U_ANGLE2) != 0) { msg.WriteAngle(ent.v.angles.y); } if ((bits & Protocol.U_ORIGIN3) != 0) { msg.WriteCoord(ent.v.origin.z); } if ((bits & Protocol.U_ANGLE3) != 0) { msg.WriteAngle(ent.v.angles.z); } } }
/// <summary> /// SV_SendServerinfo /// Sends the first message from the server to a connected client. /// This will be sent on the initial connection and upon each server load. /// </summary> static void SendServerInfo(client_t client) { MsgWriter writer = client.message; writer.WriteByte(Protocol.svc_print); writer.WriteString(String.Format("{0}\nVERSION {1,4:F2} SERVER ({2} CRC)", (char)2, QDef.VERSION, Progs.Crc)); writer.WriteByte(Protocol.svc_serverinfo); writer.WriteLong(Protocol.PROTOCOL_VERSION); writer.WriteByte(svs.maxclients); if (!Host.IsCoop && Host.Deathmatch != 0) { writer.WriteByte(Protocol.GAME_DEATHMATCH); } else { writer.WriteByte(Protocol.GAME_COOP); } string message = Progs.GetString(sv.edicts[0].v.message); writer.WriteString(message); for (int i = 1; i < sv.model_precache.Length; i++) { string tmp = sv.model_precache[i]; if (String.IsNullOrEmpty(tmp)) { break; } writer.WriteString(tmp); } writer.WriteByte(0); for (int i = 1; i < sv.sound_precache.Length; i++) { string tmp = sv.sound_precache[i]; if (tmp == null) { break; } writer.WriteString(tmp); } writer.WriteByte(0); // send music writer.WriteByte(Protocol.svc_cdtrack); writer.WriteByte((int)sv.edicts[0].v.sounds); writer.WriteByte((int)sv.edicts[0].v.sounds); // set view writer.WriteByte(Protocol.svc_setview); writer.WriteShort(NumForEdict(client.edict)); writer.WriteByte(Protocol.svc_signonnum); writer.WriteByte(1); client.sendsignon = true; client.spawned = false; // need prespawn, spawn, etc }