diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index a6f96580c..bbbb8f417 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -10140,6 +10140,30 @@ static void QCBUILTIN PF_pointerstat(pubprogfuncs_t *prinst, struct globalvars_s SV_QCStatPtr(type, prinst->stringtable+addr, num); } +//void(entity e, vector flags, entity target) setsendneeded +static void QCBUILTIN PF_setsendneeded(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + unsigned int subject = G_EDICTNUM(svprogfuncs, OFS_PARM0); + quint64_t fl = (((quint64_t)G_FLOAT(OFS_PARM1+0)&0xffffff)<<(SENDFLAGS_SHIFT+ 0)) + | (((quint64_t)G_FLOAT(OFS_PARM1+1)&0xffffff)<<(SENDFLAGS_SHIFT+24)) + | (((quint64_t)G_FLOAT(OFS_PARM1+2)&0xffffff)<<(SENDFLAGS_SHIFT+48)); + unsigned int to = G_EDICTNUM(svprogfuncs, OFS_PARM2); + if (!to) + { //broadcast + for (to = 0; to < sv.allocated_client_slots; to++) + if (svs.clients[to].pendingcsqcbits) + svs.clients[to].pendingcsqcbits[subject] |= fl; + } + else + { + to--; + if (to >= sv.allocated_client_slots || !svs.clients[to].pendingcsqcbits) + return; //some kind of error. + else + svs.clients[to].pendingcsqcbits[subject] |= fl; + } +} + //EXT_CSQC_1 static void QCBUILTIN PF_runclientphys(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { @@ -11312,6 +11336,7 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"clientstat", PF_clientstat, 0, 0, 0, 232, D("void(float num, float type, .__variant fld)", "Specifies what data to use in order to send various stats, in a client-specific way.\n'num' should be a value between 32 and 127, other values are reserved.\n'type' must be set to one of the EV_* constants, one of EV_FLOAT, EV_STRING, EV_INTEGER, EV_ENTITY.\nfld must be a reference to the field used, each player will be sent only their own copy of these fields.")}, //EXT_CSQC {"globalstat", PF_globalstat, 0, 0, 0, 233, D("void(float num, float type, string name)", "Specifies what data to use in order to send various stats, in a non-client-specific way. num and type are as in clientstat, name however, is the name of the global to read in the form of a string (pass \"foo\").")}, //EXT_CSQC_1 actually {"pointerstat", PF_pointerstat, 0, 0, 0, 0, D("void(float num, float type, __variant *address)", "Specifies what data to use in order to send various stats, in a non-client-specific way. num and type are as in clientstat, address however, is the address of the variable you would like to use (pass &foo).")}, + {"setsendneeded", PF_setsendneeded, 0, 0, 0, 0, D("void(entity ent, vector sendflags, entity unicastplayer)", "Flags the entity as needing to be resent. This builtin allows for more bits than supported by the SendEntity field, as well as allows flagging sends to specific players.")}, //END EXT_CSQC {"isbackbuffered", PF_isbackbuffered, 0, 0, 0, 234, D("float(entity player)", "Returns if the given player's network buffer will take multiple network frames in order to clear. If this builtin returns non-zero, you should delay or reduce the amount of reliable (and also unreliable) data that you are sending to that client.")}, {"rotatevectorsbyangle",PF_rotatevectorsbyangles,0,0, 0, 235, D("void(vector angle)", "rotates the v_forward,v_right,v_up matrix by the specified angles.")}, // #235 diff --git a/engine/server/server.h b/engine/server/server.h index 597009761..c471c17f8 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -352,7 +352,7 @@ typedef struct { unsigned int entnum; unsigned int bits; //delta (fte or dpp5+) - unsigned int flags; //csqc + quint64_t flags; //csqc } *resend; unsigned int numresend; unsigned int maxresend; @@ -589,12 +589,14 @@ typedef struct client_s } frameunion; packet_entities_t sentents; unsigned int *pendingdeltabits; - unsigned int *pendingcsqcbits; + quint64_t *pendingcsqcbits; unsigned int nextdeltaindex; //splurged round-robin to deal with overflows unsigned int nextcsqcindex; //splurged round-robin - #define SENDFLAGS_USABLE 0x3fffffffu //this number of bits are actually safe in a float. not all together, but otherwise safe. - #define SENDFLAGS_PRESENT 0x80000000u //this entity is present on that client - #define SENDFLAGS_REMOVED 0x40000000u //to handle remove packetloss + #define SENDFLAGS_PRESENT 0x1u //this entity is present on that client + #define SENDFLAGS_REMOVED 0x2u //to handle remove packetloss + #define SENDFLAGS_RESERVED (SENDFLAGS_PRESENT|SENDFLAGS_REMOVED) + #define SENDFLAGS_SHIFT 2u + #define SENDFLAGS_USABLE (~(quint64_t)SENDFLAGS_RESERVED) //this number of bits are actually safe in a float. not all together, but otherwise safe. #ifdef HAVE_LEGACY char *dlqueue; //name\name delimited list of files to ask the client to download. diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 36a09e4ff..ed9c68a3c 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -303,6 +303,7 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) int entnum; client_frame_t *frame = &client->frameunion.frames[currentsequence & UPDATE_MASK]; int lognum = frame->numresend; + quint64_t bits; struct resendinfo_s *resend = frame->resend; int maxlog = frame->maxresend; @@ -385,11 +386,16 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) if (!(client->pendingcsqcbits[entnum] & SENDFLAGS_PRESENT)) client->pendingcsqcbits[entnum] = SENDFLAGS_USABLE; //this entity appears new. make sure its fully transmitted. + bits = client->pendingcsqcbits[entnum]; + client->pendingcsqcbits[entnum] = 0; + csqcmsgbuffer.cursize = 0; csqcmsgbuffer.currentbit = 0; //Ask CSQC to write a buffer for it. G_INT(OFS_PARM0) = viewerent; - G_FLOAT(OFS_PARM1) = (int)(client->pendingcsqcbits[entnum] & 0xffffff); + G_FLOAT(OFS_PARM1+0) = (int)((bits>>(SENDFLAGS_SHIFT+ 0)) & 0xffffff); //each float can only hold 24 bits before it forgets its lower bits. + G_FLOAT(OFS_PARM1+1) = (int)((bits>>(SENDFLAGS_SHIFT+24)) & 0xffffff); + G_FLOAT(OFS_PARM1+2) = (int)((bits>>(SENDFLAGS_SHIFT+48)) & 0xffffff); pr_global_struct->self = EDICT_TO_PROG(svprogfuncs, ent); PR_ExecuteProgram(svprogfuncs, ent->xv->SendEntity); @@ -401,22 +407,27 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) //warn when the message is larger than the user's max size.. if (csqcmsgbuffer.cursize+5 > msg->maxsize) Con_ThrottlePrintf(&throttle, 0, "CSQC update of entity %i(%s) is larger than user %s's maximum datagram size (%u > %u).\n", entnum, PR_GetString(svprogfuncs, ent->v->classname), client->name, csqcmsgbuffer.cursize, msg->maxsize-5); + + client->pendingcsqcbits[entnum] = bits; if (csqcmsgbuffer.cursize < 32) break; - continue; + continue; //might be able to fit a different ent in there. } if (lognum > maxlog) { if (maxlog == client->max_net_ents) + { + client->pendingcsqcbits[entnum] = bits; break; + } SV_ExpandNackFrames(client, lognum+1, &frame); resend = frame->resend; maxlog = frame->maxresend; } resend[lognum].entnum = entnum; resend[lognum].bits = 0; - resend[lognum].flags = SENDFLAGS_PRESENT|client->pendingcsqcbits[entnum]; + resend[lognum].flags = SENDFLAGS_PRESENT|bits; lognum++; if (!writtenheader) @@ -433,20 +444,26 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) } SZ_Write(msg, csqcmsgbuffer.data, csqcmsgbuffer.cursize); - client->pendingcsqcbits[entnum] = SENDFLAGS_PRESENT; + client->pendingcsqcbits[entnum] |= SENDFLAGS_PRESENT; // Con_Printf("Sending update packet %i\n", ent->entnum); } - else if ((client->pendingcsqcbits[entnum] & SENDFLAGS_PRESENT) && !((int)ent->xv->pvsflags & PVSF_NOREMOVE)) + else if ((bits & SENDFLAGS_PRESENT) && !((int)ent->xv->pvsflags & PVSF_NOREMOVE)) { //Don't want to send, but they have it already if (msg->cursize + 5 >= msg->maxsize) + { + client->pendingcsqcbits[entnum] = bits; break; //we're overflowing, try removing next frame instead. + } if (lognum > maxlog) { if (maxlog == client->max_net_ents) + { + client->pendingcsqcbits[entnum] = bits; break; + } SV_ExpandNackFrames(client, lognum+1, &frame); resend = frame->resend; maxlog = frame->maxresend; @@ -465,7 +482,7 @@ void SV_EmitCSQCUpdate(client_t *client, sizebuf_t *msg, qbyte svcnumber) SV_EmitDeltaEntIndex(msg, entnum, true, client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS); // Con_Printf("Sending remove 2 packet\n"); - client->pendingcsqcbits[entnum] = 0; +// client->pendingcsqcbits[entnum] = 0; } } @@ -4279,7 +4296,7 @@ void SV_ProcessSendFlags(client_t *c) continue; if (ent->xv->SendFlags) { - c->pendingcsqcbits[e] |= (int)ent->xv->SendFlags & SENDFLAGS_USABLE; + c->pendingcsqcbits[e] |= (qint64_t)ent->xv->SendFlags << SENDFLAGS_SHIFT; h = e; } }