]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
Merge MR 'Make trace entity culling optional for spectators'
authorbones_was_here <bones_was_here@xa.org.au>
Thu, 13 Jan 2022 04:29:57 +0000 (14:29 +1000)
committerbones_was_here <bones_was_here@xa.org.au>
Thu, 13 Jan 2022 04:31:00 +0000 (14:31 +1000)
https://gitlab.com/xonotic/darkplaces/-/merge_requests/115
https://github.com/DarkPlacesEngine/darkplaces/pull/13

branch: bones_was_here/trace
commits: 2c1140a494598d75a12c01f82d7c9accff974fbb

Signed-off-by: bones_was_here <bones_was_here@xa.org.au>
1  2 
server.h
sv_main.c
sv_send.c

diff --combined server.h
index 02d3786bb6319ec8450539e9695b7d15f69bb472,b4b4b05352283e3a6bbc028a4460f23f4afe3a44..5ae7befde0f911157127168a7305f1f8d6db6a0d
+++ b/server.h
@@@ -515,7 -515,7 +515,7 @@@ void SV_StartSound (prvm_edict_t *entit
  void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float attenuation, float speed);
  
  void SV_ConnectClient (int clientnum, netconn_t *netconnection);
 -void SV_DropClient (qbool crash);
 +void SV_DropClient (qbool leaving, const char *reason, ... );
  
  void SV_ClientCommands(const char *fmt, ...) DP_FUNC_PRINTF(1);
  
@@@ -581,7 -581,7 +581,7 @@@ int SV_EntitiesInBox(const vec3_t mins
  
  qbool SV_CanSeeBox(int numsamples, vec_t eyejitter, vec_t enlarge, vec_t entboxexpand, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs);
  
- void SV_MarkWriteEntityStateToClient(entity_state_t *s);
+ void SV_MarkWriteEntityStateToClient(entity_state_t *s, client_t *client);
  
  void SV_SendServerinfo(client_t *client);
  void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int maxsize);
@@@ -603,7 -603,7 +603,7 @@@ void SV_CheckVelocity (prvm_edict_t *en
  
  void SV_SetupVM(void);
  
 -const char *Host_TimingReport(char *buf, size_t buflen); ///< for output in SV_Status_f
 +const char *SV_TimingReport(char *buf, size_t buflen); ///< for output in SV_Status_f
  
  int SV_GetPitchSign(prvm_prog_t *prog, prvm_edict_t *ent);
  void SV_GetEntityMatrix(prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qbool viewmatrix);
diff --combined sv_main.c
index ba0c5d525e3416d05719684870a7120802f7e0a7,dcc44de170efb4049eb1268803bb350ffb20d983..8c10fcb042d48cfd0596caa5eb2c403ceb6b7e6c
+++ b/sv_main.c
@@@ -50,7 -50,6 +50,7 @@@ cvar_t pausable = {CF_SERVER, "pausable
  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"};
@@@ -93,6 -92,7 +93,7 @@@ cvar_t sv_cullentities_trace_entityoccl
  cvar_t sv_cullentities_trace_samples = {CF_SERVER, "sv_cullentities_trace_samples", "2", "number of samples to test for entity culling"};
  cvar_t sv_cullentities_trace_samples_extra = {CF_SERVER, "sv_cullentities_trace_samples_extra", "2", "number of samples to test for entity culling when the entity affects its surroundings by e.g. dlight"};
  cvar_t sv_cullentities_trace_samples_players = {CF_SERVER, "sv_cullentities_trace_samples_players", "8", "number of samples to test for entity culling when the entity is a player entity"};
+ cvar_t sv_cullentities_trace_spectators = {CF_SERVER, "sv_cullentities_trace_spectators", "0", "enables trace entity culling for clients that are spectating"};
  cvar_t sv_debugmove = {CF_SERVER | CF_NOTIFY, "sv_debugmove", "0", "disables collision detection optimizations for debugging purposes"};
  cvar_t sv_echobprint = {CF_SERVER | CF_ARCHIVE, "sv_echobprint", "1", "prints gamecode bprint() calls to server console"};
  cvar_t sv_edgefriction = {CF_SERVER, "edgefriction", "1", "how much you slow down when nearing a ledge you might fall off, multiplier of sv_friction (Quake used 2, QuakeWorld used 1 due to a bug in physics code)"};
@@@ -206,8 -206,6 +207,8 @@@ cvar_t halflifebsp = {CF_SERVER, "halfl
  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;
  
@@@ -435,6 -433,30 +436,6 @@@ static void SV_AreaStats_f(cmd_state_t 
        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;
@@@ -525,11 -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);
        Cvar_RegisterVariable (&sv_cullentities_trace_samples);
        Cvar_RegisterVariable (&sv_cullentities_trace_samples_extra);
        Cvar_RegisterVariable (&sv_cullentities_trace_samples_players);
+       Cvar_RegisterVariable (&sv_cullentities_trace_spectators);
        Cvar_RegisterVariable (&sv_debugmove);
        Cvar_RegisterVariable (&sv_echobprint);
        Cvar_RegisterVariable (&sv_edgefriction);
        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);
        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)
@@@ -986,31 -1005,14 +988,31 @@@ void SV_ConnectClient (int clientnum, n
  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);
  
        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);
                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)
