X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=sv_main.c;h=e3c71e66cfd73779e9043a3e9d9fd68916e5760f;hb=0d5c60506ca1986553db0e5e449fa0d4492d6208;hp=e3234ab4c7759a514ae7bc0913d893f3f7abdacd;hpb=976cd2c64d5f04dfcefe5dd1be7a95ba99c6e973;p=xonotic%2Fdarkplaces.git diff --git a/sv_main.c b/sv_main.c index e3234ab4..e3c71e66 100644 --- 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;