]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_main.c
Rework game specific hacks to have a special group for Nexuiz-derived games.
[xonotic/darkplaces.git] / sv_main.c
index d94bb0321ec868dcd887d062bb05f54571071a7b..84a4d8c3fbf98e1687221b46dafb2992d15a57a5 100644 (file)
--- a/sv_main.c
+++ b/sv_main.c
@@ -113,9 +113,8 @@ cvar_t sv_gameplayfix_nogravityonground = {0, "sv_gameplayfix_nogravityonground"
 cvar_t sv_gameplayfix_setmodelrealbox = {0, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"};
 cvar_t sv_gameplayfix_slidemoveprojectiles = {0, "sv_gameplayfix_slidemoveprojectiles", "1", "allows MOVETYPE_FLY/FLYMISSILE/TOSS/BOUNCE/BOUNCEMISSILE entities to finish their move in a frame even if they hit something, fixes 'gravity accumulation' bug for grenades on steep slopes"};
 cvar_t sv_gameplayfix_stepdown = {0, "sv_gameplayfix_stepdown", "0", "attempts to step down stairs, not just up them (prevents the familiar thud..thud..thud.. when running down stairs and slopes)"};
-cvar_t sv_gameplayfix_stepwhilejumping = {0, "sv_gameplayfix_stepwhilejumping", "1", "applies step-up onto a ledge even while airborn, useful if you would otherwise just-miss the floor when running across small areas with gaps (for instance running across the moving platforms in dm2, or jumping to the megahealth and red armor in dm2 rather than using the bridge)"};
 cvar_t sv_gameplayfix_stepmultipletimes = {0, "sv_gameplayfix_stepmultipletimes", "0", "applies step-up onto a ledge more than once in a single frame, when running quickly up stairs"};
-cvar_t sv_gameplayfix_nostepmoveonsteepslopes = {0, "sv_gameplayfix_nostepmoveonsteepslopes", "0", "grude fix which prevents MOVETYPE_STEP (not swimming or flying) to move on slopes whose angle is bigger than 45 degree"};
+cvar_t sv_gameplayfix_nostepmoveonsteepslopes = {0, "sv_gameplayfix_nostepmoveonsteepslopes", "0", "crude fix which prevents MOVETYPE_STEP (not swimming or flying) to move on slopes whose angle is bigger than 45 degree"};
 cvar_t sv_gameplayfix_swiminbmodels = {0, "sv_gameplayfix_swiminbmodels", "1", "causes pointcontents (used to determine if you are in a liquid) to check bmodel entities as well as the world model, so you can swim around in (possibly moving) water bmodel entities"};
 cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {0, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"};
 cvar_t sv_gameplayfix_downtracesupportsongroundflag = {0, "sv_gameplayfix_downtracesupportsongroundflag", "1", "prevents very short moves from clearing onground (which may make the player stick to the floor at high netfps)"};
@@ -125,7 +124,7 @@ cvar_t sv_gameplayfix_unstickentities = {0, "sv_gameplayfix_unstickentities", "1
 cvar_t sv_gameplayfix_fixedcheckwatertransition = {0, "sv_gameplayfix_fixedcheckwatertransition", "1", "fix two very stupid bugs in SV_CheckWaterTransition when watertype is CONTENTS_EMPTY (the bugs causes waterlevel to be 1 on first frame, -1 on second frame - the fix makes it 0 on both frames)"};
 cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800", "how fast you fall (512 = roughly earth gravity)"};
 cvar_t sv_idealpitchscale = {0, "sv_idealpitchscale","0.8", "how much to look up/down slopes and stairs when not using freelook"};
-cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "0", "whether you can step up while jumping (sv_gameplayfix_stepwhilejumping must also be 1)"};
+cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "0", "whether you can step up while jumping"};
 cvar_t sv_jumpvelocity = {0, "sv_jumpvelocity", "270", "cvar that can be used by QuakeC code for jump velocity"};
 cvar_t sv_maxairspeed = {0, "sv_maxairspeed", "30", "maximum speed a player can accelerate to when airborn (note that it is possible to completely stop by moving the opposite direction)"};
 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "1000000", "upper limit on client rate cvar, should reflect your network connection quality"};
@@ -523,7 +522,6 @@ void SV_Init (void)
        Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
        Cvar_RegisterVariable (&sv_gameplayfix_slidemoveprojectiles);
        Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
-       Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
        Cvar_RegisterVariable (&sv_gameplayfix_stepmultipletimes);
        Cvar_RegisterVariable (&sv_gameplayfix_nostepmoveonsteepslopes);
        Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
@@ -1030,7 +1028,9 @@ void SV_SendServerinfo (client_t *client)
        MSG_WriteByte (&client->netconnection->message, svc_signonnum);
        MSG_WriteByte (&client->netconnection->message, 1);
 
+       client->prespawned = false;             // need prespawn, spawn, etc
        client->spawned = false;                // need prespawn, spawn, etc
+       client->begun = false;                  // need prespawn, spawn, etc
        client->sendsignon = 1;                 // send this message, and increment to 2, 2 will be set to 0 by the prespawn command
 
        // clear movement info until client enters the new level properly
@@ -1094,7 +1094,9 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection)
 
        strlcpy(client->name, "unconnected", sizeof(client->name));
        strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
+       client->prespawned = false;
        client->spawned = false;
+       client->begun = false;
        client->edict = PRVM_EDICT_NUM(clientnum+1);
        if (client->netconnection)
                client->netconnection->message.allowoverflow = true;            // we can catch it
@@ -1103,9 +1105,6 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection)
        client->unreliablemsg.maxsize = sizeof(client->unreliablemsg_data);
        // updated by receiving "rate" command from client, this is also the default if not using a DP client
        client->rate = 1000000000;
-       // no limits for local player
-       if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
-               client->rate = 1000000000;
        client->connecttime = realtime;
 
        if (!sv.loadgame)
@@ -1127,7 +1126,7 @@ void SV_ConnectClient (int clientnum, netconn_t *netconnection)
        if (client->netconnection)
                SV_SendServerinfo (client);
        else
-               client->spawned = true;
+               client->prespawned = client->spawned = client->begun = true;
 }
 
 
@@ -2210,7 +2209,7 @@ void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t
                MSG_WriteByte (msg, stats[STAT_NAILS]);
                MSG_WriteByte (msg, stats[STAT_ROCKETS]);
                MSG_WriteByte (msg, stats[STAT_CELLS]);
-               if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
+               if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_QUOTH || IS_OLDNEXUIZ_DERIVED(gamemode))
                {
                        for (i = 0;i < 32;i++)
                                if (stats[STAT_ACTIVEWEAPON] & (1<<i))
@@ -2237,7 +2236,7 @@ void SV_FlushBroadcastMessages(void)
                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])))
+               if (!client->begun || !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;
@@ -2289,6 +2288,7 @@ static void SV_SendClientDatagram (client_t *client)
        sizebuf_t msg;
        int stats[MAX_CL_STATS];
        static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE];
+       double timedelta;
 
        // obey rate limit by limiting packet frequency if the packet size
        // limiting fails
@@ -2336,13 +2336,31 @@ static void SV_SendClientDatagram (client_t *client)
                //
                // at very low rates (or very small sys_ticrate) the packet size is
                // not reduced below 128, but packets may be sent less often
-               maxsize = (int)(clientrate * sys_ticrate.value);
+
+               // how long are bursts?
+               timedelta = host_client->rate_burstsize / (double)client->rate;
+
+               // how much of the burst do we keep reserved?
+               timedelta *= 1 - net_burstreserve.value;
+
+               // only try to use excess time
+               timedelta = bound(0, realtime - host_client->netconnection->cleartime, timedelta);
+
+               // but we know next packet will be in sys_ticrate, so we can use up THAT bandwidth
+               timedelta += sys_ticrate.value;
+
+               // note: packet overhead (not counted in maxsize) is 28 bytes
+               maxsize = (int)(clientrate * timedelta) - 28;
+
+               // put it in sound bounds
                maxsize = bound(128, maxsize, 1400);
                maxsize2 = 1400;
+
                // csqc entities can easily exceed 128 bytes, so disable throttling in
                // mods that use csqc (they are likely to use less bandwidth anyway)
-               if (sv.csqc_progsize > 0)
+               if((net_usesizelimit.integer == 1) ? (sv.csqc_progsize > 0) : (net_usesizelimit.integer < 1))
                        maxsize = maxsize2;
+
                break;
        }
 
@@ -2365,7 +2383,7 @@ static void SV_SendClientDatagram (client_t *client)
        msg.cursize = 0;
        msg.allowoverflow = false;
 
-       if (host_client->spawned)
+       if (host_client->begun)
        {
                // the player is in the game
                MSG_WriteByte (&msg, svc_time);
@@ -2425,7 +2443,7 @@ static void SV_SendClientDatagram (client_t *client)
        SV_WriteDemoMessage(client, &msg, false);
 
 // send the datagram
-       NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate, client->sendsignon == 2);
+       NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate, client->rate_burstsize, client->sendsignon == 2);
        if (client->sendsignon == 1 && !client->netconnection->message.cursize)
                client->sendsignon = 2; // prevent reliable until client sends prespawn (this is the keepalive phase)
 }
@@ -2460,7 +2478,7 @@ static void SV_UpdateToReliableMessages (void)
                PRVM_serveredictstring(host_client->edict, netname) = PRVM_SetEngineString(prog, host_client->name);
                if (strcmp(host_client->old_name, host_client->name))
                {
-                       if (host_client->spawned)
+                       if (host_client->begun)
                                SV_BroadcastPrintf("%s ^7changed name to %s\n", host_client->old_name, host_client->name);
                        strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
                        // send notification to all clients
@@ -2515,8 +2533,8 @@ static void SV_UpdateToReliableMessages (void)
 
                // frags
                host_client->frags = (int)PRVM_serveredictfloat(host_client->edict, frags);
-               if(gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC)
-                       if(!host_client->spawned && host_client->netconnection)
+               if(IS_OLDNEXUIZ_DERIVED(gamemode))
+                       if(!host_client->begun && host_client->netconnection)
                                host_client->frags = -666;
                if (host_client->old_frags != host_client->frags)
                {
@@ -2529,7 +2547,7 @@ static void SV_UpdateToReliableMessages (void)
        }
 
        for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
-               if (client->netconnection && (client->spawned || client->clientconnectcalled)) // also send MSG_ALL to people who are past ClientConnect, but not spawned yet
+               if (client->netconnection && (client->begun || client->clientconnectcalled)) // also send MSG_ALL to people who are past ClientConnect, but not spawned yet
                        SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
 
        SZ_Clear (&sv.reliable_datagram);
@@ -3054,7 +3072,7 @@ static void SV_CreateBaseline (void)
        int i, entnum, large;
        prvm_edict_t *svent;
 
-       // LordHavoc: clear *all* states (note just active ones)
+       // LordHavoc: clear *all* baselines (not just active ones)
        for (entnum = 0;entnum < prog->max_edicts;entnum++)
        {
                // get the current server version
@@ -3436,7 +3454,7 @@ void SV_SpawnServer (const char *server)
        // and we need to set the ->edict pointers to point into the progs edicts
        for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
        {
-               host_client->spawned = false;
+               host_client->begun = false;
                host_client->edict = PRVM_EDICT_NUM(i + 1);
                PRVM_ED_ClearEdict(prog, host_client->edict);
        }
@@ -3500,7 +3518,7 @@ void SV_SpawnServer (const char *server)
                        PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(host_client->edict);
                        prog->ExecuteProgram(prog, PRVM_serverfunction(ClientConnect), "QC function ClientConnect is missing");
                        prog->ExecuteProgram(prog, PRVM_serverfunction(PutClientInServer), "QC function PutClientInServer is missing");
-                       host_client->spawned = true;
+                       host_client->begun = true;
                }
        }
 
@@ -3711,7 +3729,7 @@ static void SV_VM_Setup(void)
        prog->error_cmd             = Host_Error;
        prog->ExecuteProgram        = SVVM_ExecuteProgram;
 
-       PRVM_Prog_Load(prog, sv_progs.string, SV_REQFUNCS, sv_reqfuncs, SV_REQFIELDS, sv_reqfields, SV_REQGLOBALS, sv_reqglobals);
+       PRVM_Prog_Load(prog, sv_progs.string, NULL, 0, SV_REQFUNCS, sv_reqfuncs, SV_REQFIELDS, sv_reqfields, SV_REQGLOBALS, sv_reqglobals);
 
        // some mods compiled with scrambling compilers lack certain critical
        // global names and field names such as "self" and "time" and "nextthink"
@@ -3896,7 +3914,7 @@ static int SV_ThreadFunc(void *voiddata)
                playing = false;
                if (sv.active)
                        for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
-                               if(host_client->spawned)
+                               if(host_client->begun)
                                        if(host_client->netconnection)
                                                playing = true;
                if(sv.time < 10)