X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=sv_main.c;h=ac6368249cca465938f4f9b4cb49f219079259cc;hp=048f4f497be156422e90526ff2552059be896d4d;hb=af0b7a1fa11c2ceedeb9f66ca950f6c0bff8ad8f;hpb=d874bf725c78fbab7d23299254232f0de34c046a diff --git a/sv_main.c b/sv_main.c index 048f4f49..ac636824 100644 --- a/sv_main.c +++ b/sv_main.c @@ -20,10 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // sv_main.c -- server main program #include "quakedef.h" -#include "portals.h" static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "0"}; // fast but loose -static cvar_t sv_cullentities_portal = {0, "sv_cullentities_portal", "0"}; // extremely accurate visibility checking, but too slow static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "1"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0"}; static cvar_t sv_entpatch = {0, "sv_entpatch", "1"}; @@ -61,7 +59,6 @@ void SV_Init (void) Cvar_RegisterVariable (&sv_nostep); Cvar_RegisterVariable (&sv_deltacompress); Cvar_RegisterVariable (&sv_cullentities_pvs); - Cvar_RegisterVariable (&sv_cullentities_portal); Cvar_RegisterVariable (&sv_cullentities_trace); Cvar_RegisterVariable (&sv_cullentities_stats); Cvar_RegisterVariable (&sv_entpatch); @@ -72,7 +69,7 @@ void SV_Init (void) for (i = 0;i < MAX_MODELS;i++) sprintf (localmodels[i], "*%i", i); - sv_edicts_mempool = Mem_AllocPool("edicts"); + sv_edicts_mempool = Mem_AllocPool("server edicts"); } /* @@ -248,18 +245,20 @@ void SV_SendServerinfo (client_t *client) char message[128]; // edicts get reallocated on level changes, so we need to update it here - client->edict = EDICT_NUM((client - svs.clients) + 1); + client->edict = EDICT_NUM(client->number + 1); // LordHavoc: clear entityframe tracking client->entityframenumber = 0; - EntityFrame_ClearDatabase(&client->entitydatabase); + if (client->entitydatabase4) + EntityFrame4_FreeDatabase(client->entitydatabase4); + client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_clients_mempool); MSG_WriteByte (&client->message, svc_print); sprintf (message, "\002\nServer: %s build %s (progs %i crc)", gamename, buildstring, pr_crc); MSG_WriteString (&client->message,message); MSG_WriteByte (&client->message, svc_serverinfo); - MSG_WriteLong (&client->message, DPPROTOCOL_VERSION3); + MSG_WriteLong (&client->message, PROTOCOL_DARKPLACES4); MSG_WriteByte (&client->message, svs.maxclients); if (!coop.integer && deathmatch.integer) @@ -313,13 +312,14 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection) if (sv.loadgame) memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms)); memset (client, 0, sizeof(*client)); + client->active = true; client->netconnection = netconnection; Con_DPrintf("Client %s connected\n", client->netconnection->address); strcpy(client->name, "unconnected"); strcpy(client->old_name, "unconnected"); - client->active = true; + client->number = clientnum; client->spawned = false; client->edict = EDICT_NUM(clientnum+1); client->message.data = client->msgbuf; @@ -370,96 +370,8 @@ crosses a waterline. ============================================================================= */ -int fatbytes; -qbyte fatpvs[MAX_MAP_LEAFS/8]; - -void SV_AddToFatPVS (vec3_t org, mnode_t *node) -{ - int i; - qbyte *pvs; - mplane_t *plane; - float d; - - while (1) - { - // if this is a leaf, accumulate the pvs bits - if (node->contents < 0) - { - if (node->contents != CONTENTS_SOLID) - { - pvs = sv.worldmodel->brushq1.LeafPVS(sv.worldmodel, (mleaf_t *)node); - for (i=0 ; iplane; - d = DotProduct (org, plane->normal) - plane->dist; - if (d > 8) - node = node->children[0]; - else if (d < -8) - node = node->children[1]; - else - { // go down both - SV_AddToFatPVS (org, node->children[0]); - node = node->children[1]; - } - } -} - -/* -============= -SV_FatPVS - -Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the -given point. -============= -*/ -qbyte *SV_FatPVS (vec3_t org) -{ - fatbytes = (sv.worldmodel->brushq1.numleafs+31)>>3; - memset (fatpvs, 0, fatbytes); - SV_AddToFatPVS (org, sv.worldmodel->brushq1.nodes); - return fatpvs; -} - -//============================================================================= - - -int SV_BoxTouchingPVS (qbyte *pvs, vec3_t mins, vec3_t maxs, mnode_t *node) -{ - int leafnum; -loc0: - if (node->contents < 0) - { - // leaf - if (node->contents == CONTENTS_SOLID) - return false; - leafnum = (mleaf_t *)node - sv.worldmodel->brushq1.leafs - 1; - return pvs[leafnum >> 3] & (1 << (leafnum & 7)); - } - - // node - recurse down the BSP tree - switch (BoxOnPlaneSide(mins, maxs, node->plane)) - { - case 1: // front - node = node->children[0]; - goto loc0; - case 2: // back - node = node->children[1]; - goto loc0; - default: // crossing - if (node->children[0]->contents != CONTENTS_SOLID) - if (SV_BoxTouchingPVS (pvs, mins, maxs, node->children[0])) - return true; - node = node->children[1]; - goto loc0; - } - // never reached - return false; -} - +int sv_writeentitiestoclient_pvsbytes; +qbyte sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8]; /* ============= @@ -471,7 +383,7 @@ SV_WriteEntitiesToClient void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) { int e, clentnum, bits, alpha, glowcolor, glowsize, scale, effects, lightsize; - int culled_pvs, culled_portal, culled_trace, visibleentities, totalentities; + int culled_pvs, culled_trace, visibleentities, totalentities; qbyte *pvs; vec3_t origin, angles, entmins, entmaxs, testorigin, testeye; float nextfullupdate, alphaf; @@ -484,10 +396,11 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) // find the client's PVS VectorAdd (clent->v->origin, clent->v->view_ofs, testeye); - pvs = SV_FatPVS (testeye); + fatbytes = 0; + if (sv.worldmodel && sv.worldmodel->brush.FatPVS) + fatbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs)); culled_pvs = 0; - culled_portal = 0; culled_trace = 0; visibleentities = 0; totalentities = 0; @@ -585,28 +498,22 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) totalentities++; // if not touching a visible leaf - if (sv_cullentities_pvs.integer && !SV_BoxTouchingPVS(pvs, entmins, entmaxs, sv.worldmodel->brushq1.nodes)) + if (sv_cullentities_pvs.integer && fatbytes && sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, entmins, entmaxs)) { culled_pvs++; continue; } - // or not visible through the portals - if (sv_cullentities_portal.integer && !Portal_CheckBox(sv.worldmodel, testeye, entmins, entmaxs)) - { - culled_portal++; - continue; - } - // don't try to cull embedded brush models with this, they're sometimes huge (spanning several rooms) - if (sv_cullentities_trace.integer && (model == NULL || model->type != mod_brush || model->name[0] != '*')) + if (sv_cullentities_trace.integer && (model == NULL || model->brush.TraceBox == NULL || model->name[0] != '*')) { // LordHavoc: test random offsets, to maximize chance of detection testorigin[0] = lhrandom(entmins[0], entmaxs[0]); testorigin[1] = lhrandom(entmins[1], entmaxs[1]); testorigin[2] = lhrandom(entmins[2], entmaxs[2]); - if (SV_Move(testeye, vec3_origin, vec3_origin, testorigin, MOVE_NOMONSTERS, NULL).fraction == 1) + sv.worldmodel->brush.TraceBox(sv.worldmodel, &trace, testeye, testeye, testorigin, testorigin, SUPERCONTENTS_SOLID); + if (trace.fraction == 1) client->visibletime[e] = realtime + 1; else { @@ -615,7 +522,8 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) testorigin[1] = bound(entmins[1], testeye[1], entmaxs[1]); testorigin[2] = bound(entmins[2], testeye[2], entmaxs[2]); - if (SV_Move(testeye, vec3_origin, vec3_origin, testorigin, MOVE_NOMONSTERS, NULL).fraction == 1) + sv.worldmodel->brush.TraceBox(sv.worldmodel, &trace, testeye, testeye, testorigin, testorigin, SUPERCONTENTS_SOLID); + if (trace.fraction == 1) client->visibletime[e] = realtime + 1; else if (realtime > client->visibletime[e]) { @@ -772,16 +680,16 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) MSG_WriteShort (msg,e); else MSG_WriteByte (msg,e); - if (bits & U_MODEL) MSG_WriteByte (msg, ent->v->modelindex); - if (bits & U_FRAME) MSG_WriteByte (msg, ent->v->frame); - if (bits & U_COLORMAP) MSG_WriteByte (msg, ent->v->colormap); - if (bits & U_SKIN) MSG_WriteByte (msg, ent->v->skin); - if (bits & U_EFFECTS) MSG_WriteByte (msg, ent->v->effects); - if (bits & U_ORIGIN1) MSG_WriteDPCoord (msg, origin[0]); + if (bits & U_MODEL) MSG_WriteByte(msg, ent->v->modelindex); + if (bits & U_FRAME) MSG_WriteByte(msg, ent->v->frame); + if (bits & U_COLORMAP) MSG_WriteByte(msg, ent->v->colormap); + if (bits & U_SKIN) MSG_WriteByte(msg, ent->v->skin); + if (bits & U_EFFECTS) MSG_WriteByte(msg, ent->v->effects); + if (bits & U_ORIGIN1) MSG_WriteDPCoord(msg, origin[0]); if (bits & U_ANGLE1) MSG_WriteAngle(msg, angles[0]); - if (bits & U_ORIGIN2) MSG_WriteDPCoord (msg, origin[1]); + if (bits & U_ORIGIN2) MSG_WriteDPCoord(msg, origin[1]); if (bits & U_ANGLE2) MSG_WriteAngle(msg, angles[1]); - if (bits & U_ORIGIN3) MSG_WriteDPCoord (msg, origin[2]); + if (bits & U_ORIGIN3) MSG_WriteDPCoord(msg, origin[2]); if (bits & U_ANGLE3) MSG_WriteAngle(msg, angles[2]); // LordHavoc: new stuff @@ -795,7 +703,7 @@ void SV_WriteEntitiesToClient (client_t *client, edict_t *clent, sizebuf_t *msg) } if (sv_cullentities_stats.integer) - Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d portal %d trace\n", client->name, totalentities, visibleentities, culled_pvs + culled_portal + culled_trace, culled_pvs, culled_portal, culled_trace); + Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, totalentities, visibleentities, culled_pvs + culled_trace, culled_pvs, culled_trace); } #else static int numsendentities; @@ -805,6 +713,7 @@ static entity_state_t *sendentitiesindex[MAX_EDICTS]; void SV_PrepareEntitiesForSending(void) { int e, i; + float f; edict_t *ent; entity_state_t cs; // send all entities that touch the pvs @@ -842,25 +751,33 @@ void SV_PrepareEntitiesForSending(void) if (i >= 1 && i < MAX_MODELS && *PR_GetString(ent->v->model)) cs.modelindex = i; - cs.alpha = 255; - i = (int)(GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f); - if (i) + f = (GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f); + if (f) + { + i = (int)f; cs.alpha = (qbyte)bound(0, i, 255); + } // halflife - i = (int)(GETEDICTFIELDVALUE(ent, eval_renderamt)->_float); - if (i) + f = (GETEDICTFIELDVALUE(ent, eval_renderamt)->_float); + if (f) + { + i = (int)f; cs.alpha = (qbyte)bound(0, i, 255); + } cs.scale = 16; - i = (int)(GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f); - if (i) + f = (GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f); + if (f) + { + i = (int)f; cs.scale = (qbyte)bound(0, i, 255); + } cs.glowcolor = 254; - i = (int)(GETEDICTFIELDVALUE(ent, eval_glow_color)->_float); - if (i) - cs.glowcolor = i; + f = (GETEDICTFIELDVALUE(ent, eval_glow_color)->_float); + if (f) + cs.glowcolor = (int)f; if (GETEDICTFIELDVALUE(ent, eval_fullbright)->_float) cs.effects |= EF_FULLBRIGHT; @@ -915,13 +832,11 @@ 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_portal; static int sv_writeentitiestoclient_culled_trace; static int sv_writeentitiestoclient_visibleentities; static int sv_writeentitiestoclient_totalentities; -static entity_frame_t sv_writeentitiestoclient_entityframe; +//static entity_frame_t sv_writeentitiestoclient_entityframe; static int sv_writeentitiestoclient_clentnum; -static qbyte *sv_writeentitiestoclient_pvs; static vec3_t sv_writeentitiestoclient_testeye; static client_t *sv_writeentitiestoclient_client; @@ -1002,17 +917,11 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) lightmaxs[2] = min(entmaxs[2], s->origin[2] + s->specialvisibilityradius); sv_writeentitiestoclient_totalentities++; // if not touching a visible leaf - if (sv_cullentities_pvs.integer && !SV_BoxTouchingPVS(sv_writeentitiestoclient_pvs, lightmins, lightmaxs, sv.worldmodel->brushq1.nodes)) + if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes && sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, lightmins, lightmaxs)) { sv_writeentitiestoclient_culled_pvs++; return; } - // or not visible through the portals - if (sv_cullentities_portal.integer && !Portal_CheckBox(sv.worldmodel, sv_writeentitiestoclient_testeye, lightmins, lightmaxs)) - { - sv_writeentitiestoclient_culled_portal++; - return; - } // or not seen by random tracelines if (sv_cullentities_trace.integer) { @@ -1020,7 +929,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) testorigin[0] = (entmins[0] + entmaxs[0]) * 0.5f; testorigin[1] = (entmins[1] + entmaxs[1]) * 0.5f; testorigin[2] = (entmins[2] + entmaxs[2]) * 0.5f; - trace = SV_Move(sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, MOVE_NOMONSTERS, NULL); + sv.worldmodel->brush.TraceBox(sv.worldmodel, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID); if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, entmins, entmaxs)) sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1; else @@ -1029,7 +938,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) testorigin[0] = lhrandom(entmins[0], entmaxs[0]); testorigin[1] = lhrandom(entmins[1], entmaxs[1]); testorigin[2] = lhrandom(entmins[2], entmaxs[2]); - trace = SV_Move(sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, MOVE_NOMONSTERS, NULL); + sv.worldmodel->brush.TraceBox(sv.worldmodel, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID); if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, entmins, entmaxs)) sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1; else @@ -1040,7 +949,7 @@ void SV_MarkWriteEntityStateToClient(entity_state_t *s) testorigin[0] = lhrandom(lightmins[0], lightmaxs[0]); testorigin[1] = lhrandom(lightmins[1], lightmaxs[1]); testorigin[2] = lhrandom(lightmins[2], lightmaxs[2]); - trace = SV_Move(sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, MOVE_NOMONSTERS, NULL); + sv.worldmodel->brush.TraceBox(sv.worldmodel, &trace, sv_writeentitiestoclient_testeye, sv_writeentitiestoclient_testeye, testorigin, testorigin, SUPERCONTENTS_SOLID); if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, entmins, entmaxs)) sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1; } @@ -1066,11 +975,33 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg) int i; vec3_t testorigin; entity_state_t *s; + entity_database4_t *d; + int maxbytes, n, startnumber; + entity_state_t *e, inactiveentitystate; + sizebuf_t buf; + qbyte data[128]; + // prepare the buffer + memset(&buf, 0, sizeof(buf)); + buf.data = data; + buf.maxsize = sizeof(data); + + d = client->entitydatabase4; + + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + if (!d->commit[i].numentities) + break; + // if commit buffer full, just don't bother writing an update this frame + if (i == MAX_ENTITY_HISTORY) + return; + d->currentcommit = d->commit + i; + + // this state's number gets played around with later + ClearStateToDefault(&inactiveentitystate); + //inactiveentitystate = defaultstate; sv_writeentitiestoclient_client = client; sv_writeentitiestoclient_culled_pvs = 0; - sv_writeentitiestoclient_culled_portal = 0; sv_writeentitiestoclient_culled_trace = 0; sv_writeentitiestoclient_visibleentities = 0; sv_writeentitiestoclient_totalentities = 0; @@ -1080,7 +1011,9 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg) // find the client's PVS // the real place being tested from VectorAdd(clent->v->origin, clent->v->view_ofs, sv_writeentitiestoclient_testeye); - sv_writeentitiestoclient_pvs = SV_FatPVS(sv_writeentitiestoclient_testeye); + sv_writeentitiestoclient_pvsbytes = 0; + if (sv.worldmodel && sv.worldmodel->brush.FatPVS) + sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs)); sv_writeentitiestoclient_clentnum = EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes @@ -1098,26 +1031,92 @@ void SV_WriteEntitiesToClient(client_t *client, edict_t *clent, sizebuf_t *msg) for (i = 0;i < numsendentities;i++) SV_MarkWriteEntityStateToClient(sendentities + i); - EntityFrame_Clear(&sv_writeentitiestoclient_entityframe, testorigin, ++client->entityframenumber); - for (i = 0;i < numsendentities;i++) + // calculate maximum bytes to allow in this packet + // deduct 4 to account for the end data + maxbytes = min(msg->maxsize, MAX_PACKETFRAGMENT) - 4; + + d->currentcommit->numentities = 0; + d->currentcommit->framenum = ++client->entityframenumber; + MSG_WriteByte(msg, svc_entities); + MSG_WriteLong(msg, d->referenceframenum); + MSG_WriteLong(msg, d->currentcommit->framenum); + if (developer_networkentities.integer >= 1) { - s = sendentities + i; - if (sententities[s->number] == sententitiesmark) + Con_Printf("send svc_entities ref:%i num:%i (database: ref:%i commits:", d->referenceframenum, d->currentcommit->framenum, d->referenceframenum); + for (i = 0;i < MAX_ENTITY_HISTORY;i++) + if (d->commit[i].numentities) + Con_Printf(" %i", d->commit[i].framenum); + Con_Printf(")\n"); + } + if (d->currententitynumber >= sv.max_edicts) + startnumber = 1; + else + startnumber = bound(1, d->currententitynumber, sv.max_edicts - 1); + MSG_WriteShort(msg, startnumber); + // reset currententitynumber so if the loop does not break it we will + // start at beginning next frame (if it does break, it will set it) + d->currententitynumber = 1; + for (i = 0, n = startnumber;n < sv.max_edicts;n++) + { + // find the old state to delta from + e = EntityFrame4_GetReferenceEntity(d, n); + // prepare the buffer + SZ_Clear(&buf); + // make the message + if (sententities[n] == sententitiesmark) { + // entity exists, build an update (if empty there is no change) + // find the state in the list + for (;i < numsendentities && sendentities[i].number < n;i++); + s = sendentities + i; + if (s->number != n) + Sys_Error("SV_WriteEntitiesToClient: s->number != n\n"); + // build the update if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum) { s->flags |= RENDER_EXTERIORMODEL; - EntityFrame_AddEntity(&sv_writeentitiestoclient_entityframe, s); + EntityState_Write(s, &buf, e); s->flags &= ~RENDER_EXTERIORMODEL; } else - EntityFrame_AddEntity(&sv_writeentitiestoclient_entityframe, s); + EntityState_Write(s, &buf, e); + } + else + { + s = &inactiveentitystate; + s->number = n; + if (e->active) + { + // entity used to exist but doesn't anymore, send remove + MSG_WriteShort(&buf, n | 0x8000); + } + } + // if the commit is full, we're done this frame + if (msg->cursize + buf.cursize > maxbytes) + { + // next frame we will continue where we left off + break; + } + // add the entity to the commit + EntityFrame4_AddCommitEntity(d, s); + // if the message is empty, skip out now + if (buf.cursize) + { + // write the message to the packet + SZ_Write(msg, buf.data, buf.cursize); } } - EntityFrame_Write(&client->entitydatabase, &sv_writeentitiestoclient_entityframe, msg); + d->currententitynumber = n; + + // remove world message (invalid, and thus a good terminator) + MSG_WriteShort(msg, 0x8000); + // write the number of the end entity + MSG_WriteShort(msg, d->currententitynumber); + // just to be sure + d->currentcommit = NULL; if (sv_cullentities_stats.integer) - Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d portal %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_portal + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_portal, sv_writeentitiestoclient_culled_trace); + Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_trace); } #endif @@ -1208,7 +1207,7 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) if ( ent->v->waterlevel >= 2) bits |= SU_INWATER; - // dpprotocol + // PROTOCOL_DARKPLACES VectorClear(punchvector); if ((val = GETEDICTFIELDVALUE(ent, eval_punchvector))) VectorCopy(val->vector, punchvector); @@ -1231,8 +1230,8 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) { if (ent->v->punchangle[i]) bits |= (SU_PUNCH1<v->velocity[i]) bits |= (SU_VELOCITY1<v->punchangle[i]); // dpprotocol - if (bits & (SU_PUNCHVEC1<v->punchangle[i]); // PROTOCOL_DARKPLACES + if (bits & (SU_PUNCHVEC1<v->velocity[i]/16); } @@ -1292,7 +1291,7 @@ void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) MSG_WriteByte (msg, ent->v->ammo_rockets); MSG_WriteByte (msg, ent->v->ammo_cells); - if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE) + if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ) { for(i=0;i<32;i++) { @@ -1361,75 +1360,68 @@ void SV_UpdateToReliableMessages (void) char *s; // check for changes to be sent over the reliable streams - for (i=0, host_client = svs.clients ; ispawned) + // update the host_client fields we care about according to the entity fields + sv_player = EDICT_NUM(i+1); + s = PR_GetString(sv_player->v->netname); + if (s != host_client->name) { - // update the host_client fields we care about according to the entity fields - sv_player = host_client->edict; - s = PR_GetString(sv_player->v->netname); - if (s != host_client->name) - { - if (s == NULL) - s = ""; - // point the string back at host_client->name to keep it safe - strncpy(host_client->name, s, sizeof(host_client->name) - 1); - sv_player->v->netname = PR_SetString(host_client->name); - } - if ((val = GETEDICTFIELDVALUE(sv_player, eval_clientcolors)) && host_client->colors != val->_float) - host_client->colors = val->_float; - host_client->frags = sv_player->v->frags; - if (gamemode == GAME_NEHAHRA) - if ((val = GETEDICTFIELDVALUE(sv_player, eval_pmodel)) && host_client->pmodel != val->_float) - host_client->pmodel = val->_float; - - // if the fields changed, send messages about the changes - if (strcmp(host_client->old_name, host_client->name)) + if (s == NULL) + s = ""; + // point the string back at host_client->name to keep it safe + strlcpy (host_client->name, s, sizeof (host_client->name)); + sv_player->v->netname = PR_SetString(host_client->name); + } + if ((val = GETEDICTFIELDVALUE(sv_player, eval_clientcolors)) && host_client->colors != val->_float) + host_client->colors = val->_float; + host_client->frags = sv_player->v->frags; + if (gamemode == GAME_NEHAHRA) + if ((val = GETEDICTFIELDVALUE(sv_player, eval_pmodel)) && host_client->pmodel != val->_float) + host_client->pmodel = val->_float; + + // if the fields changed, send messages about the changes + if (strcmp(host_client->old_name, host_client->name)) + { + strcpy(host_client->old_name, host_client->name); + for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++) { - strcpy(host_client->old_name, host_client->name); - for (j=0, client = svs.clients ; jactive || !client->spawned) - continue; - MSG_WriteByte (&client->message, svc_updatename); - MSG_WriteByte (&client->message, i); - MSG_WriteString (&client->message, host_client->name); - } + if (!client->spawned || !client->netconnection) + continue; + MSG_WriteByte (&client->message, svc_updatename); + MSG_WriteByte (&client->message, i); + MSG_WriteString (&client->message, host_client->name); } - if (host_client->old_colors != host_client->colors) + } + if (host_client->old_colors != host_client->colors) + { + host_client->old_colors = host_client->colors; + for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++) { - host_client->old_colors = host_client->colors; - for (j=0, client = svs.clients ; jactive || !client->spawned) - continue; - MSG_WriteByte (&client->message, svc_updatecolors); - MSG_WriteByte (&client->message, i); - MSG_WriteByte (&client->message, host_client->colors); - } + if (!client->spawned || !client->netconnection) + continue; + MSG_WriteByte (&client->message, svc_updatecolors); + MSG_WriteByte (&client->message, i); + MSG_WriteByte (&client->message, host_client->colors); } - if (host_client->old_frags != host_client->frags) + } + if (host_client->old_frags != host_client->frags) + { + host_client->old_frags = host_client->frags; + for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++) { - host_client->old_frags = host_client->frags; - for (j=0, client = svs.clients ; jactive || !client->spawned) - continue; - MSG_WriteByte (&client->message, svc_updatefrags); - MSG_WriteByte (&client->message, i); - MSG_WriteShort (&client->message, host_client->frags); - } + if (!client->spawned || !client->netconnection) + continue; + MSG_WriteByte (&client->message, svc_updatefrags); + MSG_WriteByte (&client->message, i); + MSG_WriteShort (&client->message, host_client->frags); } } } - for (j=0, client = svs.clients ; jactive) - continue; - SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize); - } + for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++) + if (client->netconnection) + SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize); SZ_Clear (&sv.reliable_datagram); } @@ -1472,12 +1464,17 @@ void SV_SendClientMessages (void) SV_UpdateToReliableMessages(); // build individual updates - for (i=0, host_client = svs.clients ; iactive) continue; + if (!host_client->netconnection) + { + SZ_Clear(&host_client->message); + continue; + } - if (host_client->deadsocket) + if (host_client->deadsocket || host_client->message.overflowed) { SV_DropClient (true); // if the message couldn't send, kick off continue; @@ -1509,16 +1506,6 @@ void SV_SendClientMessages (void) } } - // check for an overflowed message. Should only happen - // on a very fucked up connection that backs up a lot, then - // changes level - if (host_client->message.overflowed) - { - SV_DropClient (true); // overflowed - host_client->message.overflowed = false; - continue; - } - if (host_client->message.cursize || host_client->dropasap) { if (!NetConn_CanSendMessage (host_client->netconnection)) @@ -1685,7 +1672,7 @@ void SV_SaveSpawnparms (void) svs.serverflags = pr_global_struct->serverflags; - for (i=0, host_client = svs.clients ; iactive) continue; @@ -1719,7 +1706,7 @@ void SV_IncreaseEdicts(void) } SV_ClearWorld(); - sv.max_edicts = min(sv.max_edicts + 32, MAX_EDICTS); + sv.max_edicts = min(sv.max_edicts + 256, MAX_EDICTS); sv.edictsengineprivate = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * sizeof(edict_engineprivate_t)); sv.edictsfields = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * pr_edict_size); sv.moved_edicts = Mem_Alloc(sv_edicts_mempool, sv.max_edicts * sizeof(edict_t *)); @@ -1768,9 +1755,9 @@ void SV_SpawnServer (const char *server) // tell all connected clients that we are going to a new level // if (sv.active) - SV_SendReconnect (); + SV_SendReconnect(); else - NetConn_OpenServerPorts(svs.maxclients > 1); + NetConn_OpenServerPorts(true); // // make cvars consistant @@ -1795,7 +1782,7 @@ void SV_SpawnServer (const char *server) // allocate server memory // start out with just enough room for clients and a reasonable estimate of entities - sv.max_edicts = ((svs.maxclients + 128) + 31) & ~31; + sv.max_edicts = max(svs.maxclients + 1, 512); sv.max_edicts = min(sv.max_edicts, MAX_EDICTS); // clear the edict memory pool @@ -1857,7 +1844,7 @@ void SV_SpawnServer (const char *server) sv.model_precache[0] = ""; sv.model_precache[1] = sv.modelname; - for (i = 1;i < sv.worldmodel->brushq1.numsubmodels;i++) + for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++) { sv.model_precache[i+1] = localmodels[i]; sv.models[i+1] = Mod_ForName (localmodels[i], false, false, false); @@ -1921,9 +1908,9 @@ void SV_SpawnServer (const char *server) #endif // send serverinfo to all connected clients - for (i=0,host_client = svs.clients ; iactive) - SV_SendServerinfo (host_client); + for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++) + if (host_client->netconnection) + SV_SendServerinfo(host_client); Con_DPrintf ("Server spawned.\n"); NetConn_Heartbeat (2);