X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=sv_main.c;h=5551acb51b9660bf919465bf001445bad0bc9ef8;hb=6b70072039c05b9f2a0a5a388e646571ee610224;hp=376d7fd8dda260a916fadc9494daffe4262557d0;hpb=a51a70c2254b27a68e5fe74cc5985b02dc36e1e9;p=xonotic%2Fdarkplaces.git diff --git a/sv_main.c b/sv_main.c index 376d7fd8..5551acb5 100644 --- a/sv_main.c +++ b/sv_main.c @@ -25,6 +25,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "csprogs.h" #include "thread.h" +// current client +client_t *host_client; + static void SV_SaveEntFile_f(cmd_state_t *cmd); static void SV_StartDownload_f(cmd_state_t *cmd); static void SV_Download_f(cmd_state_t *cmd); @@ -414,13 +417,10 @@ prvm_required_field_t sv_reqglobals[] = #undef PRVM_DECLARE_function }; -static void Host_Timescale_c(char *string) +static void Host_Timescale_c(cvar_t *var) { - double value; - value = atof(string); - - if(value < 0.00001 && value != 0) - string[0] = '0', string[1] = 0; + if(var->value < 0.00001 && var->value != 0) + Cvar_SetValueQuick(var, 0); } //============================================================================ @@ -626,6 +626,8 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_mapformat_is_quake2); Cvar_RegisterVariable (&sv_mapformat_is_quake3); + SV_InitOperatorCommands(); + sv_mempool = Mem_AllocPool("server", 0, NULL); } @@ -1152,6 +1154,126 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection) client->prespawned = client->spawned = client->begun = true; } +/* +===================== +SV_DropClient + +Called when the player is getting totally kicked off the host +if (crash = true), don't bother sending signofs +===================== +*/ +void SV_DropClient(qboolean crash) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + Con_Printf("Client \"%s\" dropped\n", host_client->name); + + SV_StopDemoRecording(host_client); + + // make sure edict is not corrupt (from a level change for example) + host_client->edict = PRVM_EDICT_NUM(host_client - svs.clients + 1); + + if (host_client->netconnection) + { + // tell the client to be gone + if (!crash) + { + // LadyHavoc: no opportunity for resending, so use unreliable 3 times + unsigned char bufdata[8]; + sizebuf_t buf; + memset(&buf, 0, sizeof(buf)); + buf.data = bufdata; + buf.maxsize = sizeof(bufdata); + MSG_WriteByte(&buf, svc_disconnect); + NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false); + NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false); + NetConn_SendUnreliableMessage(host_client->netconnection, &buf, sv.protocol, 10000, 0, false); + } + } + + // call qc ClientDisconnect function + // LadyHavoc: don't call QC if server is dead (avoids recursive + // Host_Error in some mods when they run out of edicts) + if (host_client->clientconnectcalled && sv.active && host_client->edict) + { + // call the prog function for removing a client + // this will set the body to a dead frame, among other things + int saveSelf = PRVM_serverglobaledict(self); + host_client->clientconnectcalled = false; + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict); + prog->ExecuteProgram(prog, PRVM_serverfunction(ClientDisconnect), "QC function ClientDisconnect is missing"); + PRVM_serverglobaledict(self) = saveSelf; + } + + if (host_client->netconnection) + { + // break the net connection + NetConn_Close(host_client->netconnection); + host_client->netconnection = NULL; + } + + // if a download is active, close it + if (host_client->download_file) + { + Con_DPrintf("Download of %s aborted when %s dropped\n", host_client->download_name, host_client->name); + FS_Close(host_client->download_file); + host_client->download_file = NULL; + host_client->download_name[0] = 0; + host_client->download_expectedposition = 0; + host_client->download_started = false; + } + + // remove leaving player from scoreboard + host_client->name[0] = 0; + host_client->colors = 0; + host_client->frags = 0; + // send notification to all clients + // get number of client manually just to make sure we get it right... + i = host_client - svs.clients; + MSG_WriteByte (&sv.reliable_datagram, svc_updatename); + MSG_WriteByte (&sv.reliable_datagram, i); + MSG_WriteString (&sv.reliable_datagram, host_client->name); + MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors); + MSG_WriteByte (&sv.reliable_datagram, i); + MSG_WriteByte (&sv.reliable_datagram, host_client->colors); + MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags); + MSG_WriteByte (&sv.reliable_datagram, i); + MSG_WriteShort (&sv.reliable_datagram, host_client->frags); + + // free the client now + if (host_client->entitydatabase) + EntityFrame_FreeDatabase(host_client->entitydatabase); + if (host_client->entitydatabase4) + EntityFrame4_FreeDatabase(host_client->entitydatabase4); + if (host_client->entitydatabase5) + EntityFrame5_FreeDatabase(host_client->entitydatabase5); + + if (sv.active) + { + // clear a fields that matter to DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS, and also frags + PRVM_ED_ClearEdict(prog, host_client->edict); + } + + // clear the client struct (this sets active to false) + memset(host_client, 0, sizeof(*host_client)); + + // update server listing on the master because player count changed + // (which the master uses for filtering empty/full servers) + NetConn_Heartbeat(1); + + if (sv.loadgame) + { + for (i = 0;i < svs.maxclients;i++) + if (svs.clients[i].active && !svs.clients[i].spawned) + break; + if (i == svs.maxclients) + { + Con_Printf("Loaded game, everyone rejoined - unpausing\n"); + sv.paused = sv.loadgame = false; // we're basically done with loading now + } + } +} /* =============================================================================== @@ -2725,7 +2847,7 @@ static void SV_Download_f(cmd_state_t *cmd) { // at this point we'll assume the previous download should be aborted Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name); - Host_ClientCommands("\nstopdownload\n"); + SV_ClientCommands("\nstopdownload\n"); // close the file and reset variables FS_Close(host_client->download_file); @@ -2740,7 +2862,7 @@ static void SV_Download_f(cmd_state_t *cmd) if (!sv_allowdownloads.integer && !is_csqc) { SV_ClientPrintf("Downloads are disabled on this server\n"); - Host_ClientCommands("\nstopdownload\n"); + SV_ClientCommands("\nstopdownload\n"); return; } @@ -2769,7 +2891,7 @@ static void SV_Download_f(cmd_state_t *cmd) host_client->download_file = FS_FileFromData(svs.csqc_progdata, sv.csqc_progsize, true); // no, no space is needed between %s and %s :P - Host_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions); + SV_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions); host_client->download_expectedposition = 0; host_client->download_started = false; @@ -2780,7 +2902,7 @@ static void SV_Download_f(cmd_state_t *cmd) if (!FS_FileExists(host_client->download_name)) { SV_ClientPrintf("Download rejected: server does not have the file \"%s\"\nYou may need to separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name); - Host_ClientCommands("\nstopdownload\n"); + SV_ClientCommands("\nstopdownload\n"); return; } @@ -2790,7 +2912,7 @@ static void SV_Download_f(cmd_state_t *cmd) if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name)) { SV_ClientPrintf("Download rejected: file \"%s\" is part of registered Quake(r)\nYou must purchase Quake(r) from id Software or a retailer to get this file\nPlease go to http://www.idsoftware.com/games/quake/quake/index.php?game_section=buy\n", host_client->download_name); - Host_ClientCommands("\nstopdownload\n"); + SV_ClientCommands("\nstopdownload\n"); return; } @@ -2801,7 +2923,7 @@ static void SV_Download_f(cmd_state_t *cmd) if (whichpack) { SV_ClientPrintf("Download rejected: file \"%s\" is in an archive (\"%s\")\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name, whichpack); - Host_ClientCommands("\nstopdownload\n"); + SV_ClientCommands("\nstopdownload\n"); return; } } @@ -2811,7 +2933,7 @@ static void SV_Download_f(cmd_state_t *cmd) if (!strcasecmp(extension, "cfg")) { SV_ClientPrintf("Download rejected: file \"%s\" is a .cfg file which is forbidden for security reasons\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name); - Host_ClientCommands("\nstopdownload\n"); + SV_ClientCommands("\nstopdownload\n"); return; } } @@ -2821,7 +2943,7 @@ static void SV_Download_f(cmd_state_t *cmd) if (!strncasecmp(host_client->download_name, "dlcache/", 8)) { SV_ClientPrintf("Download rejected: file \"%s\" is in the dlcache/ directory which is forbidden for security reasons\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name); - Host_ClientCommands("\nstopdownload\n"); + SV_ClientCommands("\nstopdownload\n"); return; } } @@ -2831,7 +2953,7 @@ static void SV_Download_f(cmd_state_t *cmd) if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3")) { SV_ClientPrintf("Download rejected: file \"%s\" is an archive\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name); - Host_ClientCommands("\nstopdownload\n"); + SV_ClientCommands("\nstopdownload\n"); return; } } @@ -2840,14 +2962,14 @@ static void SV_Download_f(cmd_state_t *cmd) if (!host_client->download_file) { SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name); - Host_ClientCommands("\nstopdownload\n"); + SV_ClientCommands("\nstopdownload\n"); return; } if (FS_FileSize(host_client->download_file) > 1<<30) { SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name); - Host_ClientCommands("\nstopdownload\n"); + SV_ClientCommands("\nstopdownload\n"); FS_Close(host_client->download_file); host_client->download_file = NULL; return; @@ -2856,7 +2978,7 @@ static void SV_Download_f(cmd_state_t *cmd) if (FS_FileSize(host_client->download_file) < 0) { SV_ClientPrintf("Download rejected: file \"%s\" is not a regular file\n", host_client->download_name); - Host_ClientCommands("\nstopdownload\n"); + SV_ClientCommands("\nstopdownload\n"); FS_Close(host_client->download_file); host_client->download_file = NULL; return; @@ -2875,10 +2997,10 @@ static void SV_Download_f(cmd_state_t *cmd) strlcat(extensions, " deflate", sizeof(extensions)); // no, no space is needed between %s and %s :P - Host_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions); + SV_ClientCommands("\ncl_downloadbegin %i %s%s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name, extensions); } */ - Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name); + SV_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name); host_client->download_expectedposition = 0; host_client->download_started = false; @@ -3284,7 +3406,7 @@ This is called at the start of each level ================ */ -void SV_SpawnServer (const char *server) +void SV_SpawnServer (const char *map) { prvm_prog_t *prog = SVVM_prog; prvm_edict_t *ent; @@ -3294,16 +3416,16 @@ void SV_SpawnServer (const char *server) char modelname[sizeof(sv.worldname)]; char vabuf[1024]; - Con_DPrintf("SpawnServer: %s\n", server); + Con_DPrintf("SpawnServer: %s\n", map); - dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server); + dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", map); if (!FS_FileExists(modelname)) { - dpsnprintf (modelname, sizeof(modelname), "maps/%s", server); + dpsnprintf (modelname, sizeof(modelname), "maps/%s", map); if (!FS_FileExists(modelname)) { - Con_Printf("SpawnServer: no map file named maps/%s.bsp\n", server); + Con_Printf("SpawnServer: no map file named maps/%s.bsp\n", map); return; } } @@ -3321,6 +3443,15 @@ void SV_SpawnServer (const char *server) if(sv.active) { + client_t *client; + for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++) + { + if (client->netconnection) + { + MSG_WriteByte(&client->netconnection->message, svc_stufftext); + MSG_WriteString(&client->netconnection->message, "reconnect\n"); + } + } World_End(&sv.world); if(PRVM_serverfunction(SV_Shutdown)) { @@ -3363,23 +3494,8 @@ void SV_SpawnServer (const char *server) // // tell all connected clients that we are going to a new level // - if (sv.active) - { - client_t *client; - for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++) - { - if (client->netconnection) - { - MSG_WriteByte(&client->netconnection->message, svc_stufftext); - MSG_WriteString(&client->netconnection->message, "reconnect\n"); - } - } - } - else - { - // open server port + if (!sv.active) NetConn_OpenServerPorts(true); - } // // make cvars consistant @@ -3414,7 +3530,7 @@ void SV_SpawnServer (const char *server) sv.active = true; // set level base name variables for later use - strlcpy (sv.name, server, sizeof (sv.name)); + strlcpy (sv.name, map, sizeof (sv.name)); strlcpy(sv.worldname, modelname, sizeof(sv.worldname)); FS_StripExtension(sv.worldname, sv.worldnamenoextension, sizeof(sv.worldnamenoextension)); strlcpy(sv.worldbasename, !strncmp(sv.worldnamenoextension, "maps/", 5) ? sv.worldnamenoextension + 5 : sv.worldnamenoextension, sizeof(sv.worldbasename)); @@ -3596,6 +3712,54 @@ void SV_SpawnServer (const char *server) // SV_UnlockThreadMutex(); } +/* +================== +SV_Shutdown + +This only happens at the end of a game, not between levels +================== +*/ +void SV_Shutdown(void) +{ + prvm_prog_t *prog = SVVM_prog; + int i; + + Con_DPrintf("SV_Shutdown\n"); + + if (!sv.active) + return; + + NetConn_Heartbeat(2); + NetConn_Heartbeat(2); + +// make sure all the clients know we're disconnecting + World_End(&sv.world); + if(prog->loaded) + { + if(PRVM_serverfunction(SV_Shutdown)) + { + func_t s = PRVM_serverfunction(SV_Shutdown); + PRVM_serverglobalfloat(time) = sv.time; + PRVM_serverfunction(SV_Shutdown) = 0; // prevent it from getting called again + prog->ExecuteProgram(prog, s,"SV_Shutdown() required"); + } + } + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + if (host_client->active) + SV_DropClient(false); // server shutdown + + NetConn_CloseServerPorts(); + + sv.active = false; +// +// clear structures +// + memset(&sv, 0, sizeof(sv)); + memset(svs.clients, 0, svs.maxclients*sizeof(client_t)); + + cl.islocalgame = false; +} + ///////////////////////////////////////////////////// // SV VM stuff