X-Git-Url: http://git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=sv_main.c;h=8c10fcb042d48cfd0596caa5eb2c403ceb6b7e6c;hp=dcc44de170efb4049eb1268803bb350ffb20d983;hb=f847004b9818defbfd4bf15fe7b891fee2706079;hpb=2c1140a494598d75a12c01f82d7c9accff974fbb diff --git a/sv_main.c b/sv_main.c index dcc44de1..8c10fcb0 100644 --- a/sv_main.c +++ b/sv_main.c @@ -50,6 +50,7 @@ cvar_t pausable = {CF_SERVER, "pausable","1", "allow players to pause or not (ot cvar_t pr_checkextension = {CF_SERVER | CF_READONLY, "pr_checkextension", "1", "indicates to QuakeC that the standard quakec extensions system is available (if 0, quakec should not attempt to use extensions)"}; cvar_t samelevel = {CF_SERVER | CF_NOTIFY, "samelevel","0", "repeats same level if level ends (due to timelimit or someone hitting an exit)"}; cvar_t skill = {CF_SERVER, "skill","1", "difficulty level of game, affects monster layouts in levels, 0 = easy, 1 = normal, 2 = hard, 3 = nightmare (same layout as hard but monsters fire twice)"}; +cvar_t campaign = {CF_SERVER, "campaign", "0", "singleplayer mode"}; cvar_t host_timescale = {CF_CLIENT | CF_SERVER, "host_timescale", "1.0", "controls game speed, 0.5 is half speed, 2 is double speed"}; cvar_t sv_accelerate = {CF_SERVER, "sv_accelerate", "10", "rate at which a player accelerates to sv_maxspeed"}; @@ -206,6 +207,8 @@ cvar_t halflifebsp = {CF_SERVER, "halflifebsp", "0", "indicates the current map cvar_t sv_mapformat_is_quake2 = {CF_SERVER, "sv_mapformat_is_quake2", "0", "indicates the current map is q2bsp format (useful to know because of different entity behaviors, .frame on submodels and other things)"}; cvar_t sv_mapformat_is_quake3 = {CF_SERVER, "sv_mapformat_is_quake3", "0", "indicates the current map is q2bsp format (useful to know because of different entity behaviors)"}; +cvar_t sv_writepicture_quality = {CF_SERVER | CF_ARCHIVE, "sv_writepicture_quality", "10", "WritePicture quality offset (higher means better quality, but slower)"}; + server_t sv; server_static_t svs; @@ -433,30 +436,6 @@ static void SV_AreaStats_f(cmd_state_t *cmd) World_PrintAreaStats(&sv.world, "server"); } -static qbool SV_CanSave(void) -{ - prvm_prog_t *prog = SVVM_prog; - if(SV_IsLocalServer() == 1) - { - // singleplayer checks - if ((svs.clients[0].active && PRVM_serveredictfloat(svs.clients[0].edict, deadflag))) - { - Con_Print("Can't savegame with a dead player\n"); - return false; - } - - if(host.hook.CL_Intermission && host.hook.CL_Intermission()) - { - Con_Print("Can't save in intermission.\n"); - return false; - } - } - else - Con_Print(CON_WARN "Warning: saving a multiplayer game may have strange results when restored (to properly resume, all players must join in the same player slots and then the game can be reloaded).\n"); - return true; - -} - static void SV_ServerOptions (void) { int i; @@ -547,10 +526,11 @@ void SV_Init (void) Cvar_RegisterVariable (&pr_checkextension); Cvar_RegisterVariable (&samelevel); Cvar_RegisterVariable (&skill); + Cvar_RegisterVariable (&campaign); Cvar_RegisterVariable (&host_timescale); Cvar_RegisterCallback (&host_timescale, Host_Timescale_c); - Cvar_RegisterAlias (&host_timescale, "slowmo"); - Cvar_RegisterAlias (&host_timescale, "timescale"); + Cvar_RegisterVirtual (&host_timescale, "slowmo"); + Cvar_RegisterVirtual (&host_timescale, "timescale"); Cvar_RegisterVariable (&sv_accelerate); Cvar_RegisterVariable (&sv_aim); Cvar_RegisterVariable (&sv_airaccel_qw); @@ -642,7 +622,7 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_protocolname); Cvar_RegisterVariable (&sv_random_seed); Cvar_RegisterVariable (&host_limitlocal); - Cvar_RegisterAlias(&host_limitlocal, "sv_ratelimitlocalplayer"); + Cvar_RegisterVirtual(&host_limitlocal, "sv_ratelimitlocalplayer"); Cvar_RegisterVariable (&sv_sound_land); Cvar_RegisterVariable (&sv_sound_watersplash); Cvar_RegisterVariable (&sv_stepheight); @@ -707,12 +687,15 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_mapformat_is_quake2); Cvar_RegisterVariable (&sv_mapformat_is_quake3); + Cvar_RegisterVariable (&sv_writepicture_quality); + SV_InitOperatorCommands(); - host.hook.SV_CanSave = SV_CanSave; + host.hook.SV_Shutdown = SV_Shutdown; sv_mempool = Mem_AllocPool("server", 0, NULL); SV_ServerOptions(); + Cvar_Callback(&sv_netport); } static void SV_SaveEntFile_f(cmd_state_t *cmd) @@ -1005,14 +988,31 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection) SV_DropClient Called when the player is getting totally kicked off the host -if (crash = true), don't bother sending signofs +if (leaving = true), don't bother sending signofs ===================== */ -void SV_DropClient(qbool crash) +void SV_DropClient(qbool leaving, const char *fmt, ... ) { prvm_prog_t *prog = SVVM_prog; int i; - Con_Printf("Client \"%s\" dropped\n", host_client->name); + + va_list argptr; + char reason[512] = ""; + + Con_Printf("Client \"%s\" dropped", host_client->name); + + if(fmt) + { + va_start(argptr, fmt); + dpvsnprintf(reason, sizeof(reason), fmt, argptr); + va_end(argptr); + + Con_Printf(" (%s)\n", reason); + } + else + { + Con_Printf(" \n"); + } SV_StopDemoRecording(host_client); @@ -1022,15 +1022,22 @@ void SV_DropClient(qbool crash) if (host_client->netconnection) { // tell the client to be gone - if (!crash) + if (!leaving) { // LadyHavoc: no opportunity for resending, so use unreliable 3 times - unsigned char bufdata[8]; + unsigned char bufdata[520]; // Disconnect reason string can be 512 characters sizebuf_t buf; memset(&buf, 0, sizeof(buf)); buf.data = bufdata; buf.maxsize = sizeof(bufdata); MSG_WriteByte(&buf, svc_disconnect); + if(fmt) + { + if(sv.protocol == PROTOCOL_DARKPLACES8) + MSG_WriteString(&buf, reason); + else + SV_ClientPrintf("%s\n", reason); + } 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); @@ -1058,6 +1065,10 @@ void SV_DropClient(qbool crash) NetConn_Close(host_client->netconnection); host_client->netconnection = NULL; } + if(fmt) + SV_BroadcastPrintf("\003^3%s left the game (%s)\n", host_client->name, reason); + else + SV_BroadcastPrintf("\003^3%s left the game\n", host_client->name); // if a download is active, close it if (host_client->download_file) @@ -1295,7 +1306,7 @@ static void SV_Download_f(cmd_state_t *cmd) if (!sv_allowdownloads_archive.integer) { - if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3")) + if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3") || !strcasecmp(extension, "dpk")) { 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); SV_ClientCommands("\nstopdownload\n"); @@ -1577,7 +1588,7 @@ model_t *SV_GetModelFromEdict(prvm_edict_t *ed) { prvm_prog_t *prog = SVVM_prog; int modelindex; - if (!ed || ed->priv.server->free) + if (!ed || ed->free) return NULL; modelindex = (int)PRVM_serveredictfloat(ed, modelindex); return (modelindex > 0 && modelindex < MAX_MODELS) ? sv.models[modelindex] : NULL; @@ -1604,7 +1615,7 @@ static void SV_CreateBaseline (void) // LadyHavoc: always clear state values, whether the entity is in use or not svent->priv.server->baseline = defaultstate; - if (svent->priv.server->free) + if (svent->free) continue; if (entnum > svs.maxclients && !PRVM_serveredictfloat(svent, modelindex)) continue; @@ -1856,8 +1867,16 @@ void SV_SpawnServer (const char *map) // // make cvars consistant // + if (coop.integer) + { Cvar_SetValueQuick(&deathmatch, 0); + Cvar_SetValueQuick(&campaign, 0); + } + else if(!deathmatch.integer) + Cvar_SetValueQuick(&campaign, 1); + else + Cvar_SetValueQuick(&campaign, 0); // LadyHavoc: it can be useful to have skills outside the range 0-3... //current_skill = bound(0, (int)(skill.value + 0.5), 3); //Cvar_SetValue ("skill", (float)current_skill); @@ -1958,7 +1977,7 @@ void SV_SpawnServer (const char *map) // AK possible hack since num_edicts is still 0 ent = PRVM_EDICT_NUM(0); memset (ent->fields.fp, 0, prog->entityfields * sizeof(prvm_vec_t)); - ent->priv.server->free = false; + ent->free = false; PRVM_serveredictstring(ent, model) = PRVM_SetEngineString(prog, sv.worldname); PRVM_serveredictfloat(ent, modelindex) = 1; // world model PRVM_serveredictfloat(ent, solid) = SOLID_BSP; @@ -2080,10 +2099,12 @@ void SV_Shutdown(void) prvm_prog_t *prog = SVVM_prog; int i; - Con_DPrintf("SV_Shutdown\n"); + SV_LockThreadMutex(); if (!sv.active) - return; + goto end; + + Con_DPrintf("SV_Shutdown\n"); NetConn_Heartbeat(2); NetConn_Heartbeat(2); @@ -2102,7 +2123,7 @@ void SV_Shutdown(void) } for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) if (host_client->active) - SV_DropClient(false); // server shutdown + SV_DropClient(false, "Server shutting down"); // server shutdown NetConn_CloseServerPorts(); @@ -2112,8 +2133,8 @@ void SV_Shutdown(void) // memset(&sv, 0, sizeof(sv)); memset(svs.clients, 0, svs.maxclients*sizeof(client_t)); - - cl.islocalgame = false; +end: + SV_UnlockThreadMutex(); } ///////////////////////////////////////////////////// @@ -2132,7 +2153,7 @@ static void SVVM_end_increase_edicts(prvm_prog_t *prog) // link every entity except world for (i = 1, ent = prog->edicts;i < prog->num_edicts;i++, ent++) - if (!ent->priv.server->free && !VectorCompare(PRVM_serveredictvector(ent, absmin), PRVM_serveredictvector(ent, absmax))) + if (!ent->free && !VectorCompare(PRVM_serveredictvector(ent, absmin), PRVM_serveredictvector(ent, absmax))) SV_LinkEdict(ent); } @@ -2208,9 +2229,10 @@ static void SVVM_free_edict(prvm_prog_t *prog, prvm_edict_t *ed) PRVM_serveredictfloat(ed, solid) = 0; VM_RemoveEdictSkeleton(prog, ed); +#ifdef USEODE World_Physics_RemoveFromEntity(&sv.world, ed); World_Physics_RemoveJointFromEntity(&sv.world, ed); - +#endif // make sure csqc networking is aware of the removed entity e = PRVM_NUM_FOR_EDICT(ed); sv.csqcentityversion[e] = 0; @@ -2228,7 +2250,7 @@ static void SVVM_count_edicts(prvm_prog_t *prog) for (i=0 ; inum_edicts ; i++) { ent = PRVM_EDICT_NUM(i); - if (ent->priv.server->free) + if (ent->free) continue; active++; if (PRVM_serveredictfloat(ent, solid)) @@ -2271,7 +2293,7 @@ static qbool SVVM_load_edict(prvm_prog_t *prog, prvm_edict_t *ent) static void SV_VM_Setup(void) { prvm_prog_t *prog = SVVM_prog; - PRVM_Prog_Init(prog, cmd_server); + PRVM_Prog_Init(prog, cmd_local); // allocate the mempools // TODO: move the magic numbers/constants into #defines [9/13/2006 Black] @@ -2464,13 +2486,20 @@ static void SV_CheckTimeouts(void) // never timeout loopback connections for (i = (host_isclient.integer ? 1 : 0), host_client = &svs.clients[i]; i < svs.maxclients; i++, host_client++) - { if (host_client->netconnection && host.realtime > host_client->netconnection->timeout) - { - Con_Printf("Client \"%s\" connection timed out\n", host_client->name); - SV_DropClient(false); - } - } + SV_DropClient(false, "Timed out"); +} + +/* +================== +SV_TimeReport + +Returns a time report string, for example for +================== +*/ +const char *SV_TimingReport(char *buf, size_t buflen) +{ + return va(buf, buflen, "%.1f%% CPU, %.2f%% lost, offset avg %.1fms, max %.1fms, sdev %.1fms", svs.perf_cpuload * 100, svs.perf_lost * 100, svs.perf_offset_avg * 1000, svs.perf_offset_max * 1000, svs.perf_offset_sdev * 1000); } extern cvar_t host_maxwait; @@ -2506,7 +2535,7 @@ double SV_Frame(double time) } if(svs.perf_lost > 0 && developer_extra.integer && playing) // only complain if anyone is looking - Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); + Con_DPrintf("Server can't keep up: %s\n", SV_TimingReport(vabuf, sizeof(vabuf))); } if(svs.perf_acc_realtime > 5 || sv.time < 10) @@ -2702,7 +2731,7 @@ static int SV_ThreadFunc(void *voiddata) } if(svs.perf_lost > 0 && developer_extra.integer) if(playing) - Con_DPrintf("Server can't keep up: %s\n", Host_TimingReport(vabuf, sizeof(vabuf))); + Con_DPrintf("Server can't keep up: %s\n", SV_TimingReport(vabuf, sizeof(vabuf))); svs.perf_acc_realtime = svs.perf_acc_sleeptime = svs.perf_acc_lost = svs.perf_acc_offset = svs.perf_acc_offset_squared = svs.perf_acc_offset_max = svs.perf_acc_offset_samples = 0; }