📄 sv_main.java
字号:
} } // find a client slot //newcl = null; int index = -1; for (i = 0; i < SV_MAIN.maxclients.value; i++) { cl = SV_INIT.svs.clients[i]; if (cl.state == Defines.cs_free) { index = i; break; } } if (index == -1) { Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nServer is full.\n"); Com.DPrintf("Rejected a connection.\n"); return; } gotnewcl(index, challenge, userinfo, adr, qport); } /** * Initializes player structures after successfull connection. */ public static void gotnewcl(int i, int challenge, String userinfo, netadr_t adr, int qport) { // build a new connection // accept the new client // this is the only place a client_t is ever initialized SV_MAIN.sv_client = SV_INIT.svs.clients[i]; int edictnum = i + 1; edict_t ent = GameBase.g_edicts[edictnum]; SV_INIT.svs.clients[i].edict = ent; // save challenge for checksumming SV_INIT.svs.clients[i].challenge = challenge; // get the game a chance to reject this connection or modify the // userinfo if (!(PlayerClient.ClientConnect(ent, userinfo))) { if (Info.Info_ValueForKey(userinfo, "rejmsg") != null) Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\n" + Info.Info_ValueForKey(userinfo, "rejmsg") + "\nConnection refused.\n"); else Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nConnection refused.\n"); Com.DPrintf("Game rejected a connection.\n"); return; } // parse some info from the info strings SV_INIT.svs.clients[i].userinfo = userinfo; SV_UserinfoChanged(SV_INIT.svs.clients[i]); // send the connect packet to the client Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "client_connect"); Netchan.Setup(Defines.NS_SERVER, SV_INIT.svs.clients[i].netchan, adr, qport); SV_INIT.svs.clients[i].state = Defines.cs_connected; SZ.Init(SV_INIT.svs.clients[i].datagram, SV_INIT.svs.clients[i].datagram_buf, SV_INIT.svs.clients[i].datagram_buf.length); SV_INIT.svs.clients[i].datagram.allowoverflow = true; SV_INIT.svs.clients[i].lastmessage = SV_INIT.svs.realtime; // don't timeout SV_INIT.svs.clients[i].lastconnect = SV_INIT.svs.realtime; Com.DPrintf("new client added.\n"); } /** * Checks if the rcon password is corect. */ public static int Rcon_Validate() { if (0 == SV_MAIN.rcon_password.string.length()) return 0; if (0 != Lib.strcmp(Cmd.Argv(1), SV_MAIN.rcon_password.string)) return 0; return 1; } /** * 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 = Rcon_Validate(); String 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, new Com.RD_Flusher() { public void rd_flush(int target, StringBuffer buffer) { SV_SEND.SV_FlushRedirect(target, Lib.stringToBytes(buffer.toString())); } }); if (0 == 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(); } /** * A connectionless packet has four leading 0xff characters to distinguish * it from a game channel. Clients that are in the game can still send * connectionless packets. It is used also by rcon commands. */ public static void SV_ConnectionlessPacket() { String s; String c; MSG.BeginReading(Globals.net_message); MSG.ReadLong(Globals.net_message); // skip the -1 marker s = MSG.ReadStringLine(Globals.net_message); Cmd.TokenizeString(s.toCharArray(), false); c = Cmd.Argv(0); //for debugging purposes //Com.Printf("Packet " + NET.AdrToString(Netchan.net_from) + " : " + c + "\n"); //Com.Printf(Lib.hexDump(net_message.data, 64, false) + "\n"); if (0 == Lib.strcmp(c, "ping")) SVC_Ping(); else if (0 == Lib.strcmp(c, "ack")) SVC_Ack(); else if (0 == Lib.strcmp(c, "status")) SVC_Status(); else if (0 == Lib.strcmp(c, "info")) SVC_Info(); else if (0 == Lib.strcmp(c, "getchallenge")) SVC_GetChallenge(); else if (0 == Lib.strcmp(c, "connect")) SVC_DirectConnect(); else if (0 == Lib.strcmp(c, "rcon")) SVC_RemoteCommand(); else { Com.Printf("bad connectionless packet from " + NET.AdrToString(Globals.net_from) + "\n"); Com.Printf("[" + s + "]\n"); Com.Printf("" + Lib.hexDump(Globals.net_message.data, 128, false)); } } /** * Updates the cl.ping variables. */ public static void SV_CalcPings() { int i, j; client_t cl; int total, count; for (i = 0; i < SV_MAIN.maxclients.value; i++) { cl = SV_INIT.svs.clients[i]; if (cl.state != Defines.cs_spawned) continue; total = 0; count = 0; for (j = 0; j < Defines.LATENCY_COUNTS; j++) { if (cl.frame_latency[j] > 0) { count++; total += cl.frame_latency[j]; } } if (0 == count) cl.ping = 0; else cl.ping = total / count; // let the game dll know about the ping cl.edict.client.ping = cl.ping; } } /** * Every few frames, gives all clients an allotment of milliseconds for * their command moves. If they exceed it, assume cheating. */ public static void SV_GiveMsec() { int i; client_t cl; if ((SV_INIT.sv.framenum & 15) != 0) return; for (i = 0; i < SV_MAIN.maxclients.value; i++) { cl = SV_INIT.svs.clients[i]; if (cl.state == Defines.cs_free) continue; cl.commandMsec = 1800; // 1600 + some slop } } /** * Reads packets from the network or loopback. */ public static void SV_ReadPackets() { int i; client_t cl; int qport = 0; while (NET.GetPacket(Defines.NS_SERVER, Globals.net_from, Globals.net_message)) { // check for connectionless packet (0xffffffff) first if ((Globals.net_message.data[0] == -1) && (Globals.net_message.data[1] == -1) && (Globals.net_message.data[2] == -1) && (Globals.net_message.data[3] == -1)) { SV_ConnectionlessPacket(); continue; } // read the qport out of the message so we can fix up // stupid address translating routers MSG.BeginReading(Globals.net_message); MSG.ReadLong(Globals.net_message); // sequence number MSG.ReadLong(Globals.net_message); // sequence number qport = MSG.ReadShort(Globals.net_message) & 0xffff; // check for packets from connected clients for (i = 0; i < SV_MAIN.maxclients.value; i++) { cl = SV_INIT.svs.clients[i]; if (cl.state == Defines.cs_free) continue; if (!NET.CompareBaseAdr(Globals.net_from, cl.netchan.remote_address)) continue; if (cl.netchan.qport != qport) continue; if (cl.netchan.remote_address.port != Globals.net_from.port) { Com.Printf("SV_ReadPackets: fixing up a translated port\n"); cl.netchan.remote_address.port = Globals.net_from.port; } if (Netchan.Process(cl.netchan, Globals.net_message)) { // this is a valid, sequenced packet, so process it if (cl.state != Defines.cs_zombie) { cl.lastmessage = SV_INIT.svs.realtime; // don't timeout SV_USER.SV_ExecuteClientMessage(cl); } } break; } if (i != SV_MAIN.maxclients.value) continue; } } /** * 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_DropClient(cl); cl.state = Defines.cs_free; // don't bother with zombie state } } } /** * SV_PrepWorldFrame *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -