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)
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;
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;
}
}
-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;
{
// 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)
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;
}
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);
}
// send the datagram
- NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
+ NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate);
}
/*
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);
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");
+ }
}
}
{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"},
{ev_float, "idealpitch"},
{ev_float, "items2"},
{ev_float, "light_lev"},
+ {ev_float, "modelflags"},
{ev_float, "pflags"},
{ev_float, "ping"},
{ev_float, "pitch_speed"},
{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"},
{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)