📄 sv_main.java
字号:
/* * Copyright (C) 1997-2001 Id Software, Inc. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. * */// Created on 13.01.2004 by RST.// $Id: SV_MAIN.java,v 1.16 2006/01/20 22:44:07 salomo Exp $package jake2.server;import jake2.Defines;import jake2.Globals;import jake2.game.*;import jake2.qcommon.*;import jake2.sys.NET;import jake2.sys.Timer;import jake2.util.Lib;import java.io.IOException;public class SV_MAIN { /** Addess of group servers.*/ public static netadr_t master_adr[] = new netadr_t[Defines.MAX_MASTERS]; static { for (int i = 0; i < Defines.MAX_MASTERS; i++) { master_adr[i] = new netadr_t(); } } public static client_t sv_client; // current client public static cvar_t sv_paused; public static cvar_t sv_timedemo; public static cvar_t sv_enforcetime; public static cvar_t timeout; // seconds without any message public static cvar_t zombietime; // seconds to sink messages after // disconnect public static cvar_t rcon_password; // password for remote server commands public static cvar_t allow_download; public static cvar_t allow_download_players; public static cvar_t allow_download_models; public static cvar_t allow_download_sounds; public static cvar_t allow_download_maps; public static cvar_t sv_airaccelerate; public static cvar_t sv_noreload; // don't reload level state when // reentering public static cvar_t maxclients; // FIXME: rename sv_maxclients public static cvar_t sv_showclamp; public static cvar_t hostname; public static cvar_t public_server; // should heartbeats be sent public static cvar_t sv_reconnect_limit; // minimum seconds between connect // messages /** * Send a message to the master every few minutes to let it know we are * alive, and log information. */ public static final int HEARTBEAT_SECONDS = 300; /** * Called when the player is totally leaving the server, either willingly or * unwillingly. This is NOT called if the entire server is quiting or * crashing. */ public static void SV_DropClient(client_t drop) { // add the disconnect MSG.WriteByte(drop.netchan.message, Defines.svc_disconnect); if (drop.state == Defines.cs_spawned) { // call the prog function for removing a client // this will remove the body, among other things PlayerClient.ClientDisconnect(drop.edict); } if (drop.download != null) { FS.FreeFile(drop.download); drop.download = null; } drop.state = Defines.cs_zombie; // become free in a few seconds drop.name = ""; } /* ============================================================================== * * CONNECTIONLESS COMMANDS * * ==============================================================================*/ /** * Builds the string that is sent as heartbeats and status replies. */ public static String SV_StatusString() { String player; String status = ""; int i; client_t cl; int statusLength; int playerLength; status = Cvar.Serverinfo() + "\n"; for (i = 0; i < SV_MAIN.maxclients.value; i++) { cl = SV_INIT.svs.clients[i]; if (cl.state == Defines.cs_connected || cl.state == Defines.cs_spawned) { player = "" + cl.edict.client.ps.stats[Defines.STAT_FRAGS] + " " + cl.ping + "\"" + cl.name + "\"\n"; playerLength = player.length(); statusLength = status.length(); if (statusLength + playerLength >= 1024) break; // can't hold any more status += player; } } return status; } /** * Responds with all the info that qplug or qspy can see */ public static void SVC_Status() { Netchan.OutOfBandPrint(Defines.NS_SERVER, Globals.net_from, "print\n" + SV_StatusString()); } /** * SVC_Ack */ public static void SVC_Ack() { Com.Printf("Ping acknowledge from " + NET.AdrToString(Globals.net_from) + "\n"); } /** * SVC_Info, responds with short info for broadcast scans The second parameter should * be the current protocol version number. */ public static void SVC_Info() { String string; int i, count; int version; if (SV_MAIN.maxclients.value == 1) return; // ignore in single player version = Lib.atoi(Cmd.Argv(1)); if (version != Defines.PROTOCOL_VERSION) string = SV_MAIN.hostname.string + ": wrong version\n"; else { count = 0; for (i = 0; i < SV_MAIN.maxclients.value; i++) if (SV_INIT.svs.clients[i].state >= Defines.cs_connected) count++; string = SV_MAIN.hostname.string + " " + SV_INIT.sv.name + " " + count + "/" + (int) SV_MAIN.maxclients.value + "\n"; } Netchan.OutOfBandPrint(Defines.NS_SERVER, Globals.net_from, "info\n" + string); } /** * SVC_Ping, Just responds with an acknowledgement. */ public static void SVC_Ping() { Netchan.OutOfBandPrint(Defines.NS_SERVER, Globals.net_from, "ack"); } /** * Returns a challenge number that can be used in a subsequent * client_connect command. We do this to prevent denial of service attacks * that flood the server with invalid connection IPs. With a challenge, they * must give a valid IP address. */ public static void SVC_GetChallenge() { int i; int oldest; int oldestTime; oldest = 0; oldestTime = 0x7fffffff; // see if we already have a challenge for this ip for (i = 0; i < Defines.MAX_CHALLENGES; i++) { if (NET.CompareBaseAdr(Globals.net_from, SV_INIT.svs.challenges[i].adr)) break; if (SV_INIT.svs.challenges[i].time < oldestTime) { oldestTime = SV_INIT.svs.challenges[i].time; oldest = i; } } if (i == Defines.MAX_CHALLENGES) { // overwrite the oldest SV_INIT.svs.challenges[oldest].challenge = Lib.rand() & 0x7fff; SV_INIT.svs.challenges[oldest].adr = Globals.net_from; SV_INIT.svs.challenges[oldest].time = (int) Globals.curtime; i = oldest; } // send it back Netchan.OutOfBandPrint(Defines.NS_SERVER, Globals.net_from, "challenge " + SV_INIT.svs.challenges[i].challenge); } /** * A connection request that did not come from the master. */ public static void SVC_DirectConnect() { String userinfo; netadr_t adr; int i; client_t cl; int version; int qport; adr = Globals.net_from; Com.DPrintf("SVC_DirectConnect ()\n"); version = Lib.atoi(Cmd.Argv(1)); if (version != Defines.PROTOCOL_VERSION) { Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nServer is version " + Globals.VERSION + "\n"); Com.DPrintf(" rejected connect from version " + version + "\n"); return; } qport = Lib.atoi(Cmd.Argv(2)); int challenge = Lib.atoi(Cmd.Argv(3)); userinfo = Cmd.Argv(4); // force the IP key/value pair so the game can filter based on ip userinfo = Info.Info_SetValueForKey(userinfo, "ip", NET.AdrToString(Globals.net_from)); // attractloop servers are ONLY for local clients if (SV_INIT.sv.attractloop) { if (!NET.IsLocalAddress(adr)) { Com.Printf("Remote connect in attract loop. Ignored.\n"); Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nConnection refused.\n"); return; } } // see if the challenge is valid if (!NET.IsLocalAddress(adr)) { for (i = 0; i < Defines.MAX_CHALLENGES; i++) { if (NET.CompareBaseAdr(Globals.net_from, SV_INIT.svs.challenges[i].adr)) { if (challenge == SV_INIT.svs.challenges[i].challenge) break; // good Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nBad challenge.\n"); return; } } if (i == Defines.MAX_CHALLENGES) { Netchan.OutOfBandPrint(Defines.NS_SERVER, adr, "print\nNo challenge for address.\n"); return; } } // if there is already a slot for this ip, reuse it 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(adr, cl.netchan.remote_address) && (cl.netchan.qport == qport || adr.port == cl.netchan.remote_address.port)) { if (!NET.IsLocalAddress(adr) && (SV_INIT.svs.realtime - cl.lastconnect) < ((int) SV_MAIN.sv_reconnect_limit.value * 1000)) { Com.DPrintf(NET.AdrToString(adr) + ":reconnect rejected : too soon\n"); return; } Com.Printf(NET.AdrToString(adr) + ":reconnect\n"); gotnewcl(i, challenge, userinfo, adr, qport); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -