]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_main.c
fixed bug where animated mdl skins (such as Tomaz's health box and
[xonotic/darkplaces.git] / sv_main.c
index 5a09477d1f650c44c290257676fd8e3081c5a61e..7b89111e60d83f81163ef785b0450171ff01248d 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -370,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)
@@ -558,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;
@@ -719,9 +734,13 @@ qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int
        if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float)
                cs->effects |= EF_FULLBRIGHT;
 
+       val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.modelflags);
+       if (val && val->_float)
+               cs->effects |= ((unsigned int)val->_float & 0xff) << 24;
+
        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;
@@ -815,18 +834,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;
@@ -1312,14 +1319,29 @@ 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;
-       for (numsegments = 0;numsegments < client->unreliablemsg_splitpoints;numsegments++)
-               if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > msg->maxsize)
-                       break;
+       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];
-               SZ_Write(msg, client->unreliablemsg.data, split);
+               // 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)
@@ -1339,36 +1361,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;
        }
 
@@ -1381,7 +1409,16 @@ 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);
@@ -1439,7 +1476,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);
 }
 
 /*
@@ -1472,7 +1509,7 @@ void SV_UpdateToReliableMessages (void)
                if (strcmp(host_client->old_name, host_client->name))
                {
                        if (host_client->spawned)
-                               SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
+                               SV_BroadcastPrintf("%s^%i changed name to %s\n", host_client->old_name, STRING_COLOR_DEFAULT, host_client->name);
                        strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
                        // send notification to all clients
                        MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
@@ -2418,6 +2455,19 @@ void SV_VM_CB_InitEdict(prvm_edict_t *e)
                        PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
                if( prog->fieldoffsets.playerskin >= 0 )
                        PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
+               // Assign netaddress (IP Address, etc)
+               if(prog->fieldoffsets.netaddress >= 0)
+               { // Valid Field; Process
+                       if(svs.clients[num].netconnection != NULL)
+                       {// Valid Address; Assign
+                               // Acquire Readable Address
+                               LHNETADDRESS_ToString(&svs.clients[num].netconnection->peeraddress, svs.clients[num].netaddress, sizeof(svs.clients[num].netaddress), false);
+                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString(svs.clients[num].netaddress);
+                       }
+                       else
+                               // Invalid / Bot
+                               PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString("null/botclient");
+               }
        }
 }
 
@@ -2572,6 +2622,7 @@ prvm_required_field_t reqfields[] =
        {ev_entity, "nodrawtoclient"},
        {ev_entity, "tag_entity"},
        {ev_entity, "viewmodelforclient"},
+       {ev_float, "Version"},
        {ev_float, "alpha"},
        {ev_float, "ammo_cells1"},
        {ev_float, "ammo_lava_nails"},
@@ -2607,6 +2658,7 @@ prvm_required_field_t reqfields[] =
        {ev_float, "idealpitch"},
        {ev_float, "items2"},
        {ev_float, "light_lev"},
+       {ev_float, "modelflags"},
        {ev_float, "pflags"},
        {ev_float, "ping"},
        {ev_float, "pitch_speed"},
@@ -2616,8 +2668,13 @@ prvm_required_field_t reqfields[] =
        {ev_float, "scale"},
        {ev_float, "style"},
        {ev_float, "tag_index"},
-       {ev_float, "Version"},
        {ev_float, "viewzoom"},
+       {ev_function, "SendEntity"},
+       {ev_function, "contentstransition"}, // DRESK - Support for Entity Contents Transition Event
+       {ev_function, "customizeentityforclient"},
+       {ev_string, "netaddress"},
+       {ev_string, "playermodel"},
+       {ev_string, "playerskin"},
        {ev_vector, "color"},
        {ev_vector, "colormod"},
        {ev_vector, "cursor_screen"},
@@ -2625,12 +2682,6 @@ prvm_required_field_t reqfields[] =
        {ev_vector, "cursor_trace_start"},
        {ev_vector, "movement"},
        {ev_vector, "punchvector"},
-       {ev_string, "playermodel"},
-       {ev_string, "playerskin"},
-       {ev_function, "SendEntity"},
-       {ev_function, "customizeentityforclient"},
-       // DRESK - Support for Entity Contents Transition Event
-       {ev_function, "contentstransition"},
 };
 
 void SV_VM_Setup(void)