@@@ -1304,7 -1295,7 +1306,7 @@@ static void SV_Download_f(cmd_state_t *
  
        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");
@@@ -1586,7 -1577,7 +1588,7 @@@ model_t *SV_GetModelFromEdict(prvm_edic
  {
        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;
@@@ -1613,7 -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;
@@@ -1865,16 -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);
        // 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;
@@@ -2097,12 -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);
        }
        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();
  
  //
        memset(&sv, 0, sizeof(sv));
        memset(svs.clients, 0, svs.maxclients*sizeof(client_t));
 -
 -      cl.islocalgame = false;
 +end:
 +      SV_UnlockThreadMutex();
  }
  
  /////////////////////////////////////////////////////
@@@ -2151,7 -2132,7 +2153,7 @@@ static void SVVM_end_increase_edicts(pr
  
        // 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);
  }
  
@@@ -2227,10 -2208,9 +2229,10 @@@ static void SVVM_free_edict(prvm_prog_
        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;
@@@ -2248,7 -2228,7 +2250,7 @@@ static void SVVM_count_edicts(prvm_prog
        for (i=0 ; i<prog->num_edicts ; i++)
        {
                ent = PRVM_EDICT_NUM(i);
 -              if (ent->priv.server->free)
 +              if (ent->free)
                        continue;
                active++;
                if (PRVM_serveredictfloat(ent, solid))
@@@ -2291,7 -2271,7 +2293,7 @@@ static qbool SVVM_load_edict(prvm_prog_
  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]
@@@ -2484,20 -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;
@@@ -2533,7 -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)
@@@ -2729,7 -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;
                }
  
diff --combined sv_send.c
index a1ee1050ab3cb69b14251c0be1bdc3b7ef165e27,9ff78a0860c17c2376b611277c6c64602bb70d32..3e125f3a58560589759d398858a43608d280f3e7
+++ b/sv_send.c
@@@ -34,6 -34,7 +34,7 @@@ extern cvar_t sv_cullentities_trace_sam
  extern cvar_t sv_cullentities_trace_eyejitter;
  extern cvar_t sv_cullentities_trace_expand;
  extern cvar_t sv_cullentities_trace_delay_players;
+ extern cvar_t sv_cullentities_trace_spectators;
  
  /*
  =============================================================================
@@@ -709,7 -710,7 +710,7 @@@ static void SV_PrepareEntitiesForSendin
        memset(sv.sendentitiesindex, 0, prog->num_edicts * sizeof(*sv.sendentitiesindex));
        for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
        {
 -              if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sv.sendentities + sv.numsendentities, e))
 +              if (!ent->free && SV_PrepareEntityForSending(ent, sv.sendentities + sv.numsendentities, e))
                {
                        sv.sendentitiesindex[e] = sv.sendentities + sv.numsendentities;
                        sv.numsendentities++;
@@@ -859,7 -860,7 +860,7 @@@ qbool SV_CanSeeBox(int numtraces, vec_
        return false;
  }
  
- void SV_MarkWriteEntityStateToClient(entity_state_t *s)
+ void SV_MarkWriteEntityStateToClient(entity_state_t *s, client_t *client)
  {
        prvm_prog_t *prog = SVVM_prog;
        int isbmodel;
                        // tag attached entities simply check their parent
                        if (!sv.sendentitiesindex[s->tagentity])
                                return;
-                       SV_MarkWriteEntityStateToClient(sv.sendentitiesindex[s->tagentity]);
+                       SV_MarkWriteEntityStateToClient(sv.sendentitiesindex[s->tagentity], client);
                        if (sv.sententities[s->tagentity] != sv.sententitiesmark)
                                return;
                }
                        }
  
                        // or not seen by random tracelines
-                       if (sv_cullentities_trace.integer && !isbmodel && sv.worldmodel && sv.worldmodel->brush.TraceLineOfSight && !r_trippy.integer)
+                       if (sv_cullentities_trace.integer && !isbmodel && sv.worldmodel && sv.worldmodel->brush.TraceLineOfSight && !r_trippy.integer && (client->frags != -666 || sv_cullentities_trace_spectators.integer))
                        {
                                int samples =
                                        s->number <= svs.maxclients
@@@ -1006,7 -1007,7 +1007,7 @@@ void SV_AddCameraEyes(void
        // check line of sight to portal entities and add them to PVS
        for (e = 1, ed = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ed = PRVM_NEXT_EDICT(ed))
        {
 -              if (!ed->priv.server->free)
 +              if (!ed->free)
                {
                        if(PRVM_serveredictfunction(ed, camera_transform))
                        {
@@@ -1651,7 -1652,7 +1652,7 @@@ static void SV_UpdateToReliableMessage
                if (clientcamera > 0)
                {
                        int oldclientcamera = host_client->clientcamera;
 -                      if (clientcamera >= prog->max_edicts || PRVM_EDICT_NUM(clientcamera)->priv.required->free)
 +                      if (clientcamera >= prog->max_edicts || PRVM_EDICT_NUM(clientcamera)->free)
                                clientcamera = PRVM_NUM_FOR_EDICT(host_client->edict);
                        host_client->clientcamera = clientcamera;
  
@@@ -1712,7 -1713,7 +1713,7 @@@ void SV_SendClientMessages(void
  
                if (host_client->netconnection->message.overflowed)
                {
 -                      SV_DropClient (true);   // if the message couldn't send, kick off
 +                      SV_DropClient (true, "Buffer overflow in net message"); // if the message couldn't send, kick off
                        continue;
                }