/** * If a packet has not been received from a client for timeout.value * seconds, drop the conneciton. Server frames are used instead of realtime * to avoid dropping the local client while debugging. * * When a client is normally dropped, the client_t goes into a zombie state * for a few seconds to make sure any final reliable message gets resent if * necessary. */ public static void SV_CheckTimeouts() { int i; client_t cl; int droppoint; int zombiepoint; droppoint = (int)(SV_INIT.svs.realtime - 1000 * SV_MAIN.timeout.value); zombiepoint = (int)(SV_INIT.svs.realtime - 1000 * SV_MAIN.zombietime.value); for (i = 0; i < SV_MAIN.maxclients.value; i++) { cl = SV_INIT.svs.clients[i]; // message times may be wrong across a changelevel if (cl.lastmessage > SV_INIT.svs.realtime) { cl.lastmessage = SV_INIT.svs.realtime; } if (cl.state == Defines.cs_zombie && cl.lastmessage < zombiepoint) { cl.state = Defines.cs_free; // can now be reused continue; } if ((cl.state == Defines.cs_connected || cl.state == Defines.cs_spawned) && cl.lastmessage < droppoint) { SV_SEND.SV_BroadcastPrintf(Defines.PRINT_HIGH, cl.name + " timed out\n"); SV_MAIN.SV_DropClient(cl); cl.state = Defines.cs_free; // don't bother with zombie state } } }
/** * PF_Configstring */ public static void PF_Configstring(int index, string val) { if (index < 0 || index >= Defines.MAX_CONFIGSTRINGS) { Com.Error(Defines.ERR_DROP, "configstring: bad index " + index + "\n"); } if (val == null) { val = ""; } // change the string in sv SV_INIT.sv.configstrings[index] = val; if (SV_INIT.sv.state != Defines.ss_loading) { // send the update to // everyone SZ.Clear(SV_INIT.sv.multicast); MSG.WriteChar(SV_INIT.sv.multicast, Defines.svc_configstring); MSG.WriteShort(SV_INIT.sv.multicast, index); MSG.WriteString(SV_INIT.sv.multicast, val); SV_SEND.SV_Multicast(Globals.vec3_origin, Defines.MULTICAST_ALL_R); } }
public static void PF_StartSound(edict_t entity, int channel, int sound_num, float volume, float attenuation, float timeofs) { if (null == entity) { return; } SV_SEND.SV_StartSound(null, entity, channel, sound_num, volume, attenuation, timeofs); }
/** * A client issued an rcon command. Shift down the remaining args Redirect * all printfs fromt hte server to the client. */ public static void SVC_RemoteCommand() { int i; string remaining; i = SV_MAIN.Rcon_Validate(); var msg = Lib.CtoJava(Globals.net_message.data, 4, 1024); if (i == 0) { Com.Printf("Bad rcon from " + NET.AdrToString(Globals.net_from) + ":\n" + msg + "\n"); } else { Com.Printf("Rcon from " + NET.AdrToString(Globals.net_from) + ":\n" + msg + "\n"); } Com.BeginRedirect( Defines.RD_PACKET, SV_SEND.sv_outputbuf, Defines.SV_OUTPUTBUF_LENGTH, (target, buffer) => { SV_SEND.SV_FlushRedirect(target, Lib.stringToBytes(buffer.ToString())); } ); if (0 == SV_MAIN.Rcon_Validate()) { Com.Printf("Bad rcon_password.\n"); } else { remaining = ""; for (i = 2; i < Cmd.Argc(); i++) { remaining += Cmd.Argv(i); remaining += " "; } Cmd.ExecuteString(remaining); } Com.EndRedirect(); }
/** * SV_FindIndex. */ public static int SV_FindIndex(string name, int start, int max, bool create) { int i; if (name == null || name.Length == 0) { return(0); } for (i = 1; i < max && SV_INIT.sv.configstrings[start + i] != null; i++) { if (0 == Lib.strcmp(SV_INIT.sv.configstrings[start + i], name)) { return(i); } } if (!create) { return(0); } if (i == max) { Com.Error(Defines.ERR_DROP, "*Index: overflow"); } SV_INIT.sv.configstrings[start + i] = name; if (SV_INIT.sv.state != Defines.ss_loading) { // send the update to everyone SZ.Clear(SV_INIT.sv.multicast); MSG.WriteChar(SV_INIT.sv.multicast, Defines.svc_configstring); MSG.WriteShort(SV_INIT.sv.multicast, start + i); MSG.WriteString(SV_INIT.sv.multicast, name); SV_SEND.SV_Multicast(Globals.vec3_origin, Defines.MULTICAST_ALL_R); } return(i); }
/** * PF_cprintf * * Print to a single client. */ public static void PF_cprintf(edict_t ent, int level, string fmt) { var n = 0; if (ent != null) { n = ent.index; if (n < 1 || n > SV_MAIN.maxclients.value) { Com.Error(Defines.ERR_DROP, "cprintf to a non-client"); } } if (ent != null) { SV_SEND.SV_ClientPrintf(SV_INIT.svs.clients[n - 1], level, fmt); } else { Com.Printf(fmt); } }
/** * SV_Frame. */ public static void SV_Frame(long msec) { Globals.time_before_game = Globals.time_after_game = 0; // if server is not active, do nothing if (!SV_INIT.svs.initialized) { return; } SV_INIT.svs.realtime += (int)msec; // keep the random time dependent Lib.rand(); // check timeouts SV_MAIN.SV_CheckTimeouts(); // get packets from clients SV_MAIN.SV_ReadPackets(); //if (Game.g_edicts[1] !=null) // Com.p("player at:" + Lib.vtofsbeaty(Game.g_edicts[1].s.origin )); // move autonomous things around if enough time has passed if (0 == SV_MAIN.sv_timedemo.value && SV_INIT.svs.realtime < SV_INIT.sv.time) { // never let the time get too far off if (SV_INIT.sv.time - SV_INIT.svs.realtime > 100) { if (SV_MAIN.sv_showclamp.value != 0) { Com.Printf("sv lowclamp\n"); } SV_INIT.svs.realtime = SV_INIT.sv.time - 100; } return; } // update ping based on the last known frame from all clients SV_MAIN.SV_CalcPings(); // give the clients some timeslices SV_MAIN.SV_GiveMsec(); // let everything in the world think and move SV_MAIN.SV_RunGameFrame(); // send messages back to the clients that had packets read this frame SV_SEND.SV_SendClientMessages(); // save the entire world state if recording a serverdemo SV_ENTS.SV_RecordDemoMessage(); // send a heartbeat to the master if needed SV_MAIN.Master_Heartbeat(); // clear teleport flags, etc for next frame SV_MAIN.SV_PrepWorldFrame(); }