/// <summary> /// SV_DropClient /// Called when the player is getting totally kicked off the host /// if (crash = true), don't bother sending signofs /// </summary> public static void DropClient(bool crash) { client_t client = Host.HostClient; if (!crash) { // send any final messages (don't check for errors) if (Net.CanSendMessage(client.netconnection)) { MsgWriter msg = client.message; msg.WriteByte(Protocol.svc_disconnect); Net.SendMessage(client.netconnection, msg); } if (client.edict != null && client.spawned) { // call the prog function for removing a client // this will set the body to a dead frame, among other things int saveSelf = Progs.GlobalStruct.self; Progs.GlobalStruct.self = EdictToProg(client.edict); Progs.Execute(Progs.GlobalStruct.ClientDisconnect); Progs.GlobalStruct.self = saveSelf; } Con.DPrint("Client {0} removed\n", client.name); } // break the net connection Net.Close(client.netconnection); client.netconnection = null; // free the client (the body stays around) client.active = false; client.name = null; client.old_frags = -999999; Net.ActiveConnections--; // send notification to all clients for (int i = 0; i < Server.svs.maxclients; i++) { client_t cl = Server.svs.clients[i]; if (!cl.active) { continue; } cl.message.WriteByte(Protocol.svc_updatename); cl.message.WriteByte(Host.ClientNum); cl.message.WriteString(""); cl.message.WriteByte(Protocol.svc_updatefrags); cl.message.WriteByte(Host.ClientNum); cl.message.WriteShort(0); cl.message.WriteByte(Protocol.svc_updatecolors); cl.message.WriteByte(Host.ClientNum); cl.message.WriteByte(0); } }
// CL_SendCmd public static void SendCmd() { if (Cls.state != ClientActivityState.Connected) { return; } if (Cls.signon == SIGNONS) { UserCommand cmd = new UserCommand(); // get basic movement from keyboard BaseMove(ref cmd); // allow mice or other external controllers to add to the move Input.Move(cmd); // send the unreliable message Client.SendMove(ref cmd); } if (Cls.demoplayback) { Cls.message.Clear();// SZ_Clear (cls.message); return; } // send the reliable message if (Cls.message.IsEmpty) { return; // no message at all } if (!Net.CanSendMessage(Cls.netcon)) { Con.DPrint("CL_WriteToServer: can't send\n"); return; } if (Net.SendMessage(Cls.netcon, Cls.message) == -1) { Host.Error("CL_WriteToServer: lost server connection"); } Cls.message.Clear(); }
/// <summary> /// SV_SendClientMessages /// </summary> public static void SendClientMessages() { // update frags, names, etc UpdateToReliableMessages(); // build individual updates for (int i = 0; i < svs.maxclients; i++) { Host.HostClient = svs.clients[i]; if (!Host.HostClient.active) { continue; } if (Host.HostClient.spawned) { if (!SendClientDatagram(Host.HostClient)) { continue; } } else { // the player isn't totally in the game yet // send small keepalive messages if too much time has passed // send a full message when the next signon stage has been requested // some other message data (name changes, etc) may accumulate // between signon stages if (!Host.HostClient.sendsignon) { if (Host.RealTime - Host.HostClient.last_message > 5) { SendNop(Host.HostClient); } continue; // don't send out non-signon messages } } // check for an overflowed message. Should only happen // on a very f****d up connection that backs up a lot, then // changes level if (Host.HostClient.message.IsOveflowed) { DropClient(true); Host.HostClient.message.IsOveflowed = false; continue; } if (Host.HostClient.message.Length > 0 || Host.HostClient.dropasap) { if (!Net.CanSendMessage(Host.HostClient.netconnection)) { continue; } if (Host.HostClient.dropasap) { DropClient(false); // went to another level } else { if (Net.SendMessage(Host.HostClient.netconnection, Host.HostClient.message) == -1) { DropClient(true); // if the message couldn't send, kick off } Host.HostClient.message.Clear(); Host.HostClient.last_message = Host.RealTime; Host.HostClient.sendsignon = false; } } } // clear muzzle flashes CleanupEnts(); }
/// <summary> /// Host_ShutdownServer /// This only happens at the end of a game, not between levels /// </summary> public static void ShutdownServer(bool crash) { if (!Server.IsActive) { return; } Server.sv.active = false; // stop all client sounds immediately if (Client.cls.state == cactive_t.ca_connected) { Client.Disconnect(); } // flush any pending messages - like the score!!! double start = Sys.GetFloatTime(); int count; do { count = 0; for (int i = 0; i < Server.svs.maxclients; i++) { HostClient = Server.svs.clients[i]; if (HostClient.active && !HostClient.message.IsEmpty) { if (Net.CanSendMessage(HostClient.netconnection)) { Net.SendMessage(HostClient.netconnection, HostClient.message); HostClient.message.Clear(); } else { Net.GetMessage(HostClient.netconnection); count++; } } } if ((Sys.GetFloatTime() - start) > 3.0) { break; } }while (count > 0); // make sure all the clients know we're disconnecting MsgWriter writer = new MsgWriter(4); writer.WriteByte(Protocol.svc_disconnect); count = Net.SendToAll(writer, 5); if (count != 0) { Con.Print("Host_ShutdownServer: NET_SendToAll failed for {0} clients\n", count); } for (int i = 0; i < Server.svs.maxclients; i++) { HostClient = Server.svs.clients[i]; if (HostClient.active) { Server.DropClient(crash); } } // // clear structures // Server.sv.Clear(); for (int i = 0; i < Server.svs.clients.Length; i++) { Server.svs.clients[i].Clear(); } }