]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_main.c
disable some debugging code that caused an empty packet to be sent each
[xonotic/darkplaces.git] / sv_main.c
index e3234ab4c7759a514ae7bc0913d893f3f7abdacd..e3c71e66cfd73779e9043a3e9d9fd68916e5760f 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -25,10 +25,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 void SV_VM_Init();
 void SV_VM_Setup();
 
-void VM_AutoSentStats_Clear (void);
+void VM_CustomStats_Clear (void);
 void EntityFrameCSQC_ClearVersions (void);
 void EntityFrameCSQC_InitClientVersions (int client, qboolean clear);
-void VM_SV_WriteAutoSentStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
+void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
 void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_state_t *states);
 
 
@@ -209,6 +209,7 @@ void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
                MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
        MSG_WriteByte (&sv.datagram, count);
        MSG_WriteByte (&sv.datagram, color);
+       SV_FlushBroadcastMessages();
 }
 
 /*
@@ -246,6 +247,7 @@ void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount,
                MSG_WriteByte (&sv.datagram, framecount);
                MSG_WriteByte (&sv.datagram, framerate);
        }
+       SV_FlushBroadcastMessages();
 }
 
 /*
@@ -325,6 +327,7 @@ void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int v
                MSG_WriteByte (&sv.datagram, sound_num);
        for (i = 0;i < 3;i++)
                MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
+       SV_FlushBroadcastMessages();
 }
 
 /*
@@ -367,6 +370,9 @@ void SV_SendServerinfo (client_t *client)
        if (client->entitydatabase5)
                EntityFrame5_FreeDatabase(client->entitydatabase5);
 
+       memset(client->stats, 0, sizeof(client->stats));
+       memset(client->statsdeltabits, 0, sizeof(client->statsdeltabits));
+
        if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
        {
                if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
@@ -495,6 +501,9 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection)
        client->edict = PRVM_EDICT_NUM(clientnum+1);
        if (client->netconnection)
                client->netconnection->message.allowoverflow = true;            // we can catch it
+       // prepare the unreliable message buffer
+       client->unreliablemsg.data = client->unreliablemsg_data;
+       client->unreliablemsg.maxsize = sizeof(client->unreliablemsg_data);
        // updated by receiving "rate" command from client
        client->rate = NET_MINRATE;
        // no limits for local player
@@ -534,17 +543,6 @@ FRAME UPDATES
 ===============================================================================
 */
 
-/*
-==================
-SV_ClearDatagram
-
-==================
-*/
-void SV_ClearDatagram (void)
-{
-       SZ_Clear (&sv.datagram);
-}
-
 /*
 =============================================================================
 
@@ -563,6 +561,18 @@ static int numsendentities;
 static entity_state_t sendentities[MAX_EDICTS];
 static entity_state_t *sendentitiesindex[MAX_EDICTS];
 
+static int sententitiesmark = 0;
+static int sententities[MAX_EDICTS];
+static int sententitiesconsideration[MAX_EDICTS];
+static int sv_writeentitiestoclient_culled_pvs;
+static int sv_writeentitiestoclient_culled_trace;
+static int sv_writeentitiestoclient_visibleentities;
+static int sv_writeentitiestoclient_totalentities;
+//static entity_frame_t sv_writeentitiestoclient_entityframe;
+static int sv_writeentitiestoclient_clentnum;
+static vec3_t sv_writeentitiestoclient_testeye;
+static client_t *sv_writeentitiestoclient_client;
+
 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
 {
        int i;
@@ -726,7 +736,7 @@ qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int
 
        if (ent->fields.server->movetype == MOVETYPE_STEP)
                cs->flags |= RENDER_STEP;
-       if ((cs->effects & EF_LOWPRECISION) && cs->origin[0] >= -32768 && cs->origin[1] >= -32768 && cs->origin[2] >= -32768 && cs->origin[0] <= 32767 && cs->origin[1] <= 32767 && cs->origin[2] <= 32767)
+       if (cs->number != sv_writeentitiestoclient_clentnum/* && (cs->effects & EF_LOWPRECISION)*/ && cs->origin[0] >= -32768 && cs->origin[1] >= -32768 && cs->origin[2] >= -32768 && cs->origin[0] <= 32767 && cs->origin[1] <= 32767 && cs->origin[2] <= 32767)
                cs->flags |= RENDER_LOWPRECISION;
        if (ent->fields.server->colormap >= 1024)
                cs->flags |= RENDER_COLORMAPPED;
@@ -820,18 +830,6 @@ void SV_PrepareEntitiesForSending(void)
        }
 }
 
-static int sententitiesmark = 0;
-static int sententities[MAX_EDICTS];
-static int sententitiesconsideration[MAX_EDICTS];
-static int sv_writeentitiestoclient_culled_pvs;
-static int sv_writeentitiestoclient_culled_trace;
-static int sv_writeentitiestoclient_visibleentities;
-static int sv_writeentitiestoclient_totalentities;
-//static entity_frame_t sv_writeentitiestoclient_entityframe;
-static int sv_writeentitiestoclient_clentnum;
-static vec3_t sv_writeentitiestoclient_testeye;
-static client_t *sv_writeentitiestoclient_client;
-
 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
 {
        int isbmodel;
@@ -977,7 +975,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s)
 entity_state_t sendstates[MAX_EDICTS];
 extern int csqc_clientnum;
 
-void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
+void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg)
 {
        int i, numsendstates;
        entity_state_t *s;
@@ -1026,13 +1024,22 @@ void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *
        EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
 
        if (client->entitydatabase5)
-               EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
+               EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, client->movesequence);
        else if (client->entitydatabase4)
+       {
                EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
+               Protocol_WriteStatsReliable();
+       }
        else if (client->entitydatabase)
+       {
                EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
+               Protocol_WriteStatsReliable();
+       }
        else
+       {
                EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
+               Protocol_WriteStatsReliable();
+       }
 }
 
 /*
@@ -1090,15 +1097,23 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        SV_SetIdealPitch ();            // how much to look up / down ideally
 
 // a fixangle might get lost in a dropped packet.  Oh well.
-       if ( ent->fields.server->fixangle )
+       if(ent->fields.server->fixangle)
+       {
+               // angle fixing was requested by global thinking code...
+               // so store the current angles for later use
+               memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
+               host_client->fixangle_angles_set = TRUE;
+
+               // and clear fixangle for the next frame
+               ent->fields.server->fixangle = 0;
+       }
+
+       if (host_client->fixangle_angles_set)
        {
                MSG_WriteByte (msg, svc_setangle);
                for (i=0 ; i < 3 ; i++)
-                       MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
-               // LordHavoc: moved fixangle = 0 to the physics code so it is
-               // repeatedly sent to predicted clients even though they don't always
-               // move each frame
-               //ent->fields.server->fixangle = 0;
+                       MSG_WriteAngle (msg, host_client->fixangle_angles[i], sv.protocol);
+               host_client->fixangle_angles_set = FALSE;
        }
 
        // stuff the sigil bits into the high bits of items for sbar, or else
@@ -1280,6 +1295,60 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
        }
 }
 
+void SV_FlushBroadcastMessages(void)
+{
+       int i;
+       client_t *client;
+       if (sv.datagram.cursize <= 0)
+               return;
+       for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
+       {
+               if (!client->spawned || !client->netconnection || client->unreliablemsg.cursize + sv.datagram.cursize > client->unreliablemsg.maxsize || client->unreliablemsg_splitpoints >= (int)(sizeof(client->unreliablemsg_splitpoint)/sizeof(client->unreliablemsg_splitpoint[0])))
+                       continue;
+               SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize);
+               client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize;
+       }
+       SZ_Clear(&sv.datagram);
+}
+
+void SV_WriteUnreliableMessages(client_t *client, sizebuf_t *msg)
+{
+       // scan the splitpoints to find out how many we can fit in
+       int numsegments, j, split;
+       if (!client->unreliablemsg_splitpoints)
+               return;
+       // always accept the first one if it's within 1400 bytes, this ensures
+       // that very big datagrams which are over the rate limit still get
+       // through, just to keep it working
+       if (msg->cursize + client->unreliablemsg_splitpoint[0] > msg->maxsize && msg->maxsize < 1400)
+       {
+               numsegments = 1;
+               msg->maxsize = 1400;
+       }
+       else
+               for (numsegments = 0;numsegments < client->unreliablemsg_splitpoints;numsegments++)
+                       if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > msg->maxsize)
+                               break;
+       if (numsegments > 0)
+       {
+               // some will fit, so add the ones that will fit
+               split = client->unreliablemsg_splitpoint[numsegments-1];
+               // note this discards ones that were accepted by the segments scan but
+               // can not fit, such as a really huge first one that will never ever
+               // fit in a packet...
+               if (msg->cursize + split <= msg->maxsize)
+                       SZ_Write(msg, client->unreliablemsg.data, split);
+               // remove the part we sent, keeping any remaining data
+               client->unreliablemsg.cursize -= split;
+               if (client->unreliablemsg.cursize > 0)
+                       memmove(client->unreliablemsg.data, client->unreliablemsg.data + split, client->unreliablemsg.cursize);
+               // adjust remaining splitpoints
+               client->unreliablemsg_splitpoints -= numsegments;
+               for (j = 0;j < client->unreliablemsg_splitpoints;j++)
+                       client->unreliablemsg_splitpoint[j] = client->unreliablemsg_splitpoint[numsegments + j] - split;
+       }
+}
+
 /*
 =======================
 SV_SendClientDatagram
@@ -1288,36 +1357,42 @@ SV_SendClientDatagram
 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
 void SV_SendClientDatagram (client_t *client)
 {
-       int rate, maxrate, maxsize, maxsize2, downloadsize;
+       int clientrate, maxrate, maxsize, maxsize2, downloadsize;
        sizebuf_t msg;
        int stats[MAX_CL_STATS];
 
+       // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
+       maxrate = max(NET_MINRATE, sv_maxrate.integer);
+       if (sv_maxrate.integer != maxrate)
+               Cvar_SetValueQuick(&sv_maxrate, maxrate);
+       // clientrate determines the 'cleartime' of a packet
+       // (how long to wait before sending another, based on this packet's size)
+       clientrate = bound(NET_MINRATE, client->rate, maxrate);
+
        if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
        {
-               // for good singleplayer, send huge packets
+               // for good singleplayer, send huge packets and never limit frequency
+               clientrate = 1000000000;
                maxsize = sizeof(sv_sendclientdatagram_buf);
                maxsize2 = sizeof(sv_sendclientdatagram_buf);
        }
        else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
        {
-               // no rate limiting support on older protocols because dp protocols
-               // 1-4 kick the client off if they overflow, and quake protocol shows
-               // less than the full entity set if rate limited
+               // no packet size limit support on older protocols because DP1-4 kick
+               // the client off if they overflow, and quake protocol shows less than
+               // the full entity set if rate limited
                maxsize = 1400;
                maxsize2 = 1400;
        }
        else
        {
-               // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
-               maxrate = max(NET_MINRATE, sv_maxrate.integer);
-               if (sv_maxrate.integer != maxrate)
-                       Cvar_SetValueQuick(&sv_maxrate, maxrate);
-
+               // DP5 and later protocols support packet size limiting which is a
+               // better method than limiting packet frequency as QW does
+               //
                // this rate limiting does not understand sys_ticrate 0
                // (but no one should be running that on a server!)
-               rate = bound(NET_MINRATE, client->rate, maxrate);
-               rate = (int)(rate * sys_ticrate.value);
-               maxsize = bound(50, rate, 1400);
+               maxsize = (int)(clientrate * sys_ticrate.value);
+               maxsize = bound(100, maxsize, 1400);
                maxsize2 = 1400;
        }
 
@@ -1330,24 +1405,37 @@ void SV_SendClientDatagram (client_t *client)
        msg.maxsize = maxsize;
        msg.cursize = 0;
 
-       if (host_client->spawned)
+       // obey rate limit by limiting packet frequency if the packet size
+       // limiting fails
+       // (usually this is caused by reliable messages)
+       if (!NetConn_CanSend(client->netconnection))
+       {
+               // send the datagram
+               //NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate);
+               return;
+       }
+       else if (host_client->spawned)
        {
                MSG_WriteByte (&msg, svc_time);
                MSG_WriteFloat (&msg, sv.time);
 
                // add the client specific data to the datagram
                SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
-               VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
-               SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
+               // now update the stats[] array using any registered custom fields
+               VM_SV_UpdateCustomStats (client, client->edict, &msg, stats);
+               // set host_client->statsdeltabits
+               Protocol_UpdateClientStats (stats);
 
-               // expand packet size to allow effects to go over the rate limit
-               // (dropping them is FAR too ugly)
-               msg.maxsize = maxsize2;
+               // add as many queued unreliable messages (effects) as we can fit
+               // limit effects to half of the remaining space
+               msg.maxsize -= (msg.maxsize - msg.cursize) / 2;
+               if (client->unreliablemsg.cursize)
+                       SV_WriteUnreliableMessages (client, &msg);
 
-               // copy the server datagram if there is space
-               // FIXME: put in delayed queue of effects to send
-               if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
-                       SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
+               msg.maxsize = maxsize;
+
+               // now write as many entities as we can fit, and also sends stats
+               SV_WriteEntitiesToClient (client, client->edict, &msg);
        }
        else if (realtime > client->keepalivetime)
        {
@@ -1384,7 +1472,7 @@ void SV_SendClientDatagram (client_t *client)
        }
 
 // send the datagram
-       NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
+       NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate);
 }
 
 /*
@@ -1490,6 +1578,8 @@ void SV_SendClientMessages (void)
        if (sv.protocol == PROTOCOL_QUAKEWORLD)
                Sys_Error("SV_SendClientMessages: no quakeworld support\n");
 
+       SV_FlushBroadcastMessages();
+
 // update frags, names, etc
        SV_UpdateToReliableMessages();
 
@@ -2641,7 +2731,7 @@ void SV_VM_Setup(void)
        // OP_STATE is always supported on server (due to entvars_t)
        prog->flag |= PRVM_OP_STATE;
 
-       VM_AutoSentStats_Clear();//[515]: csqc
+       VM_CustomStats_Clear();//[515]: csqc
        EntityFrameCSQC_ClearVersions();//[515]: csqc
 
        PRVM_End;